Boost.Spirit(X3,Boost 1.64):如何正确实施此递归规则

Boost.spirit (x3, boost 1.64): how to implement this recursive rule correctly, is it possible?

本文关键字:Boost 何正确 施此 规则 递归 Spirit X3      更新时间:2023-10-16

这个问题很容易提出。我有一个递归规则,我不知道该规则的综合属性类型,但我也有一些有关内部工作的问题。

在我看来,返回类型是variant<tuple<return_type_of_a, SEQ>, tuple<return_type_of_b, SEQ>>,其中SEQ是递归规则,ab是终端:

rule<class myrule, ??> SEQ = a >> SEQ | b >> SEQ;

由于规则是递归的,因此不接受以下内容,我无法完全弄清返回类型:

rule<class myrule, decltype (a>> SEQ | b >> SEQ)> seq = a >> seq | b >> seq;
  1. 我必须知道递归规则的返回类型吗?
  2. 看起来必须有某种类型的嵌套,这是自然的递归,但是如果不扁平,则不可能在编译时计算返回类型。那么,如何在编译时计算递归规则的类型呢?有什么样的扁平?
  3. 上面规则的合成应该是什么?
  4. 将规则重构为:
  5. 是否有帮助

rule<class myrule, ??> SEQ = (a | b) >> SEQ;

感谢您的帮助。

  1. 关于

    seq = a >> seq | b >> seq;
    

    首先:您的语法是严格的循环,永远不会解析:它将无限地反复该规则,直到不匹配为止。我将假设您想要类似的东西:

    expr = var | "!" >> expr;
    

    (请注意,并非所有分支都无条件地反复出现)。

  2. 如何正确实施此递归规则,是否可能?

    是。教程样本可能应该显示此。

样品

假设我们有一个非常非常简单的语法,例如

expr = var | '!' >> expr;

我们创建一个AST来反映这一点:

namespace Ast {
    using var = std::string;
    struct negated;
    using expr = boost::variant<var, boost::recursive_wrapper<negated> >;
    struct negated {
        expr e;
    };
}

规则

由于expr规则将是递归的,因此我们必须在其定义之前声明它:

    static x3::rule<struct expr_, Ast::expr> expr {"expr"};

让我们想象它已经定义了,我们将写下sub表达式:

    auto var = x3::rule<struct var_, Ast::var> {"var"}
             = x3::lexeme [ x3::alpha >> *x3::alnum ];
    auto neg = x3::rule<struct var_, Ast::negated> {"neg"}
             = "!" >> expr;

剩下的就是递归规则本身:BOOST_SPIRIT_DEFINE

    auto expr_def = var | neg;
    BOOST_SPIRIT_DEFINE(expr)

仅此而已。

演示时间

让我们添加一些测试用例:

活在coliru

#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/adapted/struct.hpp>
namespace Ast {
    using var = std::string;
    struct negated;
    using expr = boost::variant<var, boost::recursive_wrapper<negated> >;
    struct negated {
        expr e;
    };
    static inline std::ostream& operator <<(std::ostream& os, Ast::negated const& n) {
        return os << "NOT(" << n.e << ")";
    }
}
BOOST_FUSION_ADAPT_STRUCT(Ast::negated, e)
namespace Parsers {
    namespace x3 = boost::spirit::x3;
    namespace detail {
        static x3::rule<struct expr_, Ast::expr> expr {"expr"};
        auto var = x3::rule<struct var_, Ast::var> {"var"}
                 = x3::lexeme [ x3::alpha >> *x3::alnum ];
        auto neg = x3::rule<struct var_, Ast::negated> {"neg"}
                 = "!" >> expr;
        auto expr_def = var | neg;
        BOOST_SPIRIT_DEFINE(expr)
    }
    auto demo = x3::skip(x3::space) [ detail::expr ];
}
#include <iostream>
int main() {
    for (std::string const input : { "foo", "! bar", "!!!qux" }) {
        auto f = input.begin(), l = input.end();
        Ast::expr e;
        if (parse(f, l, Parsers::demo, e)) {
            std::cout << "Parsed: " << e << "n";
        } else {
            std::cout << "Parse failedn";
        }
        if (f != l)
            std::cout << "Remaining unparsed input: '" << std::string(f,l) << "'n";
    }
}

打印

Parsed: foo
Parsed: NOT(bar)
Parsed: NOT(NOT(NOT(qux)))

和(可选)(#define BOOST_SPIRIT_X3_DEBUG

活在coliru

<expr>
  <try>foo</try>
  <var>
    <try>foo</try>
    <success></success>
    <attributes>[f, o, o]</attributes>
  </var>
  <success></success>
  <attributes>[f, o, o]</attributes>
</expr>
Parsed: foo
<expr>
  <try>! bar</try>
  <var>
    <try>! bar</try>
    <fail/>
  </var>
  <neg>
    <try>! bar</try>
    <expr>
      <try> bar</try>
      <var>
        <try> bar</try>
        <success></success>
        <attributes>[b, a, r]</attributes>
      </var>
      <success></success>
      <attributes>[b, a, r]</attributes>
    </expr>
    <success></success>
    <attributes>[[b, a, r]]</attributes>
  </neg>
  <success></success>
  <attributes>[[b, a, r]]</attributes>
</expr>
Parsed: NOT(bar)
<expr>
  <try>!!!qux</try>
  <var>
    <try>!!!qux</try>
    <fail/>
  </var>
  <neg>
    <try>!!!qux</try>
    <expr>
      <try>!!qux</try>
      <var>
        <try>!!qux</try>
        <fail/>
      </var>
      <neg>
        <try>!!qux</try>
        <expr>
          <try>!qux</try>
          <var>
            <try>!qux</try>
            <fail/>
          </var>
          <neg>
            <try>!qux</try>
            <expr>
              <try>qux</try>
              <var>
                <try>qux</try>
                <success></success>
                <attributes>[q, u, x]</attributes>
              </var>
              <success></success>
              <attributes>[q, u, x]</attributes>
            </expr>
            <success></success>
            <attributes>[[q, u, x]]</attributes>
          </neg>
          <success></success>
          <attributes>[[q, u, x]]</attributes>
        </expr>
        <success></success>
        <attributes>[[[q, u, x]]]</attributes>
      </neg>
      <success></success>
      <attributes>[[[q, u, x]]]</attributes>
    </expr>
    <success></success>
    <attributes>[[[[q, u, x]]]]</attributes>
  </neg>
  <success></success>
  <attributes>[[[[q, u, x]]]]</attributes>
</expr>
Parsed: NOT(NOT(NOT(qux)))