Boost.Spirit X3 parser “no type named type in(…)”

ぐ巨炮叔叔 提交于 2019-12-02 03:25:01

Yup. This looks like another limitation with automatic propagation of attributes when single-element sequences are involved.

I'd probably bite the bullet and change the rule definition from what it is (and what you'd expect to work) to:

x3::rule<class program_, std::vector<std::string> >

That removes the root of the confusion.

Other notes:

  • you had char_ which also eats ';' so the grammar would never succeed because no ';' would follow a "statement".

  • your statements aren't lexeme, so whitespace is discarded (is this what you meant? See Boost spirit skipper issues)

  • your statement could be empty, which meant parsing would ALWAYS fail at the end of input (where it would always read an empty state, and then discover that the expected ';' was missing). Fix it by requiring at least 1 character before accepting a statement.

With some simplifications/style changes:

Live On Coliru

#include <boost/fusion/adapted.hpp>
#include <boost/spirit/home/x3.hpp>
#include <list>

namespace x3 = boost::spirit::x3;

namespace ast {
    using statement = std::string;

    struct program {
        std::list<statement> stmts;
    };
} 

BOOST_FUSION_ADAPT_STRUCT(ast::program, stmts)

namespace grammar {
    auto statement 
        = x3::rule<class statement_, ast::statement> {"statement"}
        = +~x3::char_(';');
    auto program 
        = x3::rule<class program_, std::list<ast::statement> > {"program"}
        = *(statement >> ';');
} 

#include <iostream>
#include <iomanip>

int main() {
    std::cout << "Type an expression...or [q or Q] to quit\n\n";

    using It = std::string::const_iterator;

    for (std::string str; std::getline(std::cin, str);) {
        if (str.empty() || str[0] == 'q' || str[0] == 'Q')
            break;

        auto &parser = grammar::program;
        ast::program program; // Our program (AST)

        It iter = str.begin(), end = str.end();
        if (phrase_parse(iter, end, parser, x3::space, program)) {
            std::cout << "Parsing succeeded\n";
            for (auto& s : program.stmts) {
                std::cout << "Statement: " << std::quoted(s, '\'') << "\n";
            }
        }
        else
            std::cout << "Parsing failed\n";

        if (iter != end)
            std::cout << "Remaining unparsed: " << std::quoted(std::string(iter, end), '\'') << "\n";
    }
}

Which for input "a;b;c;d;" prints:

Parsing succeeded
Statement: 'a'
Statement: 'b'
Statement: 'c'
Statement: 'd'
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!