I was trying to create a custom Parser class in Boost.Spirit (2.3), but it didn't work out. The code is:
template <class Iter>
class crule : public boost::spirit::qi::parser<crule<Iter> >
{
rule<Iter> r_;
public:
crule(const rule<Iter>& r) : r_(r) {}
template <class T>
crule(const T& t) : r_(t) {}
template<class Ctx, class Skip>
bool parse(Iter& f, const Iter& l, Ctx& context, Skip& skip, typename rule<Iter>::template attribute<Ctx, Iter>::type& attr) const {
return r_.parse(f, l, context, skip, attr);
}
template <class Ctx>
boost::spirit::info what(Ctx& context) const {
return r_.what(context);
}
template <class Context, class It>
struct attribute {
typedef typename rule<Iter>::template attribute<Context, It>::type type;
};
};
and although I have (at least I think I have) fulfilled all the requirements, I get errors when I try to use this class in a parsing expression:
shell_grammar.h:134: error: no match for 'operator!' in '!shell_grammar<Iter>::token(boost::spirit::qi::rule<Iter, boost::fusion::unused_type, boost::fusion::unused_type, boost::fusion::unused_type>) [with Iter = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >](boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, boost::fusion::unused_type, boost::fusion::unused_type, boost::fusion::unused_type>(((const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, boost::fusion::unused_type, boost::fusion::unused_type, boost::fusion::unused_type>&)((const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, boost::fusion::unused_type, boost::fusion::unused_type, boost::fusion::unused_type>*)(&((shell_grammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >*)this)->shell_grammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::reserved_words)))))'
shell_grammar.h:134: note: candidates are: operator!(bool) <built-in>
I tried to look at the implementation of other parsets (eg. not_predicate
), but can't figure out what is the difference that makes it work.
Motvation
The reason I do it is related to this question. I want to parse POSIX shell language, which has peculiar lexical rules. Particularly, the "skipper parser" has to be applied even in lexemes, but it has to be different from the "phrase level" skipper parser. Which is what the lexeme
directive can't do, and skip
doesn't pre-skip (AFAIK), which is what I need, too. So I want to create a function
something token(std::string);
that would return a rule matching the token. One way is creating my own rule
wrapper that would serve as a terminal (since rule
alone cannot be used for its reference semantics), another would be creating a new parser (that would be a nonterminal in proto
), and implement shell's token parsing in it.