Chapter 4. A Quick Tour^4

4.4 Making Things Happen During th Parse

リスナーとビジターは、アプリ固有コードと文法を分離することで、文法を読みやすくし、特定のアプリともつれあうのを防ぐのに役立っている。しかしながら最大限の柔軟性と制御を得るため、文法に直接コードの断片(アクション)埋め込むこともできる。これらのアクションは、ANTLRが生成する再帰的下向き構文解析器のコードへコピーされる。ここでは、行のデータを読んで、特定のカラムの値をプリントアウトする簡単なプログラムを実装する。そのあと「意味述語」と呼ばれる文法のon/offを切り替える特別なアクションの作り方を見る。

Embedding Arbitrary Actions in Grammar

構文解析木作成のオーバーヘッドを求めないなら、構文解析中に値を計算しプリントアウトできる。一方、それは任意のコードを式文法に埋め込めることを意味する。それには構文解析器でのアクションの効果と占める位置を理解する必要がある。

文法に埋め込まれたアクションを説明するため、データ行から特定のカラムを出力するプログラムを作成する。カラムはタブで区切られていて、各行は改行コードで終っている。この種の入力にマッチングさせるのは、文法的にとてもシンプル。しかしアクションを追加するとややこしくなる。必要とするカラム番号を渡せるように、コンストラクタを作成する必要がある。そして規則rowの(...)+ループにの内側にアクションが必要。

<snip>tour/Rows.g4</snip>

字句解析規則STUFFは、タブ/改行以外の任意の文字に一致する。これはカラム内に空白を持てることを意味する。これにふさわしいメインプログラムは、もうおなじみの形。違いは、カスタムコンストラクタ経由でカラム番号を渡すこと、パーサーに構文解析木を作らせないこと。

<snip>tour/Col.java</snip>

ここにはChapter 10 Attributes and actionsで扱う項目がたくさんある。ここでは、アクションは{}で囲まれたコードの断片、としておく。アクションmembersは、memberエリアのコードを生成された構文解析器クラスへ挿入する。規則rowのアクションは、locals句で定義されたローカル変数$iへアクセスする。また$STUFF.textで、もっとも最近STUFF字句にマッチした文字列を取得している。

コンパイルとテスト手順は以下のとおり。

$ antlr4 -no-listener Rows.g4
$ javac Rows*.java Col.java
$ java Col 1 < t.rows
parrt
tombu
bke
$ java Col 2 < t.rows
Terence Parr
Tom Burns
Kevin Edgar
$ java Col 3 < t.rows
101
020
008

これらのアクションは構文解析器でマッチした値を抽出・出力するが、構文解析器自身は変更していない。アクションはまた、構文解析器が入力句をどう認識するか、をうまく解決する。次に、埋め込みアクションのコンセプトにもう一歩踏み込む。

Altering the Parse with Semantic Predicates

意味述語はChapter 11Altering the Parse with Semantic Predicatesで扱うので、代わりに簡単なサンプルでその威力を説明する。整数の列を入力する文法を見てみよう。この入力の一部は、何個の整数が同じグループなのかを指定している。実行するまで何個の整数がマッチするかわからない。

tour/t.data
2 9 10 3 1 2 3

最初の番号(=2)は、続く2つの数9, 10とマッチすることを示す。10の次の3は、さらに次の3つとマッチする。ここでのゴールであるDataと呼ぶ文法は、9,10をグループ化し、そして1,2,3も同様にする。

$ antlr4 -no-lisener Data.g4
$ javac Data*.java
$ grun Data file -tree t.data
(file (group 2 (sequence 9 10)) (group 3 (sequence 1 2 3)))

Data文法のポイントは、「意味述語」(この場合、{$i<=$n}?)と呼ばれる特別な真偽値アクションにある。この意味述語は、整数値が規則sequenceのパラメータnで要求された数値を超えるまでtrueを返す。False述語は、文法(すなわち生成された構文解析器から)関連付けられた構文候補を消す。この場合、False述語は(...)*ループを終わらせ、規則sequenceから戻る。

<snip>tour/Data.g4</snip>

構文解析器によって使用される規則sequenceの内部文法表現を図にすると次のような感じになる。

<snip>fig. internal grammar representation of rule sequence</snip>

図中のハサミと破線は述語がその経路を切ることができて、構文解析器はexitする経路しか取れないことを表している。

たいていの場合、このような微細な管理は必要としないだろう、しかし病的な構文解析に対する武器を持っていることを知っているのは良いことだ。

ここまで構文解析レベルの機能に焦点を当ててきたが、字句解析にも興味深いものがたくさんある。それを見てみよう。

from The Definitive ANTLR4 Reference by Terence Parr