Boost.spirit(x3,boost 1.64):如何正确实现这个递归规则,是否可能?

时间:2017-09-14 03:20:52

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

这个问题很容易制定。我有一个递归规则,我不知道规则的合成属性类型,但我还有一些关于内部工作的问题。

在我看来,返回类型为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 个答案:

答案 0 :(得分:1)

  1. 关于

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

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

    expr = var | "!" >> expr;
    

    (注意并非所有分支都无条件递归)。

  2.   

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

    是。教程样本应该显示出来。

  3. 样品

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

    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"};
    

    让我们想象一下它已经定义了,我们会写下子表达式:

        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)
    

    就是这样。

    DEMO TIME

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

    <强> Live On 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 failed\n";
            }
    
            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

    <强> Live On 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)))