Boost Spirit可选解析器和回溯

时间:2014-10-03 19:57:12

标签: c++ boost boost-spirit boost-spirit-qi

为什么此解析器会在属性中保留'b',即使选项未匹配?

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

它成功解析,但res为"ab"

如果仅使用expr解析"abac",则匹配选项且属性为"aba"

"aac"相同,选项不会开始匹配,属性为"aa"

但是使用"ab",属性为"ab",即使b得到回溯,并且,例如,与下一个解析器匹配。

UPD

expr.name("expr");debug(expr);我得到了

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

2 个答案:

答案 0 :(得分:3)

首先,它UB使用auto变量来保留表达式模板,因为它们包含对临时值"a""b" [1] 即可。

改为写

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

或者,如果你坚持:

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

现在注意到隐藏在>> lit("bc")电话中的parse部分,建议您可以预期,当解析失败发生时,回溯到成功匹配的令牌。

这并不会发生:Spirit会生成PEG语法,并且总是从左到右贪婪地匹配。


对于给定的示例,ab结果,即使回溯发生,在没有qi::hold的情况下也不会回滚对该属性的影响: {{ 3}}

容器属性由ref传递,之前(成功)表达式的效果是 回滚,除非您也告诉Spirit。通过这种方式,您可以为您使用的内容付费#34; (因为复制临时工作总是很昂贵)。

参见例如

<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] 见这里:

答案 1 :(得分:2)

this SO问题

引用@sehe
  

字符串属性是容器属性,可以有许多元素   由不同的解析器子表达式分配给它。现在为   效率原因,Spirit不会回滚发射的值   回溯的属性。

所以,我已将可选解析器置于保持状态,并且已完成。

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

有关详细信息,请参阅上述问题和hold docs