static Datum stack[NSTACK]; /* the stack */
static Datum *stackp; /* next free spot on stack */
#define NPROG 2000
Inst prog[NPROG]; /* the machine */
Inst *progp; /* next free spot for code generation */
Inst *pc; /* program counter during execution */
Inst *progbase = prog; /* start of current subprogram */
int returning; /* 1 if return stmt seen */
int indef; /* 1 if parsing a func or proc */
typedef struct Frame { /* proc/func call stack frame */
Symbol *sp; /* symbol table entry */
Inst *retpc; /* where to resume after return */
Datum *argn; /* n-th argument on stack */
int nargs; /* number of arguments */
} Frame;
#define NFRAME 100
Frame frame[NFRAME];
Frame *fp; /* frame pointer */
void
whilecode(void)
{
Datum d;
Inst *savepc = pc;
execute(savepc+2); /* condition */
d = pop();
while (d.val) {
execute(*((Inst **)(savepc))); /* body */
if (returning)
break;
execute(savepc+2); /* condition */
d = pop();
}
if (!returning)
pc = *((Inst **)(savepc+1)); /* next stmt */
}
void
forcode(void)
{
Datum d;
Inst *savepc = pc;
execute(savepc+4); /* precharge */
pop();
execute(*((Inst **)(savepc))); /* condition */
d = pop();
while (d.val) {
execute(*((Inst **)(savepc+2))); /* body */
if (returning)
break;
execute(*((Inst **)(savepc+1))); /* post loop */
pop();
execute(*((Inst **)(savepc))); /* condition */
d = pop();
}
if (!returning)
pc = *((Inst **)(savepc+3)); /* next stmt */
}
void
ifcode(void)
{
Datum d;
Inst *savepc = pc; /* then part */
execute(savepc+3); /* condition */
d = pop();
if (d.val)
execute(*((Inst **)(savepc)));
else if (*((Inst **)(savepc+1))) /* else part? */
execute(*((Inst **)(savepc+1)));
if (!returning)
pc = *((Inst **)(savepc+2)); /* next stmt */
}
void
define(Symbol* sp, Formal *f) /* put func/proc in symbol table */
{
Fndefn *fd;
int n;
void
call(void) /* call a function */
{
Formal *f;
Datum *arg;
Saveval *s;
int i;
Symbol *sp = (Symbol *)pc[0]; /* symbol table entry */
/* for function */
if (fp >= &frame[NFRAME-1])
execerror(sp->name, "call nested too deeply");
fp++;
fp->sp = sp;
fp->nargs = (int)(uintptr)pc[1];
fp->retpc = pc + 2;
fp->argn = stackp - 1; /* last argument */
if(fp->nargs != sp->u.defn->nargs)
execerror(sp->name, "called with wrong number of arguments");
/* bind formals */
f = sp->u.defn->formals;
arg = stackp - fp->nargs;
while(f){
s = emalloc(sizeof(Saveval));
s->val = f->sym->u;
s->type = f->sym->type;
s->next = f->save;
f->save = s;
f->sym->u.val = arg->val;
f->sym->type = VAR;
f = f->next;
arg++;
}
for (i = 0; i < fp->nargs; i++)
pop(); /* pop arguments; no longer needed */
execute(sp->u.defn->code);
returning = 0;
}
void
restore(Symbol *sp) /* restore formals associated with symbol */
{
Formal *f;
Saveval *s;
f = sp->u.defn->formals;
while(f){
s = f->save;
if(s == 0) /* more actuals than formals */
break;
f->sym->u = s->val;
f->sym->type = s->type;
f->save = s->next;
free(s);
f = f->next;
}
}
void
restoreall(void) /* restore all variables in case of error */
{
while(fp>=frame && fp->sp){
restore(fp->sp);
--fp;
}
fp = frame;
}
static void
ret(void) /* common return from func or proc */
{
/* restore formals */
restore(fp->sp);
pc = (Inst *)fp->retpc;
--fp;
returning = 1;
}
void
funcret(void) /* return from a function */
{
Datum d;
if (fp->sp->type == PROCEDURE)
execerror(fp->sp->name, "(proc) returns value");
d = pop(); /* preserve function return value */
ret();
push(d);
}
void
procret(void) /* return from a procedure */
{
if (fp->sp->type == FUNCTION)
execerror(fp->sp->name,
"(func) returns no value");
ret();
}
void
bltin(void)
{
Datum d;
d = pop();
d.val = (*(double (*)(double))*pc++)(d.val);
push(d);
}
void
assign(void)
{
Datum d1, d2;
d1 = pop();
d2 = pop();
if (d1.sym->type != VAR && d1.sym->type != UNDEF)
execerror("assignment to non-variable",
d1.sym->name);
d1.sym->u.val = d2.val;
d1.sym->type = VAR;
push(d2);
}
void
addeq(void)
{
Datum d1, d2;
d1 = pop();
d2 = pop();
if (d1.sym->type != VAR && d1.sym->type != UNDEF)
execerror("assignment to non-variable",
d1.sym->name);
d2.val = d1.sym->u.val += d2.val;
d1.sym->type = VAR;
push(d2);
}
void
subeq(void)
{
Datum d1, d2;
d1 = pop();
d2 = pop();
if (d1.sym->type != VAR && d1.sym->type != UNDEF)
execerror("assignment to non-variable",
d1.sym->name);
d2.val = d1.sym->u.val -= d2.val;
d1.sym->type = VAR;
push(d2);
}
void
muleq(void)
{
Datum d1, d2;
d1 = pop();
d2 = pop();
if (d1.sym->type != VAR && d1.sym->type != UNDEF)
execerror("assignment to non-variable",
d1.sym->name);
d2.val = d1.sym->u.val *= d2.val;
d1.sym->type = VAR;
push(d2);
}
void
diveq(void)
{
Datum d1, d2;
d1 = pop();
d2 = pop();
if (d1.sym->type != VAR && d1.sym->type != UNDEF)
execerror("assignment to non-variable",
d1.sym->name);
d2.val = d1.sym->u.val /= d2.val;
d1.sym->type = VAR;
push(d2);
}
void
modeq(void)
{
Datum d1, d2;
long x;
d1 = pop();
d2 = pop();
if (d1.sym->type != VAR && d1.sym->type != UNDEF)
execerror("assignment to non-variable",
d1.sym->name);
/* d2.val = d1.sym->u.val %= d2.val; */
x = d1.sym->u.val;
x %= (long) d2.val;
d2.val = d1.sym->u.val = x;
d1.sym->type = VAR;
push(d2);
}
void
printtop(void) /* pop top value from stack, print it */
{
Datum d;
static Symbol *s; /* last value computed */
if (s == 0)
s = install("_", VAR, 0.0);
d = pop();
print("%.12g\n", d.val);
s->u.val = d.val;
}
void
prexpr(void) /* print numeric value */
{
Datum d;
d = pop();
print("%.12g ", d.val);
}