#include #include #include #include #include "paper.h" #include "impl.h" Lsym *curfn; void chklval(Node *lp) { if(lp->op != ONAME){ pexpr(lp); pperror("not a name"); } } static void oinvalid(Node *n, Node *res) { USED(n); USED(res); pperror("tried to evaluate nil node"); } void olist(Node *n, Node *res) { ppexpr(n->left, res); ppexpr(n->right, res); } void oeval(Node *n, Node *res) { ppexpr(n->left, res); if(res->store.type != TCODE) pperror("bad type for eval"); ppexpr(res->store.cc, res); } void oindm(Node *n, Node *res) { pperror("* unimplemented"); /* Map *m; Node l; m = cormap; if(m == 0) m = symmap; ppexpr(n->left, &l); if(l.store.type != TINT) pperror("bad type for *"); if(m == 0) pperror("no map for *"); indir(m, l.store.ival, l.store.fmt, res); res->store.comt = l.store.comt; */ } void oindc(Node *n, Node *res) { pperror("@ unimplemented"); /* Map *m; Node l; m = symmap; if(m == 0) m = cormap; ppexpr(n->left, &l); if(l.store.type != TINT) pperror("bad type for @"); if(m == 0) pperror("no map for @"); indir(m, l.store.ival, l.store.fmt, res); res->store.comt = l.store.comt; */ } void oframe(Node *n, Node *res) { pperror("unimplemented"); } void oindex(Node *n, Node *res) { Node l, r; ppexpr(n->left, &l); ppexpr(n->right, &r); if(r.store.type != TINT) pperror("bad type for []"); switch(l.store.type) { default: pperror("lhs[] has bad type"); case TLIST: nthelem(l.store.l, r.store.ival, res); break; case TSTRING: res->store.ival = 0; if(r.store.ival >= 0 && r.store.ival < l.store.string->len) { int xx8; /* to get around bug in vc */ xx8 = r.store.ival; res->store.ival = l.store.string->string[xx8]; } res->op = OCONST; res->store.type = TINT; break; } } void oappend(Node *n, Node *res) { Value *v; Node r, l; int empty; ppexpr(n->left, &l); ppexpr(n->right, &r); if(l.store.type != TLIST) pperror("must append to list"); empty = (l.store.l == nil && (n->left->op == ONAME)); append(res, &l, &r); if(empty) { v = n->left->sym->v; v->store.type = res->store.type; v->store = res->store; } } void odelete(Node *n, Node *res) { Node l, r; ppexpr(n->left, &l); ppexpr(n->right, &r); if(l.store.type != TLIST) pperror("must delete from list"); if(r.store.type != TINT) pperror("delete index must be integer"); delete(l.store.l, r.store.ival, res); } void ohead(Node *n, Node *res) { Node l; ppexpr(n->left, &l); if(l.store.type != TLIST) pperror("head needs list"); res->op = OCONST; if(l.store.l) { res->store.type = l.store.l->store.type; res->store = l.store.l->store; } else { res->store.type = TLIST; res->store.l = 0; } } void otail(Node *n, Node *res) { Node l; ppexpr(n->left, &l); if(l.store.type != TLIST) pperror("tail needs list"); res->op = OCONST; res->store.type = TLIST; if(l.store.l) res->store.l = l.store.l->next; else res->store.l = 0; } void oconst(Node *n, Node *res) { res->op = OCONST; res->store.type = n->store.type; res->store = n->store; } void oname(Node *n, Node *res) { Value *v; v = n->sym->v; if(v->set == 0) pperror("%s used but not set", n->sym->name); res->op = OCONST; res->store.type = v->store.type; res->store = v->store; } void octruct(Node *n, Node *res) { res->op = OCONST; res->store.type = TLIST; res->store.l = construct(n->left); } void oasgn(Node *n, Node *res) { int idx; char *name; Node *lp, l, r, nv; Value *v; Pointer *p; lp = n->left; switch(lp->op) { default: pperror("unknown lhs in assignment"); case OINDEX: ppexpr(lp->left, &l); ppexpr(lp->right, &r); if(r.store.type != TINT) pperror("bad type for []"); switch(l.store.type){ default: pperror("bad lhs for index"); case TSTRING: if(r.store.ival >= l.store.string->len) pperror("string index out of range"); idx = r.store.ival; ppexpr(n->right, &r); if(r.store.type != TINT) pperror("bad type for string index assignment; must be int (char)"); l.store.string->string[idx] = (char)r.store.ival; ppexpr(&l, res); return; case TLIST: nthlist(l.store.l, r.store.ival, &nv); if(nv.store.l == nil) pperror("index out of bounds"); lp = &nv; } /* wet floor */ case OCONST: if(lp->store.type != TLIST) pperror("not a list"); ppexpr(n->right, &r); lp->store.l->store.type = r.store.type; lp->store.l->store = r.store; res = lp; return; case ODOT: /* hack */ name = lp->sym->name; ppexpr(lp->left, &l); if(l.store.type != TPOINTER) pperror("indirection of non-pointer"); p = l.store.pval; if(p == nil) pperror("nil pointer type"); if(p->v == nil) pperror("nil pointer value"); memset(&r, 0, sizeof(r)); ppexpr(n->right, &r); p->meta->newindex(&l, name, &r); return; case ONAME: v = lp->sym->v; ppexpr(n->right, &r); v->set = 1; v->store = r.store; res->op = OCONST; res->store = v->store; return; } } void oadd(Node *n, Node *res) { Node l, r; if(n->right == nil){ /* unary + */ ppexpr(n->left, res); return; } ppexpr(n->left, &l); ppexpr(n->right, &r); res->op = OCONST; res->store.type = TFLOAT; switch(l.store.type) { default: pperror("bad lhs type +"); case TINT: switch(r.store.type) { case TINT: res->store.type = TINT; res->store.ival = l.store.ival+r.store.ival; break; case TFLOAT: res->store.fval = l.store.ival+r.store.fval; break; default: pperror("bad rhs type +"); } break; case TFLOAT: switch(r.store.type) { case TINT: res->store.fval = l.store.fval+r.store.ival; break; case TFLOAT: res->store.fval = l.store.fval+r.store.fval; break; default: pperror("bad rhs type +"); } break; case TSTRING: if(r.store.type == TSTRING) { res->store.type = TSTRING; res->store.string = stradd(l.store.string, r.store.string); break; } if(r.store.type == TINT) { res->store.type = TSTRING; res->store.string = straddrune(l.store.string, r.store.ival); break; } pperror("bad rhs for +"); case TLIST: res->store.type = TLIST; switch(r.store.type) { case TLIST: res->store.l = addlist(l.store.l, r.store.l); break; default: r.left = 0; r.right = 0; res->store.l = addlist(l.store.l, construct(&r)); break; } } } void osub(Node *n, Node *res) { Node l, r; ppexpr(n->left, &l); ppexpr(n->right, &r); res->op = OCONST; res->store.type = TFLOAT; switch(l.store.type) { default: pperror("bad lhs type -"); case TINT: switch(r.store.type) { case TINT: res->store.type = TINT; res->store.ival = l.store.ival-r.store.ival; break; case TFLOAT: res->store.fval = l.store.ival-r.store.fval; break; default: pperror("bad rhs type -"); } break; case TFLOAT: switch(r.store.type) { case TINT: res->store.fval = l.store.fval-r.store.ival; break; case TFLOAT: res->store.fval = l.store.fval-r.store.fval; break; default: pperror("bad rhs type -"); } break; } } void omul(Node *n, Node *res) { Node l, r; ppexpr(n->left, &l); ppexpr(n->right, &r); res->op = OCONST; res->store.type = TFLOAT; switch(l.store.type) { default: pperror("bad lhs type *"); case TINT: switch(r.store.type) { case TINT: res->store.type = TINT; res->store.ival = l.store.ival*r.store.ival; break; case TFLOAT: res->store.fval = l.store.ival*r.store.fval; break; default: pperror("bad rhs type *"); } break; case TFLOAT: switch(r.store.type) { case TINT: res->store.fval = l.store.fval*r.store.ival; break; case TFLOAT: res->store.fval = l.store.fval*r.store.fval; break; default: pperror("bad rhs type *"); } break; } } void odiv(Node *n, Node *res) { Node l, r; ppexpr(n->left, &l); ppexpr(n->right, &r); res->op = OCONST; res->store.type = TFLOAT; switch(l.store.type) { default: pperror("bad lhs type /"); case TINT: switch(r.store.type) { case TINT: res->store.type = TINT; if(r.store.ival == 0) pperror("zero divide"); res->store.ival = l.store.ival/r.store.ival; break; case TFLOAT: if(r.store.fval == 0) pperror("zero divide"); res->store.fval = l.store.ival/r.store.fval; break; default: pperror("bad rhs type /"); } break; case TFLOAT: switch(r.store.type) { case TINT: res->store.fval = l.store.fval/r.store.ival; break; case TFLOAT: res->store.fval = l.store.fval/r.store.fval; break; default: pperror("bad rhs type /"); } break; } } void omod(Node *n, Node *res) { Node l, r; ppexpr(n->left, &l); ppexpr(n->right, &r); res->op = OCONST; res->store.type = TINT; if(l.store.type != TINT || r.store.type != TINT) pperror("bad expr type %%"); res->store.ival = l.store.ival%r.store.ival; } void olsh(Node *n, Node *res) { Node l, r; ppexpr(n->left, &l); ppexpr(n->right, &r); res->op = OCONST; res->store.type = TINT; if(l.store.type != TINT || r.store.type != TINT) pperror("bad expr type <<"); res->store.ival = l.store.ival<left, &l); ppexpr(n->right, &r); res->op = OCONST; res->store.type = TINT; if(l.store.type != TINT || r.store.type != TINT) pperror("bad expr type >>"); res->store.ival = (uvlong)l.store.ival>>r.store.ival; } void olt(Node *n, Node *res) { Node l, r; ppexpr(n->left, &l); ppexpr(n->right, &r); res->op = OCONST; res->store.type = TINT; switch(l.store.type) { default: pperror("bad lhs type <"); case TINT: switch(r.store.type) { case TINT: res->store.ival = l.store.ival < r.store.ival; break; case TFLOAT: res->store.ival = l.store.ival < r.store.fval; break; default: pperror("bad rhs type <"); } break; case TFLOAT: switch(r.store.type) { case TINT: res->store.ival = l.store.fval < r.store.ival; break; case TFLOAT: res->store.ival = l.store.fval < r.store.fval; break; default: pperror("bad rhs type <"); } break; } } void ogt(Node *n, Node *res) { Node l, r; ppexpr(n->left, &l); ppexpr(n->right, &r); res->op = OCONST; res->store.type = TINT; switch(l.store.type) { default: pperror("bad lhs type >"); case TINT: switch(r.store.type) { case TINT: res->store.ival = l.store.ival > r.store.ival; break; case TFLOAT: res->store.ival = l.store.ival > r.store.fval; break; default: pperror("bad rhs type >"); } break; case TFLOAT: switch(r.store.type) { case TINT: res->store.ival = l.store.fval > r.store.ival; break; case TFLOAT: res->store.ival = l.store.fval > r.store.fval; break; default: pperror("bad rhs type >"); } break; } } void oleq(Node *n, Node *res) { Node l, r; ppexpr(n->left, &l); ppexpr(n->right, &r); res->op = OCONST; res->store.type = TINT; switch(l.store.type) { default: pperror("bad expr type <="); case TINT: switch(r.store.type) { case TINT: res->store.ival = l.store.ival <= r.store.ival; break; case TFLOAT: res->store.ival = l.store.ival <= r.store.fval; break; default: pperror("bad expr type <="); } break; case TFLOAT: switch(r.store.type) { case TINT: res->store.ival = l.store.fval <= r.store.ival; break; case TFLOAT: res->store.ival = l.store.fval <= r.store.fval; break; default: pperror("bad expr type <="); } break; } } void ogeq(Node *n, Node *res) { Node l, r; ppexpr(n->left, &l); ppexpr(n->right, &r); res->op = OCONST; res->store.type = TINT; switch(l.store.type) { default: pperror("bad lhs type >="); case TINT: switch(r.store.type) { case TINT: res->store.ival = l.store.ival >= r.store.ival; break; case TFLOAT: res->store.ival = l.store.ival >= r.store.fval; break; default: pperror("bad rhs type >="); } break; case TFLOAT: switch(r.store.type) { case TINT: res->store.ival = l.store.fval >= r.store.ival; break; case TFLOAT: res->store.ival = l.store.fval >= r.store.fval; break; default: pperror("bad rhs type >="); } break; } } void oeq(Node *n, Node *res) { Node l, r; ppexpr(n->left, &l); ppexpr(n->right, &r); res->op = OCONST; res->store.type = TINT; res->store.ival = 0; switch(l.store.type) { default: break; case TINT: switch(r.store.type) { case TINT: res->store.ival = l.store.ival == r.store.ival; break; case TFLOAT: res->store.ival = l.store.ival == r.store.fval; break; default: break; } break; case TFLOAT: switch(r.store.type) { case TINT: res->store.ival = l.store.fval == r.store.ival; break; case TFLOAT: res->store.ival = l.store.fval == r.store.fval; break; default: break; } break; case TSTRING: if(r.store.type == TSTRING) { res->store.ival = scmp(r.store.string, l.store.string); break; } break; case TLIST: if(r.store.type == TLIST) { res->store.ival = listcmp(l.store.l, r.store.l); break; } break; } if(n->op == ONEQ) res->store.ival = !res->store.ival; } void oland(Node *n, Node *res) { Node l, r; ppexpr(n->left, &l); ppexpr(n->right, &r); res->op = OCONST; res->store.type = TINT; if(l.store.type != TINT || r.store.type != TINT) pperror("bad expr type &"); res->store.ival = l.store.ival&r.store.ival; } void oxor(Node *n, Node *res) { Node l, r; ppexpr(n->left, &l); ppexpr(n->right, &r); res->op = OCONST; res->store.type = TINT; if(l.store.type != TINT || r.store.type != TINT) pperror("bad expr type ^"); res->store.ival = l.store.ival^r.store.ival; } void olor(Node *n, Node *res) { Node l, r; ppexpr(n->left, &l); ppexpr(n->right, &r); res->op = OCONST; res->store.type = TINT; if(l.store.type != TINT || r.store.type != TINT) pperror("bad expr type |"); res->store.ival = l.store.ival|r.store.ival; } void ocand(Node *n, Node *res) { Node l, r; res->op = OCONST; res->store.type = TINT; res->store.ival = 0; ppexpr(n->left, &l); if(bool(&l) == 0) return; ppexpr(n->right, &r); if(bool(&r) == 0) return; res->store.ival = 1; } void onot(Node *n, Node *res) { Node l; res->op = OCONST; res->store.type = TINT; res->store.ival = 0; ppexpr(n->left, &l); if(bool(&l) == 0) res->store.ival = 1; } void ocor(Node *n, Node *res) { Node l, r; res->op = OCONST; res->store.type = TINT; res->store.ival = 0; ppexpr(n->left, &l); if(bool(&l)) { res->store.ival = 1; return; } ppexpr(n->right, &r); if(bool(&r)) { res->store.ival = 1; return; } } void oeinc(Node *n, Node *res) { Value *v; chklval(n->left); v = n->left->sym->v; res->op = OCONST; res->store.type = v->store.type; switch(v->store.type) { case TINT: if(n->op == OEDEC) v->store.ival--; else v->store.ival++; break; case TFLOAT: if(n->op == OEDEC) v->store.fval--; else v->store.fval++; break; default: pperror("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->store.type = v->store.type; res->store = v->store; switch(v->store.type) { case TINT: if(n->op == OPDEC) v->store.ival--; else v->store.ival++; break; case TFLOAT: if(n->op == OPDEC) v->store.fval--; else v->store.fval++; break; default: pperror("bad type for post --/++"); } } void ocall(Node *n, Node *res) { int na; Lsym *s, *ofn; Node *av[Maxarg]; memset(av, 0, sizeof(av)); /* Default return value */ res->op = OCONST; res->store.type = TLIST; res->store.l = nil; chklval(n->left); s = n->left->sym; if(n->builtin && !s->builtin){ pperror("no builtin %s", s->name); return; } if(s->builtin && (n->builtin || s->proc == 0)) { ofn = curfn; curfn = s; na = 0; flatten(av, n->right, &na); (*s->builtin)(res, av, na); curfn = ofn; return; } /* * stupid hack to allow this: * defn a(*func){ * func("argument") * } * a(print); **/ if(s->proc == nil && s->v->store.cc != nil && s->v->store.cc->sym != nil) s = s->v->store.cc->sym; if(s->proc == nil) pperror("no function %s", s->name); ofn = curfn; curfn = s; call(s->name, n->right, s->proc->left, s->proc->right, res); curfn = ofn; } void odot(Node *n, Node *r) { char *name; Node res; Pointer *p; name = n->sym->name; ppexpr(n->left, &res); if(res.store.type != TPOINTER) pperror("indirection of non-pointer"); p = res.store.pval; if(p == nil) pperror("nil pointer type"); if(p->v == nil) pperror("nil pointer value"); p->meta->index(&res, name, r); } void owhat(Node *n, Node *res) { res->op = OCONST; /* Default return value */ res->store.type = TLIST; res->store.l = nil; whatis(n->sym); } static void (*expop[])(Node*, Node*) = { [OINVALID] oinvalid, [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, [OFOR] 0, [OLIST] olist, [OCALL] ocall, [OCTRUCT] octruct, [OWHILE] 0, [OELSE] 0, [OHEAD] ohead, [OTAIL] otail, [OAPPEND2] oappend, [ORET] 0, [OINDEX] oindex, [OINDC] oindc, [ODOT] odot, [OLOCAL] 0, [ODELETE] odelete, [OEVAL] oeval, [OWHAT] owhat, }; void ppexpr(Node *n, Node *r) { void (*f)(Node*, Node*); assert(n != nil); assert(r != nil); f = expop[n->op]; f(n, r); }