123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #include <u.h>
- #include <libc.h>
- #include <bio.h>
- #include "hoc.h"
- #include "y.tab.h"
- #define NSTACK 256
- 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
- initcode(void)
- {
- progp = progbase;
- stackp = stack;
- fp = frame;
- returning = 0;
- indef = 0;
- }
- void
- push(Datum d)
- {
- if (stackp >= &stack[NSTACK])
- execerror("stack too deep", 0);
- *stackp++ = d;
- }
- Datum
- pop(void)
- {
- if (stackp == stack)
- execerror("stack underflow", 0);
- return *--stackp;
- }
- void
- xpop(void) /* for when no value is wanted */
- {
- if (stackp == stack)
- execerror("stack underflow", (char *)0);
- --stackp;
- }
- void
- constpush(void)
- {
- Datum d;
- d.val = ((Symbol *)*pc++)->u.val;
- push(d);
- }
- void
- varpush(void)
- {
- Datum d;
- d.sym = (Symbol *)(*pc++);
- push(d);
- }
- 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;
- fd = emalloc(sizeof(Fndefn));
- fd->code = progbase; /* start of code */
- progbase = progp; /* next code starts here */
- fd->formals = f;
- for(n=0; f; f=f->next)
- n++;
- fd->nargs = n;
- sp->u.defn = fd;
- }
- 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
- add(void)
- {
- Datum d1, d2;
- d2 = pop();
- d1 = pop();
- d1.val += d2.val;
- push(d1);
- }
- void
- sub(void)
- {
- Datum d1, d2;
- d2 = pop();
- d1 = pop();
- d1.val -= d2.val;
- push(d1);
- }
- void
- mul(void)
- {
- Datum d1, d2;
- d2 = pop();
- d1 = pop();
- d1.val *= d2.val;
- push(d1);
- }
- void
- div(void)
- {
- Datum d1, d2;
- d2 = pop();
- if (d2.val == 0.0)
- execerror("division by zero", (char *)0);
- d1 = pop();
- d1.val /= d2.val;
- push(d1);
- }
- void
- mod(void)
- {
- Datum d1, d2;
- d2 = pop();
- if (d2.val == 0.0)
- execerror("division by zero", (char *)0);
- d1 = pop();
- /* d1.val %= d2.val; */
- d1.val = fmod(d1.val, d2.val);
- push(d1);
- }
- void
- negate(void)
- {
- Datum d;
- d = pop();
- d.val = -d.val;
- push(d);
- }
- void
- verify(Symbol* s)
- {
- if (s->type != VAR && s->type != UNDEF)
- execerror("attempt to evaluate non-variable", s->name);
- if (s->type == UNDEF)
- execerror("undefined variable", s->name);
- }
- void
- eval(void) /* evaluate variable on stack */
- {
- Datum d;
- d = pop();
- verify(d.sym);
- d.val = d.sym->u.val;
- push(d);
- }
- void
- preinc(void)
- {
- Datum d;
- d.sym = (Symbol *)(*pc++);
- verify(d.sym);
- d.val = d.sym->u.val += 1.0;
- push(d);
- }
- void
- predec(void)
- {
- Datum d;
- d.sym = (Symbol *)(*pc++);
- verify(d.sym);
- d.val = d.sym->u.val -= 1.0;
- push(d);
- }
- void
- postinc(void)
- {
- Datum d;
- double v;
- d.sym = (Symbol *)(*pc++);
- verify(d.sym);
- v = d.sym->u.val;
- d.sym->u.val += 1.0;
- d.val = v;
- push(d);
- }
- void
- postdec(void)
- {
- Datum d;
- double v;
- d.sym = (Symbol *)(*pc++);
- verify(d.sym);
- v = d.sym->u.val;
- d.sym->u.val -= 1.0;
- d.val = v;
- push(d);
- }
- void
- gt(void)
- {
- Datum d1, d2;
- d2 = pop();
- d1 = pop();
- d1.val = (double)(d1.val > d2.val);
- push(d1);
- }
- void
- lt(void)
- {
- Datum d1, d2;
- d2 = pop();
- d1 = pop();
- d1.val = (double)(d1.val < d2.val);
- push(d1);
- }
- void
- ge(void)
- {
- Datum d1, d2;
- d2 = pop();
- d1 = pop();
- d1.val = (double)(d1.val >= d2.val);
- push(d1);
- }
- void
- le(void)
- {
- Datum d1, d2;
- d2 = pop();
- d1 = pop();
- d1.val = (double)(d1.val <= d2.val);
- push(d1);
- }
- void
- eq(void)
- {
- Datum d1, d2;
- d2 = pop();
- d1 = pop();
- d1.val = (double)(d1.val == d2.val);
- push(d1);
- }
- void
- ne(void)
- {
- Datum d1, d2;
- d2 = pop();
- d1 = pop();
- d1.val = (double)(d1.val != d2.val);
- push(d1);
- }
- void
- and(void)
- {
- Datum d1, d2;
- d2 = pop();
- d1 = pop();
- d1.val = (double)(d1.val != 0.0 && d2.val != 0.0);
- push(d1);
- }
- void
- or(void)
- {
- Datum d1, d2;
- d2 = pop();
- d1 = pop();
- d1.val = (double)(d1.val != 0.0 || d2.val != 0.0);
- push(d1);
- }
- void
- not(void)
- {
- Datum d;
- d = pop();
- d.val = (double)(d.val == 0.0);
- push(d);
- }
- void
- power(void)
- {
- Datum d1, d2;
- d2 = pop();
- d1 = pop();
- d1.val = Pow(d1.val, d2.val);
- push(d1);
- }
- 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;
- int32_t 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 %= (int32_t) 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);
- }
- void
- prstr(void) /* print string value */
- {
- print("%s", (char *) *pc++);
- }
- void
- varread(void) /* read into variable */
- {
- Datum d;
- extern Biobuf *bin;
- Symbol *var = (Symbol *) *pc++;
- int c;
- Again:
- do
- c = Bgetc(bin);
- while(c==' ' || c=='\t' || c=='\n');
- if(c == Beof){
- Iseof:
- if(moreinput())
- goto Again;
- d.val = var->u.val = 0.0;
- goto Return;
- }
- if(strchr("+-.0123456789", c) == 0)
- execerror("non-number read into", var->name);
- Bungetc(bin);
- if(Bgetd(bin, &var->u.val) == Beof)
- goto Iseof;
- else
- d.val = 1.0;
- Return:
- var->type = VAR;
- push(d);
- }
- Inst*
- code(Inst f) /* install one instruction or operand */
- {
- Inst *oprogp = progp;
- if (progp >= &prog[NPROG])
- execerror("program too big", (char *)0);
- *progp++ = f;
- return oprogp;
- }
- void
- execute(Inst* p)
- {
- for (pc = p; *pc != STOP && !returning; )
- (*((++pc)[-1]))();
- }
|