在几个问题中,我看到了来自Spirit的boost.org解析器 - 生成器框架的建议,但是在评论中,人们抱怨使用不开心的Spirit。请那些人站出来向我们其他人解释使用Spirit的缺点或缺点是什么?
答案 0 :(得分:37)
这是一个非常酷的主意,我喜欢它;真正学习如何使用C ++模板特别有用。
但他们的文档建议使用精神用于中小型解析器。完整语言的解析器需要很长时间才能编译。 我将列出三个原因。
无扫描解析。虽然它非常简单,但是当需要回溯时,它可能会降低解析器的速度。它是可选的 - 可以集成词法分析器,参见使用Spirit构建的C预处理器。大约300行(包括.h和.cpp文件)的语法使用GCC编译(未优化)到6M的文件。内联和最大优化可以降低到~1,7M。
缓慢解析 - 没有静态检查语法,既没有暗示需要过多的前瞻,也没有验证基本错误,例如左递归的使用(导致递归下降的无限递归)解析器LL语法)。但是,左递归并不是一个非常难以追踪的错误,但过多的预测可能会导致指数解析时间。
繁重的模板使用 - 虽然这有一定的优势,但这会影响编译时间和代码大小。此外,语法定义通常必须对所有其他用户可见,从而影响更多的编译时间。 我已经能够通过使用正确的参数添加显式模板实例来将语法移动到.cpp文件,但这并不容易。
更新:我的回答仅限于我使用Spirit经验的经验,而不是Spirit V2。我仍然希望Spirit能够基于模板,但现在我只是在猜测。
答案 1 :(得分:24)
在提升1.41中,一个新版本的精神正在发布,并且精神上出现了一些优势::经典:
经过长时间的测试(超过2次) 精神2.0),精神2.1 最终会随着发布 即将发布的Boost 1.41版本。代码 现在非常稳定,已做好准备 生产代码。我们正在努力 及时完成文档 对于Boost 1.41。你可以偷看 文档的当前状态 这里。目前,您可以找到代码 和Boost SVN中的文档 树干。如果你有一个新项目 涉及精神,我们强烈推荐 现在从Spirit 2.1开始。请允许我 引用OvermindDL的帖子 精神邮件列表:我可能听起来像机器人一样 我经常说这个,但是 Spirit.Classic是古老的,你应该 切换到Spirit2.1,它可以做到 你做的一切都超过了一个伟大的交易 更容易,更少的代码,它 执行得更快。例如, Spirit2.1可以构建你的整个AST 内联,没有奇怪的重写,没有必要 事后建立起来......等等, 一切都是快速而快速的一步。您 真的需要更新。看到另一个 过去一天的帖子链接到 Spirit2.1的文档等。 Spirit2.1 目前在Boost Trunk,但会 正式发布Boost 1.41, 但是完成了。
答案 2 :(得分:19)
对我来说,最大的问题是,编译器或调试器看到的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<
答案 3 :(得分:14)
以下是我不喜欢的内容:
文档有限。有一个很大的网页,其中解释了“一切”,但目前的解释缺乏细节。
AST生成不佳。 AST很难解释,即使在撞到墙上以了解AST修饰符如何工作之后,很难获得易于操作的AST(即很好地映射到问题域的那个)
它极大地增加了编译时间,即使对于“中等”大小的语法也是如此
语法太重了。生活中的事实是,在C / C ++中,您必须复制代码(即在声明和定义之间)。但是,似乎在boost :: spirit中,当你声明一个语法&lt;&gt;时,你必须重复一些东西3次:D(当你想要AST时,这就是我想要的:D)
除此之外,考虑到C ++的局限性,我认为他们在解析器方面做得很好。但我认为他们应该更多地改进它。历史页面描述了当前“静态”精神面前的“动态”精神;我想知道它的速度有多快,语法有多好。
答案 4 :(得分:3)
我想说最大的问题是语法问题缺乏任何诊断或其他帮助。如果你的语法含糊不清,解析器可能无法解析你的预期,并且没有好的方法可以注意到它。