Blob
1 #include <u.h>2 #include <libc.h>3 #include <bio.h>4 #include "hoc.h"5 #include "y.tab.h"7 #define NSTACK 2569 static Datum stack[NSTACK]; /* the stack */10 static Datum *stackp; /* next free spot on stack */12 #define NPROG 200013 Inst prog[NPROG]; /* the machine */14 Inst *progp; /* next free spot for code generation */15 Inst *pc; /* program counter during execution */16 Inst *progbase = prog; /* start of current subprogram */17 int returning; /* 1 if return stmt seen */18 int indef; /* 1 if parsing a func or proc */20 typedef struct Frame { /* proc/func call stack frame */21 Symbol *sp; /* symbol table entry */22 Inst *retpc; /* where to resume after return */23 Datum *argn; /* n-th argument on stack */24 int nargs; /* number of arguments */25 } Frame;26 #define NFRAME 10027 Frame frame[NFRAME];28 Frame *fp; /* frame pointer */30 void31 initcode(void)32 {33 progp = progbase;34 stackp = stack;35 fp = frame;36 returning = 0;37 indef = 0;38 }40 void41 nop(void)42 {43 }45 void46 push(Datum d)47 {48 if (stackp >= &stack[NSTACK])49 execerror("stack too deep", 0);50 *stackp++ = d;51 }53 Datum54 pop(void)55 {56 if (stackp == stack)57 execerror("stack underflow", 0);58 return *--stackp;59 }61 void62 xpop(void) /* for when no value is wanted */63 {64 if (stackp == stack)65 execerror("stack underflow", (char *)0);66 --stackp;67 }69 void70 constpush(void)71 {72 Datum d;73 d.val = ((Symbol *)*pc++)->u.val;74 push(d);75 }77 void78 varpush(void)79 {80 Datum d;81 d.sym = (Symbol *)(*pc++);82 push(d);83 }85 void86 whilecode(void)87 {88 Datum d;89 Inst *savepc = pc;91 execute(savepc+2); /* condition */92 d = pop();93 while (d.val) {94 execute(*((Inst **)(savepc))); /* body */95 if (returning)96 break;97 execute(savepc+2); /* condition */98 d = pop();99 }100 if (!returning)101 pc = *((Inst **)(savepc+1)); /* next stmt */102 }104 void105 forcode(void)106 {107 Datum d;108 Inst *savepc = pc;110 execute(savepc+4); /* precharge */111 pop();112 execute(*((Inst **)(savepc))); /* condition */113 d = pop();114 while (d.val) {115 execute(*((Inst **)(savepc+2))); /* body */116 if (returning)117 break;118 execute(*((Inst **)(savepc+1))); /* post loop */119 pop();120 execute(*((Inst **)(savepc))); /* condition */121 d = pop();122 }123 if (!returning)124 pc = *((Inst **)(savepc+3)); /* next stmt */125 }127 void128 ifcode(void)129 {130 Datum d;131 Inst *savepc = pc; /* then part */133 execute(savepc+3); /* condition */134 d = pop();135 if (d.val)136 execute(*((Inst **)(savepc)));137 else if (*((Inst **)(savepc+1))) /* else part? */138 execute(*((Inst **)(savepc+1)));139 if (!returning)140 pc = *((Inst **)(savepc+2)); /* next stmt */141 }143 void144 define(Symbol* sp, Formal *f) /* put func/proc in symbol table */145 {146 Fndefn *fd;147 int n;149 fd = emalloc(sizeof(Fndefn));150 fd->code = progbase; /* start of code */151 progbase = progp; /* next code starts here */152 fd->formals = f;153 for(n=0; f; f=f->next)154 n++;155 fd->nargs = n;156 sp->u.defn = fd;157 }159 void160 call(void) /* call a function */161 {162 Formal *f;163 Datum *arg;164 Saveval *s;165 int i;167 Symbol *sp = (Symbol *)pc[0]; /* symbol table entry */168 /* for function */169 if (fp >= &frame[NFRAME])170 execerror(sp->name, "call nested too deeply");171 fp++;172 fp->sp = sp;173 fp->nargs = (int)pc[1];174 fp->retpc = pc + 2;175 fp->argn = stackp - 1; /* last argument */176 if(fp->nargs != sp->u.defn->nargs)177 execerror(sp->name, "called with wrong number of arguments");178 /* bind formals */179 f = sp->u.defn->formals;180 arg = stackp - fp->nargs;181 while(f){182 s = emalloc(sizeof(Saveval));183 s->val = f->sym->u;184 s->type = f->sym->type;185 s->next = f->save;186 f->save = s;187 f->sym->u.val = arg->val;188 f->sym->type = VAR;189 f = f->next;190 arg++;191 }192 for (i = 0; i < fp->nargs; i++)193 pop(); /* pop arguments; no longer needed */194 execute(sp->u.defn->code);195 returning = 0;196 }198 void199 restore(Symbol *sp) /* restore formals associated with symbol */200 {201 Formal *f;202 Saveval *s;204 f = sp->u.defn->formals;205 while(f){206 s = f->save;207 if(s == 0) /* more actuals than formals */208 break;209 f->sym->u = s->val;210 f->sym->type = s->type;211 f->save = s->next;212 free(s);213 f = f->next;214 }215 }217 void218 restoreall(void) /* restore all variables in case of error */219 {220 while(fp>=frame && fp->sp){221 restore(fp->sp);222 --fp;223 }224 fp = frame;225 }227 static void228 ret(void) /* common return from func or proc */229 {230 /* restore formals */231 restore(fp->sp);232 pc = (Inst *)fp->retpc;233 --fp;234 returning = 1;235 }237 void238 funcret(void) /* return from a function */239 {240 Datum d;241 if (fp->sp->type == PROCEDURE)242 execerror(fp->sp->name, "(proc) returns value");243 d = pop(); /* preserve function return value */244 ret();245 push(d);246 }248 void249 procret(void) /* return from a procedure */250 {251 if (fp->sp->type == FUNCTION)252 execerror(fp->sp->name,253 "(func) returns no value");254 ret();255 }257 void258 bltin(void)259 {261 Datum d;262 d = pop();263 d.val = (*(double (*)(double))*pc++)(d.val);264 push(d);265 }267 void268 add(void)269 {270 Datum d1, d2;271 d2 = pop();272 d1 = pop();273 d1.val += d2.val;274 push(d1);275 }277 void278 sub(void)279 {280 Datum d1, d2;281 d2 = pop();282 d1 = pop();283 d1.val -= d2.val;284 push(d1);285 }287 void288 mul(void)289 {290 Datum d1, d2;291 d2 = pop();292 d1 = pop();293 d1.val *= d2.val;294 push(d1);295 }297 void298 div(void)299 {300 Datum d1, d2;301 d2 = pop();302 if (d2.val == 0.0)303 execerror("division by zero", (char *)0);304 d1 = pop();305 d1.val /= d2.val;306 push(d1);307 }309 void310 mod(void)311 {312 Datum d1, d2;313 d2 = pop();314 if (d2.val == 0.0)315 execerror("division by zero", (char *)0);316 d1 = pop();317 /* d1.val %= d2.val; */318 d1.val = fmod(d1.val, d2.val);319 push(d1);320 }322 void323 negate(void)324 {325 Datum d;326 d = pop();327 d.val = -d.val;328 push(d);329 }331 void332 verify(Symbol* s)333 {334 if (s->type != VAR && s->type != UNDEF)335 execerror("attempt to evaluate non-variable", s->name);336 if (s->type == UNDEF)337 execerror("undefined variable", s->name);338 }340 void341 eval(void) /* evaluate variable on stack */342 {343 Datum d;344 d = pop();345 verify(d.sym);346 d.val = d.sym->u.val;347 push(d);348 }350 void351 preinc(void)352 {353 Datum d;354 d.sym = (Symbol *)(*pc++);355 verify(d.sym);356 d.val = d.sym->u.val += 1.0;357 push(d);358 }360 void361 predec(void)362 {363 Datum d;364 d.sym = (Symbol *)(*pc++);365 verify(d.sym);366 d.val = d.sym->u.val -= 1.0;367 push(d);368 }370 void371 postinc(void)372 {373 Datum d;374 double v;375 d.sym = (Symbol *)(*pc++);376 verify(d.sym);377 v = d.sym->u.val;378 d.sym->u.val += 1.0;379 d.val = v;380 push(d);381 }383 void384 postdec(void)385 {386 Datum d;387 double v;388 d.sym = (Symbol *)(*pc++);389 verify(d.sym);390 v = d.sym->u.val;391 d.sym->u.val -= 1.0;392 d.val = v;393 push(d);394 }396 void397 gt(void)398 {399 Datum d1, d2;400 d2 = pop();401 d1 = pop();402 d1.val = (double)(d1.val > d2.val);403 push(d1);404 }406 void407 lt(void)408 {409 Datum d1, d2;410 d2 = pop();411 d1 = pop();412 d1.val = (double)(d1.val < d2.val);413 push(d1);414 }416 void417 ge(void)418 {419 Datum d1, d2;420 d2 = pop();421 d1 = pop();422 d1.val = (double)(d1.val >= d2.val);423 push(d1);424 }426 void427 le(void)428 {429 Datum d1, d2;430 d2 = pop();431 d1 = pop();432 d1.val = (double)(d1.val <= d2.val);433 push(d1);434 }436 void437 eq(void)438 {439 Datum d1, d2;440 d2 = pop();441 d1 = pop();442 d1.val = (double)(d1.val == d2.val);443 push(d1);444 }446 void447 ne(void)448 {449 Datum d1, d2;450 d2 = pop();451 d1 = pop();452 d1.val = (double)(d1.val != d2.val);453 push(d1);454 }456 void457 and(void)458 {459 Datum d1, d2;460 d2 = pop();461 d1 = pop();462 d1.val = (double)(d1.val != 0.0 && d2.val != 0.0);463 push(d1);464 }466 void467 or(void)468 {469 Datum d1, d2;470 d2 = pop();471 d1 = pop();472 d1.val = (double)(d1.val != 0.0 || d2.val != 0.0);473 push(d1);474 }476 void477 not(void)478 {479 Datum d;480 d = pop();481 d.val = (double)(d.val == 0.0);482 push(d);483 }485 void486 power(void)487 {488 Datum d1, d2;489 d2 = pop();490 d1 = pop();491 d1.val = Pow(d1.val, d2.val);492 push(d1);493 }495 void496 assign(void)497 {498 Datum d1, d2;499 d1 = pop();500 d2 = pop();501 if (d1.sym->type != VAR && d1.sym->type != UNDEF)502 execerror("assignment to non-variable",503 d1.sym->name);504 d1.sym->u.val = d2.val;505 d1.sym->type = VAR;506 push(d2);507 }509 void510 addeq(void)511 {512 Datum d1, d2;513 d1 = pop();514 d2 = pop();515 if (d1.sym->type != VAR && d1.sym->type != UNDEF)516 execerror("assignment to non-variable",517 d1.sym->name);518 d2.val = d1.sym->u.val += d2.val;519 d1.sym->type = VAR;520 push(d2);521 }523 void524 subeq(void)525 {526 Datum d1, d2;527 d1 = pop();528 d2 = pop();529 if (d1.sym->type != VAR && d1.sym->type != UNDEF)530 execerror("assignment to non-variable",531 d1.sym->name);532 d2.val = d1.sym->u.val -= d2.val;533 d1.sym->type = VAR;534 push(d2);535 }537 void538 muleq(void)539 {540 Datum d1, d2;541 d1 = pop();542 d2 = pop();543 if (d1.sym->type != VAR && d1.sym->type != UNDEF)544 execerror("assignment to non-variable",545 d1.sym->name);546 d2.val = d1.sym->u.val *= d2.val;547 d1.sym->type = VAR;548 push(d2);549 }551 void552 diveq(void)553 {554 Datum d1, d2;555 d1 = pop();556 d2 = pop();557 if (d1.sym->type != VAR && d1.sym->type != UNDEF)558 execerror("assignment to non-variable",559 d1.sym->name);560 d2.val = d1.sym->u.val /= d2.val;561 d1.sym->type = VAR;562 push(d2);563 }565 void566 ppush(Datum *d)567 {568 push(*d);569 }571 void572 modeq(void)573 {574 Datum d1, d2;575 long x;577 d1 = pop();578 d2 = pop();579 if (d1.sym->type != VAR && d1.sym->type != UNDEF)580 execerror("assignment to non-variable",581 d1.sym->name);582 /* d2.val = d1.sym->u.val %= d2.val; */583 x = d1.sym->u.val;584 x %= (long) d2.val;585 d2.val = x;586 d1.sym->u.val = x;587 d1.sym->type = VAR;589 /* push(d2) generates a compiler error on Linux w. gcc 2.95.4 */590 ppush(&d2);591 }593 void594 printtop(void) /* pop top value from stack, print it */595 {596 Datum d;597 static Symbol *s; /* last value computed */598 if (s == 0)599 s = install("_", VAR, 0.0);600 d = pop();601 print("%.12g\n", d.val);602 s->u.val = d.val;603 }605 void606 prexpr(void) /* print numeric value */607 {608 Datum d;609 d = pop();610 print("%.12g ", d.val);611 }613 void614 prstr(void) /* print string value */615 {616 print("%s", (char *) *pc++);617 }619 void620 varread(void) /* read into variable */621 {622 Datum d;623 extern Biobuf *bin;624 Symbol *var = (Symbol *) *pc++;625 int c;627 Again:628 do629 c = Bgetc(bin);630 while(c==' ' || c=='\t');631 if(c == Beof){632 Iseof:633 if(moreinput())634 goto Again;635 d.val = var->u.val = 0.0;636 goto Return;637 }639 if(strchr("+-.0123456789", c) == 0)640 execerror("non-number read into", var->name);641 Bungetc(bin);642 if(Bgetd(bin, &var->u.val) == Beof)643 goto Iseof;644 else645 d.val = 1.0;646 Return:647 var->type = VAR;648 push(d);649 }651 Inst*652 code(Inst f) /* install one instruction or operand */653 {654 Inst *oprogp = progp;655 if (progp >= &prog[NPROG])656 execerror("program too big", (char *)0);657 *progp++ = f;658 return oprogp;659 }661 void662 execute(Inst* p)663 {664 for (pc = p; *pc != STOP && !returning; )665 (*((++pc)[-1]))();666 }