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?
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