簡體   English   中英

boost.org的Spirit解析器 - 生成器框架有哪些缺點?

[英]What are the disadvantages of the Spirit parser-generator framework from boost.org?

在幾個問題中,我看到了來自boost.orgSpirit解析器 - 生成器框架的建議 ,但是在評論中,人們抱怨使用不開心的Spirit。 請那些人站出來向我們其他人解釋使用Spirit的缺點或缺點是什么?

這是一個非常酷的主意,我喜歡它; 真正學習如何使用C ++模板特別有用。

但他們的文檔建議使用精神用於中小型解析器。 完整語言的解析器需要很長時間才能編譯。 我將列出三個原因。

  • 無掃描解析。 雖然它非常簡單,但是當需要回溯時,它可能會降低解析器的速度。 它是可選的 - 可以集成詞法分析器,參見使用Spirit構建的C預處理器。 大約300行(包括.h和.cpp文件)的語法使用GCC編譯(未優化)到6M的文件。 內聯和最大優化可以達到約1,700萬。

  • 緩慢解析 - 沒有靜態檢查語法,既不暗示需要過多的前瞻,也不驗證基本錯誤,例如左遞歸的使用(這導致遞歸下降解析器LL語法中的無限遞歸)。 但是,左遞歸並不是一個非常難以追蹤的錯誤,但過多的前瞻可能會導致指數解析時間。

  • 大量使用模板 - 雖然這具有一定的優勢,但這會影響編譯時間和代碼大小。 此外,語法定義通常必須對所有其他用戶可見,從而影響更多的編譯時間。 我已經能夠通過使用正確的參數添加顯式模板實例來將語法移動到.cpp文件,但這並不容易。

更新:我的回答僅限於我對Spirit經典的體驗,而不是Spirit V2。 我仍然希望Spirit基於模板,但現在我只是在猜測。

在1.41版本中,一個新版本的Spirit正在發布,它的精神與經典之作:經典:

經過長時間的測試(使用Spirit 2.0超過2年),Spirit 2.1將最終在即將推出的Boost 1.41版本中發布。 代碼現在非常穩定,可以用於生產代碼。 我們正在努力為Boost 1.41及時完成文檔。 您可以在此查看文檔的當前狀態。 目前,您可以在Boost SVN中繼中找到代碼和文檔。 如果您有一個涉及Spirit的新項目,我們強烈建議您現在從Spirit 2.1開始。 請允許我在Spirit郵件列表中引用OvermindDL的帖子:

我可能聽起來像機器人,我經常說這個,但是Spirit.Classic是古老的,你應該切換到Spirit2.1,它可以做你在上面做的所有事情,更容易,更少的代碼,並執行快點。 例如,Spirit2.1可以構建你的整個AST內聯,沒有奇怪的覆蓋,不需要事后構建等等......所有這些都是一個不錯的快速步驟。 你真的需要更新。 查看過去一天的其他帖子,獲取Spirit2.1等文檔的鏈接。 Spirit2.1目前在Boost Trunk中,但將在Boost 1.41正式發布,但在其他方面完成。

對我來說,最大的問題是,編譯器或調試器看到的Spirit中的表達式相當長(我復制到Spirit Classic中一個表達式的一部分下面)。 這些表情讓我害怕。 當我處理使用Spirit的程序時,我害怕使用valgrind或在gdb中打印回溯。

boost::spirit::classic::parser_result<boost::spirit::classic::action<boost::spirit::classic::sequence<boost::spirit::classic::action<boost::spirit::classic::action<optional_suffix_parser<char const*>, boost::spirit::classic::ref_actor<std::vector<std::string, std::allocator<std::string> >, boost::spirit::classic::clear_action> >, boost::spirit::classic::ref_actor<std::vector<int, std::allocator<int> >, boost::spirit::classic::clear_action> >, boost::spirit::classic::sequence<boost::spirit::classic::alternative<boost::spirit::classic::alternative<boost::spirit::classic::action<boost::spirit::classic::contiguous<boost::spirit::classic::sequence<boost::spirit::classic::alternative<boost::spirit::classic::chlit<char>, boost::spirit::classic::chlit<char> >, boost::spirit::classic::positive<boost::spirit::classic::alternative<boost::spirit::classic::alternative<boost::spirit::classic::alnum_parser, boost::spirit::classic::chlit<char> >, boost::spirit::classic::chlit<char> > > > >, boost::spirit::classic::ref_value_actor<std::vector<std::string, std::allocator<std::string> >, boost::spirit::classic::push_back_action> >, boost::spirit::classic::action<boost::spirit::classic::rule<boost::spirit::classic::scanner<char const*, boost::spirit::classic::scanner_policies<boost::spirit::classic::skipper_iteration_policy<boost::spirit::classic::iteration_policy>, boost::spirit::classic::match_policy, boost::spirit::classic::action_policy> >, boost::spirit::classic::nil_t, boost::spirit::classic::nil_t>, boost::spirit::classic::ref_const_ref_actor<std::vector<std::string, std::allocator<std::string> >, std::string, boost::spirit::classic::push_back_action> > >, boost::spirit::classic::contiguous<boost::spirit::classic::sequence<boost::spirit::classic::chlit<char>, boost::spirit::classic::action<boost::spirit::classic::uint_parser<unsigned int, 10, 1u, -1>, boost::spirit::classic::ref_value_actor<std::vector<int, std::allocator<int> >, boost::spirit::classic::push_back_action> > > > >, boost::spirit::classic::kleene_star<boost::spirit::classic::sequence<boost::spirit::classic::chlit<char>, boost::spirit::classic::alternative<boost::spirit::classic::alternative<boost::spirit::classic::action<boost::spirit::classic::contiguous<boost::spirit::classic::sequence<boost::spirit::classic::alternative<boost::spirit::classic::chlit<char>, boost::spirit::classic::chlit<char> >, boost::spirit::classic::positive<boost::spirit::classic::alternative<boost::spirit::classic::alternative<boost::spirit::classic::alnum_parser, boost::spirit::classic::chlit<char> >, boost::spirit::classic::chlit<char> > > > >, boost::spirit::classic::ref_value_actor<std::vector<std::string, std::allocator<std::string> >, boost::spirit::classic::push_back_action> >, boost::spirit::classic::action<boost::spirit::classic::rule<boost::spirit::classic::scanner<char const*, boost::spirit::classic::scanner_policies<boost::spirit::classic::skipper_iteration_policy<boost::spirit::classic::iteration_policy>, boost::spirit::classic::match_policy, boost::spirit::classic::action_policy> >, boost::spirit::classic::nil_t, boost::spirit::classic::nil_t>, boost::spirit::classic::ref_const_ref_actor<std::vector<std::string, std::allocator<std::string> >, std::string, boost::spirit::classic::push_back_action> > >, boost::spirit::classic::contiguous<boost::spirit::classic::sequence<boost::spirit::classic::chlit<char>, boost::spirit::classic::action<boost::spirit::classic::uint_parser<unsigned int, 10, 1u, -1>, boost::spirit::classic::ref_value_actor<std::vector<int, std::allocator<int> >, boost::spirit::classic::push_back_action> > > > > > > > >, void ( )(char const , char const*)>, boost::spirit::classic::scanner<char const*, boost::spirit::classic::scanner_policies<boost::spirit::classic::skipper_iteration_policy<boost::spirit::classic::iteration_policy>, boost::spirit::classic::match_policy, boost::spirit::classic::action_policy> > >::type boost::spirit::classic::action<boost::spirit::classic::sequence<boost::spirit::classic::action<boost::spirit::classic::action<

這是我不喜歡的:

  • 文件有限。 有一個很大的網頁,其中解釋了“一切”,但目前的解釋缺乏細節。

  • AST生成不佳。 AST很難解釋,甚至在撞到牆上以了解AST修飾符如何工作之后,很難獲得易於操作的AST(即很好地映射到問題域的AST)

  • 它極大地增加了編譯時間,即使對於“中等”大小的語法也是如此

  • 語法太重了。 生活中的事實是,在C / C ++中,您必須復制代碼(即在聲明和定義之間)。 但是,似乎在boost :: spirit中,當你聲明一個語法<>時,你必須重復一些東西3次:D(當你想要AST時,這就是我想要的:D)

除此之外,考慮到C ++的局限性,我認為它們在解析器方面表現相當不錯。 但我認為他們應該更多地改進它。 歷史頁面描述了當前“靜態”精神面前的“動態”精神; 我想知道它有多快,語法有多好。

我想說最大的問題是語法問題缺乏任何診斷或其他幫助。 如果你的語法含糊不清,解析器可能無法解析你的預期,並且沒有好的方法可以注意到這一點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM