plan9fox/sys/src/cmd/acid/expr.c
2011-03-30 19:35:09 +03:00

1042 lines
15 KiB
C

#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,
['W'] 8,
['X'] 4,
['Y'] 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,
['3'] 10,
['8'] 10,
};
int
fmtsize(Value *v)
{
int ret;
switch(v->fmt) {
default:
return fsize[v->fmt];
case 'i':
case 'I':
if(v->type != TINT || machdata == 0)
error("no size for i fmt pointer ++/--");
ret = (*machdata->instsize)(cormap, v->ival);
if(ret < 0) {
ret = (*machdata->instsize)(symmap, v->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->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->comt = n->sym->lt;
res->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.ival, l.fmt, res);
res->comt = l.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.ival, l.fmt, res);
res->comt = l.comt;
}
void
oframe(Node *n, Node *res)
{
char *p;
Node *lp;
uvlong ival;
Frtype *f;
p = n->sym->name;
while(*p && *p == '$')
p++;
lp = n->left;
if(localaddr(cormap, p, lp->sym->name, &ival, rget) < 0)
error("colon: %r");
res->ival = ival;
res->op = OCONST;
res->fmt = 'X';
res->type = TINT;
/* Try and set comt */
for(f = n->sym->local; f; f = f->next) {
if(f->var == lp->sym) {
res->comt = f->type;
res->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.ival+(r.ival*fsize[l.fmt]), l.fmt, res);
res->comt = l.comt;
res->fmt = l.fmt;
break;
case TLIST:
nthelem(l.l, r.ival, res);
break;
case TSTRING:
res->ival = 0;
if(r.ival >= 0 && r.ival < l.string->len) {
int xx8; /* to get around bug in vc */
xx8 = r.ival;
res->ival = l.string->string[xx8];
}
res->op = OCONST;
res->type = TINT;
res->fmt = 'c';
break;
}
}
void
oappend(Node *n, Node *res)
{
Value *v;
Node r, l;
int empty;
expr(n->left, &l);
expr(n->right, &r);
if(l.type != TLIST)
error("must append to list");
empty = (l.l == nil && (n->left->op == ONAME));
append(res, &l, &r);
if(empty) {
v = n->left->sym->v;
v->type = res->type;
v->Store = res->Store;
v->comt = res->comt;
}
}
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.l, r.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.l) {
res->type = l.l->type;
res->Store = l.l->Store;
}
else {
res->type = TLIST;
res->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.l)
res->l = l.l->next;
else
res->l = 0;
}
void
oconst(Node *n, Node *res)
{
res->op = OCONST;
res->type = n->type;
res->Store = n->Store;
res->comt = n->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->comt = v->comt;
}
void
octruct(Node *n, Node *res)
{
res->op = OCONST;
res->type = TLIST;
res->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->comt = v->comt;
}
}
void
oadd(Node *n, Node *res)
{
Node l, r;
if(n->right == nil){ /* unary + */
expr(n->left, res);
return;
}
expr(n->left, &l);
expr(n->right, &r);
res->fmt = l.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->ival = l.ival+r.ival;
break;
case TFLOAT:
res->fval = l.ival+r.fval;
break;
default:
error("bad rhs type +");
}
break;
case TFLOAT:
switch(r.type) {
case TINT:
res->fval = l.fval+r.ival;
break;
case TFLOAT:
res->fval = l.fval+r.fval;
break;
default:
error("bad rhs type +");
}
break;
case TSTRING:
if(r.type == TSTRING) {
res->type = TSTRING;
res->fmt = 's';
res->string = stradd(l.string, r.string);
break;
}
if(r.type == TINT) {
res->type = TSTRING;
res->fmt = 's';
res->string = straddrune(l.string, r.ival);
break;
}
error("bad rhs for +");
case TLIST:
res->type = TLIST;
switch(r.type) {
case TLIST:
res->l = addlist(l.l, r.l);
break;
default:
r.left = 0;
r.right = 0;
res->l = addlist(l.l, construct(&r));
break;
}
}
}
void
osub(Node *n, Node *res)
{
Node l, r;
expr(n->left, &l);
expr(n->right, &r);
res->fmt = l.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->ival = l.ival-r.ival;
break;
case TFLOAT:
res->fval = l.ival-r.fval;
break;
default:
error("bad rhs type -");
}
break;
case TFLOAT:
switch(r.type) {
case TINT:
res->fval = l.fval-r.ival;
break;
case TFLOAT:
res->fval = l.fval-r.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->fmt = l.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->ival = l.ival*r.ival;
break;
case TFLOAT:
res->fval = l.ival*r.fval;
break;
default:
error("bad rhs type *");
}
break;
case TFLOAT:
switch(r.type) {
case TINT:
res->fval = l.fval*r.ival;
break;
case TFLOAT:
res->fval = l.fval*r.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->fmt = l.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.ival == 0)
error("zero divide");
res->ival = l.ival/r.ival;
break;
case TFLOAT:
if(r.fval == 0)
error("zero divide");
res->fval = l.ival/r.fval;
break;
default:
error("bad rhs type /");
}
break;
case TFLOAT:
switch(r.type) {
case TINT:
res->fval = l.fval/r.ival;
break;
case TFLOAT:
res->fval = l.fval/r.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->fmt = l.fmt;
res->op = OCONST;
res->type = TINT;
if(l.type != TINT || r.type != TINT)
error("bad expr type %");
res->ival = l.ival%r.ival;
}
void
olsh(Node *n, Node *res)
{
Node l, r;
expr(n->left, &l);
expr(n->right, &r);
res->fmt = l.fmt;
res->op = OCONST;
res->type = TINT;
if(l.type != TINT || r.type != TINT)
error("bad expr type <<");
res->ival = l.ival<<r.ival;
}
void
orsh(Node *n, Node *res)
{
Node l, r;
expr(n->left, &l);
expr(n->right, &r);
res->fmt = l.fmt;
res->op = OCONST;
res->type = TINT;
if(l.type != TINT || r.type != TINT)
error("bad expr type >>");
res->ival = (uvlong)l.ival>>r.ival;
}
void
olt(Node *n, Node *res)
{
Node l, r;
expr(n->left, &l);
expr(n->right, &r);
res->fmt = l.fmt;
res->op = OCONST;
res->type = TINT;
switch(l.type) {
default:
error("bad lhs type <");
case TINT:
switch(r.type) {
case TINT:
res->ival = l.ival < r.ival;
break;
case TFLOAT:
res->ival = l.ival < r.fval;
break;
default:
error("bad rhs type <");
}
break;
case TFLOAT:
switch(r.type) {
case TINT:
res->ival = l.fval < r.ival;
break;
case TFLOAT:
res->ival = l.fval < r.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->fmt = 'D';
res->op = OCONST;
res->type = TINT;
switch(l.type) {
default:
error("bad lhs type >");
case TINT:
switch(r.type) {
case TINT:
res->ival = l.ival > r.ival;
break;
case TFLOAT:
res->ival = l.ival > r.fval;
break;
default:
error("bad rhs type >");
}
break;
case TFLOAT:
switch(r.type) {
case TINT:
res->ival = l.fval > r.ival;
break;
case TFLOAT:
res->ival = l.fval > r.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->fmt = 'D';
res->op = OCONST;
res->type = TINT;
switch(l.type) {
default:
error("bad expr type <=");
case TINT:
switch(r.type) {
case TINT:
res->ival = l.ival <= r.ival;
break;
case TFLOAT:
res->ival = l.ival <= r.fval;
break;
default:
error("bad expr type <=");
}
break;
case TFLOAT:
switch(r.type) {
case TINT:
res->ival = l.fval <= r.ival;
break;
case TFLOAT:
res->ival = l.fval <= r.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->fmt = 'D';
res->op = OCONST;
res->type = TINT;
switch(l.type) {
default:
error("bad lhs type >=");
case TINT:
switch(r.type) {
case TINT:
res->ival = l.ival >= r.ival;
break;
case TFLOAT:
res->ival = l.ival >= r.fval;
break;
default:
error("bad rhs type >=");
}
break;
case TFLOAT:
switch(r.type) {
case TINT:
res->ival = l.fval >= r.ival;
break;
case TFLOAT:
res->ival = l.fval >= r.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->fmt = 'D';
res->op = OCONST;
res->type = TINT;
res->ival = 0;
switch(l.type) {
default:
break;
case TINT:
switch(r.type) {
case TINT:
res->ival = l.ival == r.ival;
break;
case TFLOAT:
res->ival = l.ival == r.fval;
break;
default:
break;
}
break;
case TFLOAT:
switch(r.type) {
case TINT:
res->ival = l.fval == r.ival;
break;
case TFLOAT:
res->ival = l.fval == r.fval;
break;
default:
break;
}
break;
case TSTRING:
if(r.type == TSTRING) {
res->ival = scmp(r.string, l.string);
break;
}
break;
case TLIST:
if(r.type == TLIST) {
res->ival = listcmp(l.l, r.l);
break;
}
break;
}
if(n->op == ONEQ)
res->ival = !res->ival;
}
void
oland(Node *n, Node *res)
{
Node l, r;
expr(n->left, &l);
expr(n->right, &r);
res->fmt = l.fmt;
res->op = OCONST;
res->type = TINT;
if(l.type != TINT || r.type != TINT)
error("bad expr type &");
res->ival = l.ival&r.ival;
}
void
oxor(Node *n, Node *res)
{
Node l, r;
expr(n->left, &l);
expr(n->right, &r);
res->fmt = l.fmt;
res->op = OCONST;
res->type = TINT;
if(l.type != TINT || r.type != TINT)
error("bad expr type ^");
res->ival = l.ival^r.ival;
}
void
olor(Node *n, Node *res)
{
Node l, r;
expr(n->left, &l);
expr(n->right, &r);
res->fmt = l.fmt;
res->op = OCONST;
res->type = TINT;
if(l.type != TINT || r.type != TINT)
error("bad expr type |");
res->ival = l.ival|r.ival;
}
void
ocand(Node *n, Node *res)
{
Node l, r;
res->op = OCONST;
res->type = TINT;
res->ival = 0;
res->fmt = 'D';
expr(n->left, &l);
if(bool(&l) == 0)
return;
expr(n->right, &r);
if(bool(&r) == 0)
return;
res->ival = 1;
}
void
onot(Node *n, Node *res)
{
Node l;
res->op = OCONST;
res->type = TINT;
res->ival = 0;
expr(n->left, &l);
res->fmt = l.fmt;
if(bool(&l) == 0)
res->ival = 1;
}
void
ocor(Node *n, Node *res)
{
Node l, r;
res->op = OCONST;
res->type = TINT;
res->ival = 0;
res->fmt = 'D';
expr(n->left, &l);
if(bool(&l)) {
res->ival = 1;
return;
}
expr(n->right, &r);
if(bool(&r)) {
res->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->ival -= fmtsize(v);
else
v->ival += fmtsize(v);
break;
case TFLOAT:
if(n->op == OEDEC)
v->fval--;
else
v->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->ival -= fmtsize(v);
else
v->ival += fmtsize(v);
break;
case TFLOAT:
if(n->op == OPDEC)
v->fval--;
else
v->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->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->fmt = n->right->ival;
}
void
owhat(Node *n, Node *res)
{
res->op = OCONST; /* Default return value */
res->type = TLIST;
res->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,
};