mirror of
https://github.com/ashinn/chibi-scheme.git
synced 2025-07-13 07:57:35 +02:00
1st class opcode support
This commit is contained in:
parent
dfc38557b9
commit
13a161e797
3 changed files with 117 additions and 84 deletions
2
debug.c
2
debug.c
|
@ -5,7 +5,7 @@
|
||||||
static const char* reverse_opcode_names[] =
|
static const char* reverse_opcode_names[] =
|
||||||
{"NOOP", "TAIL-CALL", "CALL", "APPLY1", "CALLCC", "RESUMECC", "ERROR",
|
{"NOOP", "TAIL-CALL", "CALL", "APPLY1", "CALLCC", "RESUMECC", "ERROR",
|
||||||
"FCALL0", "FCALL1",
|
"FCALL0", "FCALL1",
|
||||||
"FCALL2", "FCALL3", "FCALL4", "FCALL5", "FCALL6", "FCALL7", "FCALLN",
|
"FCALL2", "FCALL3", /* "FCALL4", "FCALL5", "FCALL6", "FCALL7", */ "FCALLN",
|
||||||
"JUMP-UNLESS", "JUMP", "RET", "DONE", "PARAMETER",
|
"JUMP-UNLESS", "JUMP", "RET", "DONE", "PARAMETER",
|
||||||
"STACK-REF", "STACK-SET", "GLOBAL-REF", "GLOBAL-SET", "CLOSURE-REF",
|
"STACK-REF", "STACK-SET", "GLOBAL-REF", "GLOBAL-SET", "CLOSURE-REF",
|
||||||
"VECTOR-REF", "VECTOR-SET", "STRING-REF", "STRING-SET", "MAKE-PROCEDURE",
|
"VECTOR-REF", "VECTOR-SET", "STRING-REF", "STRING-SET", "MAKE-PROCEDURE",
|
||||||
|
|
188
eval.c
188
eval.c
|
@ -264,73 +264,7 @@ void analyze(sexp obj, bytecode *bc, unsigned int *i, env e,
|
||||||
errx(1, "unknown core form: %s", ((core_form)o1)->code);
|
errx(1, "unknown core form: %s", ((core_form)o1)->code);
|
||||||
}
|
}
|
||||||
} else if (SEXP_OPCODEP(o1)) {
|
} else if (SEXP_OPCODEP(o1)) {
|
||||||
/* verify arity */
|
analyze_opcode((opcode)o1, obj, bc, i, e, params, fv, sv, d, tailp);
|
||||||
switch (((opcode)o1)->op_class) {
|
|
||||||
case OPC_TYPE_PREDICATE:
|
|
||||||
case OPC_PREDICATE:
|
|
||||||
case OPC_ARITHMETIC:
|
|
||||||
case OPC_ARITHMETIC_INV:
|
|
||||||
case OPC_ARITHMETIC_CMP:
|
|
||||||
case OPC_CONSTRUCTOR:
|
|
||||||
case OPC_ACCESSOR:
|
|
||||||
case OPC_GENERIC:
|
|
||||||
tmp1 = sexp_length(SEXP_CDR(obj));
|
|
||||||
if (tmp1 == 0) {
|
|
||||||
errx(1, "opcode with no arguments: %s", ((opcode)o1)->name);
|
|
||||||
} else if (tmp1 == 1) {
|
|
||||||
if (((opcode)o1)->op_class == OPC_ARITHMETIC_INV) {
|
|
||||||
analyze(SEXP_CADR(obj), bc, i, e, params, fv, sv, d, 0);
|
|
||||||
emit(bc, i, ((opcode)o1)->op_inverse);
|
|
||||||
} else {
|
|
||||||
analyze(SEXP_CADR(obj), bc, i, e, params, fv, sv, d, 0);
|
|
||||||
if (((opcode)o1)->op_class != OPC_ARITHMETIC) {
|
|
||||||
emit(bc, i, ((opcode)o1)->op_name);
|
|
||||||
(*d)--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (o2 = sexp_reverse(SEXP_CDR(obj)); SEXP_PAIRP(o2);
|
|
||||||
o2 = SEXP_CDR(o2)) {
|
|
||||||
/* fprintf(stderr, ":: arg: %d\n", SEXP_CAR(o2)); */
|
|
||||||
analyze(SEXP_CAR(o2), bc, i, e, params, fv, sv, d, 0);
|
|
||||||
}
|
|
||||||
emit(bc, i, ((opcode)o1)->op_name);
|
|
||||||
(*d) -= (tmp1-1);
|
|
||||||
if (((opcode)o1)->op_class == OPC_ARITHMETIC) {
|
|
||||||
for (tmp1-=2; tmp1>0; tmp1--)
|
|
||||||
emit(bc, i, ((opcode)o1)->op_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case OPC_IO:
|
|
||||||
tmp1 = sexp_length(SEXP_CDR(obj));
|
|
||||||
if (tmp1 == ((opcode)o1)->num_args && ((opcode)o1)->var_args_p) {
|
|
||||||
emit(bc, i, OP_PARAMETER);
|
|
||||||
emit_word(bc, i, (sexp_uint_t) ((opcode)o1)->data);
|
|
||||||
(*d)++;
|
|
||||||
}
|
|
||||||
for (o2 = sexp_reverse(SEXP_CDR(obj)); SEXP_PAIRP(o2);
|
|
||||||
o2 = SEXP_CDR(o2))
|
|
||||||
analyze(SEXP_CAR(o2), bc, i, e, params, fv, sv, d, 0);
|
|
||||||
emit(bc, i, ((opcode)o1)->op_name);
|
|
||||||
(*d) -= (tmp1-1);
|
|
||||||
break;
|
|
||||||
case OPC_PARAMETER:
|
|
||||||
emit(bc, i, ((opcode)o1)->op_name);
|
|
||||||
emit_word(bc, i, (sexp_uint_t) ((opcode)o1)->data);
|
|
||||||
break;
|
|
||||||
case OPC_FOREIGN:
|
|
||||||
for (o2 = sexp_reverse(SEXP_CDR(obj)); SEXP_PAIRP(o2);
|
|
||||||
o2 = SEXP_CDR(o2)) {
|
|
||||||
analyze(SEXP_CAR(o2), bc, i, e, params, fv, sv, d, 0);
|
|
||||||
}
|
|
||||||
emit_push(bc, i, ((opcode)o1)->data);
|
|
||||||
emit(bc, i, ((opcode)o1)->op_name);
|
|
||||||
(*d) -= sexp_length(SEXP_CDR(obj));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
errx(1, "unknown opcode class: %d", ((opcode)o1)->op_class);
|
|
||||||
}
|
|
||||||
} else if (SEXP_MACROP(o1)) {
|
} else if (SEXP_MACROP(o1)) {
|
||||||
obj = sexp_expand_macro((macro) o1, obj, e);
|
obj = sexp_expand_macro((macro) o1, obj, e);
|
||||||
goto loop;
|
goto loop;
|
||||||
|
@ -378,6 +312,78 @@ void analyze(sexp obj, bytecode *bc, unsigned int *i, env e,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void analyze_opcode (opcode op, sexp obj, bytecode *bc, unsigned int *i, env e,
|
||||||
|
sexp params, sexp fv, sexp sv, unsigned int *d, int tailp)
|
||||||
|
{
|
||||||
|
int tmp1;
|
||||||
|
sexp o1;
|
||||||
|
|
||||||
|
switch (op->op_class) {
|
||||||
|
case OPC_TYPE_PREDICATE:
|
||||||
|
case OPC_PREDICATE:
|
||||||
|
case OPC_ARITHMETIC:
|
||||||
|
case OPC_ARITHMETIC_INV:
|
||||||
|
case OPC_ARITHMETIC_CMP:
|
||||||
|
case OPC_CONSTRUCTOR:
|
||||||
|
case OPC_ACCESSOR:
|
||||||
|
case OPC_GENERIC:
|
||||||
|
tmp1 = sexp_length(SEXP_CDR(obj));
|
||||||
|
if (tmp1 == 0) {
|
||||||
|
errx(1, "opcode with no arguments: %s", op->name);
|
||||||
|
} else if (tmp1 == 1) {
|
||||||
|
if (op->op_class == OPC_ARITHMETIC_INV) {
|
||||||
|
analyze(SEXP_CADR(obj), bc, i, e, params, fv, sv, d, 0);
|
||||||
|
emit(bc, i, op->op_inverse);
|
||||||
|
} else {
|
||||||
|
analyze(SEXP_CADR(obj), bc, i, e, params, fv, sv, d, 0);
|
||||||
|
if (op->op_class != OPC_ARITHMETIC) {
|
||||||
|
emit(bc, i, op->op_name);
|
||||||
|
(*d)--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (o1 = sexp_reverse(SEXP_CDR(obj)); SEXP_PAIRP(o1);
|
||||||
|
o1 = SEXP_CDR(o1)) {
|
||||||
|
analyze(SEXP_CAR(o1), bc, i, e, params, fv, sv, d, 0);
|
||||||
|
}
|
||||||
|
emit(bc, i, op->op_name);
|
||||||
|
(*d) -= (tmp1-1);
|
||||||
|
if (op->op_class == OPC_ARITHMETIC) {
|
||||||
|
for (tmp1-=2; tmp1>0; tmp1--)
|
||||||
|
emit(bc, i, op->op_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OPC_IO:
|
||||||
|
tmp1 = sexp_length(SEXP_CDR(obj));
|
||||||
|
if (tmp1 == op->num_args && op->var_args_p) {
|
||||||
|
emit(bc, i, OP_PARAMETER);
|
||||||
|
emit_word(bc, i, (sexp_uint_t) op->data);
|
||||||
|
(*d)++;
|
||||||
|
}
|
||||||
|
for (o1 = sexp_reverse(SEXP_CDR(obj)); SEXP_PAIRP(o1);
|
||||||
|
o1 = SEXP_CDR(o1))
|
||||||
|
analyze(SEXP_CAR(o1), bc, i, e, params, fv, sv, d, 0);
|
||||||
|
emit(bc, i, op->op_name);
|
||||||
|
(*d) -= (tmp1-1);
|
||||||
|
break;
|
||||||
|
case OPC_PARAMETER:
|
||||||
|
emit(bc, i, op->op_name);
|
||||||
|
emit_word(bc, i, (sexp_uint_t) op->data);
|
||||||
|
break;
|
||||||
|
case OPC_FOREIGN:
|
||||||
|
for (o1=sexp_reverse(SEXP_CDR(obj)); SEXP_PAIRP(o1); o1=SEXP_CDR(o1)) {
|
||||||
|
analyze(SEXP_CAR(o1), bc, i, e, params, fv, sv, d, 0);
|
||||||
|
}
|
||||||
|
emit_push(bc, i, op->data);
|
||||||
|
emit(bc, i, op->op_name);
|
||||||
|
(*d) -= sexp_length(SEXP_CDR(obj));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errx(1, "unknown opcode class: %d", op->op_class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void analyze_var_ref (sexp obj, bytecode *bc, unsigned int *i, env e,
|
void analyze_var_ref (sexp obj, bytecode *bc, unsigned int *i, env e,
|
||||||
sexp params, sexp fv, sexp sv, unsigned int *d) {
|
sexp params, sexp fv, sexp sv, unsigned int *d) {
|
||||||
int tmp;
|
int tmp;
|
||||||
|
@ -520,6 +526,32 @@ void analyze_lambda (sexp name, sexp formals, sexp body,
|
||||||
emit(bc, i, OP_MAKE_PROCEDURE);
|
emit(bc, i, OP_MAKE_PROCEDURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sexp make_param_list(sexp_uint_t i) {
|
||||||
|
sexp res = SEXP_NULL;
|
||||||
|
char sym[2]="a";
|
||||||
|
for (sym[0]+=i; i>0; i--) {
|
||||||
|
sym[0] = sym[0]-1;
|
||||||
|
res = sexp_cons(sexp_intern(sym), res);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
sexp make_opcode_procedure(opcode op, sexp_uint_t i, env e) {
|
||||||
|
bytecode bc = (bytecode) SEXP_ALLOC(sizeof(struct bytecode)+INIT_BCODE_SIZE);
|
||||||
|
sexp params = make_param_list(i);
|
||||||
|
unsigned int pos=0, d=0;
|
||||||
|
e = extend_env_closure(e, params, -4);
|
||||||
|
bc->tag = SEXP_BYTECODE;
|
||||||
|
bc->len = INIT_BCODE_SIZE;
|
||||||
|
analyze_opcode(op, sexp_cons((sexp) op, params), &bc, &pos, e, params,
|
||||||
|
SEXP_NULL, SEXP_NULL, &d, 0);
|
||||||
|
emit(&bc, &pos, OP_RET);
|
||||||
|
shrink_bcode(&bc, pos);
|
||||||
|
/* disasm(bc); */
|
||||||
|
return sexp_make_procedure(0, (int) sexp_make_integer(i),
|
||||||
|
(sexp) bc, SEXP_UNDEF);
|
||||||
|
}
|
||||||
|
|
||||||
bytecode compile(sexp params, sexp obj, env e, sexp fv, sexp sv, int done_p) {
|
bytecode compile(sexp params, sexp obj, env e, sexp fv, sexp sv, int done_p) {
|
||||||
unsigned int i = 0, j, d = 0, core, define_ok=1;
|
unsigned int i = 0, j, d = 0, core, define_ok=1;
|
||||||
bytecode bc = (bytecode) SEXP_ALLOC(sizeof(struct bytecode)+INIT_BCODE_SIZE);
|
bytecode bc = (bytecode) SEXP_ALLOC(sizeof(struct bytecode)+INIT_BCODE_SIZE);
|
||||||
|
@ -644,6 +676,7 @@ sexp vm(bytecode bc, env e, sexp* stack, unsigned int top) {
|
||||||
/* fprintf(stderr, "stack-ref: %d => ", (sexp_sint_t) ((sexp*)ip)[0]); */
|
/* fprintf(stderr, "stack-ref: %d => ", (sexp_sint_t) ((sexp*)ip)[0]); */
|
||||||
/* sexp_write(stack[top - (sexp_sint_t) ((sexp*)ip)[0]], cur_error_port); */
|
/* sexp_write(stack[top - (sexp_sint_t) ((sexp*)ip)[0]], cur_error_port); */
|
||||||
/* fprintf(stderr, "\n"); */
|
/* fprintf(stderr, "\n"); */
|
||||||
|
/* print_stack(stack, top); */
|
||||||
stack[top] = stack[top - (sexp_sint_t) ((sexp*)ip)[0]];
|
stack[top] = stack[top - (sexp_sint_t) ((sexp*)ip)[0]];
|
||||||
ip += sizeof(sexp);
|
ip += sizeof(sexp);
|
||||||
top++;
|
top++;
|
||||||
|
@ -837,6 +870,11 @@ sexp vm(bytecode bc, env e, sexp* stack, unsigned int top) {
|
||||||
/* print_stack(stack, top); */
|
/* print_stack(stack, top); */
|
||||||
i = sexp_unbox_integer(((sexp*)ip)[0]);
|
i = sexp_unbox_integer(((sexp*)ip)[0]);
|
||||||
tmp1 = stack[top-1];
|
tmp1 = stack[top-1];
|
||||||
|
make_call:
|
||||||
|
if (SEXP_OPCODEP(tmp1))
|
||||||
|
/* hack, compile an opcode application on the fly */
|
||||||
|
tmp1 = make_opcode_procedure((opcode) tmp1, i, e);
|
||||||
|
print_stack(stack, top);
|
||||||
if (! SEXP_PROCEDUREP(tmp1)) {
|
if (! SEXP_PROCEDUREP(tmp1)) {
|
||||||
fprintf(stderr, "error: non-procedure app\n");
|
fprintf(stderr, "error: non-procedure app\n");
|
||||||
sexp_raise(sexp_intern("non-procedure-application"));
|
sexp_raise(sexp_intern("non-procedure-application"));
|
||||||
|
@ -866,7 +904,7 @@ sexp vm(bytecode bc, env e, sexp* stack, unsigned int top) {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
stack[top-1] = sexp_make_integer(i);
|
stack[top-1] = sexp_make_integer(i);
|
||||||
stack[top] = sexp_make_integer(ip+4);
|
stack[top] = sexp_make_integer(ip+sizeof(sexp));
|
||||||
stack[top+1] = cp;
|
stack[top+1] = cp;
|
||||||
top+=2;
|
top+=2;
|
||||||
/* sexp_debug("call proc: ", tmp1); */
|
/* sexp_debug("call proc: ", tmp1); */
|
||||||
|
@ -884,22 +922,16 @@ sexp vm(bytecode bc, env e, sexp* stack, unsigned int top) {
|
||||||
/* print_stack(stack, top); */
|
/* print_stack(stack, top); */
|
||||||
break;
|
break;
|
||||||
case OP_APPLY1:
|
case OP_APPLY1:
|
||||||
|
print_stack(stack, top);
|
||||||
tmp1 = stack[top-1];
|
tmp1 = stack[top-1];
|
||||||
if (! SEXP_PROCEDUREP(tmp1))
|
|
||||||
errx(2, "non-procedure application: %p", tmp1);
|
|
||||||
tmp2 = stack[top-2];
|
tmp2 = stack[top-2];
|
||||||
i = sexp_length(tmp2);
|
i = sexp_length(tmp2);
|
||||||
top += (i-2);
|
top += (i-2);
|
||||||
for ( ; SEXP_PAIRP(tmp2); tmp2=SEXP_CDR(tmp2), top--)
|
for ( ; SEXP_PAIRP(tmp2); tmp2=SEXP_CDR(tmp2), top--)
|
||||||
stack[top-1] = SEXP_CAR(tmp2);
|
stack[top-1] = SEXP_CAR(tmp2);
|
||||||
top += i+3;
|
top += i+1;
|
||||||
stack[top-3] = sexp_make_integer(i);
|
ip -= sizeof(sexp);
|
||||||
stack[top-2] = sexp_make_integer(ip);
|
goto make_call;
|
||||||
stack[top-1] = cp;
|
|
||||||
bc = sexp_procedure_code(tmp1);
|
|
||||||
ip = bc->data;
|
|
||||||
cp = sexp_procedure_vars(tmp1);
|
|
||||||
break;
|
|
||||||
case OP_CALLCC:
|
case OP_CALLCC:
|
||||||
tmp1 = stack[top-1];
|
tmp1 = stack[top-1];
|
||||||
if (! SEXP_PROCEDUREP(tmp1))
|
if (! SEXP_PROCEDUREP(tmp1))
|
||||||
|
|
11
eval.h
11
eval.h
|
@ -107,10 +107,10 @@ enum opcode_names {
|
||||||
OP_FCALL1,
|
OP_FCALL1,
|
||||||
OP_FCALL2,
|
OP_FCALL2,
|
||||||
OP_FCALL3,
|
OP_FCALL3,
|
||||||
OP_FCALL4,
|
/* OP_FCALL4, */
|
||||||
OP_FCALL5,
|
/* OP_FCALL5, */
|
||||||
OP_FCALL6,
|
/* OP_FCALL6, */
|
||||||
OP_FCALL7,
|
/* OP_FCALL7, */
|
||||||
OP_FCALLN,
|
OP_FCALLN,
|
||||||
OP_JUMP_UNLESS,
|
OP_JUMP_UNLESS,
|
||||||
OP_JUMP,
|
OP_JUMP,
|
||||||
|
@ -182,7 +182,8 @@ void analyze_lambda (sexp name, sexp formals, sexp body,
|
||||||
sexp params, sexp fv, sexp sv, unsigned int *d, int tailp);
|
sexp params, sexp fv, sexp sv, unsigned int *d, int tailp);
|
||||||
void analyze_var_ref (sexp name, bytecode *bc, unsigned int *i, env e,
|
void analyze_var_ref (sexp name, bytecode *bc, unsigned int *i, env e,
|
||||||
sexp params, sexp fv, sexp sv, unsigned int *d);
|
sexp params, sexp fv, sexp sv, unsigned int *d);
|
||||||
|
void analyze_opcode (opcode op, sexp obj, bytecode *bc, unsigned int *i, env e,
|
||||||
|
sexp params, sexp fv, sexp sv, unsigned int *d, int tailp);
|
||||||
sexp vm(bytecode bc, env e, sexp* stack, unsigned int top);
|
sexp vm(bytecode bc, env e, sexp* stack, unsigned int top);
|
||||||
|
|
||||||
sexp eval_in_stack(sexp obj, env e, sexp* stack, unsigned int top);
|
sexp eval_in_stack(sexp obj, env e, sexp* stack, unsigned int top);
|
||||||
|
|
Loading…
Add table
Reference in a new issue