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>
source to share
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.
- boost :: spirit :: qi re-parse on output
- Understanding Boost.spirit string parsing
- Strengthening the spirit resumes parsing
<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:
source to share
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
source to share