精神:在回溯过程中丢弃属性

时间:2018-01-21 10:26:18

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

我不理解以下示例中x3的行为(取自更大的语法)。

语法有点奇怪,被授予,但大致它实现了(lal)?(<char>)?。当第二组不存在时,默认为<default>。我不明白为什么在输入"lal<char>"上我得到了defaultchar

#include <iostream>

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/adapted/std_pair.hpp>

int main()
{
  namespace x3 = boost::spirit::x3;
  namespace ascii = boost::spirit::x3::ascii;

  using ascii::alnum;
  using ascii::char_;
  using ascii::space;
  using x3::attr;
  using x3::eoi;
  using x3::lexeme;
  using x3::lit;
  using x3::string;

  const auto letter
    = lit("<") >> string("char") >> lit('>')
    | attr(std::string{"default"})
    ;

  const auto letterset
    = letter >> eoi
    | lit("lal") >> letter >> eoi
    ;

  for (std::string i: {"", "<char>", "lal", "lal<char>"})
    {
      auto res = std::string{};
      auto first = i.cbegin();
      auto last = i.cend();
      auto r = x3::phrase_parse(first, last, letterset, space, res);
      if (r && first == last)
        std::cout << i << ": " << res << '\n';
      else
        std::cout << i << ": failed\n";
    }
}

结果:

: default
<char>: char
lal: defaultdefault
lal<char>: defaultchar

我注意到如果我交换了letterset的替代品,那么我得到预期的结果,这可能是与回溯相关的一个标志:在原始情况下,我得到{{1从第一次尝试开始,以及第二次尝试的default成功。

我很想把这个称为bug,但我是x3的新手...

这是来自Boost 1.65的X3。

先谢谢@sehe:)

1 个答案:

答案 0 :(得分:2)

是的,你已经遇到了回溯的副作用。如果属性是容器(std::string是容器),则精神解析器会附加结果,但如果分支失败,则不会清除容器。

hold中有Qi指令来处理它,但不在X3中。我会看看我能对X3做些什么,我认为有一些解决方案的开销接近于零而没有可怕的hold指令。

一般的建议是尝试重写你的语法而不是回溯,但如果不可能,你可以使用一种解决方法(它应该是hold稍微高效的替代方法):

const auto recover_from_backtrack = (rule<class _, std::string>{} = eps) /
    [](auto const& ctx) { x3::_attr(ctx).clear(); x3::_pass(ctx) = false; };

const auto letterset
    = letter >> eoi
    | recover_from_backtrack
    | lit("lal") >> letter >> eoi
    ;