Boost Spirit Qi解析器不会消耗整个字符串表达式?

时间:2014-03-25 15:11:44

标签: c++ parsing boost boost-spirit

假设我有以下规则:

identifier %= 
        lexeme[
            char_("a-zA-Z")
            >> -(*char_("a-zA-Z_0-9")
            >> char_("a-zA-Z0-9"))
        ]
        ;

qi::rule<Iterator, std::string(), Skipper> identifier;

以及以下输入:

// identifier
This_is_a_valid123_Identifier

当跟踪显示标识符被正确解析并且属性已设置但是队长再次在字符串的第一个字符后面开始一个字符:

<identifier>
  <try>This_is_a_valid123_I</try>
  <skip>
    <try>This_is_a_valid123_I</try>
    <emptylines>
      <try>This_is_a_valid123_I</try>
      <fail/>
    </emptylines>
    <comment>
      <try>This_is_a_valid123_I</try>
      <fail/>
    </comment>
    <fail/>
  </skip>
  <success>his_is_a_valid123_Id</success>
  <attributes>[[T, h, i, s, _, i, s, _, a, _, v, a, l, i, d, 1, 2, 3, _, I, d, e, n, t, i, f, i, e, r]]</attributes>
</identifier>
<skip>
  <try>his_is_a_valid123_Id</try>
  <emptylines>
    <try>his_is_a_valid123_Id</try>
    <fail/>
  </emptylines>
  <comment>
    <try>his_is_a_valid123_Id</try>
    <fail/>
  </comment>
  <fail/>
</skip>

我已经尝试在lexeme表达式中使用as_string,但没有帮助。

1 个答案:

答案 0 :(得分:4)

我不明白为什么你使表达复杂化。你能试试吗

identifier %= 
                char_("a-zA-Z")
            >> *char_("a-zA-Z_0-9")
        ;

qi::rule<Iterator, std::string()> identifier;

这是您可以获得的最标准的表达方式。即使您不希望允许以_结尾的标识符,我也非常确定您不希望将这样的尾随_解析为“下一个标记”。在这种情况下,我只需在解析后添加验证。

更新发表评论:

以下是分析:

  • 首先关闭:-(*x) 红旗 。它永远不是一个有用的模式,因为*x已匹配空序列,你不能使它“更可选”

      

    (事实上,如果*x允许部分回溯,就像在正则表达式中一样,你可能已经看到指数性能甚至是运行时运行;“幸运”,*x是在灵气中总是贪心)

这确实有助于你的错误。让我们将OP中的解析器表达式看作第1,2,3行。

  • 首先,第1行匹配T
  • 第二行最初贪婪地匹配his_is_a_valid123_Identifier
  • 但是这不能满足第三行,所以-(...)开始了,第一行之后的所有内容都被撤回了。
  • 然而 :Qi

    • 回溯游标(当前输入迭代器)但是
    • 默认情况下回滚更改为容器属性。

    是。你猜到了。 std::string是容器属性。

所以你最终得到的是长度为1的成功匹配,以及属性中失败的可选序列的剩余部分。

其他一些关于如何解决这种回溯问题的背景资料: