2013-10-11 11:16:19 -04:00
|
|
|
#include <stdlib.h>
|
2013-10-12 05:48:35 -04:00
|
|
|
#include <stdio.h>
|
2013-10-15 06:19:34 -04:00
|
|
|
#include <stdarg.h>
|
2013-10-11 11:16:19 -04:00
|
|
|
|
|
|
|
#include "picrin.h"
|
2013-10-13 06:00:39 -04:00
|
|
|
#include "picrin/irep.h"
|
2013-10-15 06:18:33 -04:00
|
|
|
#include "picrin/proc.h"
|
2013-10-11 11:16:19 -04:00
|
|
|
|
2013-10-12 01:40:55 -04:00
|
|
|
static pic_value
|
|
|
|
pic_assq(pic_state *pic, pic_value key, pic_value assoc)
|
|
|
|
{
|
|
|
|
pic_value cell;
|
|
|
|
|
|
|
|
enter:
|
|
|
|
|
|
|
|
if (pic_nil_p(assoc))
|
|
|
|
return assoc;
|
|
|
|
|
|
|
|
cell = pic_car(pic, assoc);
|
|
|
|
if (pic_eq_p(pic, key, pic_car(pic, cell)))
|
|
|
|
return cell;
|
|
|
|
|
|
|
|
assoc = pic_cdr(pic, assoc);
|
|
|
|
goto enter;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct pic_pair *
|
|
|
|
pic_env_lookup(pic_state *pic, pic_value sym, struct pic_env *env)
|
|
|
|
{
|
|
|
|
pic_value v;
|
|
|
|
|
|
|
|
enter:
|
|
|
|
|
|
|
|
v = pic_assq(pic, sym, env->assoc);
|
|
|
|
if (! pic_nil_p(v)) {
|
|
|
|
return pic_pair_ptr(v);
|
|
|
|
}
|
|
|
|
if (env->parent) {
|
|
|
|
env = env->parent;
|
|
|
|
goto enter;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct pic_pair *
|
|
|
|
pic_env_define(pic_state *pic, pic_value sym, struct pic_env *env)
|
|
|
|
{
|
|
|
|
pic_value cell;
|
|
|
|
|
|
|
|
cell = pic_cons(pic, sym, pic_undef_value());
|
|
|
|
env->assoc = pic_cons(pic, cell, env->assoc);
|
|
|
|
|
|
|
|
return pic_pair_ptr(cell);
|
|
|
|
}
|
|
|
|
|
2013-10-15 06:19:34 -04:00
|
|
|
void
|
|
|
|
pic_defun(pic_state *pic, const char *name, pic_func_t cfunc)
|
|
|
|
{
|
|
|
|
struct pic_proc *proc;
|
|
|
|
struct pic_pair *cell;
|
|
|
|
|
|
|
|
proc = (struct pic_proc *)pic_obj_alloc(pic, sizeof(struct pic_proc), PIC_TT_PROC);
|
|
|
|
proc->u.cfunc = cfunc;
|
|
|
|
cell = pic_env_define(pic, pic_intern_cstr(pic, name), pic->global_env);
|
|
|
|
cell->cdr = pic_obj_value(proc);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
pic_get_args(pic_state *pic, const char *format, ...)
|
|
|
|
{
|
|
|
|
char c;
|
|
|
|
int i = 0;
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
va_start(ap, format);
|
|
|
|
while ((c = *format++)) {
|
|
|
|
switch (c) {
|
|
|
|
case 'o':
|
|
|
|
{
|
|
|
|
pic_value *p;
|
|
|
|
|
|
|
|
p = va_arg(ap, pic_value*);
|
|
|
|
*p = *pic->sp--;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-14 20:07:19 -04:00
|
|
|
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_PUSHNIL:
|
|
|
|
puts("OP_PUSHNIL");
|
|
|
|
break;
|
2013-10-15 07:05:12 -04:00
|
|
|
case OP_PUSHNUM:
|
2013-10-15 08:29:07 -04:00
|
|
|
printf("OP_PUSHNUM\t%g\n", irep->code[i].u.f);
|
2013-10-14 20:07:19 -04:00
|
|
|
break;
|
|
|
|
case OP_PUSHUNDEF:
|
|
|
|
puts("OP_PUSHUNDEF");
|
|
|
|
break;
|
|
|
|
case OP_GREF:
|
|
|
|
printf("OP_GREF\t%p\n", irep->code[i].u.gvar);
|
|
|
|
break;
|
|
|
|
case OP_GSET:
|
2013-10-15 06:18:33 -04:00
|
|
|
printf("OP_GSET\t%p\n", irep->code[i].u.gvar);
|
|
|
|
break;
|
|
|
|
case OP_CALL:
|
|
|
|
printf("OP_CALL\t%d\n", irep->code[i].u.i);
|
2013-10-14 20:07:19 -04:00
|
|
|
break;
|
|
|
|
case OP_CONS:
|
|
|
|
puts("OP_CONS");
|
|
|
|
break;
|
|
|
|
case OP_ADD:
|
|
|
|
puts("OP_ADD");
|
|
|
|
break;
|
2013-10-15 08:29:07 -04:00
|
|
|
case OP_SUB:
|
|
|
|
puts("OP_SUB");
|
|
|
|
break;
|
|
|
|
case OP_MUL:
|
|
|
|
puts("OP_MUL");
|
|
|
|
break;
|
|
|
|
case OP_DIV:
|
|
|
|
puts("OP_DIV");
|
|
|
|
break;
|
2013-10-14 20:07:19 -04:00
|
|
|
case OP_STOP:
|
|
|
|
puts("OP_STOP");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-15 06:18:33 -04:00
|
|
|
static void pic_gen_call(pic_state *, struct pic_irep *, pic_value, struct pic_env *);
|
|
|
|
|
2013-10-12 00:06:02 -04:00
|
|
|
static void
|
2013-10-11 23:53:54 -04:00
|
|
|
pic_gen(pic_state *pic, struct pic_irep *irep, pic_value obj, struct pic_env *env)
|
|
|
|
{
|
2013-10-15 08:29:07 -04:00
|
|
|
pic_value sDEFINE, sCONS, sADD, sSUB, sMUL, sDIV;
|
2013-10-11 23:53:54 -04:00
|
|
|
|
2013-10-14 05:28:52 -04:00
|
|
|
sDEFINE = pic->sDEFINE;
|
|
|
|
sCONS = pic->sCONS;
|
|
|
|
sADD = pic->sADD;
|
2013-10-15 08:29:07 -04:00
|
|
|
sSUB = pic->sSUB;
|
|
|
|
sMUL = pic->sMUL;
|
|
|
|
sDIV = pic->sDIV;
|
2013-10-11 23:53:54 -04:00
|
|
|
|
|
|
|
switch (pic_type(obj)) {
|
|
|
|
case PIC_TT_SYMBOL: {
|
2013-10-12 01:40:55 -04:00
|
|
|
struct pic_pair *gvar;
|
|
|
|
|
|
|
|
gvar = pic_env_lookup(pic, obj, env);
|
|
|
|
if (! gvar) {
|
|
|
|
pic_raise(pic, "unbound variable");
|
|
|
|
}
|
|
|
|
irep->code[irep->clen].insn = OP_GREF;
|
|
|
|
irep->code[irep->clen].u.gvar = gvar;
|
|
|
|
irep->clen++;
|
2013-10-11 23:53:54 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PIC_TT_PAIR: {
|
|
|
|
pic_value proc;
|
|
|
|
|
|
|
|
proc = pic_car(pic, obj);
|
2013-10-12 01:40:55 -04:00
|
|
|
if (pic_eq_p(pic, proc, sDEFINE)) {
|
|
|
|
struct pic_pair *gvar;
|
|
|
|
|
|
|
|
pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), env);
|
|
|
|
|
|
|
|
gvar = pic_env_define(pic, pic_car(pic, pic_cdr(pic, obj)), env);
|
|
|
|
irep->code[irep->clen].insn = OP_GSET;
|
|
|
|
irep->code[irep->clen].u.gvar = gvar;
|
|
|
|
irep->clen++;
|
|
|
|
irep->code[irep->clen].insn = OP_PUSHUNDEF;
|
|
|
|
irep->clen++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (pic_eq_p(pic, proc, sCONS)) {
|
2013-10-11 23:53:54 -04:00
|
|
|
/* generate args in reverse order*/
|
|
|
|
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, sADD)) {
|
|
|
|
/* generate args in reverse order*/
|
|
|
|
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;
|
|
|
|
}
|
2013-10-15 08:29:07 -04:00
|
|
|
else if (pic_eq_p(pic, proc, sSUB)) {
|
|
|
|
/* generate args in reverse order*/
|
|
|
|
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)) {
|
|
|
|
/* generate args in reverse order*/
|
|
|
|
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)) {
|
|
|
|
/* generate args in reverse order*/
|
|
|
|
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;
|
|
|
|
}
|
2013-10-11 23:53:54 -04:00
|
|
|
else {
|
2013-10-15 06:18:33 -04:00
|
|
|
pic_gen_call(pic, irep, obj, env);
|
2013-10-11 23:53:54 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-10-15 07:05:12 -04:00
|
|
|
case PIC_TT_FLOAT: {
|
|
|
|
irep->code[irep->clen].insn = OP_PUSHNUM;
|
|
|
|
irep->code[irep->clen].u.f = pic_float(obj);
|
2013-10-11 23:53:54 -04:00
|
|
|
irep->clen++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PIC_TT_NIL: {
|
|
|
|
irep->code[irep->clen].insn = OP_PUSHNIL;
|
|
|
|
irep->clen++;
|
|
|
|
break;
|
|
|
|
}
|
2013-10-12 05:48:35 -04:00
|
|
|
case PIC_TT_UNDEF: {
|
|
|
|
irep->code[irep->clen].insn = OP_PUSHUNDEF;
|
|
|
|
irep->clen++;
|
|
|
|
break;
|
|
|
|
}
|
2013-10-11 23:53:54 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-15 06:18:33 -04:00
|
|
|
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 - 1;
|
|
|
|
irep->clen++;
|
|
|
|
}
|
|
|
|
|
2013-10-11 23:53:54 -04:00
|
|
|
struct pic_proc *
|
|
|
|
pic_codegen(pic_state *pic, pic_value obj, struct pic_env *env)
|
|
|
|
{
|
|
|
|
struct pic_proc *proc;
|
|
|
|
struct pic_irep *irep;
|
|
|
|
struct pic_code *code;
|
|
|
|
|
2013-10-13 03:55:07 -04:00
|
|
|
proc = (struct pic_proc *)pic_obj_alloc(pic, sizeof(struct pic_proc), PIC_TT_PROC);
|
2013-10-11 23:53:54 -04:00
|
|
|
|
2013-10-14 04:04:59 -04:00
|
|
|
proc->u.irep = irep = (struct pic_irep *)pic_alloc(pic, sizeof(struct pic_irep));
|
|
|
|
irep->code = code = (struct pic_code *)pic_alloc(pic, sizeof(struct pic_code) * 1024);
|
2013-10-11 23:53:54 -04:00
|
|
|
irep->clen = 0;
|
|
|
|
irep->ccapa = 1024;
|
|
|
|
|
|
|
|
pic_gen(pic, irep, obj, env);
|
|
|
|
irep->code[irep->clen].insn = OP_STOP;
|
|
|
|
irep->clen++;
|
|
|
|
|
2013-10-14 20:07:19 -04:00
|
|
|
#if VM_DEBUG
|
|
|
|
print_irep(pic, irep);
|
|
|
|
#endif
|
|
|
|
|
2013-10-11 23:53:54 -04:00
|
|
|
return proc;
|
|
|
|
}
|
2013-10-12 00:06:02 -04:00
|
|
|
|
2013-10-12 05:48:35 -04:00
|
|
|
#define VM_LOOP for (;;) { switch (pc->insn) {
|
|
|
|
#define CASE(x) case x:
|
|
|
|
#define NEXT pc++; break
|
|
|
|
#define JUMP break
|
|
|
|
#define VM_LOOP_END } }
|
|
|
|
|
2013-10-15 06:15:51 -04:00
|
|
|
#define PUSH(v) do { pic_value v__ = (v); *++pic->sp = v__; } while (0)
|
|
|
|
#define POP() (*pic->sp--)
|
2013-10-13 04:27:44 -04:00
|
|
|
|
2013-10-12 00:06:02 -04:00
|
|
|
pic_value
|
|
|
|
pic_run(pic_state *pic, struct pic_proc *proc, pic_value args)
|
|
|
|
{
|
|
|
|
struct pic_code *pc;
|
2013-10-13 04:29:21 -04:00
|
|
|
int ai = pic_gc_arena_preserve(pic);
|
2013-10-12 00:06:02 -04:00
|
|
|
|
|
|
|
pc = proc->u.irep->code;
|
|
|
|
|
2013-10-12 05:48:35 -04:00
|
|
|
VM_LOOP {
|
|
|
|
CASE(OP_PUSHNIL) {
|
2013-10-13 04:27:44 -04:00
|
|
|
PUSH(pic_nil_value());
|
2013-10-12 05:48:35 -04:00
|
|
|
NEXT;
|
2013-10-12 00:06:02 -04:00
|
|
|
}
|
2013-10-15 07:05:12 -04:00
|
|
|
CASE(OP_PUSHNUM) {
|
|
|
|
PUSH(pic_float_value(pc->u.f));
|
2013-10-12 05:48:35 -04:00
|
|
|
NEXT;
|
2013-10-12 00:06:02 -04:00
|
|
|
}
|
2013-10-12 05:48:35 -04:00
|
|
|
CASE(OP_PUSHUNDEF) {
|
2013-10-13 04:27:44 -04:00
|
|
|
PUSH(pic_undef_value());
|
2013-10-12 05:48:35 -04:00
|
|
|
NEXT;
|
2013-10-12 01:40:01 -04:00
|
|
|
}
|
2013-10-12 05:48:35 -04:00
|
|
|
CASE(OP_GREF) {
|
2013-10-13 04:27:44 -04:00
|
|
|
PUSH(pc->u.gvar->cdr);
|
2013-10-12 05:48:35 -04:00
|
|
|
NEXT;
|
2013-10-12 01:40:55 -04:00
|
|
|
}
|
2013-10-12 05:48:35 -04:00
|
|
|
CASE(OP_GSET) {
|
2013-10-13 04:27:44 -04:00
|
|
|
pc->u.gvar->cdr = POP();
|
2013-10-12 05:48:35 -04:00
|
|
|
NEXT;
|
2013-10-12 01:40:55 -04:00
|
|
|
}
|
2013-10-15 06:18:33 -04:00
|
|
|
CASE(OP_CALL) {
|
|
|
|
pic_value c;
|
|
|
|
struct pic_proc *proc;
|
|
|
|
int ai = pic_gc_arena_preserve(pic);
|
|
|
|
|
|
|
|
pic_gc_protect(pic, c = POP());
|
|
|
|
proc = pic_proc_ptr(c);
|
|
|
|
PUSH(proc->u.cfunc(pic));
|
|
|
|
pic_gc_arena_restore(pic, ai);
|
|
|
|
NEXT;
|
|
|
|
}
|
2013-10-12 05:48:35 -04:00
|
|
|
CASE(OP_CONS) {
|
2013-10-12 00:06:02 -04:00
|
|
|
pic_value a, b;
|
2013-10-13 04:29:21 -04:00
|
|
|
pic_gc_protect(pic, a = POP());
|
|
|
|
pic_gc_protect(pic, b = POP());
|
2013-10-13 04:27:44 -04:00
|
|
|
PUSH(pic_cons(pic, a, b));
|
2013-10-13 04:29:21 -04:00
|
|
|
pic_gc_arena_restore(pic, ai);
|
2013-10-12 05:48:35 -04:00
|
|
|
NEXT;
|
2013-10-12 00:06:02 -04:00
|
|
|
}
|
2013-10-12 05:48:35 -04:00
|
|
|
CASE(OP_ADD) {
|
2013-10-12 00:06:02 -04:00
|
|
|
pic_value a, b;
|
2013-10-13 04:27:44 -04:00
|
|
|
a = POP();
|
|
|
|
b = POP();
|
2013-10-15 07:05:12 -04:00
|
|
|
PUSH(pic_float_value(pic_float(a) + pic_float(b)));
|
2013-10-12 05:48:35 -04:00
|
|
|
NEXT;
|
2013-10-12 00:06:02 -04:00
|
|
|
}
|
2013-10-15 08:29:07 -04:00
|
|
|
CASE(OP_SUB) {
|
|
|
|
pic_value a, b;
|
|
|
|
a = POP();
|
|
|
|
b = POP();
|
|
|
|
PUSH(pic_float_value(pic_float(a) - pic_float(b)));
|
|
|
|
NEXT;
|
|
|
|
}
|
|
|
|
CASE(OP_MUL) {
|
|
|
|
pic_value a, b;
|
|
|
|
a = POP();
|
|
|
|
b = POP();
|
|
|
|
PUSH(pic_float_value(pic_float(a) * pic_float(b)));
|
|
|
|
NEXT;
|
|
|
|
}
|
|
|
|
CASE(OP_DIV) {
|
|
|
|
pic_value a, b;
|
|
|
|
a = POP();
|
|
|
|
b = POP();
|
|
|
|
PUSH(pic_float_value(pic_float(a) / pic_float(b)));
|
|
|
|
NEXT;
|
|
|
|
}
|
2013-10-12 05:48:35 -04:00
|
|
|
CASE(OP_STOP) {
|
2013-10-12 00:06:02 -04:00
|
|
|
goto STOP;
|
|
|
|
}
|
2013-10-12 05:48:35 -04:00
|
|
|
} VM_LOOP_END;
|
2013-10-12 00:06:02 -04:00
|
|
|
|
|
|
|
STOP:
|
2013-10-14 04:05:49 -04:00
|
|
|
return POP();
|
2013-10-12 00:06:02 -04:00
|
|
|
}
|
2013-10-12 01:40:27 -04:00
|
|
|
|
|
|
|
void
|
|
|
|
pic_raise(pic_state *pic, const char *str)
|
|
|
|
{
|
|
|
|
puts(str);
|
|
|
|
abort();
|
|
|
|
}
|