Boost Spirit Qi Re-Establish Skipping with custom skip grammar
I have a grammar that has, up until now, been using the standard boost::spirit::ascii::space
/boost::spirit::ascii::space_type
skipper.
I have some rules that use the skipper and some that don't, like
qi::rule<Iterator, PTR<Expression>(), ascii::space_type> expression;
qi::rule<Iterator, PTR<Term>()> term;
When I use a non-skipping nonterminal (like term
) inside of a skipping nonterminal (like expression
), everything works like I would expect - whitespace only matters inside the term
nonterminal.
Further, up until now, I have been fine including nonterminals that use the skipper inside of nonterminals that don't using qi::skip
to restablish skipping, such as
index = (qi::lit('[') >> qi::skip(ascii::space)[explist >> qi::lit(']')]);
This way, whitespace is not significant inside of the []
braces, but is outside.
However, now I want to add my own custom skipper (I want to make newlines significant and later add comment-skipping). My skipper grammar looks like:
struct skip_grammar : qi::grammar<Iterator> {
qi::rule<Iterator> start;
skip_grammar() : skip_grammar::base_type(start) {
start = qi::char_("\t\r ");
}
};
I have been able to add it into my rule definitions just fine like
qi::rule<Iterator, PTR<Expression>(), skip_grammar> expression;
But I can't seem to figure out how to use m开发者_JS百科y skip grammar as an argument to qi::skip
(and replace ascii::space
). I've tried using the type, a local instance variable, and a global instance variable. The farthest I've gotten is to get clang to complain that my skip_grammar needs a copy constructor. So I tried adding a copy constructor to my skip grammar, but apparently the boost::noncopyable
base class is there for a reason, because my binary segfaulted almost immediately.
How should I be using this?
Thanks
A qi::grammar
is just a container for qi::rules
. It does not have a copy constructor because this could inadvertently create dangling references in the parser expressions on the right hand side of those rules.
Using a grammar as a skipper as you want to do it is a bit tricky and amounts to passing the start rule of the grammar to the skip parser. It might be easier to just create a rule instance for that (especially if you have a single rule skipper).
In any case, the rule needs to be passed to the skipper as a reference (by calling the rule's member function alias()
):
skip_grammar skippper;
index = '[' >> qi::skip(skipper.start.alias())[explist >> ']'];
or simply:
rule<iterator> skipper = qi::char_("\t\r ");
index = '[' >> qi::skip(skipper.alias())[explist >> ']'];
The aliasing is necessary because of the specifics of what it means to copy a rule. It is described in more detail in Spirit's FAQ here.
精彩评论