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(
        str.begin(),
        str.end(),
        expr >> lit("bc"),
        res
);

      

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.

UPD

C expr.name("expr");

and debug(expr);

I got

<expr>
  <try>abc</try>
  <success>bc</success>
  <attributes>[[a, b]]</attributes>
</expr>

      

+2


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).

Cm.

<a>
  <try>abc</try>
  <success>bc</success>
  <attributes>[a]</attributes>
</a>
<a>
  <try>bc</try>
  <fail/>
</a>
<b>
  <try>bc</try>
  <success>c</success>
  <attributes>[b]</attributes>
</b>
<a>
  <try>c</try>
  <fail/>
</a>
<bc>
  <try>bc</try>
  <success></success>
  <attributes>[]</attributes>
</bc>
Success: 'ab'

      




[1] see here:

+3


source


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

+2


source







All Articles