科学技術計算用プログラミング言語:Sci-Lispの自作(3日目):言語開発のロードマップ
Sci-Lisp自作の3日目です。もともとはネット上の情報を拾い集めて言語(とそのインタプリタ・コンパイラ)を作成をしようとしていたのですが、ちょうとAmazonのブラックフライデーに以下の本が推薦されて出てきたので思わず買ってしまいました。
インタプリタの作り方 -言語設計/開発の基本と2つの方式による実装
ちなみにこちら、英文ですがWeb上で無料公開もされています。レビューを見るに大変な良書のようです。
言語開発のロードマップ
さて、この本を頭から読んでいくだけでもかなり時間を要するので、Sci-Lisp開発とは同時並行で読み進めたいと思っていますが、2章にプログラミング言語開発(インタプリタ実装)についての概観がまとまっていましたので、紹介します。
- 字句解析(Scanning)
- 構文解析(Parsing)
- 静的分析・意味分析(Analysis)
- 中間表現(Intermediate Representations)
- 最適化(Optimizing)
- コード生成(Code Generation)
- 仮想マシン(Virtual Machine)
- ランタイム(Runtime)
次のテキストに処理を施していくことを考えます。
var agerage = (min + max) / 2;
1. 字句解析(Scanning)
スキャナによって、コメントや空白を読み捨て、意味のあるトークンだけの純粋なシーケンスを残す。
var
average
=
(
min
+
max
)
/
2
;
2. 構文解析(Parsing)
パーサによって、トークンの並びを受け取って、文法の入れ子構造を反映した木構造を構築する。これは「構文解析木」(parse tree)とも「抽象構文木」(abstract syntax tree: AST)とも呼ばれる。構文エラーがあれば、ここで報告される。
3. 静的分析・意味分析(Analysis)
変数や関数、文が何を参照しているかを、スコープに応じて明らかにする。型チェックをする言語であれば、ここで行う。
4. 中間表現(Intermediate Representation:IR)
ソース言語ごとにIRを生成するフロントエンドを1つずつ作り、ターゲットのアーキテクチャ(x86, ARM,...)ごとにバックエンドを1つずつ書けば、少ない労力でサポートすることができる。
5. 最適化(Optimizing)
ユーザーのプログラムが何を意味するのかを理解したら、それと同じセマンティクスを保ちながら、もっと実行効率の良い別のプログラムと自由に交換することができる。
pennyArea = 3.14159 * (0.75 / 2) * (0.75 / 2); ⇒ pennyArea = 0.4417860938;
6. コード生成(Code Generation)
マシンが実行できる形式に変換(アセンブリ・機械語・VM用のバイトコード等)する処理。
7. 仮想マシン(Virtual Machine)
架空のチップをエミュレートし、命令実行をランタイムでシミュレートする。ネイティブコードに変換した場合より遅くなるが、単純さと移植性が得られる。
8. ランタイム(Runtime)
ガベージコレクタやオブジェクトの種類を調べる等、実行時に行う作業。完全にコンパイルされる言語では、結果として生成される実行ファイルにランタイムの実装コードが直接挿入される。Go言語ならGoランタイムのコピーが直接埋め込まれ、VM内で実行される言語(Java, Python, JavaScript)ならランタイムはVMに含まれる。
終わりに
このインタプリタの作り方という書籍は、Sci-Lispが初めてβ版として公開されるまでには一度は読み通しておく必要があると感じました。長く果てしない道のりにも感じますが、今回紹介したロードマップを浮かべて、今自分がどの位置にいるのかを把握しておけば幾ばくか安心感を得られます。