| #include <u.h> |
| #include <libc.h> |
| #include <bio.h> |
| #include <ctype.h> |
| #include <mach.h> |
| #define Extern extern |
| #include "acid.h" |
| |
| static int fsize[256]; |
| |
| static void |
| initfsize(void) |
| { |
| fsize['A'] = 4; |
| fsize['B'] = 4; |
| fsize['C'] = 1; |
| fsize['D'] = 4; |
| fsize['F'] = 8; |
| fsize['G'] = 8; |
| fsize['O'] = 4; |
| fsize['Q'] = 4; |
| fsize['R'] = 4; |
| fsize['S'] = 4; |
| fsize['U'] = 4; |
| fsize['V'] = 8; |
| fsize['X'] = 4; |
| fsize['Y'] = 8; |
| fsize['W'] = 8; |
| fsize['Z'] = 8; |
| fsize['a'] = 4; |
| fsize['b'] = 1; |
| fsize['c'] = 1; |
| fsize['d'] = 2; |
| fsize['f'] = 4; |
| fsize['g'] = 4; |
| fsize['o'] = 2; |
| fsize['q'] = 2; |
| fsize['r'] = 2; |
| fsize['s'] = 4; |
| fsize['u'] = 2; |
| fsize['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; |
| } |
| } |
| |
| Lsym* |
| chklval(Node *lp) |
| { |
| Node res; |
| Lsym *s; |
| |
| if(lp->op == ONAME) |
| return lp->sym; |
| |
| if(lp->op == OCALL){ |
| s = chklval(lp->left); |
| if(strcmp(s->name, "var") == 0 |
| && (lp->builtin || s->proc == 0)){ |
| if(lp->right == 0) |
| error("var(string): arg count"); |
| expr(lp->right, &res); |
| if(res.type != TSTRING) |
| error("var(string): arg type"); |
| return mkvar(res.store.u.string->string); |
| } |
| } |
| error("need l-value"); |
| return nil; |
| } |
| |
| 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); |
| switch(l.type){ |
| default: |
| error("bad type for *"); |
| case TINT: |
| if(m == 0) |
| error("no map for *"); |
| indir(m, l.store.u.ival, l.store.fmt, res); |
| res->store.comt = l.store.comt; |
| break; |
| case TREG: |
| indirreg(correg, l.store.u.reg.name, l.store.fmt, res); |
| res->store.comt = l.store.comt; |
| break; |
| case TCON: |
| *res = *l.store.u.con; |
| res->store.comt = l.store.comt; |
| break; |
| } |
| } |
| |
| 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; |
| u64int ival; |
| Frtype *f; |
| |
| p = n->sym->name; |
| while(*p && *p == '$') |
| p++; |
| lp = n->left; |
| if(localaddr(cormap, acidregs, 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; |
| Node aes; |
| Value *v; |
| |
| lp = n->left; |
| switch(lp->op) { |
| case OINDM: |
| expr(lp->left, &aes); |
| if(aes.type == TREG) |
| windirreg(correg, aes.store.u.reg.name, n->right, res); |
| else |
| windir(cormap, aes, n->right, res); |
| break; |
| case OINDC: |
| expr(lp->left, &aes); |
| windir(symmap, aes, n->right, res); |
| break; |
| default: |
| v = chklval(lp)->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 = 'D'; |
| res->op = OCONST; |
| res->type = TINT; |
| res->store.u.ival = 0; |
| expr(n->left, &l); |
| res->store.fmt = l.store.fmt; |
| 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; |
| |
| v = chklval(n->left)->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; |
| |
| v = chklval(n->left)->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; |
| |
| s = chklval(n->left); |
| 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 |
| ouplus(Node *n, Node *res) |
| { |
| expr(n->left, res); |
| } |
| |
| 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[NUMO])(Node*, Node*); |
| |
| static void |
| initexpop(void) |
| { |
| expop[ONAME] = oname; |
| expop[OCONST] = oconst; |
| expop[OMUL] = omul; |
| expop[ODIV] = odiv; |
| expop[OMOD] = omod; |
| expop[OADD] = oadd; |
| expop[OSUB] = osub; |
| expop[ORSH] = orsh; |
| expop[OLSH] = olsh; |
| expop[OLT] = olt; |
| expop[OGT] = ogt; |
| expop[OLEQ] = oleq; |
| expop[OGEQ] = ogeq; |
| expop[OEQ] = oeq; |
| expop[ONEQ] = oeq; |
| expop[OLAND] = oland; |
| expop[OXOR] = oxor; |
| expop[OLOR] = olor; |
| expop[OCAND] = ocand; |
| expop[OCOR] = ocor; |
| expop[OASGN] = oasgn; |
| expop[OINDM] = oindm; |
| expop[OEDEC] = oeinc; |
| expop[OEINC] = oeinc; |
| expop[OPINC] = opinc; |
| expop[OPDEC] = opinc; |
| expop[ONOT] = onot; |
| expop[OIF] = 0; |
| expop[ODO] = 0; |
| expop[OLIST] = olist; |
| expop[OCALL] = ocall; |
| expop[OCTRUCT] = octruct; |
| expop[OWHILE] =0; |
| expop[OELSE] = 0; |
| expop[OHEAD] = ohead; |
| expop[OTAIL] = otail; |
| expop[OAPPEND] = oappend; |
| expop[ORET] = 0; |
| expop[OINDEX] =oindex; |
| expop[OINDC] = oindc; |
| expop[ODOT] = odot; |
| expop[OLOCAL] =0; |
| expop[OFRAME] = oframe; |
| expop[OCOMPLEX] =0; |
| expop[ODELETE] = odelete; |
| expop[OCAST] = ocast; |
| expop[OFMT] = ofmt; |
| expop[OEVAL] = oeval; |
| expop[OWHAT] = owhat; |
| expop[OUPLUS] = ouplus; |
| } |
| |
| void |
| initexpr(void) |
| { |
| initfsize(); |
| initexpop(); |
| } |
| |
| int |
| acidregsrw(Regs *r, char *name, u64int *u, int isr) |
| { |
| Lsym *l; |
| Value *v; |
| Node *n; |
| u64int addr; |
| |
| if(!isr){ |
| werrstr("cannot write registers"); |
| return -1; |
| } |
| USED(r); |
| l = look(name); |
| if(l == nil){ |
| werrstr("register %s not found", name); |
| return -1; |
| } |
| v = l->v; |
| switch(v->type){ |
| default: |
| werrstr("*%s: bad type", name); |
| return -1; |
| case TREG: |
| if(correg == nil){ |
| werrstr("*%s: register %s not mapped", name, v->store.u.reg); |
| return -1; |
| } |
| return rget(correg, v->store.u.reg.name, u); |
| case TCON: |
| n = v->store.u.con; |
| if(n->op != OCONST || n->type != TINT){ |
| werrstr("*%s: bad register constant", name); |
| return -1; |
| } |
| *u = n->store.u.ival; |
| return 0; |
| case TINT: |
| if(cormap == nil){ |
| werrstr("*%s: core not mapped", name); |
| return -1; |
| } |
| addr = v->store.u.ival; |
| /* XXX should use format to determine size */ |
| if(geta(cormap, addr, u) < 0) |
| return -1; |
| return 0; |
| } |
| } |