c++boostboost-spiritboost-spirit-qi

Boost spirit get the whole match as a string


I'm trying to define my own grammar using boost spirit framework and I'm defining such a matching rule:

value = (
        char_('"') >>
        (*qi::lexeme[
                char_('\\') >> char_('\\') |
                char_('\\') >> char_('"')  |
                graph - char_('"') |
                char_(' ')
        ])[some_func] >>
        char_('"')
);

I'd like to assing an action - some_func - to the part of it, and pass the whole matching string as a parameter. But unfortunately I will get something like vector<boost::variant<boost::fusion::vector2 ..a lot of stuff...)...> . Can I somehow get the whole data as a char*, std::string or even void* with size?


Solution

  • Look at qi::as_string:

    Output of demo program:

    DEBUG: 'some\\"quoted\\"string.'
    parse success
    

    To be honest, it looks like you are really trying to parse 'verbatim' strings with possible escape chars. In the respect, the use of lexeme seem wrong (the spaces get eaten). If you want to see samples of escaped string parsing, see e.g._

    2023 UPDATE

    Revisited this answer because of a broken link to liveworkspace.org, and in 2023 I'd write this like so:

    A simple rearrangement that I think could be made, at least might look like:

    template <typename It> struct parser : qi::grammar<It> {
        parser() : parser::base_type(value) {
            phx::function some_func = [](auto const& s) { //
                std::cout << "DEBUG: " << s << "\n";
            };
    
            value = qi::raw['"' >> *('\\' >> qi::char_ | ~qi::char_('"')) >> '"'][some_func(qi::_1)];
        }
      private:
        qi::rule<It> value;
    };
    

    Note that we simply declare the rule without a skipper and drop the lexeme (see Boost spirit skipper issues)

    Live On Coliru

    #include <boost/phoenix.hpp>
    #include <boost/range/iterator_range_io.hpp>
    #include <boost/spirit/include/qi.hpp>
    #include <iomanip>
    
    namespace qi  = boost::spirit::qi;
    namespace phx = boost::phoenix;
    
    template <typename It> struct parser : qi::grammar<It> {
        parser() : parser::base_type(value) {
            phx::function some_func = [](auto const& s) { //
                std::cout << "DEBUG: " << s << "\n";
            };
    
            value = qi::raw['"' >> *('\\' >> qi::char_ | ~qi::char_('"')) >> '"'][some_func(qi::_1)];
        }
      private:
        qi::rule<It> value;
    };
    
    bool doParse(std::string const& input) {
        typedef std::string::const_iterator It;
        auto f(begin(input)), l(end(input));
    
        try
        {
            parser<It> const p;
    
            bool ok = qi::phrase_parse(f, l, p, qi::space);
            if (ok)
                std::cout << "parse success\n";
            else
                std::cerr << "parse failed: " << quoted(std::string(f, l), '\'') << "\n";
    
            if (f!=l) std::cerr << "trailing unparsed: " << quoted(std::string(f,l), '\'') << "\n";
            return ok;
        } catch (qi::expectation_failure<It> const& e) {
            std::string frag(e.first, e.last);
            std::cerr << e.what() << quoted(frag, '\'') << "\n";
        }
    
        return false;
    }
    
    int main() {
        return doParse(R"("some \"quoted\" string.")") ? 0 : 255;
    }
    

    Prints

    DEBUG: "some \"quoted\" string."
    parse success