Search code examples
c++parsingboostboost-spiritboost-spirit-qi

How can I use the skipper ascii::space WITHOUT skipping eol?


I have to use boost::spirit for parsing, and I want use phrase_parse function :

qi::phrase_parse(str.begin(), str.end(), grammar, ascii::space - qi::eol); 

But the fourth term (ascii::space - qi::eol), isnt allowed by my compiler. How can I use the skipper ascii::space WITHOUT skipping eol ?


Solution

  • The simplest answer is

    qi::phrase_parse(str.begin(), str.end(), grammar, ascii::blank); 
    

    Of course, it depends on your grammar too: if it expects a specific skipper class you might need to change that. See below for a generic way to handle that (although you could just specify qi::blank_type for a Grammar that should only accept qi::blank).

    The sample handles arbitrary skippers too.

    Other hints

    Spirit has several directives that influence the use of skippers:

    • qi::lexeme

      will parse the sub-expression regardless of skipper (useful for e.g. string literals in a grammar)

    • qi::raw

      will return the raw source iterator range, meaning that skipped input will be included in the result

    • qi::no_skip, qi::skip

      can be used to explicitely change the type of skipper used for the subexpression

    Recommended reading

    The Boost Spirit site has a nice article about things like this

    Generic sample

    #include <boost/spirit/include/qi.hpp>
    
    namespace qi = boost::spirit::qi;
    
    template <typename It, typename Skipper>
        struct parser : qi::grammar<It, Skipper>
    {
        parser() : parser::base_type(start)
        {
            start = *qi::int_;
        }
    
      private:
        qi::rule<It, Skipper> start;
    };
    
    template <typename C, typename Skipper>
        void doParse(const C& input, const Skipper& skipper)
    {
        auto f(std::begin(input)), l(std::end(input));
    
        parser<decltype(f), Skipper> p;
        bool ok = qi::phrase_parse(f,l,p,skipper);
    
        if (ok)   
            std::cout << "parse success\n";
    }
    
    int main()
    {
        const std::string input = "1 2 3 4";
        doParse(input, qi::blank);
        doParse(input, qi::space);
        doParse(input, ~qi::char_("0-9"));
    }