Optional Boost Spirit parser and backtracking

Why does this parser leave 'b'

in attributes even if no option has been matched?

using namespace boost::spirit::qi;

std::string str = "abc";

auto a = char_("a");
auto b = char_("b");
qi::rule<std::string::iterator, std::string()> expr;
expr = +a >> -(b >> +a);

std::string res;

bool r = qi::parse(
        expr >> lit("bc"),


It parses successfully, but res "ab"


If parse "abac"

with expr alone, the option is matched and the attribute "aba"


Same with "aac"

, the parameter does not start to match, but the attribute "aa"


But with the "ab"

attribute "ab"

although b gets a countdown and, as in the example, matches the following parser.


C expr.name("expr");

and debug(expr);

I got

  <attributes>[[a, b]]</attributes>



source to share

2 answers

First, UB use variables auto

to store expression templates because they contain references to temporary files "a"

and [1] ."b"

Instead, write

expr = +qi::char_("a") >> -(qi::char_("b") >> +qi::char_("a"));


or, if you insist:

auto a = boost::proto::deep_copy(qi::char_("a"));
auto b = boost::proto::deep_copy(qi::char_("b"));
expr = +a >> -(b >> +a);


Now, noticing that the part >> lit("bc")

hiding in the call parse

suggests that you can expect to return to successful token matches when a seat failure occurs along the way.

This doesn't happen: Spirit generates PEG grammars and is always greedily matching from left to right.

As shown in the sample, ab

although a reverse lookup occurs, effects on attribute do not roll back without qi::hold

: Live On Coliru

The container attributes are passed along with the ref, and the effects of previous (successful) <back> expressions are rolled back unless you are also talking about Spirit. This way, you can "pay for what you use" (since copying the temporary time would be expensive).


Success: 'ab'


[1] see here:



Quoting @sehe from this SO question

The string attribute is a container attribute, and many elements can be assigned to it by various parser subexpressions. Now, for efficiency reasons, Spirit does not roll back the emitted attribute values ​​when retreating.

So, I put the extra parser on standby and it did.

expr = +qi::char_("a") >> -(qi::hold[qi::char_("b") >> +qi::char_("a")]);


For more information see the mentioned question and hold documents



All Articles