diff options
Diffstat (limited to 'src/cmd/acid/expr.c')
-rw-r--r-- | src/cmd/acid/expr.c | 1018 |
1 files changed, 1018 insertions, 0 deletions
diff --git a/src/cmd/acid/expr.c b/src/cmd/acid/expr.c new file mode 100644 index 00000000..46e522bf --- /dev/null +++ b/src/cmd/acid/expr.c @@ -0,0 +1,1018 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <ctype.h> +#include <mach.h> +#define Extern extern +#include "acid.h" + +static int fsize[] = +{ + ['A'] 4, + ['B'] 4, + ['C'] 1, + ['D'] 4, + ['F'] 8, + ['G'] 8, + ['O'] 4, + ['Q'] 4, + ['R'] 4, + ['S'] 4, + ['U'] 4, + ['V'] 8, + ['X'] 4, + ['Y'] 8, + ['W'] 8, + ['Z'] 8, + ['a'] 4, + ['b'] 1, + ['c'] 1, + ['d'] 2, + ['f'] 4, + ['g'] 4, + ['o'] 2, + ['q'] 2, + ['r'] 2, + ['s'] 4, + ['u'] 2, + ['x'] 2, +}; + +int +fmtsize(Value *v) +{ + int ret; + + switch(v->store.fmt) { + default: + return fsize[(unsigned char)v->store.fmt]; + case 'i': + case 'I': + if(v->type != TINT || mach == 0) + error("no size for i fmt pointer ++/--"); + ret = (*mach->instsize)(symmap, v->store.u.ival); + if(ret < 0) { + ret = (*mach->instsize)(symmap, v->store.u.ival); + if(ret < 0) + error("%r"); + } + return ret; + } +} + +void +chklval(Node *lp) +{ + if(lp->op != ONAME) + error("need l-value"); +} + +void +olist(Node *n, Node *res) +{ + expr(n->left, res); + expr(n->right, res); +} + +void +oeval(Node *n, Node *res) +{ + expr(n->left, res); + if(res->type != TCODE) + error("bad type for eval"); + expr(res->store.u.cc, res); +} + +void +ocast(Node *n, Node *res) +{ + if(n->sym->lt == 0) + error("%s is not a complex type", n->sym->name); + + expr(n->left, res); + res->store.comt = n->sym->lt; + res->store.fmt = 'a'; +} + +void +oindm(Node *n, Node *res) +{ + Map *m; + Node l; + + m = cormap; + if(m == 0) + m = symmap; + expr(n->left, &l); + if(l.type != TINT) + error("bad type for *"); + if(m == 0) + error("no map for *"); + indir(m, l.store.u.ival, l.store.fmt, res); + res->store.comt = l.store.comt; +} + +void +oindc(Node *n, Node *res) +{ + Map *m; + Node l; + + m = symmap; + if(m == 0) + m = cormap; + expr(n->left, &l); + if(l.type != TINT) + error("bad type for @"); + if(m == 0) + error("no map for @"); + indir(m, l.store.u.ival, l.store.fmt, res); + res->store.comt = l.store.comt; +} + +void +oframe(Node *n, Node *res) +{ + char *p; + Node *lp; + ulong ival; + Frtype *f; + + p = n->sym->name; + while(*p && *p == '$') + p++; + lp = n->left; + if(localaddr(cormap, correg, p, lp->sym->name, &ival) < 0) + error("colon: %r"); + + res->store.u.ival = ival; + res->op = OCONST; + res->store.fmt = 'X'; + res->type = TINT; + + /* Try and set comt */ + for(f = n->sym->local; f; f = f->next) { + if(f->var == lp->sym) { + res->store.comt = f->type; + res->store.fmt = 'a'; + break; + } + } +} + +void +oindex(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + + if(r.type != TINT) + error("bad type for []"); + + switch(l.type) { + default: + error("lhs[] has bad type"); + case TINT: + indir(cormap, l.store.u.ival+(r.store.u.ival*fsize[(unsigned char)l.store.fmt]), l.store.fmt, res); + res->store.comt = l.store.comt; + res->store.fmt = l.store.fmt; + break; + case TLIST: + nthelem(l.store.u.l, r.store.u.ival, res); + break; + case TSTRING: + res->store.u.ival = 0; + if(r.store.u.ival >= 0 && r.store.u.ival < l.store.u.string->len) { + int xx8; /* to get around bug in vc */ + xx8 = r.store.u.ival; + res->store.u.ival = l.store.u.string->string[xx8]; + } + res->op = OCONST; + res->type = TINT; + res->store.fmt = 'c'; + break; + } +} + +void +oappend(Node *n, Node *res) +{ + Node r, l; + + expr(n->left, &l); + expr(n->right, &r); + if(l.type != TLIST) + error("must append to list"); + append(res, &l, &r); +} + +void +odelete(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + if(l.type != TLIST) + error("must delete from list"); + if(r.type != TINT) + error("delete index must be integer"); + + delete(l.store.u.l, r.store.u.ival, res); +} + +void +ohead(Node *n, Node *res) +{ + Node l; + + expr(n->left, &l); + if(l.type != TLIST) + error("head needs list"); + res->op = OCONST; + if(l.store.u.l) { + res->type = l.store.u.l->type; + res->store = l.store.u.l->store; + } + else { + res->type = TLIST; + res->store.u.l = 0; + } +} + +void +otail(Node *n, Node *res) +{ + Node l; + + expr(n->left, &l); + if(l.type != TLIST) + error("tail needs list"); + res->op = OCONST; + res->type = TLIST; + if(l.store.u.l) + res->store.u.l = l.store.u.l->next; + else + res->store.u.l = 0; +} + +void +oconst(Node *n, Node *res) +{ + res->op = OCONST; + res->type = n->type; + res->store = n->store; + res->store.comt = n->store.comt; +} + +void +oname(Node *n, Node *res) +{ + Value *v; + + v = n->sym->v; + if(v->set == 0) + error("%s used but not set", n->sym->name); + res->op = OCONST; + res->type = v->type; + res->store = v->store; + res->store.comt = v->store.comt; +} + +void +octruct(Node *n, Node *res) +{ + res->op = OCONST; + res->type = TLIST; + res->store.u.l = construct(n->left); +} + +void +oasgn(Node *n, Node *res) +{ + Node *lp, r; + Value *v; + + lp = n->left; + switch(lp->op) { + case OINDM: + windir(cormap, lp->left, n->right, res); + break; + case OINDC: + windir(symmap, lp->left, n->right, res); + break; + default: + chklval(lp); + v = lp->sym->v; + expr(n->right, &r); + v->set = 1; + v->type = r.type; + v->store = r.store; + res->op = OCONST; + res->type = v->type; + res->store = v->store; + res->store.comt = v->store.comt; + } +} + +void +oadd(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = l.store.fmt; + res->op = OCONST; + res->type = TFLOAT; + switch(l.type) { + default: + error("bad lhs type +"); + case TINT: + switch(r.type) { + case TINT: + res->type = TINT; + res->store.u.ival = l.store.u.ival+r.store.u.ival; + break; + case TFLOAT: + res->store.u.fval = l.store.u.ival+r.store.u.fval; + break; + default: + error("bad rhs type +"); + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->store.u.fval = l.store.u.fval+r.store.u.ival; + break; + case TFLOAT: + res->store.u.fval = l.store.u.fval+r.store.u.fval; + break; + default: + error("bad rhs type +"); + } + break; + case TSTRING: + if(r.type == TSTRING) { + res->type = TSTRING; + res->store.fmt = 's'; + res->store.u.string = stradd(l.store.u.string, r.store.u.string); + break; + } + error("bad rhs for +"); + case TLIST: + res->type = TLIST; + switch(r.type) { + case TLIST: + res->store.u.l = addlist(l.store.u.l, r.store.u.l); + break; + default: + r.left = 0; + r.right = 0; + res->store.u.l = addlist(l.store.u.l, construct(&r)); + break; + } + } +} + +void +osub(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = l.store.fmt; + res->op = OCONST; + res->type = TFLOAT; + switch(l.type) { + default: + error("bad lhs type -"); + case TINT: + switch(r.type) { + case TINT: + res->type = TINT; + res->store.u.ival = l.store.u.ival-r.store.u.ival; + break; + case TFLOAT: + res->store.u.fval = l.store.u.ival-r.store.u.fval; + break; + default: + error("bad rhs type -"); + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->store.u.fval = l.store.u.fval-r.store.u.ival; + break; + case TFLOAT: + res->store.u.fval = l.store.u.fval-r.store.u.fval; + break; + default: + error("bad rhs type -"); + } + break; + } +} + +void +omul(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = l.store.fmt; + res->op = OCONST; + res->type = TFLOAT; + switch(l.type) { + default: + error("bad lhs type *"); + case TINT: + switch(r.type) { + case TINT: + res->type = TINT; + res->store.u.ival = l.store.u.ival*r.store.u.ival; + break; + case TFLOAT: + res->store.u.fval = l.store.u.ival*r.store.u.fval; + break; + default: + error("bad rhs type *"); + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->store.u.fval = l.store.u.fval*r.store.u.ival; + break; + case TFLOAT: + res->store.u.fval = l.store.u.fval*r.store.u.fval; + break; + default: + error("bad rhs type *"); + } + break; + } +} + +void +odiv(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = l.store.fmt; + res->op = OCONST; + res->type = TFLOAT; + switch(l.type) { + default: + error("bad lhs type /"); + case TINT: + switch(r.type) { + case TINT: + res->type = TINT; + if(r.store.u.ival == 0) + error("zero divide"); + res->store.u.ival = l.store.u.ival/r.store.u.ival; + break; + case TFLOAT: + if(r.store.u.fval == 0) + error("zero divide"); + res->store.u.fval = l.store.u.ival/r.store.u.fval; + break; + default: + error("bad rhs type /"); + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->store.u.fval = l.store.u.fval/r.store.u.ival; + break; + case TFLOAT: + res->store.u.fval = l.store.u.fval/r.store.u.fval; + break; + default: + error("bad rhs type /"); + } + break; + } +} + +void +omod(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = l.store.fmt; + res->op = OCONST; + res->type = TINT; + if(l.type != TINT || r.type != TINT) + error("bad expr type %"); + res->store.u.ival = l.store.u.ival%r.store.u.ival; +} + +void +olsh(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = l.store.fmt; + res->op = OCONST; + res->type = TINT; + if(l.type != TINT || r.type != TINT) + error("bad expr type <<"); + res->store.u.ival = l.store.u.ival<<r.store.u.ival; +} + +void +orsh(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = l.store.fmt; + res->op = OCONST; + res->type = TINT; + if(l.type != TINT || r.type != TINT) + error("bad expr type >>"); + res->store.u.ival = (unsigned)l.store.u.ival>>r.store.u.ival; +} + +void +olt(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + + res->store.fmt = l.store.fmt; + res->op = OCONST; + res->type = TINT; + switch(l.type) { + default: + error("bad lhs type <"); + case TINT: + switch(r.type) { + case TINT: + res->store.u.ival = l.store.u.ival < r.store.u.ival; + break; + case TFLOAT: + res->store.u.ival = l.store.u.ival < r.store.u.fval; + break; + default: + error("bad rhs type <"); + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->store.u.ival = l.store.u.fval < r.store.u.ival; + break; + case TFLOAT: + res->store.u.ival = l.store.u.fval < r.store.u.fval; + break; + default: + error("bad rhs type <"); + } + break; + } +} + +void +ogt(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = 'D'; + res->op = OCONST; + res->type = TINT; + switch(l.type) { + default: + error("bad lhs type >"); + case TINT: + switch(r.type) { + case TINT: + res->store.u.ival = l.store.u.ival > r.store.u.ival; + break; + case TFLOAT: + res->store.u.ival = l.store.u.ival > r.store.u.fval; + break; + default: + error("bad rhs type >"); + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->store.u.ival = l.store.u.fval > r.store.u.ival; + break; + case TFLOAT: + res->store.u.ival = l.store.u.fval > r.store.u.fval; + break; + default: + error("bad rhs type >"); + } + break; + } +} + +void +oleq(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = 'D'; + res->op = OCONST; + res->type = TINT; + switch(l.type) { + default: + error("bad expr type <="); + case TINT: + switch(r.type) { + case TINT: + res->store.u.ival = l.store.u.ival <= r.store.u.ival; + break; + case TFLOAT: + res->store.u.ival = l.store.u.ival <= r.store.u.fval; + break; + default: + error("bad expr type <="); + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->store.u.ival = l.store.u.fval <= r.store.u.ival; + break; + case TFLOAT: + res->store.u.ival = l.store.u.fval <= r.store.u.fval; + break; + default: + error("bad expr type <="); + } + break; + } +} + +void +ogeq(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = 'D'; + res->op = OCONST; + res->type = TINT; + switch(l.type) { + default: + error("bad lhs type >="); + case TINT: + switch(r.type) { + case TINT: + res->store.u.ival = l.store.u.ival >= r.store.u.ival; + break; + case TFLOAT: + res->store.u.ival = l.store.u.ival >= r.store.u.fval; + break; + default: + error("bad rhs type >="); + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->store.u.ival = l.store.u.fval >= r.store.u.ival; + break; + case TFLOAT: + res->store.u.ival = l.store.u.fval >= r.store.u.fval; + break; + default: + error("bad rhs type >="); + } + break; + } +} + +void +oeq(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = 'D'; + res->op = OCONST; + res->type = TINT; + res->store.u.ival = 0; + switch(l.type) { + default: + break; + case TINT: + switch(r.type) { + case TINT: + res->store.u.ival = l.store.u.ival == r.store.u.ival; + break; + case TFLOAT: + res->store.u.ival = l.store.u.ival == r.store.u.fval; + break; + default: + break; + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->store.u.ival = l.store.u.fval == r.store.u.ival; + break; + case TFLOAT: + res->store.u.ival = l.store.u.fval == r.store.u.fval; + break; + default: + break; + } + break; + case TSTRING: + if(r.type == TSTRING) { + res->store.u.ival = scmp(r.store.u.string, l.store.u.string); + break; + } + break; + case TLIST: + if(r.type == TLIST) { + res->store.u.ival = listcmp(l.store.u.l, r.store.u.l); + break; + } + break; + } + if(n->op == ONEQ) + res->store.u.ival = !res->store.u.ival; +} + + +void +oland(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = l.store.fmt; + res->op = OCONST; + res->type = TINT; + if(l.type != TINT || r.type != TINT) + error("bad expr type &"); + res->store.u.ival = l.store.u.ival&r.store.u.ival; +} + +void +oxor(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = l.store.fmt; + res->op = OCONST; + res->type = TINT; + if(l.type != TINT || r.type != TINT) + error("bad expr type ^"); + res->store.u.ival = l.store.u.ival^r.store.u.ival; +} + +void +olor(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = l.store.fmt; + res->op = OCONST; + res->type = TINT; + if(l.type != TINT || r.type != TINT) + error("bad expr type |"); + res->store.u.ival = l.store.u.ival|r.store.u.ival; +} + +void +ocand(Node *n, Node *res) +{ + Node l, r; + + res->store.fmt = l.store.fmt; + res->op = OCONST; + res->type = TINT; + res->store.u.ival = 0; + expr(n->left, &l); + if(bool(&l) == 0) + return; + expr(n->right, &r); + if(bool(&r) == 0) + return; + res->store.u.ival = 1; +} + +void +onot(Node *n, Node *res) +{ + Node l; + + res->op = OCONST; + res->type = TINT; + res->store.u.ival = 0; + expr(n->left, &l); + if(bool(&l) == 0) + res->store.u.ival = 1; +} + +void +ocor(Node *n, Node *res) +{ + Node l, r; + + res->op = OCONST; + res->type = TINT; + res->store.u.ival = 0; + expr(n->left, &l); + if(bool(&l)) { + res->store.u.ival = 1; + return; + } + expr(n->right, &r); + if(bool(&r)) { + res->store.u.ival = 1; + return; + } +} + +void +oeinc(Node *n, Node *res) +{ + Value *v; + + chklval(n->left); + v = n->left->sym->v; + res->op = OCONST; + res->type = v->type; + switch(v->type) { + case TINT: + if(n->op == OEDEC) + v->store.u.ival -= fmtsize(v); + else + v->store.u.ival += fmtsize(v); + break; + case TFLOAT: + if(n->op == OEDEC) + v->store.u.fval--; + else + v->store.u.fval++; + break; + default: + error("bad type for pre --/++"); + } + res->store = v->store; +} + +void +opinc(Node *n, Node *res) +{ + Value *v; + + chklval(n->left); + v = n->left->sym->v; + res->op = OCONST; + res->type = v->type; + res->store = v->store; + switch(v->type) { + case TINT: + if(n->op == OPDEC) + v->store.u.ival -= fmtsize(v); + else + v->store.u.ival += fmtsize(v); + break; + case TFLOAT: + if(n->op == OPDEC) + v->store.u.fval--; + else + v->store.u.fval++; + break; + default: + error("bad type for post --/++"); + } +} + +void +ocall(Node *n, Node *res) +{ + Lsym *s; + Rplace *rsav; + + res->op = OCONST; /* Default return value */ + res->type = TLIST; + res->store.u.l = 0; + + chklval(n->left); + s = n->left->sym; + + if(n->builtin && !s->builtin){ + error("no builtin %s", s->name); + return; + } + if(s->builtin && (n->builtin || s->proc == 0)) { + (*s->builtin)(res, n->right); + return; + } + if(s->proc == 0) + error("no function %s", s->name); + + rsav = ret; + call(s->name, n->right, s->proc->left, s->proc->right, res); + ret = rsav; +} + +void +ofmt(Node *n, Node *res) +{ + expr(n->left, res); + res->store.fmt = n->right->store.u.ival; +} + +void +owhat(Node *n, Node *res) +{ + res->op = OCONST; /* Default return value */ + res->type = TLIST; + res->store.u.l = 0; + whatis(n->sym); +} + +void (*expop[])(Node*, Node*) = +{ + [ONAME] oname, + [OCONST] oconst, + [OMUL] omul, + [ODIV] odiv, + [OMOD] omod, + [OADD] oadd, + [OSUB] osub, + [ORSH] orsh, + [OLSH] olsh, + [OLT] olt, + [OGT] ogt, + [OLEQ] oleq, + [OGEQ] ogeq, + [OEQ] oeq, + [ONEQ] oeq, + [OLAND] oland, + [OXOR] oxor, + [OLOR] olor, + [OCAND] ocand, + [OCOR] ocor, + [OASGN] oasgn, + [OINDM] oindm, + [OEDEC] oeinc, + [OEINC] oeinc, + [OPINC] opinc, + [OPDEC] opinc, + [ONOT] onot, + [OIF] 0, + [ODO] 0, + [OLIST] olist, + [OCALL] ocall, + [OCTRUCT] octruct, + [OWHILE] 0, + [OELSE] 0, + [OHEAD] ohead, + [OTAIL] otail, + [OAPPEND] oappend, + [ORET] 0, + [OINDEX] oindex, + [OINDC] oindc, + [ODOT] odot, + [OLOCAL] 0, + [OFRAME] oframe, + [OCOMPLEX] 0, + [ODELETE] odelete, + [OCAST] ocast, + [OFMT] ofmt, + [OEVAL] oeval, + [OWHAT] owhat, +}; |