Chapter 3. A Starter ANTLR Project^4
3.4 Building a Language Application
配列初期子のサンプルを続ける。次のゴールは初期化子の認識だけでなく、変換すること。たとえば、{99,3,451}のようなJavaのshort配列を"\u0063\u0003\u01c3"へ変換する(63は99の16進表現)。
認識を超えて移動するため、アプリは構文解析木からデータを抽出する必要がある。もっとも簡単な方法は、深さ優先でコールバック群を起動するANTLRの構文解析木走査器を持つこと。すでに見たように、ANTLRは自動的にリスナー基盤を生成する。これらのリスナーはGUIウィジェット(例えば、押されたら通知するボタン)やXMLパーサーのSAXイベントのコールバックに似ている。
入力に反応するプログラムを作るためにしなければならないことは、ArrayInitBaseListenerのサブクラスにいくつかのメソッドを実装することだけ。基本戦略は、木走査器によって呼ばれた時、変換された入力の断片をプリントアウトするリスナーメソッドを持つこと。
リスナーメカニズムの美しさは、私達が木走査をする必要がないこと。実際、ランタイムが私たちのメソッドを呼び出すため、木を走査することさえ知る必要がない。私たちが知っているのは、リスナーは文法の規則に関連した句の始まりと終わりに通知を受け取る、ということだけ。
翻訳プロジェクトを始めるということは、それぞれの入力トークン/句をどうやって出力文字列へ変えるか見つけ出すことを意味する。そのために、一般的な句-句変換を見つけ出す、いくつかの代表的なサンプルを手動で変換するのは良い考えである。この場合、変換はとてもわかり易い。
言葉で表現すると、翻訳は"X"を"Y"にするという規則の連続になる。
- { を " へ翻訳する。
- } を " へ翻訳する。
- 整数を4桁の\uで始まる16進数文字列へ翻訳する。
翻訳器をコード化するため、適切な入力トークン/句から変換された文字列をプリントアウトするメソッドを書く必要がある。組み込みの木走査器は、いろいろな句の始めと終わりにリスナーのコールバックを起動する。翻訳規則の実装は次のようになる。
<snip>starter/ShortToUnicodeString.java</snip>
すべてのenter/exitメソッドをオーバーライドする必要はなく、必要なものだけすれば良い。見慣れない式は、規則valueにマッチした整数INTトークンのコンテキストオブジェクトを要求するctx.INT()だけ。コンテキストオブジェクトは、規則認識の間に起こったことを全て記録する。
残っていることは、翻訳アプリを作成すること。
<snip>starter/Translate.java</snip>
お決まりのコードと違うのは、木走査器を生成し、構文解析器から返された構文解析木を走査するよう要求するところだけ。木走査器は、構文解析木を走査するとき、ShortToStringリスナーへの呼び出しを起動する。
$ javac ArrayInit*.java Translate.java $ java Translate {99, 3, 451} EOF "\u0063\u0003\u01c3"
私たちは最初の翻訳器を文法にさえ触ること無く作った。やったことは、適切な句変換をプリントするいくつかのメソッドを実装したことだけ。その上、異なるリスナーを渡すだけで、完全に異なる出力を生成できる。リスナーは文法から言語アプリを効果的に分離することで、文法を他のアプリへ再利用できるようにする。
from The Definitive ANTLR4 Reference by Terence Parr