plan9port/src/cmd/acid/expr.c
rsc 4f2ac1b76b Working on better handling of multithreading in general
and core dumps in particular.  See notes:

new types: register is something that when dereferenced gives you
	the registers.  the Ureg is no longer mapped at 0.
	refconst is something that gives a constant when dereferenced.

new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values

new builtin var("foo") is equivalent to the variable foo
	(it returns foo but can also be used as the lhs of an assignment).

new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
	note that getregs and setregs operate on register locations, not the
		register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.

new acid variables coretext, pids, systype, corefile, cmdline.

new behavior: local variable lookup, stk, etc., use the acid values of registers
	(*PC, *SP, and so on), so the thread support code can change the context
	completely.

unary + is applicable to more data types and prints more often.
2005-01-23 22:48:19 +00:00

1121 lines
19 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[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, 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;
ulong 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, 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 = 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;
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, ulong *u, int isr)
{
Lsym *l;
Value *v;
Node *n;
ulong addr;
u32int u32;
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, 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(get4(cormap, addr, &u32) < 0)
return -1;
*u = u32;
return 0;
}
}