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

いろんな関数が動くようになりました。


楽しすぎ。