2012-09-07 83 views
-1

我对this discussion about AST construction and evaluation in various languages感兴趣。我正在研究Java中的解决方案,以了解我可以从这个问题中学到什么。AST解决方案的评估难题

下面我编译的代码会产生不正确的结果(即“oops”异常)。它不起作用,因为Java缺少运行时分派。有没有简单的解决方法?复杂的解决方法如何?例如。使用泛型向编译器提供提示?我只是在这里猜测。

我排除了一些想法:(1)在运行时使用instanceof按参数类型分派。 (2)构建查找表,将参数类型映射到适当的处理程序。 (3)在E的每个子类中都有一个评估函数,它对这个子类进行适当的评估。

我排除了(1)和(2),因为我想让编译器和/或运行时为我完成这项工作。我排除了(3),因为我想将评估代码与表达式分开;该想法是可能存在对该表示的多个操作(重新排序,简化)。

这是我到目前为止。如上所述,此代码会产生不正确的结果。

import java.util.*; 

public class EV 
{ 
    public static Integer ev (E e, Map <String, Integer> env) { throw new RuntimeException ("oops: " + e); } 
    public static Integer ev (V e, Map <String, Integer> env) { return env.get (e.name); } 
    public static Integer ev (C e, Map <String, Integer> env) { return e.value; } 
    public static Integer ev (P e, Map <String, Integer> env) { return ev (e.a1, env) + ev (e.a2, env); } 
    public static Integer ev (T e, Map <String, Integer> env) { return ev (e.a1, env) * ev (e.a2, env); } 

    public static void main (String [] a) 
    { 
     E e = new P (new T (new C (2), new V ("a")), new V ("b")); 
     Map <String, Integer> env = new Hashtable <String, Integer>(); 
     env.put ("a", 123); 
     env.put ("b", 456); 
     System.out.println ("ev (e, env) => " + ev (e, env)); 
    } 
} 

class E {} 

class V extends E 
{ 
    String name; 
    public V (String name) { this.name = name; } 
} 

class C extends E 
{ 
    Integer value; 
    public C (Integer value) { this.value = value; } 
} 

class P extends E 
{ 
    E a1, a2; 
    public P (E a1, E a2) { this.a1 = a1; this.a2 = a2; } 
} 

class T extends E 
{ 
    E a1, a2; 
    public T (E a1, E a2) { this.a1 = a1; this.a2 = a2; } 
} 
+0

如何使用Java预编译器并为您自动生成调度方法(可以使用'instanceof'等)?但是,您需要编写该代码生成器。 – Thomas

+1

我仍然没有看到#3有什么问题。 – oldrinb

+0

我认为#3也很好。动态调度可以很容易地用多态性完成,我在OO语言中看到的所有AST实现在每个具体类中都有一个eval()方法。对于我,这说得通。 – jeff

回答

3

对于Java等单分派OO语言这样做,这是一个典型的用例的Visitor Pattern,特别是如果你也有兴趣在您的评论中提到的漂亮地打印操作。它可能适用于您评论中提到的其他一些操作,尽管它们不太合适。

+0

谢谢@Don。我倾向于尝试构建访问者的方式,以免它侵入表达类。我想这必然意味着在访问者中使用反射来调度适合于当前正在访问的任何方法。我可以忍受这一点;反思的东西可以进入访问者基类,所以即使在访问者的子类中也不会分心。 –