所以我的问题是:是否有关于'qi::rule'的规则,我应该知道禁止将包含规则的序列分配给该完全相同的规则,还是由于Boost.Spirit中的错误而导致崩溃. ?意图根据cv_and_he的评论,澄清一下,我这个小玩具示例背后的目标是弄清楚如何在运行时生成一些动态解析器.具体来说,如何从仅在运行时知道计数的规则序列中生成规则,例如parser = A1 >> A2 >> ... >> AN;,而在编译时不知道N,因此我不能只用一个硬编码一个规则固定数量的>>这样.这类似于在运行时通过将元素追加到末尾(一次添加一个)来构建列表. 解决方案我不确定您要实现的目标,但是copy()似乎就是您要追求的目标 parser = parser.copy() >> parser2;查看 在Coliru上直播 背景问题是Qi引用了非终结符,因此您得到了PEG语法建议的解析器语义. 除此之外,Proto表达式树(表达式模板)确实通过引用接受了它们的一些参数. 这两个加在一起有可能真正破坏您的生活,尤其是在动态地使用构造解析器时.简而言之,我认为之外使用继承的属性 和 qi :: symbols (包括Nabialek技巧)Spirit V2不能很好地支持即时构建规则. Proto x11/Spirit X3可能会对此做得更好.在此处查看更多背景: C ++ Boost qi递归规则构建 生成Spirit解析器可变解析器表达式的可变列表中的表达式 可以对Boost Spirit规则进行参数化 示例代码#include <boost/spirit/include/qi.hpp>#include <boost/spirit/include/phoenix.hpp>#include <boost/spirit/include/support_istream_iterator.hpp>namespace spirit = boost::spirit;namespace qi = boost::spirit::qi;namespace phoenix = boost::phoenix;int main() { std::string input("1 2"); qi::rule<std::string::iterator, void(), qi::space_type> parser; qi::rule<std::string::iterator, void(), qi::space_type> parser2; qi::rule<std::string::iterator, void(), qi::space_type> parser3; parser = qi::int_[ std::cerr << phoenix::val("First int: ") << qi::_1 << std::endl ]; parser2 = qi::int_[ std::cerr << phoenix::val("Second int: ") << qi::_1 << std::endl ]; try { // Comment out these two lines, (finished below ...) parser3 = parser >> parser2; phrase_parse(input.begin(), input.end(), parser3, qi::space); parser = parser.copy() >> parser2; phrase_parse(input.begin(), input.end(), parser, qi::space); } catch (...) { std::cerr << "Exception caught." << std::endl; }} I have the following MWE:#include <string>#include <boost/spirit/include/qi.hpp>#include <boost/spirit/include/phoenix.hpp>#include <boost/spirit/include/support_istream_iterator.hpp>namespace spirit = boost::spirit;namespace qi = boost::spirit::qi;namespace phoenix = boost::phoenix;int main() { std::string input("1 2"); qi::rule<std::string::iterator, void(), qi::space_type> parser; qi::rule<std::string::iterator, void(), qi::space_type> parser2; qi::rule<std::string::iterator, void(), qi::space_type> parser3; parser = qi::int_[ std::cerr << phoenix::val("First int: ") << qi::_1 << std::endl ]; parser2 = qi::int_[ std::cerr << phoenix::val("Second int: ") << qi::_1 << std::endl ]; try { // Comment out these two lines, (finished below ...) parser3 = parser >> parser2; phrase_parse(input.begin(), input.end(), parser3, qi::space); // ... then un-comment these lines, and the program will crash (and no // exception is caught below).// parser = parser >> parser2;// phrase_parse(input.begin(), input.end(), parser, qi::space); } catch (...) { std::cerr << "Exception caught." << std::endl; }}As noted in the commented lines, if I assign a third qi::rule to a sequence of another two rules, and parse using that third rule, my program works as expected. However, if I assign the same sequence to the first rule in the sequence, then parse using that first rule, the program will crash when I run it, apparently without even throwing an exception since the catch (...) { . . . } block does not execute.So my question is: is there some rule about 'qi::rule's I should know that forbids assigning a sequence that contains a rule to that very same rule, or is this crash due to a bug in Boost.Spirit.Qi?IntentTo clarify, in light of cv_and_he's comment, my goal behind this little toy example is to figure out how to do some dynamic parser generation at runtime; specifically how to generate a rule from a sequence of rules whose count is only know at runtime, such as parser = A1 >> A2 >> ... >> AN;, where N is not known at compile-time, so I can't just hard-code one rule with a fixed number of '>>' that way. This would be something akin to building a list at run time by appending elements to the end, one at a time. 解决方案 I'm not sure what you were trying to achieve, but copy() would seem to be what you're after parser = parser.copy() >> parser2;See it Live on ColiruBackgroundThe problem is Qi takes non-terminals by reference, so you get the parser semantics a PEG grammar would suggest. Besides that, Proto expression trees (expression templates) do take some of their arguments by reference. These two combined have a potential to really mess up your life, especially when construction parsers dynamically. In short, I'd argue that, outside using inherited attributes and qi::symbols (including the Nabialek trick)constructing rules on the fly is not well supported in Spirit V2. Proto x11 / Spirit X3 may change this for the better.See more background here:C++ Boost qi recursive rule constructionGenerating Spirit parser expressions from a variadic list of alternative parser expressionsCan Boost Spirit Rules be parameterizedSample code#include <boost/spirit/include/qi.hpp>#include <boost/spirit/include/phoenix.hpp>#include <boost/spirit/include/support_istream_iterator.hpp>namespace spirit = boost::spirit;namespace qi = boost::spirit::qi;namespace phoenix = boost::phoenix;int main() { std::string input("1 2"); qi::rule<std::string::iterator, void(), qi::space_type> parser; qi::rule<std::string::iterator, void(), qi::space_type> parser2; qi::rule<std::string::iterator, void(), qi::space_type> parser3; parser = qi::int_[ std::cerr << phoenix::val("First int: ") << qi::_1 << std::endl ]; parser2 = qi::int_[ std::cerr << phoenix::val("Second int: ") << qi::_1 << std::endl ]; try { // Comment out these two lines, (finished below ...) parser3 = parser >> parser2; phrase_parse(input.begin(), input.end(), parser3, qi::space); parser = parser.copy() >> parser2; phrase_parse(input.begin(), input.end(), parser, qi::space); } catch (...) { std::cerr << "Exception caught." << std::endl; }} 这篇关于将规则分配给包括自身的序列时,Boost.Spirit.Qi崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 10-23 05:40