I'm trying to write a parser using boost::spirit::qi which will parse everything between a pair of "
as-is, and allowing escaping of "
characters. I.E., "ab\n\""
should return ab\n\"
. I've tried with the following code (godbolt link):
#include <boost/spirit/include/qi.hpp>
#include <string>
namespace qi = boost::spirit::qi;
int main() {
std::string input{R"("ab\n\"")"};
std::cout << "[" << input << "]\n";
std::string output;
using Skipper = qi::rule<std::string::const_iterator>;
Skipper skip = qi::space;
qi::rule<std::string::const_iterator, std::string(), Skipper> qstring;
qstring %= qi::lit("\"")
> ( *( (qi::print - qi::lit('"') - qi::lit("\\")) | (qi::char_("\\") > qi::print) ) )
// ^^^^^
> qi::lit("\"");
auto success = qi::phrase_parse(input.cbegin(), input.cend(), qstring, skip, output);
if (!success) {
std::cout << "Failed to parse";
return 1;
}
std::cout << "output = [" << output << "]\n";
return 0;
}
This fails to compile based on some template errors,
/opt/compiler-explorer/libs/boost_1_81_0/boost/spirit/home/support/container.hpp:130:12: error: 'char' is not a class, struct, or union type
130 | struct container_value
| ^~~~~~~~~~~~~~~
.....
/opt/compiler-explorer/libs/boost_1_81_0/boost/spirit/home/qi/detail/pass_container.hpp:320:66: error: no type named 'type' in 'struct boost::spirit::traits::container_value<char, void>'
320 | typedef typename traits::container_value<Attr>::type value_type;
I can get the code to compile if I change the underlined qi::char_("\\")
with qi::lit("\\")
, but that doesn't create an attribute for the \
which it matches. I've also found that I can get it to compile if I create a new rule which embodies just the Kleene star, but is there a way to get boost to use the correct types in a single expression?
qi::rule<std::string::const_iterator, std::string(), Skipper> qstring;
qi::rule<std::string::const_iterator, std::string(), Skipper> qstringbody;
qstringbody %= ( *( (qi::print - qi::lit('"') - qi::lit("\\")) | (qi::char_("\\") > qi::print) ) );
qstring %= qi::lit("\"")
> qstringbody
> qi::lit("\"");