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

后端 未结 1 408
半阙折子戏
半阙折子戏 2020-12-21 14:34


I was toying with Boost.Spirit X3 calculator example when I encountered an error I couldn\'t get my head around.
I minimized the program to reduce complexity still

相关标签:
1条回答
  • 2020-12-21 14:48

    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'
    
    0 讨论(0)
提交回复
热议问题