凄い人見つけた
日曜日, 8月 31st, 2008Lispのひび
なんかね、13歳でLisp処理系作ってるらしいですよ。
私が13歳の頃はもぐらたたきを作るのが精一杯でしたよ。
それに引き換え、最近の若い人は凄いですね。
私もCで簡易Schemeインタプリタを作ったことがあるので、
返事がもらえるかは分かりませんが、気になったことを適当に書いておきますね。
* リーダはどうやって書いてるんだろう
readを追加。数値アトムを読み込むことに成功。
80文字までのバッファでfgetsでstdinから読む。長すぎる場合、sskipが内部でバッファ切り替えなどもやるような仕組みでLispの本と同じ。
(T216の現状)
アトム読み込みのとき、isspace(..)の代わりに*.. == ‘ ‘と書いていて間違いだった。改行とかも考慮するんだぁ。
後はリストを上手く読み込むように再帰構造を作るだけ。
(isspace)
とのことですが、関数readが括弧に出会ったら、再帰呼び出しを使ってるんでしょうか。
quoteのsyntax sugarをまだ作られていないとのことですが、
再帰呼び出しを使ってるのであれば、quoteのsyntax sugarはすぐに作れます。
readしてあとでquoteで覆うだけです。
でも、Cで書くなら、再帰呼び出しに頼らず、自分でスタックを持った方がいいかもしれません。
* GCどうするんだろう
GCって意外と簡潔に実装できるものだったんだ。
全体の状況と使用中の状況の差異を確認して、回収するだけなのか。
(GC)
一見難しそうに見えて、実は簡単…と見せかけてやっぱりやっかいなのがGCかと思います。
基本的には現在の環境から辿れるものを残して、それ以外を全て回収すればいいのですが、
問題となるのは、C側の変数しかもっていないオブジェクトです。
適当な例を挙げますと、
LObject *list2(LObject *x, LObject *y)
{
LObject *c1, *c2;
c1 = cons();
c2 = cons(); /* もしここでGCが発生したら? */
set_car(c1, x);
set_cdr(c1, c2);
set_car(c2, y);
set_car(c2, NIL);
return c1;
}
コメントの通り、c2のためのconsingの最中にGCが発生したときに、
どうやってc1のもつコンスをGCの魔の手(?)から守るのか。これが結構問題です。
手っ取り早く解決したいなら、
c1 = cons(); push_obj(c1); /* pushしたらGCで回収されない */ c2 = cons(); /* もしここでGCが発生したら? */ /* 中略 */ pop_obj(c1); /* 保護を解除 */ return c1;
みたいなコードを書くのが楽かもしれません。
(タイプ数は増えるのである意味非常に面倒ですが(笑))
* 変数はどうやって実現するのか
ローカル変数をうまく作るにはスタックを使えばよさそうですが、
無限エクステンドを実現するには、それだけでは少々問題があります。
「環境リスト」というものを作ればこの辺は楽に解決できます。
(ただし、速さを考えるのであればこの実装方法は少々問題があるんですが(笑))
* 関数はどうするのか
五関数や四則演算が動くと楽しいんですが、次に問題になるのが関数です。
なんでもいいから動けばいいやというのであれば、
prognさえ作れればほぼ完成です。
引数をどうにかして渡してしまえば関数の本体をevalするだけですから。
しかし、厄介なのが、どうやってクロージャを実現するかです。
(まあ、LISP 1.5にクロージャはありませんが、どうせなら作るべきでしょう。)
これは調べるところを調べれば答えが載っているのですが、
自分で考えてみると非常に面白いかと思います。






