コンパイラへの道 の1

一級継続が無く、(現在の仕様では)クロージャも無いので、基本的にはMinCamlのステップを踏んで個々をデザインしていくことが出来る。

最終出力の確認

最終出力は"あいまいでない"プリミティブ関数の呼び出しの連続で構成されるBB(Basic Block)と、BB同士を接続するコントロールフローとなる。これらはデバッグのために依然Schemeとして実行可能でなければならない。
通常のシチュエーションでは、これらの出力をLLVMに通すことで、実行バイナリを得る。
あいまいさを無くすためには、事前に"可能な限り"オブジェクトに重ならない名前を付ける。これらにはCPS変換やSSAを使うのが普通で、今回はCPSでなくSSA表現を使う(LLVMの表現と近いため)。
コントロールフローの表現能力は処理能力に直結する。テーブルの参照による分岐はプロトコルの処理やステートマシンの実現では普通に用いられる。(また、HDLや他の表現を出力する際にも必要になる)

LLVMとbit型

LLVMにはN-bitの整数型が存在する。しかし、これは構造体で使用できない(packed structureであっても1-byte = 8-bitで整列される)。
もちろん、LLVMのbit型を用いた実現とskySchemeの用いる命令スケジューリング手法を比較することは重要な課題といえる。

最初の一歩

実際には既に何度か試作しているが、問題点が集積されてきたのできちんとボトムアップに作り直す。
以下のパーツを作る(作った)。

  • hash table

いわゆるputとgetによるtableを作る。
これはR6RSのhash tableと仕様を合わせれば特に問題は無い。

  • reader,writer

reader,writerは純粋にR5RS schemeを必要とする唯一のモジュールといえる。他のモジュールは効率さえ無視すればすべてScheme間で実装を使いまわすことが出来る。
writerは単に特定のportに1 byteの数値を書き出す機能だけを必要とする。readerは現在の読み取り位置も取り扱うことが出来なければならない。
現在は、Scheme由来の文字データ処理を使用していない。

  • 名前付きcell

従来、(伝統的な理由から)ASTに定義位置やそのほかのデバッグ情報を埋めこんでいたが、今後は個々のセルにtableを持たせ、そこにreaderから得た位置情報や各種デバッグ情報を挿入する。
cellが単純に名前情報だけを持たないのは、コンパイラのソース中で当該cellを作成したタイミングを知りたいことがあるので、コンパイラ自身を変換してcons等のオペレーションにもデバッグ情報を付与するアイデアがあるため。

  • pretty printer, pretty logging

pretty printerは名前付きcellをprettyに出力するために自前で用意する必要が有る。もっとも、名前付きcellのtable等をstripする方向での実装が単純に有力といえる。
errorやdisplayによるエラー出力はパースしたり書式の適用が面倒なタイミングもあるため、

(error-line (red "hoge") (in-file "../hoge.lsp"))

のように、あらかじめエラーも構造化して記述する。このことで、コンソールにはエスケープシーケンスによって赤字を出しながら、ログはHTMLによる赤字にするなどの対処ができる。