Search code examples
c++parsingboostboost-spirit

C++ Boost Spirit, parsing data and storing the maximum


I'm trying the code sehe gave here : Boolean expression (grammar) parser in c++

I would like to create a string variable max, that would store the maximum variable encountered at each parsing (on the lexicographic order, for example).

I tried things like :

  1. var_ = qi::lexeme[ +alpha ] [_val = _1, if_(phx::ref(m) < _1) [phx::ref(m) = _1]];, but there is a (really long) compilation error

  2. var_ = qi::lexeme[ +alpha [_val = _1, if_(phx::ref(m) < _1) [phx::ref(m) = _1]]]; but with this one I only get the first caracter of a variable, which is restrincting.

I also tried to simplify things using integers instead of string for variables, but var_ = int_ [...] didn't work either, because int_ is already a parser (I think).

Do you have any ideas ?

Thanks in advance


Solution

  • I'd say that

    start = *word [ if_(_1>_val) [_val=_1] ];
    

    should be fine. However, due to a bug (?) Phoenix statements in a single-statement semantic action do not compile. You can easily work around it using a no-op statement, like e.g. _pass=true in this context:

    start = *word [ if_(_1>_val) [_val=_1], _pass = true ];
    

    Now, for this I assumed a

    rule<It, std::string()> word = +alpha;
    

    If you insist you can cram it all into one rule though:

    start = *as_string[lexeme[+alpha]] [ if_(_1>_val) [_val=_1], _pass = true ];
    

    I don't recommend that.

    Demo

    Live On Colir

    #define BOOST_SPIRIT_USE_PHOENIX_V3
    #include <boost/spirit/include/qi.hpp>
    #include <boost/spirit/include/phoenix.hpp>
    
    namespace qi  = boost::spirit::qi;
    namespace phx = boost::phoenix;
    
    template <typename It, typename Skipper>
    struct max_parser : qi::grammar<It, std::string(), Skipper> {
        max_parser() : max_parser::base_type(start) {
            using namespace qi;
            using phx::if_;
    
    #if 1
            word  = lexeme [ +alpha ];
            start = *word [ if_(_1>_val) [_val=_1], _pass = true ];
    #else
            start = *as_string[lexeme[+alpha]] [ if_(_1>_val) [_val=_1], _pass = true ];
    #endif
        }
    
      private:
        qi::rule<It, std::string(), Skipper> start, word;
    };
    
    
    int main() {
    
        std::string const input("beauty shall be in ze eye of the beholder");
        using It = std::string::const_iterator;
        max_parser<It, qi::space_type> parser;
    
        std::string data;
        It it = input.begin(), end = input.end();
        bool ok = qi::phrase_parse(it, end, parser, qi::space, data);
    
        if (ok) {
            std::cout << "Parse success: " << data << "\n";
        } else {
            std::cout << "Parse failed\n";
        }
    
        if (it != end)
            std::cout << "Remaining unparsed: '" << std::string(it,end) << "'\n";
    }
    

    Prints:

    Parse success: ze