5. ASTの実装 - Node.java
2016/07/03第14回福岡市西区プログラム勉強会5
public final class Node {
private final Map<Attribute<?>, Object> attrs; /* アトリビュート(後述) */
private final List<Node> children; /* 子ノード */
/* コンストラクタ */
public Node(List<Node> children){/* 省略 */}
public Node(Node...children){/* 省略 */}
/* アトリビュート(後述)の取得と設定、存在の確認 */
public final <T> void setAttribute(Attribute<T> attribute, T value){/* 省略 */}
public final <T> T getAttribute(Attribute<T> attribute){/* 省略 */}
public Map<Attribute<?>, Object> attributes() {/* 省略 */}
public final <T> boolean hasAttribute(Attribute<T> attribute){/* 省略 */}
/* 子ノードの追加と取得 */
public final void addChildren(Node...children){/* 省略 */}
public final void addChildren(List<Node> children) {/* 省略 */}
public List<Node> children(){/* 省略 */}
/* 等値演算とハッシュコード(ツリー比較、テスト用) */
@Override public boolean equals(Object obj){/* 省略 */}
@Override public int hashCode() {/* 省略 */}
/* ビジター受け入れメソッド(後述) */
public final void startVisit(Visitor visitor) {/* 省略 */}
}
6. 追加可能で静的型検査可能なアトリビュート・
マップ
2016/07/03第14回福岡市西区プログラム勉強会6
public interface Attribute<T> {
}
• アトリビュートのキーとなるenum型群のためのインターフェー
ス
• 型パラメータTがミソ
public class Attributes{
public enum LocationAttr implements Attribute<Location>{
LOCATION;
}
public static final LocationAttr LOCATION =
LocationAttr.LOCATION;
public enum StringAttr implements Attribute<String>{
SYMBOL;
}
public static final StringAttr SYMBOL = StringAttr.SYMBOL;
}
public final <T> T getAttribute(Attribute<T> attribute){/* 省略 */}
• NodeのgetAttributeメソッド…キーの型パラメータの型と同じ型が返る
• enumにしてるのはキーをお手
軽にシングルトンにするため
• Locationはノードの由来となっ
たコードの位置を示すデータ構
造(エラーメッセージ等に利用)
• ここでは記号文字列を格納する
SYMBOLとソースコード上の位
置を示すLOCATIONだけだが、
Attribute<T>を継承すれば追加
できる。
7. ツリーを辿る(1)…ビジタ(Visitor)
2016/07/03第14回福岡市西区プログラム勉強会7
アルゴリズムによって定まる順番
でツリーのノードを訪問するビジ
ター
深さ優先探索や幅優先探索など
ツリーを辿る定番デザイン・パター
ン
長所: enterとleaveメソッドの呼び
出しによりサブツリーの開始と終
了を認識できる
短所: コールバックによるイベント
駆動的なコードになり構造をツリー
の意識した記述がしにくい
ASTではサブツリーのパターンに
よって処理を分けて記述するような
ことがしたい
ノードの種類を増やしてビジタのメ
ソッドを増やして実装をFatにすれば
ある程度できるが、メンテが面倒に
短所: 継承が必須であり、用途毎
にビジタ・クラスが増える
代入文
id: d 式: *
id: c式: +
id: bid: a
enter #0
leave
#6
enter
#1
leave
#0
enter #2
leave #5
enter #3
leave #3
enter #4
leave #1
enter #5
leave #2
enter #6
leave #4
順番の例、深さ優先探索の場合
• vをビジタ・オブジェクトとして以下の様に動作:
• ノードに初回訪問時にv.enter()が呼ばれる
• ノードへの最後の訪問時(leafノードでは
v.enter()の直後)にv.leave()が呼ばれる