【问题标题】:boost spirit how to access child nodes (leaves) from parent nodes提振精神如何从父节点访问子节点(叶子)
【发布时间】:2013-10-26 22:16:24
【问题描述】:

我想评估布尔表达式,例如 a=b & s

            =
           / \
          /   \
          a    b 

               &
              / \  
             /   \
            =     <
           / \    /\
          /   \  /  \
          a    b s   9   

叶子节点是值。离开节点的父节点始终是比较运算符,例如 =、!=、、>=、

如何从其父节点访问值节点(叶子)。 我在以下位置使用示例: How to calculate boolean expression in Spirit

Boolean expression (grammar) parser in c++ 这是取自这些链接的评估代码:

结构 eval : boost::static_visitor { 评估(){} // bool operator()(const var& v) const { std::cout& b) const { 递归(b.oper1) && 递归(b.oper2); } bool operator()(const binop& b) const { 递归(b.oper1)||递归(b.oper2); } bool operator()(const unop& u) const { 返回 !recurse(u.oper1); } //------------添加其他操作符---------------------------- bool operator()(const binop& u) const { // 稍后实现 返回真; } bool operator()(const binop& u) const { // 稍后实现 返回真; } bool operator()(const binop& u) const { // 稍后实现 返回真; } bool operator()(const binop& u) const { // 稍后实现 返回真; } bool operator()(const binop& u) const { // 稍后实现 返回真; } bool operator()(const binop& u) const { // 稍后实现 返回真; }

谢谢。欢迎提出任何建议。

【问题讨论】:

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


    【解决方案1】:

    您是否查看过现有运算符的其他评估重载?你有没有注意到他们是如何得到他们的操作数的值的(实际上可能是子表达式)?

    我以二进制为例:

    bool operator()(const binop<op_or>& b) const
    {
        return recurse(b.oper1) || recurse(b.oper2);
    }
    

    如您所见,它只是将|| 应用于两个操作数的值。在 AST[1] 中找不到该值。因此,我们将每个操作数视为一个表达式,然后递归地调用它的 eval 方法。

    因为表达式类型是一个变体,调用eval其实就是给变体申请一个访问者,而我had already written the helpful wrapper that does this so it's easy to recurse

    private:
    template<typename T>
        bool recurse(T const& v) const 
        { return boost::apply_visitor(*this, v); }
    

    所以,不知道你的语法的其余部分,但假设你以与现有语法相同的方式扩展它:

    bool operator()(const binop<op_equal>& u) const {
        return recurse(b.oper1) == recurse(b.oper2);
    }
    

    应该是对的。请注意,使用巧妙的宏,您可以很快完成:

    struct eval : boost::static_visitor<value> {
    
        // terminal
        value operator()(const var& v) const {
            std::cout<<"feuille:\n"<<v<<std::endl;
            return true; // TODO get value from var
        }
    
        // unary operator
        value operator()(const unop<op_not>& u) const { return !recurse(u.oper1); }
    
        /*
         * binary operators
         */
    #define EXPR_DEF_BINOP(tag, op) \
        value operator()(const binop<tag>& u) const { \
            return recurse(b.oper1) op recurse(b.oper2); \
        }
    
        EXPR_DEF_BINOP(op_and,           &&)
        EXPR_DEF_BINOP(op_equal,         ==)
        EXPR_DEF_BINOP(op_greater,       >)
        EXPR_DEF_BINOP(op_greater_equal, >=)
        EXPR_DEF_BINOP(op_less,          <)
        EXPR_DEF_BINOP(op_less_equal,    <=)
        EXPR_DEF_BINOP(op_not_equal,     !=)
        EXPR_DEF_BINOP(op_or,            ||)
    
    #undef EXPR_DEF_BINOP
    
      private:
        template<typename T>
            value recurse(T const& v) const 
            { return boost::apply_visitor(*this, v); }
    };
    

    还有一些注意事项:

    • 我在叶节点评估函数中添加了一个 TODO
    • 我将类型更改为value(来自bool)。这是因为您的语法支持非布尔表达式,否则运算符 &lt;=&gt;= 将没有意义。[2],因此您的值为不同的类型(也):

      using value = variant<bool, int32_t>;
      

      剩下的交给你


    [1] 记住 AST = 抽象语法树:它是源代码的 1:1 表示。 (“半例外”将是文字,尽管您仍然需要告诉评估者如何使用文字的值。)

    [2] 可以说

    • a&lt;b 可能暗示 !a &amp;&amp; b
    • a&gt;b 可能暗示 !b &amp;&amp; a
    • a!=b 可能暗示 a XOR b
    • a==b 可能暗示 !(a XOR b)

    【讨论】:

    • 有帮助!我想知道布尔表达式示例如何支持 Unicode。我试过了:
    • 有帮助!我想知道布尔表达式示例如何支持 Unicode。我尝试使用:模板 在评估函数(请参阅原始链接)而不是模板 。谢谢。
    • 你不能只用一个编码替换一个船长(IIRC standard_wide 甚至是一个命名空间?)。相反,只需look around for information。 Unicode 与布尔表达式关系不大。就此而言,wstring 也不是。 This 看起来很清晰
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多