Schemeをつくろう(7) ビルトイン関数の登録。
足し算だけじゃ寂しくなってきたので、ビルトイン関数を登録したいと思います。
新たなオブジェクト定義
ビルトイン関数を実行させようと思うと、新たなオブジェクトが必要となるので、function型を作ります。
struct function { int length; struct object *(*f)(); };
引数の長さと、関数ポインタがあれば、なんとかなりそうな予感。
ついでに、オブジェクトの定義を増やします。
struct object { int type; union { struct cell cell; struct symbol symbol; struct integer integer; struct function function; } data; }; typedef struct object* object; object function(int length, object(*f)()); object call(object f, object args);
*書くのが面倒になってきたので、objectの定義を変更しました。
実装
引数の長さにあわせて呼び出すようにします。
object function(int length, object (*f)()) { object o = new_object(); o->type = T_FUNCTION; o->data.function.length = length; o->data.function.f = f; return o; } object call(object f, object args) { if (f->type != T_FUNCTION) error("function : can't call"); switch (f->data.function.length) { case 0 : return f->data.function.f(); case 1 : return f->data.function.f(car(args)); case 2 : return f->data.function.f(car(args), car(cdr(args))); case 99 : return f->data.function.f(args); default : error("function : argument length error"); } }
- 可変長な引数は99にしました(適当
- エラーも適当(汁
使ってみる。
Cから使ってみます。
display(call(function(1, cdr), cons(cons(integer(1), integer(2)), /* 引数 */ null()))); /* おわり */ newline(); /* (cdr '(1 . 2)) => 2 */
なんとか実行出来るようです!
環境づくり。
次は、環境を作ります。
static object set_func(object env, char *name, int length, object(*f)()) { return cons(cons(symbol(name), function(length, f)), env); } object setup_env(void) { object env = null(); env = set_func(env , "+" , 99 , add); env = set_func(env , "car" , 1 , car); env = set_func(env , "cdr" , 1 , cdr); env = set_func(env , "cons" , 2 , cons); return env; }
環境といってもこんなもんです(汗
((cons . function:0x8049307[2]) (cdr . function:0x8049360[1]) (car . function:0x8049335[1]) (+ . function:0x804875d[99]))
単なるリストだったり。
後は今まで作った所とゴニョゴニョ繋げます。
遊んでみる
input> (+ (car (cons 1 2)) (cdr (cons 2 3))) 4
いろんな関数が動くようになりました。
楽しすぎ。