|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <bio.h> | 
|  | #include <ctype.h> | 
|  | #include <mach.h> | 
|  | #define Extern extern | 
|  | #include "acid.h" | 
|  |  | 
|  | void | 
|  | error(char *fmt, ...) | 
|  | { | 
|  | int i; | 
|  | char buf[2048]; | 
|  | va_list arg; | 
|  |  | 
|  | /* Unstack io channels */ | 
|  | if(iop != 0) { | 
|  | for(i = 1; i < iop; i++) | 
|  | Bterm(io[i]); | 
|  | bout = io[0]; | 
|  | iop = 0; | 
|  | } | 
|  |  | 
|  | ret = 0; | 
|  | gotint = 0; | 
|  | Bflush(bout); | 
|  | if(silent) | 
|  | silent = 0; | 
|  | else { | 
|  | va_start(arg, fmt); | 
|  | vseprint(buf, buf+sizeof(buf), fmt, arg); | 
|  | va_end(arg); | 
|  | fprint(2, "%Z: (error) %s\n", buf); | 
|  | } | 
|  | while(popio()) | 
|  | ; | 
|  | interactive = 1; | 
|  | longjmp(err, 1); | 
|  | } | 
|  |  | 
|  | void | 
|  | unwind(void) | 
|  | { | 
|  | int i; | 
|  | Lsym *s; | 
|  | Value *v; | 
|  |  | 
|  | for(i = 0; i < Hashsize; i++) { | 
|  | for(s = hash[i]; s; s = s->hash) { | 
|  | while(s->v->pop) { | 
|  | v = s->v->pop; | 
|  | free(s->v); | 
|  | s->v = v; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | execute(Node *n) | 
|  | { | 
|  | Value *v; | 
|  | Lsym *sl; | 
|  | Node *l, *r; | 
|  | int i, s, e; | 
|  | Node res, xx; | 
|  | static int stmnt; | 
|  |  | 
|  | gc(); | 
|  | if(gotint) | 
|  | error("interrupted"); | 
|  |  | 
|  | if(n == 0) | 
|  | return; | 
|  |  | 
|  | if(stmnt++ > 5000) { | 
|  | Bflush(bout); | 
|  | stmnt = 0; | 
|  | } | 
|  |  | 
|  | l = n->left; | 
|  | r = n->right; | 
|  |  | 
|  | switch(n->op) { | 
|  | default: | 
|  | expr(n, &res); | 
|  | if(ret || (res.type == TLIST && res.store.u.l == 0)) | 
|  | break; | 
|  | prnt->right = &res; | 
|  | expr(prnt, &xx); | 
|  | break; | 
|  | case OASGN: | 
|  | case OCALL: | 
|  | expr(n, &res); | 
|  | break; | 
|  | case OCOMPLEX: | 
|  | decl(n); | 
|  | break; | 
|  | case OLOCAL: | 
|  | for(n = n->left; n; n = n->left) { | 
|  | if(ret == 0) | 
|  | error("local not in function"); | 
|  | sl = n->sym; | 
|  | if(sl->v->ret == ret) | 
|  | error("%s declared twice", sl->name); | 
|  | v = gmalloc(sizeof(Value)); | 
|  | v->ret = ret; | 
|  | v->pop = sl->v; | 
|  | sl->v = v; | 
|  | v->scope = 0; | 
|  | *(ret->tail) = sl; | 
|  | ret->tail = &v->scope; | 
|  | v->set = 0; | 
|  | } | 
|  | break; | 
|  | case ORET: | 
|  | if(ret == 0) | 
|  | error("return not in function"); | 
|  | expr(n->left, ret->val); | 
|  | longjmp(ret->rlab, 1); | 
|  | case OLIST: | 
|  | execute(n->left); | 
|  | execute(n->right); | 
|  | break; | 
|  | case OIF: | 
|  | expr(l, &res); | 
|  | if(r && r->op == OELSE) { | 
|  | if(bool(&res)) | 
|  | execute(r->left); | 
|  | else | 
|  | execute(r->right); | 
|  | } | 
|  | else if(bool(&res)) | 
|  | execute(r); | 
|  | break; | 
|  | case OWHILE: | 
|  | for(;;) { | 
|  | expr(l, &res); | 
|  | if(!bool(&res)) | 
|  | break; | 
|  | execute(r); | 
|  | } | 
|  | break; | 
|  | case ODO: | 
|  | expr(l->left, &res); | 
|  | if(res.type != TINT) | 
|  | error("loop must have integer start"); | 
|  | s = res.store.u.ival; | 
|  | expr(l->right, &res); | 
|  | if(res.type != TINT) | 
|  | error("loop must have integer end"); | 
|  | e = res.store.u.ival; | 
|  | for(i = s; i <= e; i++) | 
|  | execute(r); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | int | 
|  | bool(Node *n) | 
|  | { | 
|  | int true = 0; | 
|  |  | 
|  | if(n->op != OCONST) | 
|  | fatal("bool: not const"); | 
|  |  | 
|  | switch(n->type) { | 
|  | case TINT: | 
|  | if(n->store.u.ival != 0) | 
|  | true = 1; | 
|  | break; | 
|  | case TFLOAT: | 
|  | if(n->store.u.fval != 0.0) | 
|  | true = 1; | 
|  | break; | 
|  | case TSTRING: | 
|  | if(n->store.u.string->len) | 
|  | true = 1; | 
|  | break; | 
|  | case TLIST: | 
|  | if(n->store.u.l) | 
|  | true = 1; | 
|  | break; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void | 
|  | convflt(Node *r, char *flt) | 
|  | { | 
|  | char c; | 
|  |  | 
|  | c = flt[0]; | 
|  | if(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) { | 
|  | r->type = TSTRING; | 
|  | r->store.fmt = 's'; | 
|  | r->store.u.string = strnode(flt); | 
|  | } | 
|  | else { | 
|  | r->type = TFLOAT; | 
|  | r->store.u.fval = atof(flt); | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | indir(Map *m, u64int addr, char fmt, Node *r) | 
|  | { | 
|  | int i; | 
|  | u32int ival; | 
|  | u64int vval; | 
|  | int ret; | 
|  | u8int cval; | 
|  | u16int sval; | 
|  | char buf[512], reg[12]; | 
|  |  | 
|  | r->op = OCONST; | 
|  | r->store.fmt = fmt; | 
|  | switch(fmt) { | 
|  | default: | 
|  | error("bad pointer format '%c' for *", fmt); | 
|  | case 'c': | 
|  | case 'C': | 
|  | case 'b': | 
|  | r->type = TINT; | 
|  | ret = get1(m, addr, &cval, 1); | 
|  | if (ret < 0) | 
|  | error("indir: %r"); | 
|  | r->store.u.ival = cval; | 
|  | break; | 
|  | case 'x': | 
|  | case 'd': | 
|  | case 'u': | 
|  | case 'o': | 
|  | case 'q': | 
|  | case 'r': | 
|  | r->type = TINT; | 
|  | ret = get2(m, addr, &sval); | 
|  | if (ret < 0) | 
|  | error("indir: %r"); | 
|  | r->store.u.ival = sval; | 
|  | break; | 
|  | case 'a': | 
|  | case 'A': | 
|  | case 'B': | 
|  | case 'X': | 
|  | case 'D': | 
|  | case 'U': | 
|  | case 'O': | 
|  | case 'Q': | 
|  | r->type = TINT; | 
|  | ret = get4(m, addr, &ival); | 
|  | if (ret < 0) | 
|  | error("indir: %r"); | 
|  | r->store.u.ival = ival; | 
|  | break; | 
|  | case 'V': | 
|  | case 'W': | 
|  | case 'Y': | 
|  | case 'Z': | 
|  | r->type = TINT; | 
|  | ret = get8(m, addr, &vval); | 
|  | if (ret < 0) | 
|  | error("indir: %r"); | 
|  | r->store.u.ival = vval; | 
|  | break; | 
|  | case 's': | 
|  | r->type = TSTRING; | 
|  | for(i = 0; i < sizeof(buf)-1; i++) { | 
|  | ret = get1(m, addr, (uchar*)&buf[i], 1); | 
|  | if (ret < 0) | 
|  | error("indir: %r"); | 
|  | addr++; | 
|  | if(buf[i] == '\0') | 
|  | break; | 
|  | } | 
|  | buf[i] = 0; | 
|  | if(i == 0) | 
|  | strcpy(buf, "(null)"); | 
|  | r->store.u.string = strnode(buf); | 
|  | break; | 
|  | case 'R': | 
|  | r->type = TSTRING; | 
|  | assert(sizeof(Rune) == 4); | 
|  | for(i = 0; i < sizeof(buf)-4; i += 4) { | 
|  | ret = get4(m, addr, &ival); | 
|  | if (ret < 0) | 
|  | error("indir: %r"); | 
|  | memmove(buf+i, &ival, 4); | 
|  | addr += 4; | 
|  | if(ival == 0) | 
|  | break; | 
|  | } | 
|  | ival = 0; | 
|  | memmove(buf+i, &ival, 4); | 
|  | r->store.u.string = runenode((Rune*)buf); | 
|  | break; | 
|  | case 'i': | 
|  | case 'I': | 
|  | if ((*mach->das)(m, addr, fmt, buf, sizeof(buf)) < 0) | 
|  | error("indir: %r"); | 
|  | r->type = TSTRING; | 
|  | r->store.fmt = 's'; | 
|  | r->store.u.string = strnode(buf); | 
|  | break; | 
|  | case 'f': | 
|  | ret = get1(m, addr, (uchar*)buf, mach->szfloat); | 
|  | if (ret < 0) | 
|  | error("indir: %r"); | 
|  | mach->ftoa32(buf, sizeof(buf), (void*) buf); | 
|  | convflt(r, buf); | 
|  | break; | 
|  | case 'g': | 
|  | ret = get1(m, addr, (uchar*)buf, mach->szfloat); | 
|  | if (ret < 0) | 
|  | error("indir: %r"); | 
|  | mach->ftoa32(buf, sizeof(buf), (void*) buf); | 
|  | r->type = TSTRING; | 
|  | r->store.u.string = strnode(buf); | 
|  | break; | 
|  | case 'F': | 
|  | ret = get1(m, addr, (uchar*)buf, mach->szdouble); | 
|  | if (ret < 0) | 
|  | error("indir: %r"); | 
|  | mach->ftoa64(buf, sizeof(buf), (void*) buf); | 
|  | convflt(r, buf); | 
|  | break; | 
|  | case '3':	/* little endian ieee 80 with hole in bytes 8&9 */ | 
|  | ret = get1(m, addr, (uchar*)reg, 10); | 
|  | if (ret < 0) | 
|  | error("indir: %r"); | 
|  | memmove(reg+10, reg+8, 2);	/* open hole */ | 
|  | memset(reg+8, 0, 2);		/* fill it */ | 
|  | leieeeftoa80(buf, sizeof(buf), reg); | 
|  | convflt(r, buf); | 
|  | break; | 
|  | case '8':	/* big-endian ieee 80 */ | 
|  | ret = get1(m, addr, (uchar*)reg, 10); | 
|  | if (ret < 0) | 
|  | error("indir: %r"); | 
|  | beieeeftoa80(buf, sizeof(buf), reg); | 
|  | convflt(r, buf); | 
|  | break; | 
|  | case 'G': | 
|  | ret = get1(m, addr, (uchar*)buf, mach->szdouble); | 
|  | if (ret < 0) | 
|  | error("indir: %r"); | 
|  | mach->ftoa64(buf, sizeof(buf), (void*) buf); | 
|  | r->type = TSTRING; | 
|  | r->store.u.string = strnode(buf); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | indirreg(Regs *regs, char *name, char fmt, Node *r) | 
|  | { | 
|  | u64int val; | 
|  |  | 
|  | if(regs == 0) | 
|  | error("no register set for *%s=", name); | 
|  |  | 
|  | r->op = OCONST; | 
|  | r->store.fmt = fmt; | 
|  | switch(fmt){ | 
|  | default: | 
|  | error("bad pointer format '%c' for *%s", fmt, name); | 
|  | case 'c': | 
|  | case 'C': | 
|  | case 'b': | 
|  | case 'x': | 
|  | case 'd': | 
|  | case 'u': | 
|  | case 'o': | 
|  | case 'q': | 
|  | case 'r': | 
|  | case 'a': | 
|  | case 'A': | 
|  | case 'B': | 
|  | case 'X': | 
|  | case 'D': | 
|  | case 'U': | 
|  | case 'O': | 
|  | case 'Q': | 
|  | case 'V': | 
|  | case 'W': | 
|  | case 'Y': | 
|  | case 'Z': | 
|  | if(rget(regs, name, &val) < 0) | 
|  | error("reading %s: %r", name); | 
|  | r->type = TINT; | 
|  | r->store.u.ival = val; | 
|  | break; | 
|  | case 'f': | 
|  | case 'g': | 
|  | case 'F': | 
|  | case '3': | 
|  | case '8': | 
|  | case 'G': | 
|  | error("floating point registers not supported"); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | windir(Map *m, Node aes, Node *rval, Node *r) | 
|  | { | 
|  | uchar cval; | 
|  | ushort sval; | 
|  | Node res; | 
|  | int ret; | 
|  |  | 
|  | if(m == 0) | 
|  | error("no map for */@="); | 
|  |  | 
|  | if(aes.type != TINT) | 
|  | error("bad type lhs of */@="); | 
|  |  | 
|  | expr(rval, &res); | 
|  |  | 
|  | if(m != cormap && wtflag == 0) | 
|  | error("not in write mode"); | 
|  |  | 
|  | r->type = res.type; | 
|  | r->store.fmt = res.store.fmt; | 
|  | r->store = res.store; | 
|  |  | 
|  | switch(res.store.fmt) { | 
|  | default: | 
|  | error("bad pointer format '%c' for */@=", res.store.fmt); | 
|  | case 'c': | 
|  | case 'C': | 
|  | case 'b': | 
|  | cval = res.store.u.ival; | 
|  | ret = put1(m, aes.store.u.ival, &cval, 1); | 
|  | break; | 
|  | case 'r': | 
|  | case 'x': | 
|  | case 'd': | 
|  | case 'u': | 
|  | case 'o': | 
|  | sval = res.store.u.ival; | 
|  | ret = put2(m, aes.store.u.ival, sval); | 
|  | r->store.u.ival = sval; | 
|  | break; | 
|  | case 'a': | 
|  | case 'A': | 
|  | case 'B': | 
|  | case 'X': | 
|  | case 'D': | 
|  | case 'U': | 
|  | case 'O': | 
|  | ret = put4(m, aes.store.u.ival, res.store.u.ival); | 
|  | break; | 
|  | case 'V': | 
|  | case 'W': | 
|  | case 'Y': | 
|  | case 'Z': | 
|  | ret = put8(m, aes.store.u.ival, res.store.u.ival); | 
|  | break; | 
|  | case 's': | 
|  | case 'R': | 
|  | ret = put1(m, aes.store.u.ival, (uchar*)res.store.u.string->string, res.store.u.string->len); | 
|  | break; | 
|  | } | 
|  | if (ret < 0) | 
|  | error("windir: %r"); | 
|  | } | 
|  |  | 
|  | void | 
|  | windirreg(Regs *regs, char *name, Node *rval, Node *r) | 
|  | { | 
|  | Node res; | 
|  |  | 
|  | if(regs == 0) | 
|  | error("no register set for *%s=", name); | 
|  |  | 
|  | expr(rval, &res); | 
|  |  | 
|  | r->type = res.type; | 
|  | r->store.fmt = res.store.fmt; | 
|  | r->store = res.store; | 
|  |  | 
|  | switch(res.store.fmt){ | 
|  | default: | 
|  | error("bad format '%c' for *%s=", res.store.fmt, name); | 
|  | case 'c': | 
|  | case 'C': | 
|  | case 'b': | 
|  | case 'x': | 
|  | case 'd': | 
|  | case 'u': | 
|  | case 'o': | 
|  | case 'q': | 
|  | case 'r': | 
|  | case 'a': | 
|  | case 'A': | 
|  | case 'B': | 
|  | case 'X': | 
|  | case 'D': | 
|  | case 'U': | 
|  | case 'O': | 
|  | case 'Q': | 
|  | case 'V': | 
|  | case 'W': | 
|  | case 'Y': | 
|  | case 'Z': | 
|  | if(rput(regs, name, res.store.u.ival) < 0) | 
|  | error("writing %s: %r", name); | 
|  | break; | 
|  | case 'f': | 
|  | case 'g': | 
|  | case 'F': | 
|  | case '3': | 
|  | case '8': | 
|  | case 'G': | 
|  | error("floating point registers not supported"); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | call(char *fn, Node *parameters, Node *local, Node *body, Node *retexp) | 
|  | { | 
|  | int np, i; | 
|  | Rplace rlab; | 
|  | Node *n, res; | 
|  | Value *v, *f; | 
|  | Lsym *s, *next; | 
|  | Node *avp[Maxarg], *ava[Maxarg]; | 
|  |  | 
|  | rlab.local = 0; | 
|  |  | 
|  | na = 0; | 
|  | flatten(avp, parameters); | 
|  | np = na; | 
|  | na = 0; | 
|  | flatten(ava, local); | 
|  | if(np != na) { | 
|  | if(np < na) | 
|  | error("%s: too few arguments", fn); | 
|  | error("%s: too many arguments", fn); | 
|  | } | 
|  |  | 
|  | rlab.tail = &rlab.local; | 
|  |  | 
|  | ret = &rlab; | 
|  | for(i = 0; i < np; i++) { | 
|  | n = ava[i]; | 
|  | switch(n->op) { | 
|  | default: | 
|  | error("%s: %d formal not a name", fn, i); | 
|  | case ONAME: | 
|  | expr(avp[i], &res); | 
|  | s = n->sym; | 
|  | break; | 
|  | case OINDM: | 
|  | res.store.u.cc = avp[i]; | 
|  | res.type = TCODE; | 
|  | res.store.comt = 0; | 
|  | if(n->left->op != ONAME) | 
|  | error("%s: %d formal not a name", fn, i); | 
|  | s = n->left->sym; | 
|  | break; | 
|  | } | 
|  | if(s->v->ret == ret) | 
|  | error("%s already declared at this scope", s->name); | 
|  |  | 
|  | v = gmalloc(sizeof(Value)); | 
|  | v->ret = ret; | 
|  | v->pop = s->v; | 
|  | s->v = v; | 
|  | v->scope = 0; | 
|  | *(rlab.tail) = s; | 
|  | rlab.tail = &v->scope; | 
|  |  | 
|  | v->store = res.store; | 
|  | v->type = res.type; | 
|  | v->set = 1; | 
|  | } | 
|  |  | 
|  | ret->val = retexp; | 
|  | if(setjmp(rlab.rlab) == 0) | 
|  | execute(body); | 
|  |  | 
|  | for(s = rlab.local; s; s = next) { | 
|  | f = s->v; | 
|  | next = f->scope; | 
|  | s->v = f->pop; | 
|  | free(f); | 
|  | } | 
|  | } |