2

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?

rhashimoto
  • 15,650
  • 2
  • 52
  • 80
  • Sorry. I noticed you already used (too many) of these techniques after I voted as duplicate. See my answer. – sehe Feb 01 '14 at 02:26

1 Answers1

4

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

sehe
  • 374,641
  • 47
  • 450
  • 633
  • 1
    Huh. I was looking in the wrong place entirely. I verified your fix works in my actual parser. Thanks so much! – rhashimoto Feb 01 '14 at 02:43