Search code examples
boostboost-spiritboost-spirit-qi

Simple Line, escaped elements with different type


i want to parse the following line with boost::spirit

0  "a"  "b"  "c"

I've created my rules like this:

qi::rule<std::string::const_iterator, std::string()> escaped_ = qi::char_('"') >> *(qi::char_ - qi::char_('"')) >> qi::char_('"');

int id;
std::string v1,v2,v3;

qi::phrase_parse(bein, end, (qi::int_ >> escaped_ >> escaped_ >> escaped_ >> qi::eol), id, v1, v2, v3);

But the parsing failed and i don't know why. Hopefully someone can help.


Solution

  • phrase_parse takes (it, it, parser, skipper[, attribute...]). You forgot to pass a skipper:

    bool ok = qi::phrase_parse(begin, end, (qi::int_ >> escaped_ >> escaped_ >> escaped_ >> qi::eol), qi::blank, id, v1, v2, v3);
    

    I suggest qi::blank there because your grammar treats eol as significant (skipping it would never match).

    Note the qi::rule subtly omits the skipper, hence it's implicitly a lexeme[]:

    qi::rule<It, std::string(), qi::blank_type> escaped_ = qi::lexeme['"' >> *(qi::char_ - '"') >> '"'];
    

    See also: Boost spirit skipper issues

    Final note, you like didn't want to parse " as part of the resulting values (change qi::char_('"') into qi::lit('"') or, equivalently '"' if possible).

    Demo

    Live On Coliru

    #include <boost/spirit/include/qi.hpp>
    
    namespace qi = boost::spirit::qi;
    
    int main() {
        typedef std::string::const_iterator It;
    
        qi::rule<It, std::string()> escaped_ = '"' >> *(qi::char_ - '"') >> '"';
    
        std::string const input("0  \"a\"  \"b\"  \"c\"\n");
        It begin(input.begin()), end(input.end());
    
        int id;
        std::string v1,v2,v3;
    
        bool ok = qi::phrase_parse(begin, end, (qi::int_ >> escaped_ >> escaped_ >> escaped_ >> qi::eol), qi::blank, id, v1, v2, v3);
    
        if (ok) {
            std::cout << "Parse succeeded:" 
                      << " "  << id
                      << " '" << v1 << "'"
                      << " '" << v2 << "'"
                      << " '" << v3 << "'\n";
        } else {
            std::cout << "Parse failed\n";
        }
    
        if (begin != end)
            std::cout << "Remaining unparsed '" << std::string(begin, end) << "'\n";
    
    }
    

    Prints

    Parse succeeded: 0 'a' 'b' 'c'