I'm parsing some input that is vaguely structured like C-ish code. Like this:
Name0
{
Name1
{
//A COMMENT!!
Param0 *= 2
Param2 = "lol"
}
}
Part of that is comments, which I want to totally ignore (and it's not working). I consider two things to be a node
, the named scopes (category
rule) like Name0 {}
and the values (param
rule) like Param0 *= 2
... then there is comment
. I've tried setting things up like this:
typedef boost::variant<boost::recursive_wrapper<Category>, Param> Node;
qi::rule<Iterator, Node(), ascii::space_type> node;
So the node
rule puts either a Category
or a Param
in a variant
. Here are the other rules (I've omitted some rules that don't really matter for this):
qi::rule<Iterator> comment; //comment has no return type
qi::rule<Iterator, Category(), ascii::space_type> category;
qi::rule<Iterator, Param(), ascii::space_type> param;
And their actual code:
comment = "//" >> *(char_ - eol);
param %=
tagstring
>> operators
>> value;
category %=
tagstring
>> '{'
>> *node
> '}';
node %= comment | category | param;
comment
is setup to use =
instead of %=
, and it has no return type. However, comments end up creating null Category
s in my output Node
s wherever they show up. I've tried moving comment
out of the node
rule and into category
like this:
category %=
tagstring
>> '{'
>> *(comment | node)
> '}';
And various other things, but those null entries keep popping up. I had to make comment
output a string and put std::string
in my Node
variant
just to sorta catch them, but that messes up my ability to stick in commenting in other parts of my rules (unless I actually grab the string in every location).
How can I completely ignore the comment
and have it not show up in any output in any way?
edit: You'd think omit
would do it, but didn't seem to change anything...
edit 2: Referencing this SO answer, I have a shaky solution in this:
node %= category | param;
category %=
tagstring
>> '{'
>> *comment >> *(node >> *comment)
> '}';
However, I want to try to stick comments into all sorts of places (between tagstring
and {
, in my unshown root
rule between root category
s, etc). Is there a simpler method than this? I was hoping it could be done with a simple >> commentwrapper
plugged into wherever I wanted...
Alright, so making your own skipper isn't too bad. And it elegantly solves this commenting problem, just as Mike M said. I define my rules in a struct called Parser
that is templated with an Iterator
. Had to make some adjustments to use the skipper. First, here is the skipper which is defined in Parser
with all my other rules:
typedef qi::rule<Iterator> Skipper;
Skipper skipper;
So skipper
is a rule of type Skipper
. Here is what my Parser
struct looked like originally, where it was using the ascii::space
rule of type ascii::space_type
as its skipper, which IS NOT the same type as qi::rule<Iterator>
that skipper
is based on!
struct Parser : qi::grammar<Iterator, std::vector<Category>(), ascii::space_type>
{
qi::rule<Iterator, std::vector<Category>(), ascii::space_type> root;
...
So every instance of ascii::space_type
in the rule templates must be replaced with Skipper
! That includes other rules besides the root
that is shown here, such as param
and category
from my question. Leaving any remnant of the old ascii::space_type
behind gives cryptic compiler errors.
struct Parser : qi::grammar<Iterator, std::vector<Category>(), qi::rule<Iterator>>
{
typedef qi::rule<Iterator> Skipper;
Skipper skipper;
qi::rule<Iterator, std::vector<Category>(), Skipper> root;
...
The original skipper was merely space
, mine is now an alternative of space
and comment
. No old functionality (space skipping) is lost.
skipper = space | comment;
Then the phrase_parse
call needs to be adjusted from this old version that used ascii::space
:
bool r = phrase_parse(iter, end, parser, ascii::space, result);
to
bool r = phrase_parse(iter, end, parser, parser.skipper, result);
And now comments disappear as easily as white space. Awesome.