言語ゲーム

とあるエンジニアが嘘ばかり書く日記

Twitter: @propella

cola/flash PEG と S 式パーサの実装

おおまかな作業の進捗を書く。

Tamarin 向け lisp コンパイラを作るための作業は次の通り。

  • ライブラリを作る。リスト、ストリーム等
  • パーサを作る。パーサ用関数。パーサ用パーサ。S 式パーサ。<- いまここ
  • アセンブラを作る。
  • コンパイラを作る。

何やってるか説明します。

開発中の lisp 自身で書かれた lisp 言語の特徴は文法を記述するためのミニ言語(PEG パーサ)を活用しているのでソースがコンパクトだという事です。PEG も lisp でブートストラップして PEG 自身で書きます。PEG は文字列のパースに使う以外に、出来上がったリストのパースにも使ってリストのパターンマッチとして使います。

もともと lisp で使ってる S 式のパーサなんて簡単なので、これで実際どれくらい行数が稼げるかというと微妙ですが、パーサはアプリケーションで便利に使えるので全体としてかなりコンパクトになると思います。

この lispscheme に足りてなくて一番痛いのが末尾呼出最適化です。これは Tamarin に必要な機能が無いのでどうしようもありません。Tamarin はスタックの使い方に自由が効かなくて、最適化出来ないような作りになっているのです。これは JVM でも同じようで、ScalaClojure も限定された末尾呼出しか対応していません。

作業してて一番勉強になったのはマクロの便利さです。マクロが嫌いな事には変わりありませんが、マクロほど作るのが簡単で応用が効く仕組みはありません。ようするにコンパイル前に一回余分に変換を入れるだけなので、マクロを実装する手間は 10 行程度。これでだけで山ほど制御構文が簡単に実装出来てしまうのです。

ここ数週間なかなか進んでる感じがしなくて苦しい状況でしたが、パーサが動き出してようやく実用的な雰囲気がしてきました。最初は Hello World を一行出すだけでやっとだったのに、何百行もあるコードを文句も言わず読み込んで黙々とバイトコードを掃き出すさまは何とも感慨深いです。

現在のサイズはざっと六千行です。半分くらいがユニットテスト用のコードなのと、ライブラリとしてブート用とランタイムとほとんど同じで微妙に違うやつが重複してあるので完成時点でテストを抜いて三千行くらいを目指しています。かなり同僚が書いたコードが混ざっているので自分の一存でソースを公開出来ないけど、出来るだけ早く公開したいです。