完成、 LISP インタープリター

9月20日木曜日、雨

長かった。

足掛け8日間。
ようやく LISP インタープリター、作りあげることができました。

Example にも書いているとおりだけれど、こんな評価が可能です。

$ ./ulisp
> (quote ulisp)
ulisp
> t
True
> (set (quote hello) (quote ulisp))
ulisp
> hello
ulisp
> (set (quote r) (lambda (x y) (cond ((atom x) y) (t (r (cdr x) (cons (car x) y))))))
(*applicable* (x y) (cond ((atom x) y) (t (r (cdr x) (cons (car x) y)))))
> (r (quote (a b c d e f)) ())
(f e d c b a)
> 

setq という命令が set quoted 〜 を意味していたのだとか、今回の実装を通じて知ることができました。
ほんと、たくさん勉強になった。

setjmp/longjmp の使い方もそうだし、 FILE オブジェクトをメモリー上に構築できる fmemopen や、文字列ビルダーとして流用可能な FILE オブジェクトを構築できる open_memstream だとか。

恥ずかしながら、マクロの副作用のことをすっかり忘れていてテストの ASSERT_EQ でトークンを読み飛ばすような失敗もしでかした。

* * *

使い回せるから便利だというそれだけの理由で評価関数 eval に S 式を渡すようにしていて、その頭に環境、お尻に評価対象の S 式を突っ込んでいる。

これは、まずい選択だったと反省している。

「使える」から使うというのでなく、違うものには違う型を与えるべきだった。

「べき」という言葉を、僕はできるだけ使わないようにしているのだけれど、今回のこの選択はそれを反故にして当然とおもえるぐらいの、まずい選択だとおもっている。

* * *

もう少し工夫するといいだろうという、将来への申し送り事項としては……

1 エラーメッセージに入力行と列を添えて親切に
 このためにはトークンの読み取り時に入力位置を覚えつつ、つくりだしたトークン(と、これをラップする S 式)に結びつける必要がある。

2 値の導入
 やっぱり数値計算とか文字列処理とか、あれば便利な気がする。
 いまはペアでなければシンボル(変数・記号)だけれど、タグを使うようにして数字や文字列を識別できるようにすればいい。これらの評価は数字や文字列そのものになればいい。

3 特殊形式の上書き
 それができて嬉しいのか、よくわからないけれど、できることをできないように縛るのは違う気がするし……。(いまは、例えば atom と読んだら、これを atom としてしか解釈しない)

4 末尾再帰の最適化
 関数型言語大好きクラスターは、やっぱり気になるだろうから。

5 遅延評価
 これを入れたら LISP/Scheme ではなくなるけれど、評価をできるだけ遅らせるバージョンもつくってみたい。
 あ、いや。処理系の上に遅延評価系を実装する演習が「計算機プログラムの構造と解釈」にあったような……?

この記事が気に入ったらサポートをしてみませんか?