I have a parser for parsing an Identifier like foo, bar, baz
and one for parsing also nested identifiers like foo::bar, foo::bar.baz, foo::bar.baz.baham
They both parse into the same ast struct, which looks like this:
struct identifier : x3::position_tagged{
std::vector <std::string> namespaces;
std::vector <std::string> classes;
std::string identifier;
};
The parser for an identifier
looks like this:
#define VEC_ATR x3::attr(std::vector<std::string>({})) //ugly hack
auto const identifier_def =
VEC_ATR
>> VEC_ATR
>> id_string;
and for the nested_identifier
like this:
auto const nested_identifier_def =
x3::lexeme[
(+(id_string >> "::") >> +(id_string >> ".") > id_string)
| (+(id_string >> "::") >> VEC_ATR > id_string)
| (VEC_ATR >> +(id_string >> ".") > id_string)
| identifier
];
I know shame on me for the macro.
The identifier parser works fine, but the
nested_identifier
has a strange behaviour
if I try to parse something like foo::bar::baz
the ast objects which falls out of the parser, has all the namespaces, in this case foo
and bar
twice in the namespaces
vector.
I have a small example of this strange behaviour
here.
Can anybody explain me why this happens, and how I can avoid this?
The reason why you get that behaviour is that the alternative parser does not automatically rollback the changes made to the external attribute when one of its branches fails.
In your case this is what happens:
In Spirit.Qi the solution in this case is quite easy, simply use the hold directive. Unfortunately this directive is not yet implemented in Spirit.X3. A possible alternative could be putting each of the alternative branches in its own
x3::rule
either explicitly or withas<ast::identifier>(alternative_branch)
as used here by sehe. Here is a simplified example that shows theas
approach.Another possibility could be implementing the
hold
directive, here is my attempt(running on WandBox):