【问题标题】:Boost Spirit Qi parser not working when factored out into qi::grammar分解为 qi::grammar 时,Boost Spirit Qi 解析器不起作用
【发布时间】:2017-08-01 09:47:38
【问题描述】:

我正在使用 Spirit 解析器来解析像 id 1234 这样的字符串。它与内联 start = qi::lit("id") >> qi::int_; 完美配合,但如果我想将其放入单独的基于 qi::grammar 的结构中,则不能。请参阅以下示例中的案例 1、2 和 3:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

#include <iostream>
#include <fstream>

namespace qi  = boost::spirit::qi;
namespace phoenix = boost::phoenix;

struct Context{};

template <typename Iterator, typename SkipParser>
struct IdGrammar : qi::grammar<Iterator, SkipParser>
{
    explicit IdGrammar(Context& out) : IdGrammar::base_type(start, "IdGrammar")
    {
        start = qi::lit("id") >> qi::int_;
    }

    qi::rule<Iterator, SkipParser> start;
};

template <typename Iterator, typename SkipParser>
struct MyGrammar : qi::grammar<Iterator, SkipParser>
{
    explicit MyGrammar(Context& out)
        : MyGrammar::base_type(start, "MyGrammar")
    {
        IdGrammar<Iterator, SkipParser> idGrammar(out);
//      start = idGrammar >> *(',' >> idGrammar); // 1 = Parsing fails
        start = idGrammar; // 2 = Parsing fails
//      start = qi::lit("id") >> qi::int_; // 3 = Parsing succeeds

        start.name("the start");
        qi::on_error<qi::fail>(
            start,
            phoenix::ref(std::cout) << phoenix::val("Parsing error: expecting ") << qi::_4 // what failed?
                                    << phoenix::val(" here: \"")
                                    << phoenix::construct<std::string>(qi::_3, qi::_2) // iterators to error-pos, end
                                    << phoenix::val("\"")
                                    << std::endl);
    }

    qi::rule<Iterator, SkipParser> start;
};

int main()
{
    typedef std::string::const_iterator iterator_type;
    Context ctx;
    MyGrammar<iterator_type, qi::space_type> roman_parser(ctx); // Our grammar

    std::string str = "id 5012";

    iterator_type iter = str.begin(), end = str.end();
    bool r = phrase_parse(iter, end, roman_parser, qi::space);

    if (r && iter == end)
    {
        std::cout << "Parsing succeeded\n";
    }
    else
    {
        std::string rest(iter, end);
        std::cout << "Parsing failed\n";
        std::cout << "stopped at: \"" << rest << "\"\n";
    }
}

Run example on Coliru

失败案例(1 和 2)的输出是:

Parsing failed
stopped at: "id 5012"

这里有什么不同?请注意,我删除了整数结果的任何分配以保持示例最小 - 假设这与问题无关。

【问题讨论】:

    标签: parsing boost-spirit


    【解决方案1】:

    idGrammar 的生命周期必须长于构造函数作用域。 使其成为成员变量:

    template <typename Iterator, typename SkipParser>
    struct MyGrammar : qi::grammar<Iterator, SkipParser>
    {
        explicit MyGrammar(Context& out)
            : MyGrammar::base_type(start, "MyGrammar")
              , idGrammar(out)
        {
          start = idGrammar >> *(',' >> idGrammar); // 1 = Now parsing succeeds
    //        start = idGrammar; // 2 = Now parsing succeeds
    //      start = qi::lit("id") >> qi::int_; // 3 = Parsing succeeds
    
            start.name("the start");
            qi::on_error<qi::fail>(
                start,
                phoenix::ref(std::cout) << phoenix::val("Parsing error: expecting ") << qi::_4 // what failed?
                                        << phoenix::val(" here: \"")
                                        << phoenix::construct<std::string>(qi::_3, qi::_2) // iterators to error-pos, end
                                        << phoenix::val("\"")
                                        << std::endl);
        }
    
        qi::rule<Iterator, SkipParser> start;
        IdGrammar<Iterator, SkipParser> idGrammar;
    };
    

    【讨论】:

    • 我在尝试更多替代方案时得出了相同的结论。构造解析规则时可能没有任何个临时对象。例如,我做的另一个(当然是愚蠢的)尝试是一个结构字段qi::rule&lt;Iterator, SkipParser&gt; idGrammar;,然后我将IdGrammar 实例分配给它——同样的生命周期问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多