#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;
	}
}
