【问题标题】:Pre-order and Post-order Visitor预购和后购访客
【发布时间】:2013-03-23 15:07:40
【问题描述】:

我正在开发一个用 Ruby 编写的编译器,目前正处于语义分析阶段(类型检查)。我有一个需要以两种方式访问​​的 AST:预购和后购,我想知道在 Ruby 中执行此操作的最佳方法是什么。我知道将块传递给each 本质上是访问者模式,但由于我需要以两种方式(前、后)访问,而 Ruby 不支持方法重载,我不知道如何处理。

(注意:我试图让 Node 对象控制它们的访问方式,因此我的访问者不会臃肿)

这是我正在考虑尝试的:

每个Node类accept_pre和accept_post有两个accept方法,调用其他Node对应的accept_pre和accept_post方法

class Node
  def initialize(a, b, c)
    @a, @b, @c = a, b, c
  end

  def accept_pre(visitor)
    @a.accept_pre visitor
    @b.accept_pre visitor
    @c.accept_pre visitor
    vistor.visit_node(self)
  end

  def accept_post(visitor)
    visitor.visit_node(self)
    @c.accept_post visitor
    @b.accept_post visitor
    @a.accept_post visitor
  end
end

有没有更好的方法来做到这一点?可以用.each 完成吗,即使我需要两个订单?

任何帮助将不胜感激。

【问题讨论】:

    标签: ruby compiler-construction abstract-syntax-tree visitor-pattern


    【解决方案1】:

    您可以使用遍历选项 arg 将两个排序合并为一个接受。您当然可以使用每个节点的成员来分派子节点的接受。

    class Node
      def initialize(a, b, c)
        @a, @b, @c = a, b, c
      end
    
      def accept(visitor, traversal=:pre)
        visitor.visit(self) if traversal == :pre
    
        order = traversal == :pre ? :each : :reverse_each
        [@a,@b,@c].send(order) { |e| e.accept(visitor, traversal) }
    
        visitor.visit(self) if traversal == :post
      end
    end
    

    【讨论】:

    • 您还需要反转孩子的遍历。
    • 这实际上看起来是一个很好的解决方案。我不知道send 方法。谢谢!
    猜你喜欢
    • 2012-09-21
    • 1970-01-01
    • 2020-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多