2014-10-03 92 views
2

为什么此解析器在属性中保留'b'?即使选项不匹配?Boost Spirit可选解析器和回溯

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

它解析成功,但资源是"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> 

回答

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

现在注意到在parse呼叫>> lit("bc")部分隐藏,暗示可能是可预期的回溯到上成功地匹配令牌当分析失败发生在路上时。

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


在对样品给出ab结果,即使回溯确实发生,对属性的影响不无qi::hold回滚:Live On Coliru

容器属性沿着由参传递并且以前(成功)表达式的效果是而不是回滚,除非您也告诉Spirit。这样,你可以“支付你使用的东西”(因为一直复制临时对象会花费很多)。

参见例如

<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]在这里看到:

+0

嗯,我已经取代'auto's与规则。 – 2014-10-03 20:27:34

+0

但是,我不明白,你使用二进制减号?那是不同的语言,不是吗? – 2014-10-03 20:28:35

+0

@MikhailCheshkov我只是注意到这个错字。 **更新了答案。请原谅我的错误:/ – sehe 2014-10-03 20:34:12

2

引用从this @sehe SO质疑

的字符串的属性是一个容器属性和许多元件可以被 分配到它通过不同的解析器子表达式。现在对于效率的原因,Spirit不回滚发射的 属性的回溯值。

所以,我已经把可选的解析器搁置了,它就完成了。

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

欲了解更多信息,请参见上述问题,hold docs

+0

该信息在我的答案中是正确的。嗯。也许是因为我没有在那里显示“hold”的用法。好吧,+1(感谢您支持我的缺席) – sehe 2014-10-03 21:03:33

相关问题