blob: 088b98f848935ad3ee0848bcd89e4d3f25a5fcb2 [file] [log] [blame]
#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;
}
}