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

Parsing a list of doubles with boost::spirit


Here is a code sample.

// file temp.cpp

#include <iostream>

#include <vector>
#include <boost/spirit/include/qi.hpp>

namespace qi = boost::spirit::qi;

struct parser : qi::grammar<std::string::const_iterator, std::vector<double> >
{
    parser() : parser::base_type( vector )
    {
        vector  = +qi::double_;
    }

    qi::rule<std::string::const_iterator, std::vector<double> > vector;
};

int main()
{
    std::string const x( "1 2 3 4" );
    std::string::const_iterator b = x.begin();
    std::string::const_iterator e = x.end();
    parser p;
    bool const r = qi::phrase_parse( b, e, p, qi::space );
    // bool const r = qi::phrase_parse( b, e, +qi::double_, qi::space ); // this this it PASSES
    std::cerr << ( (b == e && r) ? "PASSED" : "FAILED" ) << std::endl;
}

I want to parse std::string x with parser p.

As follows from the definition of struct parser, the lines

qi::phrase_parse( b, e, p, qi::space ); // PASSES

and

qi::phrase_parse( b, e, +qi::double_, qi::space ); // FAILS

should be equivalent. However, the with first one parsing fails and with the second one it passes.

What am I doing wrong at the definition of struct parser ?


Solution

  • You should "inform" grammar about skipping spaces - one more argument in template.

    #include <iostream> 
    
    #include <vector> 
    #include <boost/spirit/include/qi.hpp> 
    
    namespace qi = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;
    
    struct parser
      : qi::grammar<std::string::const_iterator, std::vector<double>(), ascii::space_type> 
    { 
      parser() : parser::base_type( vector ) 
      { 
        vector  %= +(qi::double_); 
      } 
    
      qi::rule<std::string::const_iterator, std::vector<double>(), ascii::space_type> vector;
    }; 
    
    int main() 
    { 
      std::string const x( "1 2 3 4" ); 
      std::string::const_iterator b = x.begin(); 
      std::string::const_iterator e = x.end(); 
      parser p; 
      bool const r = qi::phrase_parse( b, e, p, ascii::space ); 
      //bool const r = qi::phrase_parse( b, e, +qi::double_, qi::space );
      std::cout << ( (b == e && r) ? "PASSED" : "FAILED" ) << std::endl; 
    } 
    

    I've also done few small corrections e.g. you should add brackets in arguments, which tells about attribute type: std::vector<double>().