diff options
Diffstat (limited to 'src/cmd/acid/exec.c')
-rw-r--r-- | src/cmd/acid/exec.c | 538 |
1 files changed, 538 insertions, 0 deletions
diff --git a/src/cmd/acid/exec.c b/src/cmd/acid/exec.c new file mode 100644 index 00000000..1d5b231a --- /dev/null +++ b/src/cmd/acid/exec.c @@ -0,0 +1,538 @@ +#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); + } +} + +static char* +regbyoff(ulong addr) +{ + Regdesc *r; + + if(mach == nil) + error("no mach, no registers"); + for(r=mach->reglist; r->name; r++) + if(r->offset == addr) + return r->name; + error("no register at %#lux", addr); + return nil; +} + +int +xget1(Map *m, ulong addr, u8int *a, int n) +{ + if(addr < 0x100) + return lget1(m, correg, locreg(regbyoff(addr)), a, n); + else + return get1(m, addr, a, n); +} + +int +xget2(Map *m, ulong addr, u16int *a) +{ + if(addr < 0x100) + return lget2(m, correg, locreg(regbyoff(addr)), a); + else + return get2(m, addr, a); +} + +int +xget4(Map *m, ulong addr, u32int *a) +{ + if(addr < 0x100) + return lget4(m, correg, locreg(regbyoff(addr)), a); + else + return get4(m, addr, a); +} + +int +xget8(Map *m, ulong addr, u64int *a) +{ + if(addr < 0x100) + return lget8(m, correg, locreg(regbyoff(addr)), a); + else + return get8(m, addr, a); +} + +void +indir(Map *m, ulong 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 = xget1(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 = xget2(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 = xget4(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 = xget8(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 = xget1(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; + for(i = 0; i < sizeof(buf)-2; i += 2) { + ret = xget1(m, addr, (uchar*)&buf[i], 2); + if (ret < 0) + error("indir: %r"); + addr += 2; + if(buf[i] == 0 && buf[i+1] == 0) + break; + } + buf[i++] = 0; + buf[i] = 0; + 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 = xget1(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 = xget1(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 = xget1(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 = xget1(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 = xget1(m, addr, (uchar*)reg, 10); + if (ret < 0) + error("indir: %r"); + beieeeftoa80(buf, sizeof(buf), reg); + convflt(r, buf); + break; + case 'G': + ret = xget1(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 +windir(Map *m, Node *addr, Node *rval, Node *r) +{ + uchar cval; + ushort sval; + Node res, aes; + int ret; + + if(m == 0) + error("no map for */@="); + + expr(rval, &res); + expr(addr, &aes); + + if(aes.type != TINT) + error("bad type lhs of @/*"); + + 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 +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); + } +} |