Question

I'm trying to implement a simple parser using boost::spirit that (among other things) accepts strings in double quotes, e.g. "Hello, World". Here's a stripped down program that illustrates my issue:

#include <iostream>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>

namespace qi = boost::spirit::qi;

static void print(const std::vector<char>& v) {
   std::cout << std::string(v.begin(), v.end()) << '\n';
}

template<typename Iterator>
class Grammar : public qi::grammar<Iterator, boost::spirit::ascii::space_type> {
   typedef boost::spirit::ascii::space_type space_type;
   qi::rule<Iterator, space_type> start;
   qi::rule<Iterator, std::vector<char>()> string;
   qi::rule<Iterator, char()> unescapedChar;

public:
   Grammar() : Grammar::base_type(start) {
      start = string[&print];
      string %= qi::lexeme['"' >> qi::no_skip[*unescapedChar] >> '"'];
      unescapedChar %= qi::char_ - qi::lit('"');
   }
};

int main() {
   const std::string s("\"how now brown cow\"");
   boost::iostreams::filtering_istream fs(boost::make_iterator_range(s.begin(), s.end()));;

   typedef boost::spirit::istream_iterator iterator;
   qi::phrase_parse(
      iterator(fs), iterator(),
      Grammar<iterator>(),
      boost::spirit::ascii::space);

   return 0;
}

In this program the unescapedChar rule defines the allowable characters within a string (anything but double quotes) and the string rule is a Kleene star of unescapedChar within double quotes.

The output of this program when passed "how now brown cow" (with the quotes as part of the string) is hownowbrowncow. The std::vector<char> attribute of string is missing all the spaces. I want the spaces to be in the parsed result.

Neither the unescapedChar nor the string rule declarations specify a skip type. I also tried to use the lexeme and no_skip directives both individually and together (as shown above). I have tried boost 1.49 and boost 1.55. In each case the output has no embedded spaces.

In my actual parser I do want to skip spaces, just not within quoted strings. What am I doing incorrectly?

Was it helpful?

Solution

I think your problem is the input stream skipping whitespace

See http://en.cppreference.com/w/cpp/io/manip/skipws

Adding

fs.unsetf(std::ios::skipws);

fixes things

See it Live on Coliru

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top