blob: 3864cd0aecfae657bb0912fad6f4116925e73732 [file] [log] [blame]
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#include <mach.h>
#define Extern extern
#include "acid.h"
void
error(char *fmt, ...)
{
int i;
char buf[2048];
va_list arg;
/* Unstack io channels */
if(iop != 0) {
for(i = 1; i < iop; i++)
Bterm(io[i]);
bout = io[0];
iop = 0;
}
ret = 0;
gotint = 0;
Bflush(bout);
if(silent)
silent = 0;
else {
va_start(arg, fmt);
vseprint(buf, buf+sizeof(buf), fmt, arg);
va_end(arg);
fprint(2, "%Z: (error) %s\n", buf);
}
while(popio())
;
interactive = 1;
longjmp(err, 1);
}
void
unwind(void)
{
int i;
Lsym *s;
Value *v;
for(i = 0; i < Hashsize; i++) {
for(s = hash[i]; s; s = s->hash) {
while(s->v->pop) {
v = s->v->pop;
free(s->v);
s->v = v;
}
}
}
}
void
execute(Node *n)
{
Value *v;
Lsym *sl;
Node *l, *r;
int i, s, e;
Node res, xx;
static int stmnt;
gc();
if(gotint)
error("interrupted");
if(n == 0)
return;
if(stmnt++ > 5000) {
Bflush(bout);
stmnt = 0;
}
l = n->left;
r = n->right;
switch(n->op) {
default:
expr(n, &res);
if(ret || (res.type == TLIST && res.store.u.l == 0))
break;
prnt->right = &res;
expr(prnt, &xx);
break;
case OASGN:
case OCALL:
expr(n, &res);
break;
case OCOMPLEX:
decl(n);
break;
case OLOCAL:
for(n = n->left; n; n = n->left) {
if(ret == 0)
error("local not in function");
sl = n->sym;
if(sl->v->ret == ret)
error("%s declared twice", sl->name);
v = gmalloc(sizeof(Value));
v->ret = ret;
v->pop = sl->v;
sl->v = v;
v->scope = 0;
*(ret->tail) = sl;
ret->tail = &v->scope;
v->set = 0;
}
break;
case ORET:
if(ret == 0)
error("return not in function");
expr(n->left, ret->val);
longjmp(ret->rlab, 1);
case OLIST:
execute(n->left);
execute(n->right);
break;
case OIF:
expr(l, &res);
if(r && r->op == OELSE) {
if(bool(&res))
execute(r->left);
else
execute(r->right);
}
else if(bool(&res))
execute(r);
break;
case OWHILE:
for(;;) {
expr(l, &res);
if(!bool(&res))
break;
execute(r);
}
break;
case ODO:
expr(l->left, &res);
if(res.type != TINT)
error("loop must have integer start");
s = res.store.u.ival;
expr(l->right, &res);
if(res.type != TINT)
error("loop must have integer end");
e = res.store.u.ival;
for(i = s; i <= e; i++)
execute(r);
break;
}
}
int
bool(Node *n)
{
int true = 0;
if(n->op != OCONST)
fatal("bool: not const");
switch(n->type) {
case TINT:
if(n->store.u.ival != 0)
true = 1;
break;
case TFLOAT:
if(n->store.u.fval != 0.0)
true = 1;
break;
case TSTRING:
if(n->store.u.string->len)
true = 1;
break;
case TLIST:
if(n->store.u.l)
true = 1;
break;
}
return true;
}
void
convflt(Node *r, char *flt)
{
char c;
c = flt[0];
if(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) {
r->type = TSTRING;
r->store.fmt = 's';
r->store.u.string = strnode(flt);
}
else {
r->type = TFLOAT;
r->store.u.fval = atof(flt);
}
}
void
indir(Map *m, u64int addr, char fmt, Node *r)
{
int i;
u32int ival;
u64int vval;
int ret;
u8int cval;
u16int sval;
char buf[512], reg[12];
r->op = OCONST;
r->store.fmt = fmt;
switch(fmt) {
default:
error("bad pointer format '%c' for *", fmt);
case 'c':
case 'C':
case 'b':
r->type = TINT;
ret = get1(m, addr, &cval, 1);
if (ret < 0)
error("indir: %r");
r->store.u.ival = cval;
break;
case 'x':
case 'd':
case 'u':
case 'o':
case 'q':
case 'r':
r->type = TINT;
ret = get2(m, addr, &sval);
if (ret < 0)
error("indir: %r");
r->store.u.ival = sval;
break;
case 'a':
case 'A':
case 'B':
case 'X':
case 'D':
case 'U':
case 'O':
case 'Q':
r->type = TINT;
ret = get4(m, addr, &ival);
if (ret < 0)
error("indir: %r");
r->store.u.ival = ival;
break;
case 'V':
case 'W':
case 'Y':
case 'Z':
r->type = TINT;
ret = get8(m, addr, &vval);
if (ret < 0)
error("indir: %r");
r->store.u.ival = vval;
break;
case 's':
r->type = TSTRING;
for(i = 0; i < sizeof(buf)-1; i++) {
ret = get1(m, addr, (uchar*)&buf[i], 1);
if (ret < 0)
error("indir: %r");
addr++;
if(buf[i] == '\0')
break;
}
buf[i] = 0;
if(i == 0)
strcpy(buf, "(null)");
r->store.u.string = strnode(buf);
break;
case 'R':
r->type = TSTRING;
assert(sizeof(Rune) == 4);
for(i = 0; i < sizeof(buf)-4; i += 4) {
ret = get4(m, addr, &ival);
if (ret < 0)
error("indir: %r");
memmove(buf+i, &ival, 4);
addr += 4;
if(ival == 0)
break;
}
ival = 0;
memmove(buf+i, &ival, 4);
r->store.u.string = runenode((Rune*)buf);
break;
case 'i':
case 'I':
if ((*mach->das)(m, addr, fmt, buf, sizeof(buf)) < 0)
error("indir: %r");
r->type = TSTRING;
r->store.fmt = 's';
r->store.u.string = strnode(buf);
break;
case 'f':
ret = get1(m, addr, (uchar*)buf, mach->szfloat);
if (ret < 0)
error("indir: %r");
mach->ftoa32(buf, sizeof(buf), (void*) buf);
convflt(r, buf);
break;
case 'g':
ret = get1(m, addr, (uchar*)buf, mach->szfloat);
if (ret < 0)
error("indir: %r");
mach->ftoa32(buf, sizeof(buf), (void*) buf);
r->type = TSTRING;
r->store.u.string = strnode(buf);
break;
case 'F':
ret = get1(m, addr, (uchar*)buf, mach->szdouble);
if (ret < 0)
error("indir: %r");
mach->ftoa64(buf, sizeof(buf), (void*) buf);
convflt(r, buf);
break;
case '3': /* little endian ieee 80 with hole in bytes 8&9 */
ret = get1(m, addr, (uchar*)reg, 10);
if (ret < 0)
error("indir: %r");
memmove(reg+10, reg+8, 2); /* open hole */
memset(reg+8, 0, 2); /* fill it */
leieeeftoa80(buf, sizeof(buf), reg);
convflt(r, buf);
break;
case '8': /* big-endian ieee 80 */
ret = get1(m, addr, (uchar*)reg, 10);
if (ret < 0)
error("indir: %r");
beieeeftoa80(buf, sizeof(buf), reg);
convflt(r, buf);
break;
case 'G':
ret = get1(m, addr, (uchar*)buf, mach->szdouble);
if (ret < 0)
error("indir: %r");
mach->ftoa64(buf, sizeof(buf), (void*) buf);
r->type = TSTRING;
r->store.u.string = strnode(buf);
break;
}
}
void
indirreg(Regs *regs, char *name, char fmt, Node *r)
{
u64int val;
if(regs == 0)
error("no register set for *%s=", name);
r->op = OCONST;
r->store.fmt = fmt;
switch(fmt){
default:
error("bad pointer format '%c' for *%s", fmt, name);
case 'c':
case 'C':
case 'b':
case 'x':
case 'd':
case 'u':
case 'o':
case 'q':
case 'r':
case 'a':
case 'A':
case 'B':
case 'X':
case 'D':
case 'U':
case 'O':
case 'Q':
case 'V':
case 'W':
case 'Y':
case 'Z':
if(rget(regs, name, &val) < 0)
error("reading %s: %r", name);
r->type = TINT;
r->store.u.ival = val;
break;
case 'f':
case 'g':
case 'F':
case '3':
case '8':
case 'G':
error("floating point registers not supported");
break;
}
}
void
windir(Map *m, Node aes, Node *rval, Node *r)
{
uchar cval;
ushort sval;
Node res;
int ret;
if(m == 0)
error("no map for */@=");
if(aes.type != TINT)
error("bad type lhs of */@=");
expr(rval, &res);
if(m != cormap && wtflag == 0)
error("not in write mode");
r->type = res.type;
r->store.fmt = res.store.fmt;
r->store = res.store;
switch(res.store.fmt) {
default:
error("bad pointer format '%c' for */@=", res.store.fmt);
case 'c':
case 'C':
case 'b':
cval = res.store.u.ival;
ret = put1(m, aes.store.u.ival, &cval, 1);
break;
case 'r':
case 'x':
case 'd':
case 'u':
case 'o':
sval = res.store.u.ival;
ret = put2(m, aes.store.u.ival, sval);
r->store.u.ival = sval;
break;
case 'a':
case 'A':
case 'B':
case 'X':
case 'D':
case 'U':
case 'O':
ret = put4(m, aes.store.u.ival, res.store.u.ival);
break;
case 'V':
case 'W':
case 'Y':
case 'Z':
ret = put8(m, aes.store.u.ival, res.store.u.ival);
break;
case 's':
case 'R':
ret = put1(m, aes.store.u.ival, (uchar*)res.store.u.string->string, res.store.u.string->len);
break;
}
if (ret < 0)
error("windir: %r");
}
void
windirreg(Regs *regs, char *name, Node *rval, Node *r)
{
Node res;
if(regs == 0)
error("no register set for *%s=", name);
expr(rval, &res);
r->type = res.type;
r->store.fmt = res.store.fmt;
r->store = res.store;
switch(res.store.fmt){
default:
error("bad format '%c' for *%s=", res.store.fmt, name);
case 'c':
case 'C':
case 'b':
case 'x':
case 'd':
case 'u':
case 'o':
case 'q':
case 'r':
case 'a':
case 'A':
case 'B':
case 'X':
case 'D':
case 'U':
case 'O':
case 'Q':
case 'V':
case 'W':
case 'Y':
case 'Z':
if(rput(regs, name, res.store.u.ival) < 0)
error("writing %s: %r", name);
break;
case 'f':
case 'g':
case 'F':
case '3':
case '8':
case 'G':
error("floating point registers not supported");
break;
}
}
void
call(char *fn, Node *parameters, Node *local, Node *body, Node *retexp)
{
int np, i;
Rplace rlab;
Node *n, res;
Value *v, *f;
Lsym *s, *next;
Node *avp[Maxarg], *ava[Maxarg];
rlab.local = 0;
na = 0;
flatten(avp, parameters);
np = na;
na = 0;
flatten(ava, local);
if(np != na) {
if(np < na)
error("%s: too few arguments", fn);
error("%s: too many arguments", fn);
}
rlab.tail = &rlab.local;
ret = &rlab;
for(i = 0; i < np; i++) {
n = ava[i];
switch(n->op) {
default:
error("%s: %d formal not a name", fn, i);
case ONAME:
expr(avp[i], &res);
s = n->sym;
break;
case OINDM:
res.store.u.cc = avp[i];
res.type = TCODE;
res.store.comt = 0;
if(n->left->op != ONAME)
error("%s: %d formal not a name", fn, i);
s = n->left->sym;
break;
}
if(s->v->ret == ret)
error("%s already declared at this scope", s->name);
v = gmalloc(sizeof(Value));
v->ret = ret;
v->pop = s->v;
s->v = v;
v->scope = 0;
*(rlab.tail) = s;
rlab.tail = &v->scope;
v->store = res.store;
v->type = res.type;
v->set = 1;
}
ret->val = retexp;
if(setjmp(rlab.rlab) == 0)
execute(body);
for(s = rlab.local; s; s = next) {
f = s->v;
next = f->scope;
s->v = f->pop;
free(f);
}
}