Add to a spirit qi symbol table in a semantic action

前端 未结 1 1149
清酒与你
清酒与你 2021-01-21 12:08

Going by the opening paragraph of the boost::spirit::qi::symbols documentation, I assumed that it wouldn\'t be too hard to add symbols to a qi::symbols from a semantic action. U

相关标签:
1条回答
  • 2021-01-21 12:42

    This question has been answered before. However, there is quite a range of problems with your posted code, so I'll fix them up one by one to spare you unnecessary staring at pages of error messages.

    The working code (plus verification of output) is here on liveworkspace.org.

    Notes:

    1. the semantic action must be a Phoenix actor, i.e. you need

      • boost::bind, phoenix::bind, std::bind
      • phoenix::lambda<> or phoenix::function<>
      • a function pointer or polymorphic calleable object (as per the documentation)

        I'd recommend phoenix::bind (in this particular case), which I show below

    2. There was a mismatch between the parser's skipper and the start rule
    3. qi::char_ eats all characters. Combined with the skipper, this resulted in parse failure, because (obviously) the digits in the value were also being eaten by +qi::char_. I show you one of many solutions, based on qi::lexeme[+qi::graph]
    4. use qi::lexeme to 'bypass' the skipper (i.e. to prevent +qi::graph to cut across whitespace because the skipper, well, skipped it)
    5. qi::parse doesn't take a skipper; use qi::phrase_parse for that (the reason it appeared to work is that any trailing 'variadic' arguments are bound to the exposed attributes of the parser, which in this case are unspecified, and therefore qi::unused_type).
    6. if you want to pass test.begin() and test.end() directly to qi::phrase_parse, you need to make it clear that you want const iterators. The more typical solution would be to introduce explicitely typed variables (first and last, e.g.)


    #define BOOST_SPIRIT_USE_PHOENIX_V3
    #include <boost/spirit/include/qi.hpp>
    #include <boost/spirit/include/phoenix.hpp>
    #include <string>
    
    namespace qi = boost::spirit::qi;
    namespace phx = boost::phoenix;
    
    typedef qi::symbols<char, unsigned int> constants_dictionary;
    
    template <typename Iter> struct parser : qi::grammar<Iter, qi::space_type> 
    {
        parser(constants_dictionary &dict) : parser::base_type(start) 
        {
            start = qi::lit("@") >> (qi::lexeme [+qi::graph] >> qi::uint_)
                [ phx::bind(dict.add, qi::_1, qi::_2) ]
                ;
        }
    
        qi::rule<Iter, qi::space_type> start;
    };
    
    int main() {
        constants_dictionary dict;
        parser<std::string::const_iterator> prsr(dict);
        const std::string test = "@foo 3";
    
        if (qi::phrase_parse(test.begin(), test.end(), prsr, qi::space))
        {
            std::cout << "check: " << dict.at("foo") << "\n";
        }
    }
    
    0 讨论(0)
提交回复
热议问题