さまざまな言語での AST の構築と評価に関するこの議論に興味を持ちました。この問題から何を学べるかを確認するためだけに、Java のソリューションに取り組んでいます。
以下のコードはコンパイルされますが、正しくない結果 (つまり、"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; }
}