GoF本 Interpreter
ねらい
モチベーション
- 同じような類の問題が頻出するので、それに特化した言語をつくりたくなることがある
- BNFで表されるような言語
つかいどころ
- 文法が簡潔であること
- 複雑な文法には不向き
- 文法を表現するクラス構造が巨大で管理不能になる
- ASTを作らずに翻訳を行うような別のしくみを適用したほうがいい
- 例) パーサジェネレータ ... パーサを生成するプログラム
- 複雑な文法には不向き
- 実行効率があまり重要でない
- 高効率な実装は、ふつう直接ASTを処理せず、中間形式を経由する
- ASTから中間形式への変換にはInterpreter Patternが利用できる
登場人物
- AbstractExpression
- ASTのすべてのノード共通のインタフェースを定義
- Interpret()処理を定義
- ASTのすべてのノード共通のインタフェースを定義
- TerminalExpression
- ASTの葉ノード
- 翻訳対象の言語でいうとリテラルとか
- ASTの葉ノード
- NonterminalExpression
- Context
- Client
- TerminalExpression/NonterminalExpressionオブジェクトからなるASTに対し、Interpret()を呼び出す
クライアントコードからの利用
- contextを初期化し、ASTのInterpret(context)を実行
結果
- 文法の変更・拡張が容易
- 継承・override
- 複雑な文法はメンテ困難
- BNFの1式ごとにクラスが必要
- Interpret()以外にもいろいろできる
- ASTのpretty printing
- 型チェック
実装にあたり考えるべきこと
- ASTの生成
- パース処理についてはInterpreterパターンの守備範囲外
- Clientがパースする?
- Clientはパースされたものを受け取る?
- Clientの中でASTを組み立てる?
- パース処理についてはInterpreterパターンの守備範囲外
- Interpret()の実装
- Expressionに実装すると、処理が散らばる
- Visitorパターンを併用し、visitorオブジェクトに実装してまとめる方法もある
- 各Expression派生は、Visitorのどの処理でInterpretされればよいかを知っている
- TerminalExpressionオブジェクトの共用
- Flyweightパターン
- extrinsicな状態はContextに外出しする
Compositeとどうちがうの
関連するパターン
- Composite
- ASTがCompositeパターン
- Flyweight
- TerminalExpressionに適用可能
- Iterator
- 木の走査に適用可能
- 先行順 (preorder)
- 中間順 (inorder)
- 後行順 (postorder)
- 木の走査に適用可能
- Visitor
- 翻訳処理を各Expression派生クラスに散らばらせず、知識をひとまとめに
よくわかんなかったやつ
- parser generator
- compiler generator
- table-driven parser