diff --git a/Makefile b/Makefile index f2abb399..59f3ada0 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ build: cd src; \ yacc -d parse.y; \ lex scan.l - $(CC) -Wall -o bin/picrin -I./include -lreadline src/main.c src/state.c src/gc.c src/pair.c src/port.c src/symbol.c src/value.c src/y.tab.c src/lex.yy.c src/bool.c src/vm.c src/init.c src/number.c src/time.c + $(CC) -Wall -o bin/picrin -I./include -lreadline src/main.c src/state.c src/gc.c src/pair.c src/port.c src/symbol.c src/value.c src/y.tab.c src/lex.yy.c src/bool.c src/vm.c src/init.c src/number.c src/time.c src/codegen.c clean: rm -f src/y.tab.c src/y.tab.h src/lex.yy.c diff --git a/src/codegen.c b/src/codegen.c new file mode 100644 index 00000000..38993077 --- /dev/null +++ b/src/codegen.c @@ -0,0 +1,450 @@ +#include + +#include "picrin.h" +#include "picrin/pair.h" +#include "picrin/irep.h" +#include "picrin/proc.h" + +static bool +env_lookup(pic_state *pic, pic_value sym, struct pic_env *env, int *depth, int *idx) +{ + pic_value v; + int d = 0; + + enter: + + v = pic_assq(pic, sym, env->assoc); + if (! pic_nil_p(v)) { + if (env->parent == NULL) { /* global */ + *depth = -1; + } + else { /* non-global */ + *depth = d; + } + *idx = (int)pic_float(pic_pair_ptr(v)->cdr); + return true; + } + if (env->parent) { + env = env->parent; + ++d; + goto enter; + } + return false; +} + +static int +env_global_define(pic_state *pic, pic_value sym) +{ + pic_value f; + int d, idx; + + if (env_lookup(pic, sym, pic->global_env, &d, &idx)) { + return idx; + } + + idx = pic->glen++; + f = pic_float_value(idx); + pic->global_env->assoc = pic_acons(pic, sym, f, pic->global_env->assoc); + + return idx; +} + +static struct pic_env * +env_new(pic_state *pic, pic_value args, struct pic_env *env) +{ + struct pic_env *inner_env; + pic_value v, f; + int i; + + inner_env = (struct pic_env *)pic_alloc(pic, sizeof(struct pic_env)); + inner_env->assoc = pic_nil_value(); + inner_env->parent = env; + + i = -1; + for (v = args; ! pic_nil_p(v); v = pic_cdr(pic, v)) { + pic_value sym = pic_car(pic, v); + + f = pic_float_value(i--); + inner_env->assoc = pic_acons(pic, sym, f, inner_env->assoc); + } + + return inner_env; +} + +void +pic_defun(pic_state *pic, const char *name, pic_func_t cfunc) +{ + struct pic_proc *proc; + int idx; + + proc = (struct pic_proc *)pic_obj_alloc(pic, sizeof(struct pic_proc), PIC_TT_PROC); + proc->cfunc_p = true; + proc->u.cfunc = cfunc; + idx = env_global_define(pic, pic_intern_cstr(pic, name)); + pic->globals[idx] = pic_obj_value(proc); +} + +static void +print_irep(pic_state *pic, struct pic_irep *irep) +{ + int i; + + printf("## irep %p [clen = %zd, ccapa = %zd]\n", irep, irep->clen, irep->ccapa); + for (i = 0; i < irep->clen; ++i) { + switch (irep->code[i].insn) { + case OP_POP: + puts("OP_POP"); + break; + case OP_PUSHNIL: + puts("OP_PUSHNIL"); + break; + case OP_PUSHTRUE: + puts("OP_PUSHTRUE"); + break; + case OP_PUSHFALSE: + puts("OP_PUSHFALSE"); + break; + case OP_PUSHNUM: + printf("OP_PUSHNUM\t%g\n", irep->code[i].u.f); + break; + case OP_GREF: + printf("OP_GREF\t%i\n", irep->code[i].u.i); + break; + case OP_GSET: + printf("OP_GSET\t%i\n", irep->code[i].u.i); + break; + case OP_LREF: + printf("OP_LREF\t%d\n", irep->code[i].u.i); + break; + case OP_JMP: + printf("OP_JMP\t%d\n", irep->code[i].u.i); + break; + case OP_JMPIF: + printf("OP_JMPIF\t%d\n", irep->code[i].u.i); + break; + case OP_CALL: + printf("OP_CALL\t%d\n", irep->code[i].u.i); + break; + case OP_RET: + puts("OP_RET"); + break; + case OP_LAMBDA: + printf("OP_LAMBDA\t%d\n", irep->code[i].u.i); + break; + case OP_CONS: + puts("OP_CONS"); + break; + case OP_CAR: + puts("OP_CAR"); + break; + case OP_NILP: + puts("OP_NILP"); + break; + case OP_CDR: + puts("OP_CDR"); + break; + case OP_ADD: + puts("OP_ADD"); + break; + case OP_SUB: + puts("OP_SUB"); + break; + case OP_MUL: + puts("OP_MUL"); + break; + case OP_DIV: + puts("OP_DIV"); + break; + case OP_STOP: + puts("OP_STOP"); + break; + } + } +} + +static struct pic_irep * +new_irep(pic_state *pic) +{ + struct pic_irep *irep; + + irep = (struct pic_irep *)pic_alloc(pic, sizeof(struct pic_irep)); + irep->code = (struct pic_code *)pic_alloc(pic, sizeof(struct pic_code) * 1024); + irep->clen = 0; + irep->ccapa = 1024; + return irep; +} + +static void pic_gen_call(pic_state *, struct pic_irep *, pic_value, struct pic_env *); +static struct pic_irep *pic_gen_lambda(pic_state *, pic_value, struct pic_env *); + +static void +pic_gen(pic_state *pic, struct pic_irep *irep, pic_value obj, struct pic_env *env) +{ + pic_value sDEFINE, sLAMBDA, sIF, sBEGIN; + pic_value sCONS, sCAR, sCDR, sNILP; + pic_value sADD, sSUB, sMUL, sDIV; + + sDEFINE = pic->sDEFINE; + sLAMBDA = pic->sLAMBDA; + sIF = pic->sIF; + sBEGIN = pic->sBEGIN; + sCONS = pic->sCONS; + sCAR = pic->sCAR; + sCDR = pic->sCDR; + sNILP = pic->sNILP; + sADD = pic->sADD; + sSUB = pic->sSUB; + sMUL = pic->sMUL; + sDIV = pic->sDIV; + + switch (pic_type(obj)) { + case PIC_TT_SYMBOL: { + bool b; + int depth, idx; + + b = env_lookup(pic, obj, env, &depth, &idx); + if (! b) { + pic_raise(pic, "unbound variable"); + } + + if (depth == -1) { /* global */ + irep->code[irep->clen].insn = OP_GREF; + irep->code[irep->clen].u.i = idx; + irep->clen++; + } + else if (depth == 0) { /* local */ + irep->code[irep->clen].insn = OP_LREF; + irep->code[irep->clen].u.i = idx; + irep->clen++; + } + else { /* nonlocal */ + pic_raise(pic, "reference to closed variable not supported"); + } + break; + } + case PIC_TT_PAIR: { + pic_value proc; + + proc = pic_car(pic, obj); + if (pic_eq_p(pic, proc, sDEFINE)) { + int idx; + + idx = env_global_define(pic, pic_car(pic, pic_cdr(pic, obj))); + + pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), env); + + irep->code[irep->clen].insn = OP_GSET; + irep->code[irep->clen].u.i = idx; + irep->clen++; + irep->code[irep->clen].insn = OP_PUSHFALSE; + irep->clen++; + break; + } + else if (pic_eq_p(pic, proc, sLAMBDA)) { + irep->code[irep->clen].insn = OP_LAMBDA; + irep->code[irep->clen].u.i = pic->ilen; + irep->clen++; + + pic->irep[pic->ilen++] = pic_gen_lambda(pic, obj, env); + break; + } + else if (pic_eq_p(pic, proc, sIF)) { + int s,t; + + pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, obj)), env); + + irep->code[irep->clen].insn = OP_JMPIF; + s = irep->clen++; + + /* if false branch */ + pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, pic_cdr(pic, pic_cdr(pic, obj)))), env); + irep->code[irep->clen].insn = OP_JMP; + t = irep->clen++; + + irep->code[s].u.i = irep->clen - s; + + /* if true branch */ + pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), env); + irep->code[t].u.i = irep->clen - t; + break; + } + else if (pic_eq_p(pic, proc, sBEGIN)) { + pic_value v, seq; + + seq = pic_cdr(pic, obj); + for (v = seq; ! pic_nil_p(v); v = pic_cdr(pic, v)) { + pic_gen(pic, irep, pic_car(pic, v), env); + irep->code[irep->clen].insn = OP_POP; + irep->clen++; + } + irep->clen--; + break; + } + else if (pic_eq_p(pic, proc, sCONS)) { + pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), env); + pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, obj)), env); + irep->code[irep->clen].insn = OP_CONS; + irep->clen++; + break; + } + else if (pic_eq_p(pic, proc, sCAR)) { + pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, obj)), env); + irep->code[irep->clen].insn = OP_CAR; + irep->clen++; + break; + } + else if (pic_eq_p(pic, proc, sCDR)) { + pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, obj)), env); + irep->code[irep->clen].insn = OP_CDR; + irep->clen++; + break; + } + else if (pic_eq_p(pic, proc, sNILP)) { + pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, obj)), env); + irep->code[irep->clen].insn = OP_NILP; + irep->clen++; + break; + } + else if (pic_eq_p(pic, proc, sADD)) { + pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), env); + pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, obj)), env); + irep->code[irep->clen].insn = OP_ADD; + irep->clen++; + break; + } + else if (pic_eq_p(pic, proc, sSUB)) { + pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), env); + pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, obj)), env); + irep->code[irep->clen].insn = OP_SUB; + irep->clen++; + break; + } + else if (pic_eq_p(pic, proc, sMUL)) { + pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), env); + pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, obj)), env); + irep->code[irep->clen].insn = OP_MUL; + irep->clen++; + break; + } + else if (pic_eq_p(pic, proc, sDIV)) { + pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), env); + pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, obj)), env); + irep->code[irep->clen].insn = OP_DIV; + irep->clen++; + break; + } + else { + pic_gen_call(pic, irep, obj, env); + break; + } + } + case PIC_TT_BOOL: { + if (pic_true_p(obj)) { + irep->code[irep->clen].insn = OP_PUSHTRUE; + } + else { + irep->code[irep->clen].insn = OP_PUSHFALSE; + } + irep->clen++; + break; + } + case PIC_TT_FLOAT: { + irep->code[irep->clen].insn = OP_PUSHNUM; + irep->code[irep->clen].u.f = pic_float(obj); + irep->clen++; + break; + } + case PIC_TT_NIL: { + irep->code[irep->clen].insn = OP_PUSHNIL; + irep->clen++; + break; + } + case PIC_TT_PROC: + case PIC_TT_UNDEF: + case PIC_TT_PORT: { + pic_raise(pic, "invalid expression given"); + } + } +} + +static pic_value +reverse(pic_state *pic, pic_value list, pic_value acc) +{ + if (pic_nil_p(list)) + return acc; + return reverse(pic, pic_cdr(pic, list), pic_cons(pic, pic_car(pic, list), acc)); +} + +static void +pic_gen_call(pic_state *pic, struct pic_irep *irep, pic_value obj, struct pic_env *env) +{ + pic_value seq; + int i = 0; + + seq = reverse(pic, obj, pic_nil_value()); + for (; ! pic_nil_p(seq); seq = pic_cdr(pic, seq)) { + pic_value v; + + v = pic_car(pic, seq); + pic_gen(pic, irep, v, env); + ++i; + } + irep->code[irep->clen].insn = OP_CALL; + irep->code[irep->clen].u.i = i; + irep->clen++; +} + +static struct pic_irep * +pic_gen_lambda(pic_state *pic, pic_value obj, struct pic_env *env) +{ + struct pic_env *inner_env; + pic_value args, body, v; + struct pic_irep *irep; + + irep = new_irep(pic); + + /* arguments */ + args = pic_car(pic, pic_cdr(pic, obj)); + inner_env = env_new(pic, args, env); + + /* body */ + body = pic_cdr(pic, pic_cdr(pic, obj)); + for (v = body; ! pic_nil_p(v); v = pic_cdr(pic, v)) { + pic_gen(pic, irep, pic_car(pic, v), inner_env); + irep->code[irep->clen].insn = OP_POP; + irep->clen++; + } + irep->clen--; + irep->code[irep->clen].insn = OP_RET; + irep->clen++; + pic_free(pic, inner_env); + +#if VM_DEBUG + printf("LAMBDA_%zd:\n", pic->ilen); + print_irep(pic, irep); + puts(""); +#endif + + return irep; +} + +struct pic_proc * +pic_codegen(pic_state *pic, pic_value obj, struct pic_env *env) +{ + struct pic_proc *proc; + struct pic_irep *irep; + + proc = (struct pic_proc *)pic_obj_alloc(pic, sizeof(struct pic_proc), PIC_TT_PROC); + proc->cfunc_p = false; + proc->u.irep = irep = new_irep(pic); + + pic_gen(pic, irep, obj, env); + irep->code[irep->clen].insn = OP_STOP; + irep->clen++; + +#if VM_DEBUG + print_irep(pic, irep); +#endif + + return proc; +} diff --git a/src/vm.c b/src/vm.c index d090a796..01ba27cd 100644 --- a/src/vm.c +++ b/src/vm.c @@ -3,88 +3,9 @@ #include #include "picrin.h" -#include "picrin/irep.h" -#include "picrin/proc.h" #include "picrin/pair.h" - -static bool -env_lookup(pic_state *pic, pic_value sym, struct pic_env *env, int *depth, int *idx) -{ - pic_value v; - int d = 0; - - enter: - - v = pic_assq(pic, sym, env->assoc); - if (! pic_nil_p(v)) { - if (env->parent == NULL) { /* global */ - *depth = -1; - } - else { /* non-global */ - *depth = d; - } - *idx = (int)pic_float(pic_pair_ptr(v)->cdr); - return true; - } - if (env->parent) { - env = env->parent; - ++d; - goto enter; - } - return false; -} - -static int -env_global_define(pic_state *pic, pic_value sym) -{ - pic_value f; - int d, idx; - - if (env_lookup(pic, sym, pic->global_env, &d, &idx)) { - return idx; - } - - idx = pic->glen++; - f = pic_float_value(idx); - pic->global_env->assoc = pic_acons(pic, sym, f, pic->global_env->assoc); - - return idx; -} - -static struct pic_env * -env_new(pic_state *pic, pic_value args, struct pic_env *env) -{ - struct pic_env *inner_env; - pic_value v, f; - int i; - - inner_env = (struct pic_env *)pic_alloc(pic, sizeof(struct pic_env)); - inner_env->assoc = pic_nil_value(); - inner_env->parent = env; - - i = -1; - for (v = args; ! pic_nil_p(v); v = pic_cdr(pic, v)) { - pic_value sym = pic_car(pic, v); - - f = pic_float_value(i--); - inner_env->assoc = pic_acons(pic, sym, f, inner_env->assoc); - } - - return inner_env; -} - -void -pic_defun(pic_state *pic, const char *name, pic_func_t cfunc) -{ - struct pic_proc *proc; - int idx; - - proc = (struct pic_proc *)pic_obj_alloc(pic, sizeof(struct pic_proc), PIC_TT_PROC); - proc->cfunc_p = true; - proc->u.cfunc = cfunc; - idx = env_global_define(pic, pic_intern_cstr(pic, name)); - pic->globals[idx] = pic_obj_value(proc); -} +#include "picrin/proc.h" +#include "picrin/irep.h" void pic_get_args(pic_state *pic, const char *format, ...) @@ -118,371 +39,6 @@ pic_get_args(pic_state *pic, const char *format, ...) } } -static void -print_irep(pic_state *pic, struct pic_irep *irep) -{ - int i; - - printf("## irep %p [clen = %zd, ccapa = %zd]\n", irep, irep->clen, irep->ccapa); - for (i = 0; i < irep->clen; ++i) { - switch (irep->code[i].insn) { - case OP_POP: - puts("OP_POP"); - break; - case OP_PUSHNIL: - puts("OP_PUSHNIL"); - break; - case OP_PUSHTRUE: - puts("OP_PUSHTRUE"); - break; - case OP_PUSHFALSE: - puts("OP_PUSHFALSE"); - break; - case OP_PUSHNUM: - printf("OP_PUSHNUM\t%g\n", irep->code[i].u.f); - break; - case OP_GREF: - printf("OP_GREF\t%i\n", irep->code[i].u.i); - break; - case OP_GSET: - printf("OP_GSET\t%i\n", irep->code[i].u.i); - break; - case OP_LREF: - printf("OP_LREF\t%d\n", irep->code[i].u.i); - break; - case OP_JMP: - printf("OP_JMP\t%d\n", irep->code[i].u.i); - break; - case OP_JMPIF: - printf("OP_JMPIF\t%d\n", irep->code[i].u.i); - break; - case OP_CALL: - printf("OP_CALL\t%d\n", irep->code[i].u.i); - break; - case OP_RET: - puts("OP_RET"); - break; - case OP_LAMBDA: - printf("OP_LAMBDA\t%d\n", irep->code[i].u.i); - break; - case OP_CONS: - puts("OP_CONS"); - break; - case OP_CAR: - puts("OP_CAR"); - break; - case OP_NILP: - puts("OP_NILP"); - break; - case OP_CDR: - puts("OP_CDR"); - break; - case OP_ADD: - puts("OP_ADD"); - break; - case OP_SUB: - puts("OP_SUB"); - break; - case OP_MUL: - puts("OP_MUL"); - break; - case OP_DIV: - puts("OP_DIV"); - break; - case OP_STOP: - puts("OP_STOP"); - break; - } - } -} - -static struct pic_irep * -new_irep(pic_state *pic) -{ - struct pic_irep *irep; - - irep = (struct pic_irep *)pic_alloc(pic, sizeof(struct pic_irep)); - irep->code = (struct pic_code *)pic_alloc(pic, sizeof(struct pic_code) * 1024); - irep->clen = 0; - irep->ccapa = 1024; - return irep; -} - -static void pic_gen_call(pic_state *, struct pic_irep *, pic_value, struct pic_env *); -static struct pic_irep *pic_gen_lambda(pic_state *, pic_value, struct pic_env *); - -static void -pic_gen(pic_state *pic, struct pic_irep *irep, pic_value obj, struct pic_env *env) -{ - pic_value sDEFINE, sLAMBDA, sIF, sBEGIN; - pic_value sCONS, sCAR, sCDR, sNILP; - pic_value sADD, sSUB, sMUL, sDIV; - - sDEFINE = pic->sDEFINE; - sLAMBDA = pic->sLAMBDA; - sIF = pic->sIF; - sBEGIN = pic->sBEGIN; - sCONS = pic->sCONS; - sCAR = pic->sCAR; - sCDR = pic->sCDR; - sNILP = pic->sNILP; - sADD = pic->sADD; - sSUB = pic->sSUB; - sMUL = pic->sMUL; - sDIV = pic->sDIV; - - switch (pic_type(obj)) { - case PIC_TT_SYMBOL: { - bool b; - int depth, idx; - - b = env_lookup(pic, obj, env, &depth, &idx); - if (! b) { - pic_raise(pic, "unbound variable"); - } - - if (depth == -1) { /* global */ - irep->code[irep->clen].insn = OP_GREF; - irep->code[irep->clen].u.i = idx; - irep->clen++; - } - else if (depth == 0) { /* local */ - irep->code[irep->clen].insn = OP_LREF; - irep->code[irep->clen].u.i = idx; - irep->clen++; - } - else { /* nonlocal */ - pic_raise(pic, "reference to closed variable not supported"); - } - break; - } - case PIC_TT_PAIR: { - pic_value proc; - - proc = pic_car(pic, obj); - if (pic_eq_p(pic, proc, sDEFINE)) { - int idx; - - idx = env_global_define(pic, pic_car(pic, pic_cdr(pic, obj))); - - pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), env); - - irep->code[irep->clen].insn = OP_GSET; - irep->code[irep->clen].u.i = idx; - irep->clen++; - irep->code[irep->clen].insn = OP_PUSHFALSE; - irep->clen++; - break; - } - else if (pic_eq_p(pic, proc, sLAMBDA)) { - irep->code[irep->clen].insn = OP_LAMBDA; - irep->code[irep->clen].u.i = pic->ilen; - irep->clen++; - - pic->irep[pic->ilen++] = pic_gen_lambda(pic, obj, env); - break; - } - else if (pic_eq_p(pic, proc, sIF)) { - int s,t; - - pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, obj)), env); - - irep->code[irep->clen].insn = OP_JMPIF; - s = irep->clen++; - - /* if false branch */ - pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, pic_cdr(pic, pic_cdr(pic, obj)))), env); - irep->code[irep->clen].insn = OP_JMP; - t = irep->clen++; - - irep->code[s].u.i = irep->clen - s; - - /* if true branch */ - pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), env); - irep->code[t].u.i = irep->clen - t; - break; - } - else if (pic_eq_p(pic, proc, sBEGIN)) { - pic_value v, seq; - - seq = pic_cdr(pic, obj); - for (v = seq; ! pic_nil_p(v); v = pic_cdr(pic, v)) { - pic_gen(pic, irep, pic_car(pic, v), env); - irep->code[irep->clen].insn = OP_POP; - irep->clen++; - } - irep->clen--; - break; - } - else if (pic_eq_p(pic, proc, sCONS)) { - pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), env); - pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, obj)), env); - irep->code[irep->clen].insn = OP_CONS; - irep->clen++; - break; - } - else if (pic_eq_p(pic, proc, sCAR)) { - pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, obj)), env); - irep->code[irep->clen].insn = OP_CAR; - irep->clen++; - break; - } - else if (pic_eq_p(pic, proc, sCDR)) { - pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, obj)), env); - irep->code[irep->clen].insn = OP_CDR; - irep->clen++; - break; - } - else if (pic_eq_p(pic, proc, sNILP)) { - pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, obj)), env); - irep->code[irep->clen].insn = OP_NILP; - irep->clen++; - break; - } - else if (pic_eq_p(pic, proc, sADD)) { - pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), env); - pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, obj)), env); - irep->code[irep->clen].insn = OP_ADD; - irep->clen++; - break; - } - else if (pic_eq_p(pic, proc, sSUB)) { - pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), env); - pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, obj)), env); - irep->code[irep->clen].insn = OP_SUB; - irep->clen++; - break; - } - else if (pic_eq_p(pic, proc, sMUL)) { - pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), env); - pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, obj)), env); - irep->code[irep->clen].insn = OP_MUL; - irep->clen++; - break; - } - else if (pic_eq_p(pic, proc, sDIV)) { - pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), env); - pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, obj)), env); - irep->code[irep->clen].insn = OP_DIV; - irep->clen++; - break; - } - else { - pic_gen_call(pic, irep, obj, env); - break; - } - } - case PIC_TT_BOOL: { - if (pic_true_p(obj)) { - irep->code[irep->clen].insn = OP_PUSHTRUE; - } - else { - irep->code[irep->clen].insn = OP_PUSHFALSE; - } - irep->clen++; - break; - } - case PIC_TT_FLOAT: { - irep->code[irep->clen].insn = OP_PUSHNUM; - irep->code[irep->clen].u.f = pic_float(obj); - irep->clen++; - break; - } - case PIC_TT_NIL: { - irep->code[irep->clen].insn = OP_PUSHNIL; - irep->clen++; - break; - } - case PIC_TT_PROC: - case PIC_TT_UNDEF: - case PIC_TT_PORT: { - pic_raise(pic, "invalid expression given"); - } - } -} - -static pic_value -reverse(pic_state *pic, pic_value list, pic_value acc) -{ - if (pic_nil_p(list)) - return acc; - return reverse(pic, pic_cdr(pic, list), pic_cons(pic, pic_car(pic, list), acc)); -} - -static void -pic_gen_call(pic_state *pic, struct pic_irep *irep, pic_value obj, struct pic_env *env) -{ - pic_value seq; - int i = 0; - - seq = reverse(pic, obj, pic_nil_value()); - for (; ! pic_nil_p(seq); seq = pic_cdr(pic, seq)) { - pic_value v; - - v = pic_car(pic, seq); - pic_gen(pic, irep, v, env); - ++i; - } - irep->code[irep->clen].insn = OP_CALL; - irep->code[irep->clen].u.i = i; - irep->clen++; -} - -static struct pic_irep * -pic_gen_lambda(pic_state *pic, pic_value obj, struct pic_env *env) -{ - struct pic_env *inner_env; - pic_value args, body, v; - struct pic_irep *irep; - - irep = new_irep(pic); - - /* arguments */ - args = pic_car(pic, pic_cdr(pic, obj)); - inner_env = env_new(pic, args, env); - - /* body */ - body = pic_cdr(pic, pic_cdr(pic, obj)); - for (v = body; ! pic_nil_p(v); v = pic_cdr(pic, v)) { - pic_gen(pic, irep, pic_car(pic, v), inner_env); - irep->code[irep->clen].insn = OP_POP; - irep->clen++; - } - irep->clen--; - irep->code[irep->clen].insn = OP_RET; - irep->clen++; - pic_free(pic, inner_env); - -#if VM_DEBUG - printf("LAMBDA_%zd:\n", pic->ilen); - print_irep(pic, irep); - puts(""); -#endif - - return irep; -} - -struct pic_proc * -pic_codegen(pic_state *pic, pic_value obj, struct pic_env *env) -{ - struct pic_proc *proc; - struct pic_irep *irep; - - proc = (struct pic_proc *)pic_obj_alloc(pic, sizeof(struct pic_proc), PIC_TT_PROC); - proc->cfunc_p = false; - proc->u.irep = irep = new_irep(pic); - - pic_gen(pic, irep, obj, env); - irep->code[irep->clen].insn = OP_STOP; - irep->clen++; - -#if VM_DEBUG - print_irep(pic, irep); -#endif - - return proc; -} - #if PIC_DIRECT_THREADED_VM # define VM_LOOP JUMP; # define CASE(x) L_##x: