orangain flavor

じっくりコトコト煮込んだみかん2。知らないことを知りたい。

言語実装パターンを読んだ

言語実装パターン ―コンパイラ技術によるテキスト処理から言語実装まで

言語実装パターン ―コンパイラ技術によるテキスト処理から言語実装まで

「言語実装」と聞くとコンパイラの本かと思いますが、本書は「言語アプリケーション」を実装するための本です。言語アプリケーションには設定ファイルの読み取り、データの読み取り、コード生成、コード変換器、インタプリタなど、入力ファイルを処理・解析したり、変換したりするアプリケーションが含まれます。

このようなアプリケーションはだいたい同じような構成になり、以下のような要素を組み合わせて実装することになりますが、各要素の実装パターンが数種類紹介されていて、メリット・デメリットを考慮して適切なものを選択できるようになっています。

(私が知らないだけの可能性は高いですが)このような知見がまとまった書籍は他にないような気がします。言語の変換を行う際に、実装の指針となりとても役立ちました。

ANTLR 4の学習

言語アプリケーションの実装において、すべてを手で実装するのは現実的ではなく、特に構文解析にはパーサージェネレーター(あるいはパーサーコンビネーター)を使うのが一般的です。本書では著者のTerence Parrさんが開発しているパーサージェネレーターのANTLRを使います。

原著が2009年に執筆された本書ではANTLR 3が使われていますが、現在一般的なのは2013年に公開されたANTLR 4です。ANTLR 4はフルスクラッチで書き直され、考え方が大きく変わっています。木構造を生成する文法が削除されるなど、文法定義も互換性がありません。

このため、ANTLR 4で書籍内のサンプルコードを動かすことはできません。おとなしくANTLR 3で動かせばいいのですが、せっかくだし最新のバージョンを使いたかったのでANTLR 4の勉強もはじめました。

この本はANTLR自体を解説した本ではありません。ANTLR 4のリファレンスはGitHubで公開されていますし、文法定義の説明もWebに多くありますが、生成されたパーサーの使い方に関する情報があまり見当たらないように思いました。

ANTLR 4の学習には、(英語ですが)同じくTerence Parrさんが書かれたThe Definitive ANTLR 4 Referenceを読むのがオススメです。タイトルにReferenceとありますが、リファレンスは一部だけで、ANTLR 4の使い方が丁寧に解説されています。

The Definitive ANTLR 4 Reference by Terence Parr | The Pragmatic Bookshelf

以降では、主に参考にした箇所についてコメントします。

中間表現の木構造のパターン

4章「中間形式木の構築」に登場するパターンは、中身は簡単なことなのに難しい名前がついていてわかりにくく感じたので、5章「木の走査と書換え」に登場するパターンとの関連性と合わせて図示してみました。

f:id:mi_kattun:20171119125054p:plain

ちなみにANTLR 3では文法定義にアクションとして抽象構文木を生成するコードを書いたり、木文法で訪問器を生成したりしていたようですが、ANTLR 4が生成するパーサーでは構文解析木が自動的に構築されるように変更されました。外部訪問器の基底クラスも生成されるので、抽象構文木は必要なら外部訪問器を使って自分で生成します。

この方が文法定義がスッキリして分かりやすいコードになるので、良い変更だと思います。

ちなみにパターン15「木パターン照合器」についても、ANTLR 3にあった木書換えの文法はなくなったので、ANTLR 4では代わりに ParseTreePatternを使うようです*1

記号表のパターン

6章「プログラム記号の記録と識別」と7章「データ集合体のための記号表管理」に登場する記号表は以下のライブラリとして利用でき、助けられました。

github.com

コード変換のパターン

11章「コンピュータ言語の変換」に登場するパターン29「構文主導変換器」とパターン30「規則方式変換器」の違いがちょっとわかりづらかったです。構文ベースで変換するのが前者で、規則ベースで変換するのが後者ということだと思います。しかし、パターン30の例は変換規則DSLとしてANTLRの文法定義を使い、アクションでprint文を使って出力するというもので、これはパターン29でもあるのではないかと感じました。

パターン31「目的構成体ごとに固有の生成器クラス」と12章「テンプレートを使ったDSL生成」との関連もよくわからなかったです。パターン31の最後に「toString()の中で文字列を生成する代わりにテンプレートを使うこともできます。しかしながら、その場合は、特性の生成器クラスはやめてテンプレートだけを使うようにしたほうが良いでしょう。」という説明がありますが、12章はパターン31をより高度にしたものという理解で良いのでしょうか。12章をパターン32として、11章のパターンと比較する説明があると良かったと思います。

まとめ

わかりにくいと書いたところもありますが、私の読み込みが足りないだけとも言えます。全体的に見れば最初に書いたように実装の指針となる良書でした。もし叶うならば、ANTLR 4で書き直されたバージョンを読んでみたいです。

*1:まだ試してないので試したい。