Search code examples
boostboost-spirit

rules working on 1.46 boost::spirit and stopped working on boost spirit 1.55


constant_double_quotation_string %= char_( '"' ) >> 
    *( spirit::qi::string( "\\\"" )[ _val += _1 ] | 
     ( char_ - '"' ) ) >> char_( '"' ); 

constant_single_quotation_string %= char_( '\'' ) >> 
    *( spirit::qi::string( "\\\'" )[ _val += _1 ] | 
     ( char_ - '\'' ) ) >> char_( '\'' ); 

now it is saying char is not a class or structure or union type with gcc 4.7.2?


Solution

  • Elaborating on my earlier answer

    In case you actually do want to expose the unescaped value, I'd suggest:

    • not using raw (obviously, because we don't wish to mirror the exact input sequence in the presence of escaped characters)
    • still not using semantic actions
    • instead playing clever with lit('\\') to match the escape character without adding it to the output sequence.

    Here I chose to use a single rule definition for both the double-/single quoted literal parsers. Instead, I pass in the expected quote character as an inherited attribute:

    qi::rule<It, std::string(char)> 
         q_literal;
    
    q_literal = lit(_r1) >> *('\\' >> char_ | (char_ - lit(_r1))) >> lit(_r1);
    start     = q_literal('"') | q_literal('\'');
    

    Demo

    Live On Coliru

    #include <boost/spirit/include/qi.hpp>
    
    namespace qi = boost::spirit::qi;
    
    template <typename It, typename Skipper = qi::space_type>
    struct my_grammar : qi::grammar<It, std::string(), Skipper> {
    
        my_grammar() : my_grammar::base_type(start) {
            using namespace qi;
    
            start     = q_literal('"') | q_literal('\'');
    
            q_literal = lit(_r1) >> *('\\' >> char_ | (char_ - lit(_r1))) >> lit(_r1);
    
            BOOST_SPIRIT_DEBUG_NODES( (start)(q_literal) )
        }
    
      private:
        qi::rule<It, std::string(), Skipper> start;
    
        // drop skipper to make these rules implicitly 'lexeme'
        // see: https://stackoverflow.com/questions/17072987/boost-spirit-skipper-issues/17073965#17073965
        qi::rule<It, std::string(char)> q_literal;
    };
    
    int main() {
        using It = std::string::const_iterator;
        my_grammar<It> g;
    
        for (std::string const& input : {
                "\"hello world\"",
                "\"hello \\\"world\\\"\"",
                "'bye world'",
                "'bye \"\\'world\\'\"'",
                "bogus" })
        {
            std::cout << "\n------- Parsing: " << input << '\n';
            It f = input.begin(), l = input.end();
    
            std::string result;
            bool ok = qi::phrase_parse(f, l, g, qi::space, result);
    
            if (ok)
                std::cout << "Parse success: " << result << "\n";
            else
                std::cout << "Parse failed\n";
    
            if (f!=l)
                std::cout << "Remaining unparsed input '"  << std::string(f,l) << "'\n";
        }
    }
    

    Printing the unescaped literals:

    ------- Parsing: "hello world"
    Parse success: hello world
    
    ------- Parsing: "hello \"world\""
    Parse success: hello "world"
    
    ------- Parsing: 'bye world'
    Parse success: bye world
    
    ------- Parsing: 'bye "\'world\'"'
    Parse success: bye "'world'"
    
    ------- Parsing: bogus
    Parse failed
    Remaining unparsed input 'bogus'