boost::qi::parse seems to cause compilation errors
boost, boost-spirit, c++, compiler-errors
Solution
I think the most important culprit was the fact that you were using `qi::parse` instead of `qi::phrase_parse`, while your grammar explicitely uses a skipper.
I also rewrote the defintion of the `etfvalue` recursive variant. I'm not sure whether your version should have worked, but at least now, you can just use `etfnode` in all places where you'd expect to. It looks more consistent to me this way.
Here's code that compiles fine for me. It parses the sample input (see `main()`) with the following output:
Parsing succeeded
Unparsed remaining: ';'
If you actually wanted to accept the trailing `;`, fix the main rule to be more like
start = *(mapPair >> ';'); // or *(mapPair >> (';'|qi::eoi))
Good luck!
//add streaming operators for etfnode and etfvalue if you want to debug this:
//#define BOOST_SPIRIT_DEBUG
#include <map>
#include <string>
#include <boost/variant/recursive_wrapper.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted.hpp>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
enum DataType {
DT_INT,
DT_STRING,
DT_FLOAT,
DT_BOOL,
DT_LIST,
DT_PAIR,
DT_MAP
};
struct etfnode;
typedef boost::variant<
int,
std::string,
double,
bool,
boost::recursive_wrapper<std::vector<etfnode> >,
boost::recursive_wrapper<std::pair<etfnode, etfnode> >,
boost::recursive_wrapper<std::map<std::string, etfnode> >
> etfvalue;
struct etfnode {
DataType type;
etfvalue value;
etfnode(const std::string& s) { value = s; type = DT_STRING; }
etfnode(const int i) { value = i; type = DT_INT; }
etfnode(const double d) { value = d; type = DT_FLOAT; }
etfnode(const bool b) { value = b; type = DT_BOOL; }
etfnode(const std::vector<etfnode>& n) { value = n; type = DT_LIST; }
etfnode(const std::pair<etfnode, etfnode>& p) { value = p; type = DT_PAIR; }
etfnode(const std::map<std::string, etfnode>& p) { value = p; type = DT_MAP; }
etfnode() { }
};
template<typename Iterator>
struct etf_parser : qi::grammar<Iterator, std::map<std::string, etfnode>(), ascii::space_type> {
etf_parser() : etf_parser::base_type(start) {
using qi::int_;
using qi::lit;
using qi::double_;
using qi::bool_;
using qi::lexeme;
using ascii::char_;
quoted_string = lexeme['"' >> +(char_ - '"') >> '"'];
dataVal = (quoted_string | double_ | int_ | bool_
| listObj | pairObj
| mapObj
);
listObj = '{' >> dataVal % ',' >> '}';
pairObj = lit('<') >> dataVal >> ',' >> dataVal >> '>';
mapKey = +qi::char_("a-zA-Z_-0-9.");
mapPair = mapKey >> lit('=') >> dataVal;
mapObj = '(' >> mapPair % ',' >> ')';
start = mapPair % ';';
BOOST_SPIRIT_DEBUG_NODE(quoted_string);
BOOST_SPIRIT_DEBUG_NODE(dataVal);
BOOST_SPIRIT_DEBUG_NODE(listObj);
//BOOST_SPIRIT_DEBUG_NODE(pairObj);
BOOST_SPIRIT_DEBUG_NODE(mapObj);
BOOST_SPIRIT_DEBUG_NODE(mapKey);
BOOST_SPIRIT_DEBUG_NODE(mapPair);
BOOST_SPIRIT_DEBUG_NODE(start);
}
qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;
// Data value parsers
qi::rule<Iterator, etfnode(), ascii::space_type> dataVal;
qi::rule<Iterator, std::vector<etfnode>(), ascii::space_type> listObj;
qi::rule<Iterator, std::pair<etfnode, etfnode>(), ascii::space_type> pairObj;
qi::rule<Iterator, std::map<std::string, etfnode>(), ascii::space_type> mapObj;
qi::rule<Iterator, std::pair<std::string, etfnode>(), ascii::space_type> mapPair;
qi::rule<Iterator, std::string(), ascii::space_type> mapKey;
qi::rule<Iterator, std::map<std::string, etfnode>(), ascii::space_type> start;
};
int main()
{
etf_parser<std::string::const_iterator> parser;
std::map<std::string, etfnode> results;
std::string content = "foo = 6;\n"
"bar = <\"bar\", 16.5>;\n"
"baz = {\n"
" (\n"
" foobar = \"foo\",\n"
" bar = 12\n"
" ),\n"
" \"foobar\"\n"
"};";
std::string::const_iterator begin = content.begin();
std::string::const_iterator end = content.end();
bool result = qi::phrase_parse(begin, end, parser, ascii::space, results);
if(result) printf("Parsing succeeded\n"); else printf("Parsing failed\n");
if (begin!=end)
std::cout << "Unparsed remaining: '" << std::string(begin,end) << "'\n";
//m_root = etfnode(results);
}
Problem
I'm trying to write a parser using Boost::Spirit, and I have the parser written and compiling. The problem is, when I try to compile the parsing function, the compiler throws out a bunch of template errors. Here's the Qi grammar: ``` template<typename Iterator> struct etf_parser : qi::grammar<Iterator, std::map<std::string, etfnode>(), ascii::space_type> { etf_parser() : etf_parser::base_type(start) { using qi::int_; using qi::lit; using qi::double_; using qi::bool_; using qi::lexeme; using ascii::char_; quoted_string %= lexeme['"' >> +(char_ - '"') >> '"']; dataVal %= (quoted_string | double_ | int_ | bool_ | listObj | pairObj | mapObj); pairObj %= ('<' >> dataVal >> ',' >> dataVal >> '>'); listObj %= '{' >> dataVal % ',' >> '}'; mapKey %= +qi::char_("a-zA-Z_-0-9."); mapPair %= mapKey >> lit('=') >> dataVal; mapObj %= '(' >> mapPair % ',' >> ')'; start %= mapPair >> ';'; } qi::rule<Iterator, std::string(), ascii::space_type> quoted_string; // Data value parsers qi::rule<Iterator, etfnode(), ascii::space_type> dataVal; qi::rule<Iterator, std::vector<etfnode>(), ascii::space_type> listObj; qi::rule<Iterator, std::pair<etfnode, etfnode>(), ascii::space_type> pairObj; qi::rule<Iterator, std::map<std::string, etfnode>(), ascii::space_type> mapObj; qi::rule<Iterator, std::pair<std::string, etfnode>(), ascii::space_type> mapPair; qi::rule<Iterator, std::string(), ascii::space_type> mapKey; qi::rule<Iterator, std::map<std::string, etfnode>(), ascii::space_type> start; }; ``` And here's the parsing function. When I comment out the qi::parse call, the code compiles fine: ``` ETFDocument::ETFDocument(std::string content) { etf_parser<std::string::const_iterator> parser; std::map<std::string, rwnode> results; std::string::const_iterator begin = content.begin(); std::string::const_iterator end = content.end(); bool result = qi::parse(begin, end, parser, results); if(result) printf("Parsing succeeded\n"); else printf("Parsing failed\n"); m_root = etfnode(results); } ``` The compiler spits out the following error when I try to compile: ``` In file included from /usr/include/boost/spirit/home/qi/nonterminal.hpp:14:0, from /usr/include/boost/spirit/home/qi.hpp:20, from /usr/include/boost/spirit/include/qi.hpp:16, from libmcg/etf.cpp:8: /usr/include/boost/spirit/home/qi/nonterminal/rule.hpp: In instantiation of ‘bool boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>::parse(Iterator&, const Iterator&, Context&, const Skipper&, Attribute&) const [with Context = boost::spirit::context<boost::fusion::cons<std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >&, boost::fusion::nil>, boost::spirit::locals<> >; Skipper = boost::spirit::unused_type; Attribute = std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >; Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >; T1 = std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >(); T2 = boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l>; T3 = boost::spirit::unused_type; T4 = boost::spirit::unused_type]’: /usr/include/boost/spirit/home/qi/reference.hpp:43:71: required from ‘bool boost::spirit::qi::reference<Subject>::parse(Iterator&, const Iterator&, Context&, const Skipper&, Attribute&) const [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >; Context = boost::spirit::context<boost::fusion::cons<std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >&, boost::fusion::nil>, boost::spirit::locals<> >; Skipper = boost::spirit::unused_type; Attribute = std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >; Subject = const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l>, boost::spirit::unused_type, boost::spirit::unused_type>]’ /usr/include/boost/spirit/home/qi/parse.hpp:86:82: required from ‘bool boost::spirit::qi::parse(Iterator&, Iterator, const Expr&, Attr&) [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >; Expr = etf_parser<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> > >; Attr = std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >]’ libmcg/etf.cpp:113:53: required from here /usr/include/boost/spirit/home/qi/nonterminal/rule.hpp:303:17: error: no match for call to ‘(const function_type {aka const boost::function<bool(__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&, const __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&, boost::spirit::context<boost::fusion::cons<std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >&, boost::fusion::nil>, boost::fusion::vector0<> >&, const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >&)>}) (__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&, const __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&, boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l>, boost::spirit::unused_type, boost::spirit::unused_type>::context_type&, const boost::spirit::unused_type&)’ In file included from /usr/include/boost/function/detail/maybe_include.hpp:33:0, from /usr/include/boost/function/detail/function_iterate.hpp:14, from /usr/include/boost/preprocessor/iteration/detail/iter/forward1.hpp:67, from /usr/include/boost/function.hpp:64, from /usr/include/boost/spirit/home/qi/nonterminal/rule.hpp:16, from /usr/include/boost/spirit/home/qi/nonterminal.hpp:14, from /usr/include/boost/spirit/home/qi.hpp:20, from /usr/include/boost/spirit/include/qi.hpp:16, from libmcg/etf.cpp:8: /usr/include/boost/function/function_template.hpp:1021:7: note: candidate is: /usr/include/boost/function/function_template.hpp:754:17: note: boost::function4<R, T1, T2, T3, T4>::result_type boost::function4<R, T1, T2, T3, T4>::operator()(T0, T1, T2, T3) const [with R = bool; T0 = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&; T1 = const __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >&; T2 = boost::spirit::context<boost::fusion::cons<std::map<std::basic_string<char>, boost::recursive_wrapper<ETFDocument::etfnode> >&, boost::fusion::nil>, boost::fusion::vector0<> >&; T3 = const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >&; boost::function4<R, T1, T2, T3, T4>::result_type = bool] /usr/include/boost/function/function_template.hpp:754:17: note: no known conversion for argument 4 from ‘const boost::spirit::unused_type’ to ‘const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >&’ ``` As far as I can tell, it's looking for a Skipper, but getting boost::spirit::unused_type instead. I'm not sure why this would happen, since I specified a Skipper in my parser definition. I'm using boost v1.49.0 on gcc 4.7.1. EDIT: Here's the definition for etfnode. There's a typedef at the beginning of the cpp file (containing the other code fragments) that aliases "etfnode" to "rwnode". ``` enum DataType { DT_INT, DT_STRING, DT_FLOAT, DT_BOOL, DT_LIST, DT_PAIR, DT_MAP }; struct etfnode; typedef boost::recursive_wrapper<etfnode> rwnode; typedef boost::variant< int, std::string, double, bool, std::vector<rwnode>, std::pair<rwnode, rwnode>, std::map<std::string, rwnode> > etfvalue; struct etfnode { DataType type; etfvalue value; etfnode(const std::string& s); etfnode(const int i); etfnode(const double d); etfnode(const bool b); etfnode(const std::vector<rwnode>& n); etfnode(const std::pair<rwnode, rwnode>& p); etfnode(const std::map<std::string, rwnode>& p); etfnode(); }; ``` And a test string: ``` foo = 6; bar = <"bar", 16.5>; baz = { ( foobar = "foo", bar = 12 ), "foobar" }; ```