将规则分配给包含自身的序列时,Boost.Spirit.Qi崩溃

时间:2013-11-23 05:21:31

标签: c++ boost-spirit boost-spirit-qi

我有以下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;
    }

}

如注释行中所述,如果我将第三个qi :: rule分配给另外两个规则的序列,并使用该第三个规则进行解析,我的程序将按预期工作。但是,如果我将相同的序列分配给序列中的第一个规则,然后使用该第一个规则进行解析,程序将在运行时崩溃,显然甚至没有抛出异常,因为catch (...) { . . . }块没有执行。

所以我的问题是:是否有一些关于'qi::rule的规则我应该知道禁止将包含规则的序列分配给同一规则,或者由于Boost中的错误导致崩溃。 Spirit.Qi?

意图

为了澄清,根据cv_and_he的评论,我在这个小玩具示例背后的目标是弄清楚如何在运行时生成一些动态解析器​​;具体来说,如何从一系列规则生成规则,这些规则的计数只在运行时知道,例如parser = A1 >> A2 >> ... >> AN;,其中N在编译时是未知的,所以我不能只是硬编码一条固定数量为“>>”的规则。这类似于在运行时通过将元素追加到末尾来构建列表,一次一个。

1 个答案:

答案 0 :(得分:2)

我不确定你想要达到的目标,但复制()似乎就是你所追求的目标

    parser = parser.copy() >> parser2;

查看 Live on Coliru


背景

问题是Qi通过引用获取非终端,因此您可以获得PEG语法建议的解析器语义。

除此之外,Proto表达式树(表达式模板)确实通过引用获取了一些参数。

这两者结合起来可能会让你的生活陷入困境,特别是在构造解析器动态时。简而言之,我认为,在外面

  • 使用继承的属性
  • qi :: symbols (包括Nabialek技巧)
Spirit V2不能很好地支持动态构建规则。 Proto x11 / Spirit X3可能会更好地改变它。

在此处查看更多背景信息:


示例代码

#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;
    }

}