summaryrefslogtreecommitdiff
path: root/sys/src/cmd/acid
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/acid
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/acid')
-rwxr-xr-xsys/src/cmd/acid/acid.h298
-rwxr-xr-xsys/src/cmd/acid/builtin.c1315
-rwxr-xr-xsys/src/cmd/acid/dbg.y411
-rwxr-xr-xsys/src/cmd/acid/dot.c153
-rwxr-xr-xsys/src/cmd/acid/exec.c498
-rwxr-xr-xsys/src/cmd/acid/expr.c1041
-rwxr-xr-xsys/src/cmd/acid/lex.c609
-rwxr-xr-xsys/src/cmd/acid/list.c277
-rwxr-xr-xsys/src/cmd/acid/main.c595
-rwxr-xr-xsys/src/cmd/acid/mkfile33
-rwxr-xr-xsys/src/cmd/acid/print.c445
-rwxr-xr-xsys/src/cmd/acid/proc.c279
-rwxr-xr-xsys/src/cmd/acid/util.c304
13 files changed, 6258 insertions, 0 deletions
diff --git a/sys/src/cmd/acid/acid.h b/sys/src/cmd/acid/acid.h
new file mode 100755
index 000000000..ef398e7b8
--- /dev/null
+++ b/sys/src/cmd/acid/acid.h
@@ -0,0 +1,298 @@
+/* acid.h */
+enum
+{
+ Eof = -1,
+ Strsize = 4096,
+ Hashsize = 128,
+ Maxarg = 512,
+ NFD = 100,
+ Maxproc = 50,
+ Maxval = 10,
+ Mempergc = 1024*1024,
+};
+
+#pragma varargck type "L" void
+
+typedef struct Node Node;
+typedef struct String String;
+typedef struct Lsym Lsym;
+typedef struct List List;
+typedef struct Store Store;
+typedef struct Gc Gc;
+typedef struct Strc Strc;
+typedef struct Rplace Rplace;
+typedef struct Ptab Ptab;
+typedef struct Value Value;
+typedef struct Type Type;
+typedef struct Frtype Frtype;
+
+Extern int kernel;
+Extern int remote;
+Extern int text;
+Extern int silent;
+Extern Fhdr fhdr;
+Extern int line;
+Extern Biobuf* bout;
+Extern Biobuf* io[32];
+Extern int iop;
+Extern char symbol[Strsize];
+Extern int interactive;
+Extern int na;
+Extern int wtflag;
+Extern Map* cormap;
+Extern Map* symmap;
+Extern Lsym* hash[Hashsize];
+Extern long dogc;
+Extern Rplace* ret;
+Extern char* aout;
+Extern int gotint;
+Extern Gc* gcl;
+Extern int stacked;
+Extern jmp_buf err;
+Extern Node* prnt;
+Extern List* tracelist;
+Extern int initialising;
+Extern int quiet;
+
+extern void (*expop[])(Node*, Node*);
+#define expr(n, r) (r)->comt=0; (*expop[(n)->op])(n, r);
+extern int fmtsize(Value *v) ;
+
+enum
+{
+ TINT,
+ TFLOAT,
+ TSTRING,
+ TLIST,
+ TCODE,
+};
+
+struct Type
+{
+ Type* next;
+ int offset;
+ char fmt;
+ char depth;
+ Lsym* type;
+ Lsym* tag;
+ Lsym* base;
+};
+
+struct Frtype
+{
+ Lsym* var;
+ Type* type;
+ Frtype* next;
+};
+
+struct Ptab
+{
+ int pid;
+ int ctl;
+};
+Extern Ptab ptab[Maxproc];
+
+struct Rplace
+{
+ jmp_buf rlab;
+ Node* stak;
+ Node* val;
+ Lsym* local;
+ Lsym** tail;
+};
+
+struct Gc
+{
+ char gcmark;
+ Gc* gclink;
+};
+
+struct Store
+{
+ char fmt;
+ Type* comt;
+ union {
+ vlong ival;
+ double fval;
+ String* string;
+ List* l;
+ Node* cc;
+ };
+};
+
+struct List
+{
+ Gc;
+ List* next;
+ char type;
+ Store;
+};
+
+struct Value
+{
+ char set;
+ char type;
+ Store;
+ Value* pop;
+ Lsym* scope;
+ Rplace* ret;
+};
+
+struct Lsym
+{
+ char* name;
+ int lexval;
+ Lsym* hash;
+ Value* v;
+ Type* lt;
+ Node* proc;
+ Frtype* local;
+ void (*builtin)(Node*, Node*);
+};
+
+struct Node
+{
+ Gc;
+ char op;
+ char type;
+ Node* left;
+ Node* right;
+ Lsym* sym;
+ int builtin;
+ Store;
+};
+#define ZN (Node*)0
+
+struct String
+{
+ Gc;
+ char *string;
+ int len;
+};
+
+List* addlist(List*, List*);
+List* al(int);
+Node* an(int, Node*, Node*);
+void append(Node*, Node*, Node*);
+int bool(Node*);
+void build(Node*);
+void call(char*, Node*, Node*, Node*, Node*);
+void catcher(void*, char*);
+void checkqid(int, int);
+void cmd(void);
+Node* con(vlong);
+List* construct(Node*);
+void ctrace(int);
+void decl(Node*);
+void defcomplex(Node*, Node*);
+void deinstall(int);
+void delete(List*, int n, Node*);
+void dostop(int);
+Lsym* enter(char*, int);
+void error(char*, ...);
+void execute(Node*);
+void fatal(char*, ...);
+void flatten(Node**, Node*);
+void gc(void);
+char* getstatus(int);
+void* gmalloc(long);
+void indir(Map*, uvlong, char, Node*);
+void installbuiltin(void);
+void kinit(void);
+int Lfmt(Fmt*);
+int listcmp(List*, List*);
+int listlen(List*);
+List* listvar(char*, vlong);
+void loadmodule(char*);
+void loadvars(void);
+Lsym* look(char*);
+void ltag(char*);
+void marklist(List*);
+Lsym* mkvar(char*);
+void msg(int, char*);
+void notes(int);
+int nproc(char**);
+void nthelem(List*, int, Node*);
+int numsym(char);
+void odot(Node*, Node*);
+void pcode(Node*, int);
+void pexpr(Node*);
+int popio(void);
+void pstr(String*);
+void pushfile(char*);
+void pushstr(Node*);
+void readtext(char*);
+void restartio(void);
+uvlong rget(Map*, char*);
+String *runenode(Rune*);
+int scmp(String*, String*);
+void sproc(int);
+String* stradd(String*, String*);
+String* straddrune(String*, Rune);
+String* strnode(char*);
+String* strnodlen(char*, int);
+char* system(void);
+void trlist(Map*, uvlong, uvlong, Symbol*);
+void unwind(void);
+void userinit(void);
+void varreg(void);
+void varsym(void);
+Waitmsg* waitfor(int);
+void whatis(Lsym*);
+void windir(Map*, Node*, Node*, Node*);
+void yyerror(char*, ...);
+int yylex(void);
+int yyparse(void);
+
+enum
+{
+ ONAME,
+ OCONST,
+ OMUL,
+ ODIV,
+ OMOD,
+ OADD,
+ OSUB,
+ ORSH,
+ OLSH,
+ OLT,
+ OGT,
+ OLEQ,
+ OGEQ,
+ OEQ,
+ ONEQ,
+ OLAND,
+ OXOR,
+ OLOR,
+ OCAND,
+ OCOR,
+ OASGN,
+ OINDM,
+ OEDEC,
+ OEINC,
+ OPINC,
+ OPDEC,
+ ONOT,
+ OIF,
+ ODO,
+ OLIST,
+ OCALL,
+ OCTRUCT,
+ OWHILE,
+ OELSE,
+ OHEAD,
+ OTAIL,
+ OAPPEND,
+ ORET,
+ OINDEX,
+ OINDC,
+ ODOT,
+ OLOCAL,
+ OFRAME,
+ OCOMPLEX,
+ ODELETE,
+ OCAST,
+ OFMT,
+ OEVAL,
+ OWHAT,
+};
diff --git a/sys/src/cmd/acid/builtin.c b/sys/src/cmd/acid/builtin.c
new file mode 100755
index 000000000..9232a7fa0
--- /dev/null
+++ b/sys/src/cmd/acid/builtin.c
@@ -0,0 +1,1315 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ctype.h>
+#include <mach.h>
+#include <regexp.h>
+#define Extern extern
+#include "acid.h"
+#include "y.tab.h"
+
+void cvtatof(Node*, Node*);
+void cvtatoi(Node*, Node*);
+void cvtitoa(Node*, Node*);
+void bprint(Node*, Node*);
+void funcbound(Node*, Node*);
+void printto(Node*, Node*);
+void getfile(Node*, Node*);
+void fmt(Node*, Node*);
+void pcfile(Node*, Node*);
+void pcline(Node*, Node*);
+void setproc(Node*, Node*);
+void strace(Node*, Node*);
+void follow(Node*, Node*);
+void reason(Node*, Node*);
+void newproc(Node*, Node*);
+void startstop(Node*, Node*);
+void match(Node*, Node*);
+void status(Node*, Node*);
+void kill(Node*,Node*);
+void waitstop(Node*, Node*);
+void stop(Node*, Node*);
+void start(Node*, Node*);
+void filepc(Node*, Node*);
+void doerror(Node*, Node*);
+void rc(Node*, Node*);
+void doaccess(Node*, Node*);
+void map(Node*, Node*);
+void readfile(Node*, Node*);
+void interpret(Node*, Node*);
+void include(Node*, Node*);
+void regexp(Node*, Node*);
+void dosysr1(Node*, Node*);
+void fmtof(Node*, Node*) ;
+void dofmtsize(Node*, Node*) ;
+
+typedef struct Btab Btab;
+struct Btab
+{
+ char *name;
+ void (*fn)(Node*, Node*);
+} tab[] =
+{
+ "atof", cvtatof,
+ "atoi", cvtatoi,
+ "error", doerror,
+ "file", getfile,
+ "readfile", readfile,
+ "access", doaccess,
+ "filepc", filepc,
+ "fnbound", funcbound,
+ "fmt", fmt,
+ "follow", follow,
+ "itoa", cvtitoa,
+ "kill", kill,
+ "match", match,
+ "newproc", newproc,
+ "pcfile", pcfile,
+ "pcline", pcline,
+ "print", bprint,
+ "printto", printto,
+ "rc", rc,
+ "reason", reason,
+ "setproc", setproc,
+ "start", start,
+ "startstop", startstop,
+ "status", status,
+ "stop", stop,
+ "strace", strace,
+ "sysr1", dosysr1,
+ "waitstop", waitstop,
+ "map", map,
+ "interpret", interpret,
+ "include", include,
+ "regexp", regexp,
+ "fmtof", fmtof,
+ "fmtsize", dofmtsize,
+ 0
+};
+
+char vfmt[] = "aBbcCdDfFgGiIoOqQrRsSuUVWxXYZ38";
+
+void
+mkprint(Lsym *s)
+{
+ prnt = malloc(sizeof(Node));
+ memset(prnt, 0, sizeof(Node));
+ prnt->op = OCALL;
+ prnt->left = malloc(sizeof(Node));
+ memset(prnt->left, 0, sizeof(Node));
+ prnt->left->sym = s;
+}
+
+void
+installbuiltin(void)
+{
+ Btab *b;
+ Lsym *s;
+
+ b = tab;
+ while(b->name) {
+ s = look(b->name);
+ if(s == 0)
+ s = enter(b->name, Tid);
+
+ s->builtin = b->fn;
+ if(b->fn == bprint)
+ mkprint(s);
+ b++;
+ }
+}
+
+void
+dosysr1(Node *r, Node*)
+{
+ extern int sysr1(void);
+
+ r->op = OCONST;
+ r->type = TINT;
+ r->fmt = 'D';
+ r->ival = sysr1();
+}
+
+void
+match(Node *r, Node *args)
+{
+ int i;
+ List *f;
+ Node *av[Maxarg];
+ Node resi, resl;
+
+ na = 0;
+ flatten(av, args);
+ if(na != 2)
+ error("match(obj, list): arg count");
+
+ expr(av[1], &resl);
+ if(resl.type != TLIST)
+ error("match(obj, list): need list");
+ expr(av[0], &resi);
+
+ r->op = OCONST;
+ r->type = TINT;
+ r->fmt = 'D';
+ r->ival = -1;
+
+ i = 0;
+ for(f = resl.l; f; f = f->next) {
+ if(resi.type == f->type) {
+ switch(resi.type) {
+ case TINT:
+ if(resi.ival == f->ival) {
+ r->ival = i;
+ return;
+ }
+ break;
+ case TFLOAT:
+ if(resi.fval == f->fval) {
+ r->ival = i;
+ return;
+ }
+ break;
+ case TSTRING:
+ if(scmp(resi.string, f->string)) {
+ r->ival = i;
+ return;
+ }
+ break;
+ case TLIST:
+ error("match(obj, list): not defined for list");
+ }
+ }
+ i++;
+ }
+}
+
+void
+newproc(Node *r, Node *args)
+{
+ int i;
+ Node res;
+ char *p, *e;
+ char *argv[Maxarg], buf[Strsize];
+
+ i = 1;
+ argv[0] = aout;
+
+ if(args) {
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("newproc(): arg not string");
+ if(res.string->len >= sizeof(buf))
+ error("newproc(): too many arguments");
+ memmove(buf, res.string->string, res.string->len);
+ buf[res.string->len] = '\0';
+ p = buf;
+ e = buf+res.string->len;
+ for(;;) {
+ while(p < e && (*p == '\t' || *p == ' '))
+ *p++ = '\0';
+ if(p >= e)
+ break;
+ argv[i++] = p;
+ if(i >= Maxarg)
+ error("newproc: too many arguments");
+ while(p < e && *p != '\t' && *p != ' ')
+ p++;
+ }
+ }
+ argv[i] = 0;
+ r->op = OCONST;
+ r->type = TINT;
+ r->fmt = 'D';
+ r->ival = nproc(argv);
+}
+
+void
+startstop(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ if(args == 0)
+ error("startstop(pid): no pid");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("startstop(pid): arg type");
+
+ msg(res.ival, "startstop");
+ notes(res.ival);
+ dostop(res.ival);
+}
+
+void
+waitstop(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ if(args == 0)
+ error("waitstop(pid): no pid");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("waitstop(pid): arg type");
+
+ Bflush(bout);
+ msg(res.ival, "waitstop");
+ notes(res.ival);
+ dostop(res.ival);
+}
+
+void
+start(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ if(args == 0)
+ error("start(pid): no pid");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("start(pid): arg type");
+
+ msg(res.ival, "start");
+}
+
+void
+stop(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ if(args == 0)
+ error("stop(pid): no pid");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("stop(pid): arg type");
+
+ Bflush(bout);
+ msg(res.ival, "stop");
+ notes(res.ival);
+ dostop(res.ival);
+}
+
+void
+kill(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ if(args == 0)
+ error("kill(pid): no pid");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("kill(pid): arg type");
+
+ msg(res.ival, "kill");
+ deinstall(res.ival);
+}
+
+void
+status(Node *r, Node *args)
+{
+ Node res;
+ char *p;
+
+ USED(r);
+ if(args == 0)
+ error("status(pid): no pid");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("status(pid): arg type");
+
+ p = getstatus(res.ival);
+ r->string = strnode(p);
+ r->op = OCONST;
+ r->fmt = 's';
+ r->type = TSTRING;
+}
+
+void
+reason(Node *r, Node *args)
+{
+ Node res;
+
+ if(args == 0)
+ error("reason(cause): no cause");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("reason(cause): arg type");
+
+ r->op = OCONST;
+ r->type = TSTRING;
+ r->fmt = 's';
+ r->string = strnode((*machdata->excep)(cormap, rget));
+}
+
+void
+follow(Node *r, Node *args)
+{
+ int n, i;
+ Node res;
+ uvlong f[10];
+ List **tail, *l;
+
+ if(args == 0)
+ error("follow(addr): no addr");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("follow(addr): arg type");
+
+ n = (*machdata->foll)(cormap, res.ival, rget, f);
+ if (n < 0)
+ error("follow(addr): %r");
+ tail = &r->l;
+ for(i = 0; i < n; i++) {
+ l = al(TINT);
+ l->ival = f[i];
+ l->fmt = 'X';
+ *tail = l;
+ tail = &l->next;
+ }
+}
+
+void
+funcbound(Node *r, Node *args)
+{
+ int n;
+ Node res;
+ uvlong bounds[2];
+ List *l;
+
+ if(args == 0)
+ error("fnbound(addr): no addr");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("fnbound(addr): arg type");
+
+ n = fnbound(res.ival, bounds);
+ if (n != 0) {
+ r->l = al(TINT);
+ l = r->l;
+ l->ival = bounds[0];
+ l->fmt = 'X';
+ l->next = al(TINT);
+ l = l->next;
+ l->ival = bounds[1];
+ l->fmt = 'X';
+ }
+}
+
+void
+setproc(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ if(args == 0)
+ error("setproc(pid): no pid");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("setproc(pid): arg type");
+
+ sproc(res.ival);
+}
+
+void
+filepc(Node *r, Node *args)
+{
+ Node res;
+ char *p, c;
+
+ if(args == 0)
+ error("filepc(filename:line): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("filepc(filename:line): arg type");
+
+ p = strchr(res.string->string, ':');
+ if(p == 0)
+ error("filepc(filename:line): bad arg format");
+
+ c = *p;
+ *p++ = '\0';
+ r->ival = file2pc(res.string->string, strtol(p, 0, 0));
+ p[-1] = c;
+ if(r->ival == ~0)
+ error("filepc(filename:line): can't find address");
+
+ r->op = OCONST;
+ r->type = TINT;
+ r->fmt = 'V';
+}
+
+void
+interpret(Node *r, Node *args)
+{
+ Node res;
+ int isave;
+
+ if(args == 0)
+ error("interpret(string): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("interpret(string): arg type");
+
+ pushstr(&res);
+
+ isave = interactive;
+ interactive = 0;
+ r->ival = yyparse();
+ interactive = isave;
+ popio();
+ r->op = OCONST;
+ r->type = TINT;
+ r->fmt = 'D';
+}
+
+void
+include(Node *r, Node *args)
+{
+ Node res;
+ int isave;
+
+ if(args == 0)
+ error("include(string): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("include(string): arg type");
+
+ pushfile(res.string->string);
+
+ isave = interactive;
+ interactive = 0;
+ r->ival = yyparse();
+ interactive = isave;
+ popio();
+ r->op = OCONST;
+ r->type = TINT;
+ r->fmt = 'D';
+}
+
+void
+rc(Node *r, Node *args)
+{
+ Node res;
+ int pid;
+ char *p, *q, *argv[4];
+ Waitmsg *w;
+
+ USED(r);
+ if(args == 0)
+ error("error(string): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("error(string): arg type");
+
+ argv[0] = "/bin/rc";
+ argv[1] = "-c";
+ argv[2] = res.string->string;
+ argv[3] = 0;
+
+ pid = fork();
+ switch(pid) {
+ case -1:
+ error("fork %r");
+ case 0:
+ exec("/bin/rc", argv);
+ exits(0);
+ default:
+ w = waitfor(pid);
+ break;
+ }
+ p = w->msg;
+ q = strrchr(p, ':');
+ if (q)
+ p = q+1;
+
+ r->op = OCONST;
+ r->type = TSTRING;
+ r->string = strnode(p);
+ free(w);
+ r->fmt = 's';
+}
+
+void
+doerror(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ if(args == 0)
+ error("error(string): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("error(string): arg type");
+
+ error(res.string->string);
+}
+
+void
+doaccess(Node *r, Node *args)
+{
+ Node res;
+
+ if(args == 0)
+ error("access(filename): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("access(filename): arg type");
+
+ r->op = OCONST;
+ r->type = TINT;
+ r->ival = 0;
+ if(access(res.string->string, 4) == 0)
+ r->ival = 1;
+}
+
+void
+readfile(Node *r, Node *args)
+{
+ Node res;
+ int n, fd;
+ char *buf;
+ Dir *db;
+
+ if(args == 0)
+ error("readfile(filename): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("readfile(filename): arg type");
+
+ fd = open(res.string->string, OREAD);
+ if(fd < 0)
+ return;
+
+ db = dirfstat(fd);
+ if(db == nil || db->length == 0)
+ n = 8192;
+ else
+ n = db->length;
+ free(db);
+
+ buf = malloc(n);
+ n = read(fd, buf, n);
+
+ if(n > 0) {
+ r->op = OCONST;
+ r->type = TSTRING;
+ r->string = strnodlen(buf, n);
+ r->fmt = 's';
+ }
+ free(buf);
+ close(fd);
+}
+
+void
+getfile(Node *r, Node *args)
+{
+ int n;
+ char *p;
+ Node res;
+ String *s;
+ Biobuf *bp;
+ List **l, *new;
+
+ if(args == 0)
+ error("file(filename): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("file(filename): arg type");
+
+ r->op = OCONST;
+ r->type = TLIST;
+ r->l = 0;
+
+ p = res.string->string;
+ bp = Bopen(p, OREAD);
+ if(bp == 0)
+ return;
+
+ l = &r->l;
+ for(;;) {
+ p = Brdline(bp, '\n');
+ n = Blinelen(bp);
+ if(p == 0) {
+ if(n == 0)
+ break;
+ s = strnodlen(0, n);
+ Bread(bp, s->string, n);
+ }
+ else
+ s = strnodlen(p, n-1);
+
+ new = al(TSTRING);
+ new->string = s;
+ new->fmt = 's';
+ *l = new;
+ l = &new->next;
+ }
+ Bterm(bp);
+}
+
+void
+cvtatof(Node *r, Node *args)
+{
+ Node res;
+
+ if(args == 0)
+ error("atof(string): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("atof(string): arg type");
+
+ r->op = OCONST;
+ r->type = TFLOAT;
+ r->fval = atof(res.string->string);
+ r->fmt = 'f';
+}
+
+void
+cvtatoi(Node *r, Node *args)
+{
+ Node res;
+
+ if(args == 0)
+ error("atoi(string): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("atoi(string): arg type");
+
+ r->op = OCONST;
+ r->type = TINT;
+ r->ival = strtoull(res.string->string, 0, 0);
+ r->fmt = 'V';
+}
+
+static char *fmtflags = "-0123456789. #,u";
+static char *fmtverbs = "bdox";
+
+static int
+acidfmt(char *fmt, char *buf, int blen)
+{
+ char *r, *w, *e;
+
+ w = buf;
+ e = buf+blen;
+ for(r=fmt; *r; r++){
+ if(w >= e)
+ return -1;
+ if(*r != '%'){
+ *w++ = *r;
+ continue;
+ }
+ if(*r == '%'){
+ *w++ = *r++;
+ if(*r == '%'){
+ if(w >= e)
+ return -1;
+ *w++ = *r;
+ continue;
+ }
+ while(*r && strchr(fmtflags, *r)){
+ if(w >= e)
+ return -1;
+ *w++ = *r++;
+ }
+ if(*r == 0 || strchr(fmtverbs, *r) == nil)
+ return -1;
+ if(w+3 > e)
+ return -1;
+ *w++ = 'l';
+ *w++ = 'l';
+ *w++ = *r;
+ }
+ }
+ if(w >= e)
+ return -1;
+ *w = 0;
+
+ return 0;
+}
+
+void
+cvtitoa(Node *r, Node *args)
+{
+ Node res;
+ Node *av[Maxarg];
+ vlong ival;
+ char buf[128], fmt[32];
+
+ if(args == 0)
+err:
+ error("itoa(number [, fmt]): arg count");
+ na = 0;
+ flatten(av, args);
+ if(na == 0 || na > 2)
+ goto err;
+ expr(av[0], &res);
+ if(res.type != TINT)
+ error("itoa(number [, fmt]): arg type");
+ ival = res.ival;
+ strncpy(fmt, "%lld", sizeof(fmt));
+ if(na == 2){
+ expr(av[1], &res);
+ if(res.type != TSTRING)
+ error("itoa(number [, fmt]): fmt type");
+ if(acidfmt(res.string->string, fmt, sizeof(buf)))
+ error("itoa(number [, fmt]): malformed fmt");
+ }
+
+ snprint(buf, sizeof(buf), fmt, ival);
+ r->op = OCONST;
+ r->type = TSTRING;
+ r->string = strnode(buf);
+ r->fmt = 's';
+}
+
+List*
+mapent(Map *m)
+{
+ int i;
+ List *l, *n, **t, *h;
+
+ h = 0;
+ t = &h;
+ for(i = 0; i < m->nsegs; i++) {
+ if(m->seg[i].inuse == 0)
+ continue;
+ l = al(TSTRING);
+ n = al(TLIST);
+ n->l = l;
+ *t = n;
+ t = &n->next;
+ l->string = strnode(m->seg[i].name);
+ l->fmt = 's';
+ l->next = al(TINT);
+ l = l->next;
+ l->ival = m->seg[i].b;
+ l->fmt = 'W';
+ l->next = al(TINT);
+ l = l->next;
+ l->ival = m->seg[i].e;
+ l->fmt = 'W';
+ l->next = al(TINT);
+ l = l->next;
+ l->ival = m->seg[i].f;
+ l->fmt = 'W';
+ }
+ return h;
+}
+
+void
+map(Node *r, Node *args)
+{
+ int i;
+ Map *m;
+ List *l;
+ char *ent;
+ Node *av[Maxarg], res;
+
+ na = 0;
+ flatten(av, args);
+
+ if(na != 0) {
+ expr(av[0], &res);
+ if(res.type != TLIST)
+ error("map(list): map needs a list");
+ if(listlen(res.l) != 4)
+ error("map(list): list must have 4 entries");
+
+ l = res.l;
+ if(l->type != TSTRING)
+ error("map name must be a string");
+ ent = l->string->string;
+ m = symmap;
+ i = findseg(m, ent);
+ if(i < 0) {
+ m = cormap;
+ i = findseg(m, ent);
+ }
+ if(i < 0)
+ error("%s is not a map entry", ent);
+ l = l->next;
+ if(l->type != TINT)
+ error("map entry not int");
+ m->seg[i].b = l->ival;
+ if (strcmp(ent, "text") == 0)
+ textseg(l->ival, &fhdr);
+ l = l->next;
+ if(l->type != TINT)
+ error("map entry not int");
+ m->seg[i].e = l->ival;
+ l = l->next;
+ if(l->type != TINT)
+ error("map entry not int");
+ m->seg[i].f = l->ival;
+ }
+
+ r->type = TLIST;
+ r->l = 0;
+ if(symmap)
+ r->l = mapent(symmap);
+ if(cormap) {
+ if(r->l == 0)
+ r->l = mapent(cormap);
+ else {
+ for(l = r->l; l->next; l = l->next)
+ ;
+ l->next = mapent(cormap);
+ }
+ }
+}
+
+void
+flatten(Node **av, Node *n)
+{
+ if(n == 0)
+ return;
+
+ switch(n->op) {
+ case OLIST:
+ flatten(av, n->left);
+ flatten(av, n->right);
+ break;
+ default:
+ av[na++] = n;
+ if(na >= Maxarg)
+ error("too many function arguments");
+ break;
+ }
+}
+
+void
+strace(Node *r, Node *args)
+{
+ Node *av[Maxarg], *n, res;
+ uvlong pc, sp;
+
+ na = 0;
+ flatten(av, args);
+ if(na != 3)
+ error("strace(pc, sp, link): arg count");
+
+ n = av[0];
+ expr(n, &res);
+ if(res.type != TINT)
+ error("strace(pc, sp, link): pc bad type");
+ pc = res.ival;
+
+ n = av[1];
+ expr(n, &res);
+ if(res.type != TINT)
+ error("strace(pc, sp, link): sp bad type");
+ sp = res.ival;
+
+ n = av[2];
+ expr(n, &res);
+ if(res.type != TINT)
+ error("strace(pc, sp, link): link bad type");
+
+ tracelist = 0;
+ if ((*machdata->ctrace)(cormap, pc, sp, res.ival, trlist) <= 0)
+ error("no stack frame: %r");
+ r->type = TLIST;
+ r->l = tracelist;
+}
+
+void
+regerror(char *msg)
+{
+ error(msg);
+}
+
+void
+regexp(Node *r, Node *args)
+{
+ Node res;
+ Reprog *rp;
+ Node *av[Maxarg];
+
+ na = 0;
+ flatten(av, args);
+ if(na != 2)
+ error("regexp(pattern, string): arg count");
+ expr(av[0], &res);
+ if(res.type != TSTRING)
+ error("regexp(pattern, string): pattern must be string");
+ rp = regcomp(res.string->string);
+ if(rp == 0)
+ return;
+
+ expr(av[1], &res);
+ if(res.type != TSTRING)
+ error("regexp(pattern, string): bad string");
+
+ r->fmt = 'D';
+ r->type = TINT;
+ r->ival = regexec(rp, res.string->string, 0, 0);
+ free(rp);
+}
+
+void
+fmt(Node *r, Node *args)
+{
+ Node res;
+ Node *av[Maxarg];
+
+ na = 0;
+ flatten(av, args);
+ if(na != 2)
+ error("fmt(obj, fmt): arg count");
+ expr(av[1], &res);
+ if(res.type != TINT || strchr(vfmt, res.ival) == 0)
+ error("fmt(obj, fmt): bad format '%c'", (char)res.ival);
+ expr(av[0], r);
+ r->fmt = res.ival;
+}
+
+void
+patom(char type, Store *res)
+{
+ int i;
+ char buf[512];
+ extern char *typenames[];
+
+ switch(res->fmt) {
+ case 'c':
+ Bprint(bout, "%c", (int)res->ival);
+ break;
+ case 'C':
+ if(res->ival < ' ' || res->ival >= 0x7f)
+ Bprint(bout, "%3d", (int)res->ival&0xff);
+ else
+ Bprint(bout, "%3c", (int)res->ival);
+ break;
+ case 'r':
+ Bprint(bout, "%C", (int)res->ival);
+ break;
+ case 'B':
+ memset(buf, '0', 34);
+ buf[1] = 'b';
+ for(i = 0; i < 32; i++) {
+ if(res->ival & (1<<i))
+ buf[33-i] = '1';
+ }
+ buf[35] = '\0';
+ Bprint(bout, "%s", buf);
+ break;
+ case 'b':
+ Bprint(bout, "%.2x", (int)res->ival&0xff);
+ break;
+ case 'X':
+ Bprint(bout, "%.8lux", (ulong)res->ival);
+ break;
+ case 'x':
+ Bprint(bout, "%.4lux", (ulong)res->ival&0xffff);
+ break;
+ case 'D':
+ Bprint(bout, "%d", (int)res->ival);
+ break;
+ case 'd':
+ Bprint(bout, "%d", (ushort)res->ival);
+ break;
+ case 'u':
+ Bprint(bout, "%d", (int)res->ival&0xffff);
+ break;
+ case 'U':
+ Bprint(bout, "%lud", (ulong)res->ival);
+ break;
+ case 'Z':
+ Bprint(bout, "%llud", res->ival);
+ break;
+ case 'V':
+ Bprint(bout, "%lld", res->ival);
+ break;
+ case 'W':
+ Bprint(bout, "%.8llux", res->ival);
+ break;
+ case 'Y':
+ Bprint(bout, "%.16llux", res->ival);
+ break;
+ case 'o':
+ Bprint(bout, "0%.11uo", (int)res->ival&0xffff);
+ break;
+ case 'O':
+ Bprint(bout, "0%.6uo", (int)res->ival);
+ break;
+ case 'q':
+ Bprint(bout, "0%.11o", (short)(res->ival&0xffff));
+ break;
+ case 'Q':
+ Bprint(bout, "0%.6o", (int)res->ival);
+ break;
+ case 'f':
+ case 'F':
+ case '3':
+ case '8':
+ if(type != TFLOAT)
+ Bprint(bout, "*%c<%s>*", res->fmt, typenames[type]);
+ else
+ Bprint(bout, "%g", res->fval);
+ break;
+ case 's':
+ case 'g':
+ case 'G':
+ if(type != TSTRING)
+ Bprint(bout, "*%c<%s>*", res->fmt, typenames[type]);
+ else
+ Bwrite(bout, res->string->string, res->string->len);
+ break;
+ case 'R':
+ if(type != TSTRING)
+ Bprint(bout, "*%c<%s>*", res->fmt, typenames[type]);
+ else
+ Bprint(bout, "%S", (Rune*)res->string->string);
+ break;
+ case 'a':
+ case 'A':
+ symoff(buf, sizeof(buf), res->ival, CANY);
+ Bprint(bout, "%s", buf);
+ break;
+ case 'I':
+ case 'i':
+ if(type != TINT)
+ Bprint(bout, "*%c<%s>*", res->fmt, typenames[type]);
+ else {
+ if (symmap == nil || (*machdata->das)(symmap, res->ival, res->fmt, buf, sizeof(buf)) < 0)
+ Bprint(bout, "no instruction");
+ else
+ Bprint(bout, "%s", buf);
+ }
+ break;
+ }
+}
+
+void
+blprint(List *l)
+{
+ Bprint(bout, "{");
+ while(l) {
+ switch(l->type) {
+ default:
+ patom(l->type, &l->Store);
+ break;
+ case TSTRING:
+ Bputc(bout, '"');
+ patom(l->type, &l->Store);
+ Bputc(bout, '"');
+ break;
+ case TLIST:
+ blprint(l->l);
+ break;
+ case TCODE:
+ pcode(l->cc, 0);
+ break;
+ }
+ l = l->next;
+ if(l)
+ Bprint(bout, ", ");
+ }
+ Bprint(bout, "}");
+}
+
+int
+comx(Node res)
+{
+ Lsym *sl;
+ Node *n, xx;
+
+ if(res.fmt != 'a' && res.fmt != 'A')
+ return 0;
+
+ if(res.comt == 0 || res.comt->base == 0)
+ return 0;
+
+ sl = res.comt->base;
+ if(sl->proc) {
+ res.left = ZN;
+ res.right = ZN;
+ n = an(ONAME, ZN, ZN);
+ n->sym = sl;
+ n = an(OCALL, n, &res);
+ n->left->sym = sl;
+ expr(n, &xx);
+ return 1;
+ }
+ print("(%s)", sl->name);
+ return 0;
+}
+
+void
+bprint(Node *r, Node *args)
+{
+ int i, nas;
+ Node res, *av[Maxarg];
+
+ USED(r);
+ na = 0;
+ flatten(av, args);
+ nas = na;
+ for(i = 0; i < nas; i++) {
+ expr(av[i], &res);
+ switch(res.type) {
+ default:
+ if(comx(res))
+ break;
+ patom(res.type, &res.Store);
+ break;
+ case TCODE:
+ pcode(res.cc, 0);
+ break;
+ case TLIST:
+ blprint(res.l);
+ break;
+ }
+ }
+ if(ret == 0)
+ Bputc(bout, '\n');
+}
+
+void
+printto(Node *r, Node *args)
+{
+ int fd;
+ Biobuf *b;
+ int i, nas;
+ Node res, *av[Maxarg];
+
+ USED(r);
+ na = 0;
+ flatten(av, args);
+ nas = na;
+
+ expr(av[0], &res);
+ if(res.type != TSTRING)
+ error("printto(string, ...): need string");
+
+ fd = create(res.string->string, OWRITE, 0666);
+ if(fd < 0)
+ fd = open(res.string->string, OWRITE);
+ if(fd < 0)
+ error("printto: open %s: %r", res.string->string);
+
+ b = gmalloc(sizeof(Biobuf));
+ Binit(b, fd, OWRITE);
+
+ Bflush(bout);
+ io[iop++] = bout;
+ bout = b;
+
+ for(i = 1; i < nas; i++) {
+ expr(av[i], &res);
+ switch(res.type) {
+ default:
+ if(comx(res))
+ break;
+ patom(res.type, &res.Store);
+ break;
+ case TLIST:
+ blprint(res.l);
+ break;
+ }
+ }
+ if(ret == 0)
+ Bputc(bout, '\n');
+
+ Bterm(b);
+ close(fd);
+ free(b);
+ bout = io[--iop];
+}
+
+void
+pcfile(Node *r, Node *args)
+{
+ Node res;
+ char *p, buf[128];
+
+ if(args == 0)
+ error("pcfile(addr): arg count");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("pcfile(addr): arg type");
+
+ r->type = TSTRING;
+ r->fmt = 's';
+ if(fileline(buf, sizeof(buf), res.ival) == 0) {
+ r->string = strnode("?file?");
+ return;
+ }
+ p = strrchr(buf, ':');
+ if(p == 0)
+ error("pcfile(addr): funny file %s", buf);
+ *p = '\0';
+ r->string = strnode(buf);
+}
+
+void
+pcline(Node *r, Node *args)
+{
+ Node res;
+ char *p, buf[128];
+
+ if(args == 0)
+ error("pcline(addr): arg count");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("pcline(addr): arg type");
+
+ r->type = TINT;
+ r->fmt = 'D';
+ if(fileline(buf, sizeof(buf), res.ival) == 0) {
+ r->ival = 0;
+ return;
+ }
+
+ p = strrchr(buf, ':');
+ if(p == 0)
+ error("pcline(addr): funny file %s", buf);
+ r->ival = strtol(p+1, 0, 0);
+}
+
+void fmtof(Node *r, Node *args)
+{
+ Node *av[Maxarg];
+ Node res;
+
+ na = 0;
+ flatten(av, args);
+ if(na < 1)
+ error("fmtof(obj): no argument");
+ if(na > 1)
+ error("fmtof(obj): too many arguments") ;
+ expr(av[0], &res);
+
+ r->op = OCONST;
+ r->type = TINT ;
+ r->ival = res.fmt ;
+ r->fmt = 'c';
+}
+
+void dofmtsize(Node *r, Node *args)
+{
+ Node *av[Maxarg];
+ Node res;
+ Store * s ;
+ Value v ;
+
+ na = 0;
+ flatten(av, args);
+ if(na < 1)
+ error("fmtsize(obj): no argument");
+ if(na > 1)
+ error("fmtsize(obj): too many arguments") ;
+ expr(av[0], &res);
+
+ v.type = res.type ;
+ s = &v.Store ;
+ *s = res ;
+
+ r->op = OCONST;
+ r->type = TINT ;
+ r->ival = fmtsize(&v) ;
+ r->fmt = 'D';
+}
diff --git a/sys/src/cmd/acid/dbg.y b/sys/src/cmd/acid/dbg.y
new file mode 100755
index 000000000..0bc2a3d74
--- /dev/null
+++ b/sys/src/cmd/acid/dbg.y
@@ -0,0 +1,411 @@
+%{
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern extern
+#include "acid.h"
+%}
+
+%union
+{
+ Node *node;
+ Lsym *sym;
+ uvlong ival;
+ float fval;
+ String *string;
+}
+
+%type <node> expr monexpr term stmnt name args zexpr slist
+%type <node> member members mname castexpr idlist
+%type <sym> zname
+
+%left ';'
+%right '='
+%left Tfmt
+%left Toror
+%left Tandand
+%left '|'
+%left '^'
+%left '&'
+%left Teq Tneq
+%left '<' '>' Tleq Tgeq
+%left Tlsh Trsh
+%left '+' '-'
+%left '*' '/' '%'
+%right Tdec Tinc Tindir '.' '[' '('
+
+%token <sym> Tid
+%token <ival> Tconst Tfmt
+%token <fval> Tfconst
+%token <string> Tstring
+%token Tif Tdo Tthen Telse Twhile Tloop Thead Ttail Tappend Tfn Tret Tlocal
+%token Tcomplex Twhat Tdelete Teval Tbuiltin
+
+%%
+
+prog :
+ | prog bigstmnt
+ ;
+
+bigstmnt : stmnt
+ {
+ /* make stmnt a root so it isn't collected! */
+ mkvar("_thiscmd")->proc = $1;
+ execute($1);
+ mkvar("_thiscmd")->proc = nil;
+ gc();
+ if(interactive)
+ Bprint(bout, "acid: ");
+ }
+ | Tfn Tid '(' args ')' zsemi '{' slist '}'
+ {
+ $2->proc = an(OLIST, $4, $8);
+ }
+ | Tfn Tid
+ {
+ $2->proc = nil;
+ }
+ | Tcomplex name '{' members '}' ';'
+ {
+ defcomplex($2, $4);
+ }
+ ;
+
+zsemi :
+ | ';' zsemi
+
+members : member
+ | members member
+ {
+ $$ = an(OLIST, $1, $2);
+ }
+ ;
+
+mname : Tid
+ {
+ $$ = an(ONAME, ZN, ZN);
+ $$->sym = $1;
+ }
+ ;
+
+member : Tconst Tconst mname ';'
+ {
+ $3->ival = $2;
+ $3->fmt = $1;
+ $$ = $3;
+ }
+ | Tconst mname Tconst mname ';'
+ {
+ $4->ival = $3;
+ $4->fmt = $1;
+ $4->right = $2;
+ $$ = $4;
+ }
+ | mname Tconst mname ';'
+ {
+ $3->ival = $2;
+ $3->left = $1;
+ $$ = $3;
+ }
+ | '{' members '}' ';'
+ {
+ $$ = an(OCTRUCT, $2, ZN);
+ }
+ ;
+
+zname :
+ { $$ = 0; }
+ | Tid
+ ;
+
+slist : stmnt
+ | slist stmnt
+ {
+ $$ = an(OLIST, $1, $2);
+ }
+ ;
+
+stmnt : zexpr ';'
+ | '{' slist '}'
+ {
+ $$ = $2;
+ }
+ | Tif expr Tthen stmnt
+ {
+ $$ = an(OIF, $2, $4);
+ }
+ | Tif expr Tthen stmnt Telse stmnt
+ {
+ $$ = an(OIF, $2, an(OELSE, $4, $6));
+ }
+ | Tloop expr ',' expr Tdo stmnt
+ {
+ $$ = an(ODO, an(OLIST, $2, $4), $6);
+ }
+ | Twhile expr Tdo stmnt
+ {
+ $$ = an(OWHILE, $2, $4);
+ }
+ | Tret expr ';'
+ {
+ $$ = an(ORET, $2, ZN);
+ }
+ | Tlocal idlist
+ {
+ $$ = an(OLOCAL, $2, ZN);
+ }
+ | Tcomplex Tid name ';'
+ {
+ $$ = an(OCOMPLEX, $3, ZN);
+ $$->sym = $2;
+ }
+ ;
+
+idlist : Tid
+ {
+ $$ = an(ONAME, ZN, ZN);
+ $$->sym = $1;
+ }
+ | idlist ',' Tid
+ {
+ $$ = an(ONAME, $1, ZN);
+ $$->sym = $3;
+ }
+ ;
+
+zexpr :
+ { $$ = 0; }
+ | expr
+ ;
+
+expr : castexpr
+ | expr '*' expr
+ {
+ $$ = an(OMUL, $1, $3);
+ }
+ | expr '/' expr
+ {
+ $$ = an(ODIV, $1, $3);
+ }
+ | expr '%' expr
+ {
+ $$ = an(OMOD, $1, $3);
+ }
+ | expr '+' expr
+ {
+ $$ = an(OADD, $1, $3);
+ }
+ | expr '-' expr
+ {
+ $$ = an(OSUB, $1, $3);
+ }
+ | expr Trsh expr
+ {
+ $$ = an(ORSH, $1, $3);
+ }
+ | expr Tlsh expr
+ {
+ $$ = an(OLSH, $1, $3);
+ }
+ | expr '<' expr
+ {
+ $$ = an(OLT, $1, $3);
+ }
+ | expr '>' expr
+ {
+ $$ = an(OGT, $1, $3);
+ }
+ | expr Tleq expr
+ {
+ $$ = an(OLEQ, $1, $3);
+ }
+ | expr Tgeq expr
+ {
+ $$ = an(OGEQ, $1, $3);
+ }
+ | expr Teq expr
+ {
+ $$ = an(OEQ, $1, $3);
+ }
+ | expr Tneq expr
+ {
+ $$ = an(ONEQ, $1, $3);
+ }
+ | expr '&' expr
+ {
+ $$ = an(OLAND, $1, $3);
+ }
+ | expr '^' expr
+ {
+ $$ = an(OXOR, $1, $3);
+ }
+ | expr '|' expr
+ {
+ $$ = an(OLOR, $1, $3);
+ }
+ | expr Tandand expr
+ {
+ $$ = an(OCAND, $1, $3);
+ }
+ | expr Toror expr
+ {
+ $$ = an(OCOR, $1, $3);
+ }
+ | expr '=' expr
+ {
+ $$ = an(OASGN, $1, $3);
+ }
+ | expr Tfmt
+ {
+ $$ = an(OFMT, $1, con($2));
+ }
+ ;
+
+castexpr : monexpr
+ | '(' Tid ')' monexpr
+ {
+ $$ = an(OCAST, $4, ZN);
+ $$->sym = $2;
+ }
+ ;
+
+monexpr : term
+ | '*' monexpr
+ {
+ $$ = an(OINDM, $2, ZN);
+ }
+ | '@' monexpr
+ {
+ $$ = an(OINDC, $2, ZN);
+ }
+ | '+' monexpr
+ {
+ $$ = an(OADD, $2, ZN);
+ }
+ | '-' monexpr
+ {
+ $$ = con(0);
+ $$ = an(OSUB, $$, $2);
+ }
+ | Tdec monexpr
+ {
+ $$ = an(OEDEC, $2, ZN);
+ }
+ | Tinc monexpr
+ {
+ $$ = an(OEINC, $2, ZN);
+ }
+ | Thead monexpr
+ {
+ $$ = an(OHEAD, $2, ZN);
+ }
+ | Ttail monexpr
+ {
+ $$ = an(OTAIL, $2, ZN);
+ }
+ | Tappend monexpr ',' monexpr
+ {
+ $$ = an(OAPPEND, $2, $4);
+ }
+ | Tdelete monexpr ',' monexpr
+ {
+ $$ = an(ODELETE, $2, $4);
+ }
+ | '!' monexpr
+ {
+ $$ = an(ONOT, $2, ZN);
+ }
+ | '~' monexpr
+ {
+ $$ = an(OXOR, $2, con(-1));
+ }
+ | Teval monexpr
+ {
+ $$ = an(OEVAL, $2, ZN);
+ }
+ ;
+
+term : '(' expr ')'
+ {
+ $$ = $2;
+ }
+ | '{' args '}'
+ {
+ $$ = an(OCTRUCT, $2, ZN);
+ }
+ | term '[' expr ']'
+ {
+ $$ = an(OINDEX, $1, $3);
+ }
+ | term Tdec
+ {
+ $$ = an(OPDEC, $1, ZN);
+ }
+ | term '.' Tid
+ {
+ $$ = an(ODOT, $1, ZN);
+ $$->sym = $3;
+ }
+ | term Tindir Tid
+ {
+ $$ = an(ODOT, an(OINDM, $1, ZN), ZN);
+ $$->sym = $3;
+ }
+ | term Tinc
+ {
+ $$ = an(OPINC, $1, ZN);
+ }
+ | name '(' args ')'
+ {
+ $$ = an(OCALL, $1, $3);
+ }
+ | Tbuiltin name '(' args ')'
+ {
+ $$ = an(OCALL, $2, $4);
+ $$->builtin = 1;
+ }
+ | name
+ | Tconst
+ {
+ $$ = con($1);
+ }
+ | Tfconst
+ {
+ $$ = an(OCONST, ZN, ZN);
+ $$->type = TFLOAT;
+ $$->fmt = 'f';
+ $$->fval = $1;
+ }
+ | Tstring
+ {
+ $$ = an(OCONST, ZN, ZN);
+ $$->type = TSTRING;
+ $$->string = $1;
+ $$->fmt = 's';
+ }
+ | Twhat zname
+ {
+ $$ = an(OWHAT, ZN, ZN);
+ $$->sym = $2;
+ }
+ ;
+
+name : Tid
+ {
+ $$ = an(ONAME, ZN, ZN);
+ $$->sym = $1;
+ }
+ | Tid ':' name
+ {
+ $$ = an(OFRAME, $3, ZN);
+ $$->sym = $1;
+ }
+ ;
+
+args : zexpr
+ | args ',' zexpr
+ {
+ $$ = an(OLIST, $1, $3);
+ }
+ ;
diff --git a/sys/src/cmd/acid/dot.c b/sys/src/cmd/acid/dot.c
new file mode 100755
index 000000000..4ff1d61e4
--- /dev/null
+++ b/sys/src/cmd/acid/dot.c
@@ -0,0 +1,153 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ctype.h>
+#include <mach.h>
+#define Extern extern
+#include "acid.h"
+
+Type*
+srch(Type *t, char *s)
+{
+ Type *f;
+
+ f = 0;
+ while(t) {
+ if(strcmp(t->tag->name, s) == 0) {
+ if(f == 0 || t->depth < f->depth)
+ f = t;
+ }
+ t = t->next;
+ }
+ return f;
+}
+
+void
+odot(Node *n, Node *r)
+{
+ char *s;
+ Type *t;
+ Node res;
+ uvlong addr;
+
+ s = n->sym->name;
+ if(s == 0)
+ fatal("dodot: no tag");
+
+ expr(n->left, &res);
+ if(res.comt == 0)
+ error("no type specified for (expr).%s", s);
+
+ if(res.type != TINT)
+ error("pointer must be integer for (expr).%s", s);
+
+ t = srch(res.comt, s);
+ if(t == 0)
+ error("no tag for (expr).%s", s);
+
+ /* Propagate types */
+ if(t->type)
+ r->comt = t->type->lt;
+
+ addr = res.ival+t->offset;
+ if(t->fmt == 'a') {
+ r->op = OCONST;
+ r->fmt = 'a';
+ r->type = TINT;
+ r->ival = addr;
+ }
+ else
+ indir(cormap, addr, t->fmt, r);
+
+}
+
+static Type **tail;
+static Lsym *base;
+
+void
+buildtype(Node *m, int d)
+{
+ Type *t;
+
+ if(m == ZN)
+ return;
+
+ switch(m->op) {
+ case OLIST:
+ buildtype(m->left, d);
+ buildtype(m->right, d);
+ break;
+
+ case OCTRUCT:
+ buildtype(m->left, d+1);
+ break;
+ default:
+ t = malloc(sizeof(Type));
+ t->next = 0;
+ t->depth = d;
+ t->tag = m->sym;
+ t->base = base;
+ t->offset = m->ival;
+ if(m->left) {
+ t->type = m->left->sym;
+ t->fmt = 'a';
+ }
+ else {
+ t->type = 0;
+ if(m->right)
+ t->type = m->right->sym;
+ t->fmt = m->fmt;
+ }
+
+ *tail = t;
+ tail = &t->next;
+ }
+}
+
+void
+defcomplex(Node *tn, Node *m)
+{
+ tail = &tn->sym->lt;
+ base = tn->sym;
+ buildtype(m, 0);
+}
+
+void
+decl(Node *n)
+{
+ Node *l;
+ Value *v;
+ Frtype *f;
+ Lsym *type;
+
+ type = n->sym;
+ if(type->lt == 0)
+ error("%s is not a complex type", type->name);
+
+ l = n->left;
+ if(l->op == ONAME) {
+ v = l->sym->v;
+ v->comt = type->lt;
+ v->fmt = 'a';
+ return;
+ }
+
+ /*
+ * Frame declaration
+ */
+ for(f = l->sym->local; f; f = f->next) {
+ if(f->var == l->left->sym) {
+ f->type = n->sym->lt;
+ return;
+ }
+ }
+ f = malloc(sizeof(Frtype));
+ if(f == 0)
+ fatal("out of memory");
+
+ f->type = type->lt;
+
+ f->var = l->left->sym;
+ f->next = l->sym->local;
+ l->sym->local = f;
+}
diff --git a/sys/src/cmd/acid/exec.c b/sys/src/cmd/acid/exec.c
new file mode 100755
index 000000000..3d9bd590b
--- /dev/null
+++ b/sys/src/cmd/acid/exec.c
@@ -0,0 +1,498 @@
+#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, "%L: (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;
+ vlong 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.l == 0 && n->op != OADD))
+ 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.ival;
+ expr(l->right, &res);
+ if(res.type != TINT)
+ error("loop must have integer end");
+ e = res.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->ival != 0)
+ true = 1;
+ break;
+ case TFLOAT:
+ if(n->fval != 0.0)
+ true = 1;
+ break;
+ case TSTRING:
+ if(n->string->len)
+ true = 1;
+ break;
+ case TLIST:
+ if(n->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->fmt = 's';
+ r->string = strnode(flt);
+ }
+ else {
+ r->type = TFLOAT;
+ r->fval = atof(flt);
+ }
+}
+
+void
+indir(Map *m, uvlong addr, char fmt, Node *r)
+{
+ int i;
+ ulong lval;
+ uvlong uvval;
+ int ret;
+ uchar cval;
+ ushort sval;
+ char buf[512], reg[12];
+
+ r->op = OCONST;
+ r->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->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->ival = sval;
+ break;
+ case 'a':
+ case 'A':
+ case 'W':
+ r->type = TINT;
+ ret = geta(m, addr, &uvval);
+ if (ret < 0)
+ error("indir: %r");
+ r->ival = uvval;
+ break;
+ case 'B':
+ case 'X':
+ case 'D':
+ case 'U':
+ case 'O':
+ case 'Q':
+ r->type = TINT;
+ ret = get4(m, addr, &lval);
+ if (ret < 0)
+ error("indir: %r");
+ r->ival = lval;
+ break;
+ case 'V':
+ case 'Y':
+ case 'Z':
+ r->type = TINT;
+ ret = get8(m, addr, &uvval);
+ if (ret < 0)
+ error("indir: %r");
+ r->ival = uvval;
+ 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->string = strnode(buf);
+ break;
+ case 'R':
+ r->type = TSTRING;
+ for(i = 0; i < sizeof(buf)-2; i += 2) {
+ ret = get1(m, addr, (uchar*)&buf[i], 2);
+ if (ret < 0)
+ error("indir: %r");
+ addr += 2;
+ if(buf[i] == 0 && buf[i+1] == 0)
+ break;
+ }
+ buf[i++] = 0;
+ buf[i] = 0;
+ r->string = runenode((Rune*)buf);
+ break;
+ case 'i':
+ case 'I':
+ if ((*machdata->das)(m, addr, fmt, buf, sizeof(buf)) < 0)
+ error("indir: %r");
+ r->type = TSTRING;
+ r->fmt = 's';
+ r->string = strnode(buf);
+ break;
+ case 'f':
+ ret = get1(m, addr, (uchar*)buf, mach->szfloat);
+ if (ret < 0)
+ error("indir: %r");
+ machdata->sftos(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");
+ machdata->sftos(buf, sizeof(buf), (void*) buf);
+ r->type = TSTRING;
+ r->string = strnode(buf);
+ break;
+ case 'F':
+ ret = get1(m, addr, (uchar*)buf, mach->szdouble);
+ if (ret < 0)
+ error("indir: %r");
+ machdata->dftos(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 */
+ leieee80ftos(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");
+ beieee80ftos(buf, sizeof(buf), reg);
+ convflt(r, buf);
+ break;
+ case 'G':
+ ret = get1(m, addr, (uchar*)buf, mach->szdouble);
+ if (ret < 0)
+ error("indir: %r");
+ machdata->dftos(buf, sizeof(buf), (void*) buf);
+ r->type = TSTRING;
+ r->string = strnode(buf);
+ break;
+ }
+}
+
+void
+windir(Map *m, Node *addr, Node *rval, Node *r)
+{
+ uchar cval;
+ ushort sval;
+ long lval;
+ Node res, aes;
+ int ret;
+
+ if(m == 0)
+ error("no map for */@=");
+
+ expr(rval, &res);
+ expr(addr, &aes);
+
+ if(aes.type != TINT)
+ error("bad type lhs of @/*");
+
+ if(m != cormap && wtflag == 0)
+ error("not in write mode");
+
+ r->type = res.type;
+ r->fmt = res.fmt;
+ r->Store = res.Store;
+
+ switch(res.fmt) {
+ default:
+ error("bad pointer format '%c' for */@=", res.fmt);
+ case 'c':
+ case 'C':
+ case 'b':
+ cval = res.ival;
+ ret = put1(m, aes.ival, &cval, 1);
+ break;
+ case 'r':
+ case 'x':
+ case 'd':
+ case 'u':
+ case 'o':
+ sval = res.ival;
+ ret = put2(m, aes.ival, sval);
+ r->ival = sval;
+ break;
+ case 'a':
+ case 'A':
+ case 'W':
+ ret = puta(m, aes.ival, res.ival);
+ break;
+ case 'B':
+ case 'X':
+ case 'D':
+ case 'U':
+ case 'O':
+ lval = res.ival;
+ ret = put4(m, aes.ival, lval);
+ break;
+ case 'V':
+ case 'Y':
+ case 'Z':
+ ret = put8(m, aes.ival, res.ival);
+ break;
+ case 's':
+ case 'R':
+ ret = put1(m, aes.ival, (uchar*)res.string->string, res.string->len);
+ break;
+ }
+ if (ret < 0)
+ error("windir: %r");
+}
+
+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.cc = avp[i];
+ res.type = TCODE;
+ res.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);
+ }
+}
diff --git a/sys/src/cmd/acid/expr.c b/sys/src/cmd/acid/expr.c
new file mode 100755
index 000000000..b13c625db
--- /dev/null
+++ b/sys/src/cmd/acid/expr.c
@@ -0,0 +1,1041 @@
+#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,
+};
diff --git a/sys/src/cmd/acid/lex.c b/sys/src/cmd/acid/lex.c
new file mode 100755
index 000000000..ca28548c1
--- /dev/null
+++ b/sys/src/cmd/acid/lex.c
@@ -0,0 +1,609 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ctype.h>
+#include <mach.h>
+#define Extern extern
+#include "acid.h"
+#include "y.tab.h"
+
+struct keywd
+{
+ char *name;
+ int terminal;
+}
+keywds[] =
+{
+ "do", Tdo,
+ "if", Tif,
+ "then", Tthen,
+ "else", Telse,
+ "while", Twhile,
+ "loop", Tloop,
+ "head", Thead,
+ "tail", Ttail,
+ "append", Tappend,
+ "defn", Tfn,
+ "return", Tret,
+ "local", Tlocal,
+ "aggr", Tcomplex,
+ "union", Tcomplex,
+ "adt", Tcomplex,
+ "complex", Tcomplex,
+ "delete", Tdelete,
+ "whatis", Twhat,
+ "eval", Teval,
+ "builtin", Tbuiltin,
+ 0, 0
+};
+
+char cmap[256] =
+{
+ ['0'] '\0'+1,
+ ['n'] '\n'+1,
+ ['r'] '\r'+1,
+ ['t'] '\t'+1,
+ ['b'] '\b'+1,
+ ['f'] '\f'+1,
+ ['a'] '\a'+1,
+ ['v'] '\v'+1,
+ ['\\'] '\\'+1,
+ ['"'] '"'+1,
+};
+
+void
+kinit(void)
+{
+ int i;
+
+ for(i = 0; keywds[i].name; i++)
+ enter(keywds[i].name, keywds[i].terminal);
+}
+
+typedef struct IOstack IOstack;
+struct IOstack
+{
+ char *name;
+ int line;
+ char *text;
+ char *ip;
+ Biobuf *fin;
+ IOstack *prev;
+};
+IOstack *lexio;
+
+void
+pushfile(char *file)
+{
+ Biobuf *b;
+ IOstack *io;
+
+ if(file)
+ b = Bopen(file, OREAD);
+ else{
+ b = Bopen("/fd/0", OREAD);
+ file = "<stdin>";
+ }
+
+ if(b == 0)
+ error("pushfile: %s: %r", file);
+
+ io = malloc(sizeof(IOstack));
+ if(io == 0)
+ fatal("no memory");
+ io->name = strdup(file);
+ if(io->name == 0)
+ fatal("no memory");
+ io->line = line;
+ line = 1;
+ io->text = 0;
+ io->fin = b;
+ io->prev = lexio;
+ lexio = io;
+}
+
+void
+pushstr(Node *s)
+{
+ IOstack *io;
+
+ io = malloc(sizeof(IOstack));
+ if(io == 0)
+ fatal("no memory");
+ io->line = line;
+ line = 1;
+ io->name = strdup("<string>");
+ if(io->name == 0)
+ fatal("no memory");
+ io->line = line;
+ line = 1;
+ io->text = strdup(s->string->string);
+ if(io->text == 0)
+ fatal("no memory");
+ io->ip = io->text;
+ io->fin = 0;
+ io->prev = lexio;
+ lexio = io;
+}
+
+void
+restartio(void)
+{
+ Bflush(lexio->fin);
+ Binit(lexio->fin, 0, OREAD);
+}
+
+int
+popio(void)
+{
+ IOstack *s;
+
+ if(lexio == 0)
+ return 0;
+
+ if(lexio->prev == 0){
+ if(lexio->fin)
+ restartio();
+ return 0;
+ }
+
+ if(lexio->fin)
+ Bterm(lexio->fin);
+ else
+ free(lexio->text);
+ free(lexio->name);
+ line = lexio->line;
+ s = lexio;
+ lexio = s->prev;
+ free(s);
+ return 1;
+}
+
+int
+Lfmt(Fmt *f)
+{
+ int i;
+ char buf[1024];
+ IOstack *e;
+
+ e = lexio;
+ if(e) {
+ i = snprint(buf, sizeof(buf), "%s:%d", e->name, line);
+ while(e->prev) {
+ e = e->prev;
+ if(initialising && e->prev == 0)
+ break;
+ i += snprint(buf+i, sizeof(buf)-i, " [%s:%d]", e->name, e->line);
+ }
+ } else
+ snprint(buf, sizeof(buf), "no file:0");
+ fmtstrcpy(f, buf);
+ return 0;
+}
+
+void
+unlexc(int s)
+{
+ if(s == '\n')
+ line--;
+
+ if(lexio->fin)
+ Bungetc(lexio->fin);
+ else
+ lexio->ip--;
+}
+
+int
+lexc(void)
+{
+ int c;
+
+ if(lexio->fin) {
+ c = Bgetc(lexio->fin);
+ if(gotint)
+ error("interrupt");
+ return c;
+ }
+
+ c = *lexio->ip++;
+ if(c == 0)
+ return -1;
+ return c;
+}
+
+int
+escchar(char c)
+{
+ int n;
+ char buf[Strsize];
+
+ if(c >= '0' && c <= '9') {
+ n = 1;
+ buf[0] = c;
+ for(;;) {
+ c = lexc();
+ if(c == Eof)
+ error("%d: <eof> in escape sequence", line);
+ if(strchr("0123456789xX", c) == 0) {
+ unlexc(c);
+ break;
+ }
+ if(n >= Strsize)
+ error("string escape too long");
+ buf[n++] = c;
+ }
+ buf[n] = '\0';
+ return strtol(buf, 0, 0);
+ }
+
+ n = cmap[c];
+ if(n == 0)
+ return c;
+ return n-1;
+}
+
+void
+eatstring(void)
+{
+ int esc, c, cnt;
+ char buf[Strsize];
+
+ esc = 0;
+ for(cnt = 0;;) {
+ c = lexc();
+ switch(c) {
+ case Eof:
+ error("%d: <eof> in string constant", line);
+
+ case '\n':
+ error("newline in string constant");
+ goto done;
+
+ case '\\':
+ if(esc)
+ goto Default;
+ esc = 1;
+ break;
+
+ case '"':
+ if(esc == 0)
+ goto done;
+
+ /* Fall through */
+ default:
+ Default:
+ if(esc) {
+ c = escchar(c);
+ esc = 0;
+ }
+ buf[cnt++] = c;
+ break;
+ }
+ if(cnt >= Strsize)
+ error("string token too long");
+ }
+done:
+ buf[cnt] = '\0';
+ yylval.string = strnode(buf);
+}
+
+void
+eatnl(void)
+{
+ int c;
+
+ line++;
+ for(;;) {
+ c = lexc();
+ if(c == Eof)
+ error("eof in comment");
+ if(c == '\n')
+ return;
+ }
+}
+
+int
+yylex(void)
+{
+ int c;
+ extern char vfmt[];
+
+loop:
+ Bflush(bout);
+ c = lexc();
+ switch(c) {
+ case Eof:
+ if(gotint) {
+ gotint = 0;
+ stacked = 0;
+ Bprint(bout, "\nacid: ");
+ goto loop;
+ }
+ return Eof;
+
+ case '"':
+ eatstring();
+ return Tstring;
+
+ case ' ':
+ case '\t':
+ goto loop;
+
+ case '\n':
+ line++;
+ if(interactive == 0)
+ goto loop;
+ if(stacked) {
+ print("\t");
+ goto loop;
+ }
+ return ';';
+
+ case '.':
+ c = lexc();
+ unlexc(c);
+ if(isdigit(c))
+ return numsym('.');
+
+ return '.';
+
+ case '(':
+ case ')':
+ case '[':
+ case ']':
+ case ';':
+ case ':':
+ case ',':
+ case '~':
+ case '?':
+ case '*':
+ case '@':
+ case '^':
+ case '%':
+ return c;
+ case '{':
+ stacked++;
+ return c;
+ case '}':
+ stacked--;
+ return c;
+
+ case '\\':
+ c = lexc();
+ if(strchr(vfmt, c) == 0) {
+ unlexc(c);
+ return '\\';
+ }
+ yylval.ival = c;
+ return Tfmt;
+
+ case '!':
+ c = lexc();
+ if(c == '=')
+ return Tneq;
+ unlexc(c);
+ return '!';
+
+ case '+':
+ c = lexc();
+ if(c == '+')
+ return Tinc;
+ unlexc(c);
+ return '+';
+
+ case '/':
+ c = lexc();
+ if(c == '/') {
+ eatnl();
+ goto loop;
+ }
+ unlexc(c);
+ return '/';
+
+ case '\'':
+ c = lexc();
+ if(c == '\\')
+ yylval.ival = escchar(lexc());
+ else
+ yylval.ival = c;
+ c = lexc();
+ if(c != '\'') {
+ error("missing '");
+ unlexc(c);
+ }
+ return Tconst;
+
+ case '&':
+ c = lexc();
+ if(c == '&')
+ return Tandand;
+ unlexc(c);
+ return '&';
+
+ case '=':
+ c = lexc();
+ if(c == '=')
+ return Teq;
+ unlexc(c);
+ return '=';
+
+ case '|':
+ c = lexc();
+ if(c == '|')
+ return Toror;
+ unlexc(c);
+ return '|';
+
+ case '<':
+ c = lexc();
+ if(c == '=')
+ return Tleq;
+ if(c == '<')
+ return Tlsh;
+ unlexc(c);
+ return '<';
+
+ case '>':
+ c = lexc();
+ if(c == '=')
+ return Tgeq;
+ if(c == '>')
+ return Trsh;
+ unlexc(c);
+ return '>';
+
+ case '-':
+ c = lexc();
+
+ if(c == '>')
+ return Tindir;
+
+ if(c == '-')
+ return Tdec;
+ unlexc(c);
+ return '-';
+
+ default:
+ return numsym(c);
+ }
+}
+
+int
+numsym(char first)
+{
+ int c, isbin, isfloat, ishex;
+ char *sel, *p;
+ Lsym *s;
+
+ symbol[0] = first;
+ p = symbol;
+
+ ishex = 0;
+ isbin = 0;
+ isfloat = 0;
+ if(first == '.')
+ isfloat = 1;
+
+ if(isdigit(*p++) || isfloat) {
+ for(;;) {
+ c = lexc();
+ if(c < 0)
+ error("%d: <eof> eating symbols", line);
+
+ if(c == '\n')
+ line++;
+ sel = "01234567890.xb";
+ if(ishex)
+ sel = "01234567890abcdefABCDEF";
+ else if(isbin)
+ sel = "01";
+ else if(isfloat)
+ sel = "01234567890eE-+";
+
+ if(strchr(sel, c) == 0) {
+ unlexc(c);
+ break;
+ }
+ if(c == '.')
+ isfloat = 1;
+ if(!isbin && c == 'x')
+ ishex = 1;
+ if(!ishex && c == 'b')
+ isbin = 1;
+ *p++ = c;
+ }
+ *p = '\0';
+ if(isfloat) {
+ yylval.fval = atof(symbol);
+ return Tfconst;
+ }
+
+ if(isbin)
+ yylval.ival = strtoull(symbol+2, 0, 2);
+ else
+ yylval.ival = strtoull(symbol, 0, 0);
+ return Tconst;
+ }
+
+ for(;;) {
+ c = lexc();
+ if(c < 0)
+ error("%d <eof> eating symbols", line);
+ if(c == '\n')
+ line++;
+ if(c != '_' && c != '$' && c <= '~' && !isalnum(c)) { /* checking against ~ lets UTF names through */
+ unlexc(c);
+ break;
+ }
+ *p++ = c;
+ }
+
+ *p = '\0';
+
+ s = look(symbol);
+ if(s == 0)
+ s = enter(symbol, Tid);
+
+ yylval.sym = s;
+ return s->lexval;
+}
+
+Lsym*
+enter(char *name, int t)
+{
+ Lsym *s;
+ uint h;
+ char *p;
+ Value *v;
+
+ h = 0;
+ for(p = name; *p; p++)
+ h = h*3 + *p;
+ h %= Hashsize;
+
+ s = gmalloc(sizeof(Lsym));
+ memset(s, 0, sizeof(Lsym));
+ s->name = strdup(name);
+
+ s->hash = hash[h];
+ hash[h] = s;
+ s->lexval = t;
+
+ v = gmalloc(sizeof(Value));
+ s->v = v;
+
+ v->fmt = 'X';
+ v->type = TINT;
+ memset(v, 0, sizeof(Value));
+
+ return s;
+}
+
+Lsym*
+look(char *name)
+{
+ Lsym *s;
+ uint h;
+ char *p;
+
+ h = 0;
+ for(p = name; *p; p++)
+ h = h*3 + *p;
+ h %= Hashsize;
+
+ for(s = hash[h]; s; s = s->hash)
+ if(strcmp(name, s->name) == 0)
+ return s;
+ return 0;
+}
+
+Lsym*
+mkvar(char *s)
+{
+ Lsym *l;
+
+ l = look(s);
+ if(l == 0)
+ l = enter(s, Tid);
+ return l;
+}
diff --git a/sys/src/cmd/acid/list.c b/sys/src/cmd/acid/list.c
new file mode 100755
index 000000000..5ad7c54e4
--- /dev/null
+++ b/sys/src/cmd/acid/list.c
@@ -0,0 +1,277 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ctype.h>
+#include <mach.h>
+#define Extern extern
+#include "acid.h"
+
+static List **tail;
+
+List*
+construct(Node *l)
+{
+ List *lh, **save;
+
+ save = tail;
+ lh = 0;
+ tail = &lh;
+ build(l);
+ tail = save;
+
+ return lh;
+}
+
+int
+listlen(List *l)
+{
+ int len;
+
+ len = 0;
+ while(l) {
+ len++;
+ l = l->next;
+ }
+ return len;
+}
+
+void
+build(Node *n)
+{
+ List *l;
+ Node res;
+
+ if(n == 0)
+ return;
+
+ switch(n->op) {
+ case OLIST:
+ build(n->left);
+ build(n->right);
+ return;
+ default:
+ expr(n, &res);
+ l = al(res.type);
+ l->Store = res.Store;
+ *tail = l;
+ tail = &l->next;
+ }
+}
+
+List*
+addlist(List *l, List *r)
+{
+ List *f;
+
+ if(l == 0)
+ return r;
+
+ for(f = l; f->next; f = f->next)
+ ;
+ f->next = r;
+
+ return l;
+}
+
+void
+append(Node *r, Node *list, Node *val)
+{
+ List *l, *f;
+
+ l = al(val->type);
+ l->Store = val->Store;
+ l->next = 0;
+
+ r->op = OCONST;
+ r->type = TLIST;
+
+ if(list->l == 0) {
+ list->l = l;
+ r->l = l;
+ return;
+ }
+ for(f = list->l; f->next; f = f->next)
+ ;
+ f->next = l;
+ r->l = list->l;
+}
+
+int
+listcmp(List *l, List *r)
+{
+ if(l == r)
+ return 1;
+
+ while(l) {
+ if(r == 0)
+ return 0;
+ if(l->type != r->type)
+ return 0;
+ switch(l->type) {
+ case TINT:
+ if(l->ival != r->ival)
+ return 0;
+ break;
+ case TFLOAT:
+ if(l->fval != r->fval)
+ return 0;
+ break;
+ case TSTRING:
+ if(scmp(l->string, r->string) == 0)
+ return 0;
+ break;
+ case TLIST:
+ if(listcmp(l->l, r->l) == 0)
+ return 0;
+ break;
+ }
+ l = l->next;
+ r = r->next;
+ }
+ if(l != r)
+ return 0;
+ return 1;
+}
+
+void
+nthelem(List *l, int n, Node *res)
+{
+ if(n < 0)
+ error("negative index in []");
+
+ while(l && n--)
+ l = l->next;
+
+ res->op = OCONST;
+ if(l == 0) {
+ res->type = TLIST;
+ res->l = 0;
+ return;
+ }
+ res->type = l->type;
+ res->Store = l->Store;
+}
+
+void
+delete(List *l, int n, Node *res)
+{
+ List **tl;
+
+ if(n < 0)
+ error("negative index in delete");
+
+ res->op = OCONST;
+ res->type = TLIST;
+ res->l = l;
+
+ for(tl = &res->l; l && n--; l = l->next)
+ tl = &l->next;
+
+ if(l == 0)
+ error("element beyond end of list");
+ *tl = l->next;
+}
+
+List*
+listvar(char *s, vlong v)
+{
+ List *l, *tl;
+
+ tl = al(TLIST);
+
+ l = al(TSTRING);
+ tl->l = l;
+ l->fmt = 's';
+ l->string = strnode(s);
+ l->next = al(TINT);
+ l = l->next;
+ l->fmt = 'X';
+ l->ival = v;
+
+ return tl;
+}
+
+static List*
+listlocals(Map *map, Symbol *fn, uvlong fp)
+{
+ int i;
+ uvlong val;
+ Symbol s;
+ List **tail, *l2;
+
+ l2 = 0;
+ tail = &l2;
+ s = *fn;
+
+ for(i = 0; localsym(&s, i); i++) {
+ if(s.class != CAUTO)
+ continue;
+ if(s.name[0] == '.')
+ continue;
+
+ if(geta(map, fp-s.value, &val) > 0) {
+ *tail = listvar(s.name, val);
+ tail = &(*tail)->next;
+ }
+ }
+ return l2;
+}
+
+static List*
+listparams(Map *map, Symbol *fn, uvlong fp)
+{
+ int i;
+ Symbol s;
+ uvlong v;
+ List **tail, *l2;
+
+ l2 = 0;
+ tail = &l2;
+ fp += mach->szaddr; /* skip saved pc */
+ s = *fn;
+ for(i = 0; localsym(&s, i); i++) {
+ if (s.class != CPARAM)
+ continue;
+
+ if(geta(map, fp+s.value, &v) > 0) {
+ *tail = listvar(s.name, v);
+ tail = &(*tail)->next;
+ }
+ }
+ return l2;
+}
+
+void
+trlist(Map *map, uvlong pc, uvlong sp, Symbol *sym)
+{
+ List *q, *l;
+
+ static List **tail;
+
+ if (tracelist == 0) { /* first time */
+ tracelist = al(TLIST);
+ tail = &tracelist;
+ }
+
+ q = al(TLIST);
+ *tail = q;
+ tail = &q->next;
+
+ l = al(TINT); /* Function address */
+ q->l = l;
+ l->ival = sym->value;
+ l->fmt = 'X';
+
+ l->next = al(TINT); /* called from address */
+ l = l->next;
+ l->ival = pc;
+ l->fmt = 'Y';
+
+ l->next = al(TLIST); /* make list of params */
+ l = l->next;
+ l->l = listparams(map, sym, sp);
+
+ l->next = al(TLIST); /* make list of locals */
+ l = l->next;
+ l->l = listlocals(map, sym, sp);
+}
diff --git a/sys/src/cmd/acid/main.c b/sys/src/cmd/acid/main.c
new file mode 100755
index 000000000..bb27cc9e3
--- /dev/null
+++ b/sys/src/cmd/acid/main.c
@@ -0,0 +1,595 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern
+#include "acid.h"
+#include "y.tab.h"
+
+extern int _ifmt(Fmt*);
+
+static Biobuf bioout;
+static char prog[128];
+static char* lm[16];
+static int nlm;
+static char* mtype;
+
+static int attachfiles(char*, int);
+int xfmt(Fmt*);
+int isnumeric(char*);
+void die(void);
+void loadmoduleobjtype(void);
+
+void
+usage(void)
+{
+ fprint(2, "usage: acid [-kqw] [-l library] [-m machine] [pid] [file]\n");
+ exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+ Lsym *l;
+ Node *n;
+ char *s;
+ int pid, i;
+
+ argv0 = argv[0];
+ pid = 0;
+ aout = "8.out";
+ quiet = 1;
+
+ mtype = 0;
+ ARGBEGIN{
+ case 'm':
+ mtype = ARGF();
+ break;
+ case 'w':
+ wtflag = 1;
+ break;
+ case 'l':
+ s = ARGF();
+ if(s == 0)
+ usage();
+ lm[nlm++] = s;
+ break;
+ case 'k':
+ kernel++;
+ break;
+ case 'q':
+ quiet = 0;
+ break;
+ case 'r':
+ pid = 1;
+ remote++;
+ kernel++;
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(argc > 0) {
+ if(remote)
+ aout = argv[0];
+ else
+ if(isnumeric(argv[0])) {
+ pid = strtol(argv[0], 0, 0);
+ snprint(prog, sizeof(prog), "/proc/%d/text", pid);
+ aout = prog;
+ if(argc > 1)
+ aout = argv[1];
+ else if(kernel)
+ aout = system();
+ }
+ else {
+ if(kernel) {
+ fprint(2, "acid: -k requires a pid\n");
+ usage();
+ }
+ aout = argv[0];
+ }
+ } else
+ if(remote)
+ aout = "/mips/9ch";
+
+ fmtinstall('x', xfmt);
+ fmtinstall('L', Lfmt);
+ Binit(&bioout, 1, OWRITE);
+ bout = &bioout;
+
+ kinit();
+ initialising = 1;
+ pushfile(0);
+ loadvars();
+ installbuiltin();
+
+ if(mtype && machbyname(mtype) == 0)
+ print("unknown machine %s", mtype);
+
+ if (attachfiles(aout, pid) < 0)
+ varreg(); /* use default register set on error */
+
+ loadmodule("/sys/lib/acid/port");
+ loadmoduleobjtype();
+
+ for(i = 0; i < nlm; i++) {
+ if(access(lm[i], AREAD) >= 0)
+ loadmodule(lm[i]);
+ else {
+ s = smprint("/sys/lib/acid/%s", lm[i]);
+ loadmodule(s);
+ free(s);
+ }
+ }
+
+ userinit();
+ varsym();
+
+ l = look("acidmap");
+ if(l && l->proc) {
+ n = an(ONAME, ZN, ZN);
+ n->sym = l;
+ n = an(OCALL, n, ZN);
+ execute(n);
+ }
+
+ interactive = 1;
+ initialising = 0;
+ line = 1;
+
+ notify(catcher);
+
+ for(;;) {
+ if(setjmp(err)) {
+ Binit(&bioout, 1, OWRITE);
+ unwind();
+ }
+ stacked = 0;
+
+ Bprint(bout, "acid: ");
+
+ if(yyparse() != 1)
+ die();
+ restartio();
+
+ unwind();
+ }
+ /* not reached */
+}
+
+static int
+attachfiles(char *aout, int pid)
+{
+ interactive = 0;
+ if(setjmp(err))
+ return -1;
+
+ if(aout) { /* executable given */
+ if(wtflag)
+ text = open(aout, ORDWR);
+ else
+ text = open(aout, OREAD);
+
+ if(text < 0)
+ error("%s: can't open %s: %r\n", argv0, aout);
+ readtext(aout);
+ }
+ if(pid) /* pid given */
+ sproc(pid);
+ return 0;
+}
+
+void
+die(void)
+{
+ Lsym *s;
+ List *f;
+
+ Bprint(bout, "\n");
+
+ s = look("proclist");
+ if(s && s->v->type == TLIST) {
+ for(f = s->v->l; f; f = f->next)
+ Bprint(bout, "echo kill > /proc/%d/ctl\n", (int)f->ival);
+ }
+ exits(0);
+}
+
+void
+loadmoduleobjtype(void)
+{
+ char *buf;
+
+ buf = smprint("/sys/lib/acid/%s", mach->name);
+ loadmodule(buf);
+ free(buf);
+}
+
+void
+userinit(void)
+{
+ Lsym *l;
+ Node *n;
+ char *buf, *p;
+
+ p = getenv("home");
+ if(p != 0) {
+ buf = smprint("%s/lib/acid", p);
+ silent = 1;
+ loadmodule(buf);
+ free(buf);
+ }
+
+ interactive = 0;
+ if(setjmp(err)) {
+ unwind();
+ return;
+ }
+ l = look("acidinit");
+ if(l && l->proc) {
+ n = an(ONAME, ZN, ZN);
+ n->sym = l;
+ n = an(OCALL, n, ZN);
+ execute(n);
+ }
+}
+
+void
+loadmodule(char *s)
+{
+ interactive = 0;
+ if(setjmp(err)) {
+ unwind();
+ return;
+ }
+ pushfile(s);
+ silent = 0;
+ yyparse();
+ popio();
+ return;
+}
+
+void
+readtext(char *s)
+{
+ Dir *d;
+ Lsym *l;
+ Value *v;
+ uvlong length;
+ Symbol sym;
+ extern Machdata mipsmach;
+
+ if(mtype != 0){
+ symmap = newmap(0, 1);
+ if(symmap == 0)
+ print("%s: (error) loadmap: cannot make symbol map\n", argv0);
+ length = 1<<24;
+ d = dirfstat(text);
+ if(d != nil){
+ length = d->length;
+ free(d);
+ }
+ setmap(symmap, text, 0, length, 0, "binary");
+ return;
+ }
+
+ machdata = &mipsmach;
+
+ if(!crackhdr(text, &fhdr)) {
+ print("can't decode file header\n");
+ return;
+ }
+
+ symmap = loadmap(0, text, &fhdr);
+ if(symmap == 0)
+ print("%s: (error) loadmap: cannot make symbol map\n", argv0);
+
+ if(syminit(text, &fhdr) < 0) {
+ print("%s: (error) syminit: %r\n", argv0);
+ return;
+ }
+ print("%s:%s\n", s, fhdr.name);
+
+ if(mach->sbreg && lookup(0, mach->sbreg, &sym)) {
+ mach->sb = sym.value;
+ l = enter("SB", Tid);
+ l->v->fmt = 'X';
+ l->v->ival = mach->sb;
+ l->v->type = TINT;
+ l->v->set = 1;
+ }
+
+ l = mkvar("objtype");
+ v = l->v;
+ v->fmt = 's';
+ v->set = 1;
+ v->string = strnode(mach->name);
+ v->type = TSTRING;
+
+ l = mkvar("textfile");
+ v = l->v;
+ v->fmt = 's';
+ v->set = 1;
+ v->string = strnode(s);
+ v->type = TSTRING;
+
+ machbytype(fhdr.type);
+ varreg();
+}
+
+Node*
+an(int op, Node *l, Node *r)
+{
+ Node *n;
+
+ n = gmalloc(sizeof(Node));
+ memset(n, 0, sizeof(Node));
+ n->gclink = gcl;
+ gcl = n;
+ n->op = op;
+ n->left = l;
+ n->right = r;
+ return n;
+}
+
+List*
+al(int t)
+{
+ List *l;
+
+ l = gmalloc(sizeof(List));
+ memset(l, 0, sizeof(List));
+ l->type = t;
+ l->gclink = gcl;
+ gcl = l;
+ return l;
+}
+
+Node*
+con(vlong v)
+{
+ Node *n;
+
+ n = an(OCONST, ZN, ZN);
+ n->ival = v;
+ n->fmt = 'W';
+ n->type = TINT;
+ return n;
+}
+
+void
+fatal(char *fmt, ...)
+{
+ char buf[128];
+ va_list arg;
+
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ fprint(2, "%s: %L (fatal problem) %s\n", argv0, buf);
+ exits(buf);
+}
+
+void
+yyerror(char *fmt, ...)
+{
+ char buf[128];
+ va_list arg;
+
+ if(strcmp(fmt, "syntax error") == 0) {
+ yyerror("syntax error, near symbol '%s'", symbol);
+ return;
+ }
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ print("%L: %s\n", buf);
+}
+
+void
+marktree(Node *n)
+{
+
+ if(n == 0)
+ return;
+
+ marktree(n->left);
+ marktree(n->right);
+
+ n->gcmark = 1;
+ if(n->op != OCONST)
+ return;
+
+ switch(n->type) {
+ case TSTRING:
+ n->string->gcmark = 1;
+ break;
+ case TLIST:
+ marklist(n->l);
+ break;
+ case TCODE:
+ marktree(n->cc);
+ break;
+ }
+}
+
+void
+marklist(List *l)
+{
+ while(l) {
+ l->gcmark = 1;
+ switch(l->type) {
+ case TSTRING:
+ l->string->gcmark = 1;
+ break;
+ case TLIST:
+ marklist(l->l);
+ break;
+ case TCODE:
+ marktree(l->cc);
+ break;
+ }
+ l = l->next;
+ }
+}
+
+void
+gc(void)
+{
+ int i;
+ Lsym *f;
+ Value *v;
+ Gc *m, **p, *next;
+
+ if(dogc < Mempergc)
+ return;
+ dogc = 0;
+
+ /* Mark */
+ for(m = gcl; m; m = m->gclink)
+ m->gcmark = 0;
+
+ /* Scan */
+ for(i = 0; i < Hashsize; i++) {
+ for(f = hash[i]; f; f = f->hash) {
+ marktree(f->proc);
+ if(f->lexval != Tid)
+ continue;
+ for(v = f->v; v; v = v->pop) {
+ switch(v->type) {
+ case TSTRING:
+ v->string->gcmark = 1;
+ break;
+ case TLIST:
+ marklist(v->l);
+ break;
+ case TCODE:
+ marktree(v->cc);
+ break;
+ }
+ }
+ }
+ }
+
+ /* Free */
+ p = &gcl;
+ for(m = gcl; m; m = next) {
+ next = m->gclink;
+ if(m->gcmark == 0) {
+ *p = next;
+ free(m); /* Sleazy reliance on my malloc */
+ }
+ else
+ p = &m->gclink;
+ }
+}
+
+void*
+gmalloc(long l)
+{
+ void *p;
+
+ dogc += l;
+ p = malloc(l);
+ if(p == 0)
+ fatal("out of memory");
+ return p;
+}
+
+void
+checkqid(int f1, int pid)
+{
+ int fd;
+ Dir *d1, *d2;
+ char buf[128];
+
+ if(kernel)
+ return;
+
+ d1 = dirfstat(f1);
+ if(d1 == nil){
+ print("checkqid: (qid not checked) dirfstat: %r\n");
+ return;
+ }
+
+ snprint(buf, sizeof(buf), "/proc/%d/text", pid);
+ fd = open(buf, OREAD);
+ if(fd < 0 || (d2 = dirfstat(fd)) == nil){
+ print("checkqid: (qid not checked) dirstat %s: %r\n", buf);
+ free(d1);
+ if(fd >= 0)
+ close(fd);
+ return;
+ }
+
+ close(fd);
+
+ if(d1->qid.path != d2->qid.path || d1->qid.vers != d2->qid.vers || d1->qid.type != d2->qid.type){
+ print("path %llux %llux vers %lud %lud type %d %d\n",
+ d1->qid.path, d2->qid.path, d1->qid.vers, d2->qid.vers, d1->qid.type, d2->qid.type);
+ print("warning: image does not match text for pid %d\n", pid);
+ }
+ free(d1);
+ free(d2);
+}
+
+void
+catcher(void *junk, char *s)
+{
+ USED(junk);
+
+ if(strstr(s, "interrupt")) {
+ gotint = 1;
+ noted(NCONT);
+ }
+ noted(NDFLT);
+}
+
+char*
+system(void)
+{
+ char *cpu, *p, *q;
+ static char *kernel;
+
+ cpu = getenv("cputype");
+ if(cpu == 0) {
+ cpu = "mips";
+ print("$cputype not set; assuming %s\n", cpu);
+ }
+ p = getenv("terminal");
+ if(p == 0 || (p=strchr(p, ' ')) == 0 || p[1] == ' ' || p[1] == 0) {
+ p = "ch";
+ print("missing or bad $terminal; assuming %s\n", p);
+ }
+ else{
+ p++;
+ q = strchr(p, ' ');
+ if(q)
+ *q = 0;
+ }
+
+ if(kernel != nil)
+ free(kernel);
+ kernel = smprint("/%s/9%s", cpu, p);
+
+ return kernel;
+}
+
+int
+isnumeric(char *s)
+{
+ while(*s) {
+ if(*s < '0' || *s > '9')
+ return 0;
+ s++;
+ }
+ return 1;
+}
+
+int
+xfmt(Fmt *f)
+{
+ f->flags ^= FmtSharp;
+ return _ifmt(f);
+}
diff --git a/sys/src/cmd/acid/mkfile b/sys/src/cmd/acid/mkfile
new file mode 100755
index 000000000..7a4b9c6f2
--- /dev/null
+++ b/sys/src/cmd/acid/mkfile
@@ -0,0 +1,33 @@
+</$objtype/mkfile
+
+TARG=acid
+UOFILES= main.$O\
+ lex.$O\
+ util.$O\
+ exec.$O\
+ expr.$O\
+ list.$O\
+ builtin.$O\
+ proc.$O\
+ dot.$O\
+ print.$O\
+
+OFILES=$UOFILES y.tab.$O
+
+YFILES=dbg.y
+HFILES=acid.h
+
+BIN=/$objtype/bin
+
+UPDATE=\
+ mkfile\
+ $HFILES\
+ ${UOFILES:%.$O=%.c}\
+ $YFILES\
+
+</sys/src/cmd/mkone
+
+lex.$O: y.tab.h
+util.$O: y.tab.h
+builtin.$O: y.tab.h
+main.$O: y.tab.h
diff --git a/sys/src/cmd/acid/print.c b/sys/src/cmd/acid/print.c
new file mode 100755
index 000000000..6ca4e570b
--- /dev/null
+++ b/sys/src/cmd/acid/print.c
@@ -0,0 +1,445 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ctype.h>
+#include <mach.h>
+#define Extern extern
+#include "acid.h"
+
+static char *binop[] =
+{
+ [OMUL] "*",
+ [ODIV] "/",
+ [OMOD] "%",
+ [OADD] "+",
+ [OSUB] "-",
+ [ORSH] ">>",
+ [OLSH] "<<",
+ [OLT] "<",
+ [OGT] ">",
+ [OLEQ] "<=",
+ [OGEQ] ">=",
+ [OEQ] "==",
+ [ONEQ] "!=",
+ [OLAND] "&",
+ [OXOR] "^",
+ [OLOR] "|",
+ [OCAND] "&&",
+ [OCOR] "||",
+ [OASGN] " = ",
+};
+
+static char *tabs = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
+char *typenames[] =
+{
+ [TINT] "integer",
+ [TFLOAT] "float",
+ [TSTRING] "string",
+ [TLIST] "list",
+ [TCODE] "code",
+};
+
+int
+cmp(void *va, void *vb)
+{
+ char **a = va;
+ char **b = vb;
+
+ return strcmp(*a, *b);
+}
+
+void
+fundefs(void)
+{
+ Lsym *l;
+ char **vec;
+ int i, j, n, max, col, f, g, s;
+
+ max = 0;
+ f = 0;
+ g = 100;
+ vec = malloc(sizeof(char*)*g);
+ if(vec == 0)
+ fatal("out of memory");
+
+ for(i = 0; i < Hashsize; i++) {
+ for(l = hash[i]; l; l = l->hash) {
+ if(l->proc == 0 && l->builtin == 0)
+ continue;
+ n = strlen(l->name);
+ if(n > max)
+ max = n;
+ if(f >= g) {
+ g *= 2;
+ vec = realloc(vec, sizeof(char*)*g);
+ if(vec == 0)
+ fatal("out of memory");
+ }
+ vec[f++] = l->name;
+ }
+ }
+ qsort(vec, f, sizeof(char*), cmp);
+ max++;
+ col = 60/max;
+ s = (f+col-1)/col;
+
+ for(i = 0; i < s; i++) {
+ for(j = i; j < f; j += s)
+ Bprint(bout, "%-*s", max, vec[j]);
+ Bprint(bout, "\n");
+ }
+}
+
+void
+whatis(Lsym *l)
+{
+ int t;
+ int def;
+ Type *ti;
+
+ if(l == 0) {
+ fundefs();
+ return;
+ }
+
+ def = 0;
+ if(l->v->set) {
+ t = l->v->type;
+ Bprint(bout, "%s variable", typenames[t]);
+ if(t == TINT || t == TFLOAT)
+ Bprint(bout, " format %c", l->v->fmt);
+ if(l->v->comt)
+ Bprint(bout, " complex %s", l->v->comt->base->name);
+ Bputc(bout, '\n');
+ def = 1;
+ }
+ if(l->lt) {
+ Bprint(bout, "complex %s {\n", l->name);
+ for(ti = l->lt; ti; ti = ti->next) {
+ if(ti->type) {
+ if(ti->fmt == 'a') {
+ Bprint(bout, "\t%s %d %s;\n",
+ ti->type->name, ti->offset,
+ ti->tag->name);
+ }
+ else {
+ Bprint(bout, "\t'%c' %s %d %s;\n",
+ ti->fmt, ti->type->name, ti->offset,
+ ti->tag->name);
+ }
+ }
+ else
+ Bprint(bout, "\t'%c' %d %s;\n",
+ ti->fmt, ti->offset, ti->tag->name);
+ }
+ Bprint(bout, "};\n");
+ def = 1;
+ }
+ if(l->proc) {
+ Bprint(bout, "defn %s(", l->name);
+ pexpr(l->proc->left);
+ Bprint(bout, ") {\n");
+ pcode(l->proc->right, 1);
+ Bprint(bout, "}\n");
+ def = 1;
+ }
+ if(l->builtin) {
+ Bprint(bout, "builtin function\n");
+ def = 1;
+ }
+ if(def == 0)
+ Bprint(bout, "%s is undefined\n", l->name);
+}
+
+void
+slist(Node *n, int d)
+{
+ if(n == 0)
+ return;
+ if(n->op == OLIST)
+ Bprint(bout, "%.*s{\n", d-1, tabs);
+ pcode(n, d);
+ if(n->op == OLIST)
+ Bprint(bout, "%.*s}\n", d-1, tabs);
+}
+
+void
+pcode(Node *n, int d)
+{
+ Node *r, *l;
+
+ if(n == 0)
+ return;
+
+ r = n->right;
+ l = n->left;
+
+ switch(n->op) {
+ default:
+ Bprint(bout, "%.*s", d, tabs);
+ pexpr(n);
+ Bprint(bout, ";\n");
+ break;
+ case OLIST:
+ pcode(n->left, d);
+ pcode(n->right, d);
+ break;
+ case OLOCAL:
+ Bprint(bout, "%.*slocal", d, tabs);
+ while(l) {
+ Bprint(bout, " %s", l->sym->name);
+ l = l->left;
+ if(l == 0)
+ Bprint(bout, ";\n");
+ else
+ Bprint(bout, ",");
+ }
+ break;
+ case OCOMPLEX:
+ Bprint(bout, "%.*scomplex %s %s;\n", d, tabs, n->sym->name, l->sym->name);
+ break;
+ case OIF:
+ Bprint(bout, "%.*sif ", d, tabs);
+ pexpr(l);
+ d++;
+ Bprint(bout, " then\n");
+ if(r && r->op == OELSE) {
+ slist(r->left, d);
+ Bprint(bout, "%.*selse\n", d-1, tabs);
+ slist(r->right, d);
+ }
+ else
+ slist(r, d);
+ break;
+ case OWHILE:
+ Bprint(bout, "%.*swhile ", d, tabs);
+ pexpr(l);
+ d++;
+ Bprint(bout, " do\n");
+ slist(r, d);
+ break;
+ case ORET:
+ Bprint(bout, "%.*sreturn ", d, tabs);
+ pexpr(l);
+ Bprint(bout, ";\n");
+ break;
+ case ODO:
+ Bprint(bout, "%.*sloop ", d, tabs);
+ pexpr(l->left);
+ Bprint(bout, ", ");
+ pexpr(l->right);
+ Bprint(bout, " do\n");
+ slist(r, d+1);
+ }
+}
+
+void
+pexpr(Node *n)
+{
+ Node *r, *l;
+
+ if(n == 0)
+ return;
+
+ r = n->right;
+ l = n->left;
+
+ switch(n->op) {
+ case ONAME:
+ Bprint(bout, "%s", n->sym->name);
+ break;
+ case OCONST:
+ switch(n->type) {
+ case TINT:
+ Bprint(bout, "%lld", n->ival);
+ break;
+ case TFLOAT:
+ Bprint(bout, "%g", n->fval);
+ break;
+ case TSTRING:
+ pstr(n->string);
+ break;
+ case TLIST:
+ break;
+ }
+ break;
+ case OMUL:
+ case ODIV:
+ case OMOD:
+ case OADD:
+ case OSUB:
+ case ORSH:
+ case OLSH:
+ case OLT:
+ case OGT:
+ case OLEQ:
+ case OGEQ:
+ case OEQ:
+ case ONEQ:
+ case OLAND:
+ case OXOR:
+ case OLOR:
+ case OCAND:
+ case OCOR:
+ Bputc(bout, '(');
+ pexpr(l);
+ Bprint(bout, binop[n->op]);
+ pexpr(r);
+ Bputc(bout, ')');
+ break;
+ case OASGN:
+ pexpr(l);
+ Bprint(bout, binop[n->op]);
+ pexpr(r);
+ break;
+ case OINDM:
+ Bprint(bout, "*");
+ pexpr(l);
+ break;
+ case OEDEC:
+ Bprint(bout, "--");
+ pexpr(l);
+ break;
+ case OEINC:
+ Bprint(bout, "++");
+ pexpr(l);
+ break;
+ case OPINC:
+ pexpr(l);
+ Bprint(bout, "++");
+ break;
+ case OPDEC:
+ pexpr(l);
+ Bprint(bout, "--");
+ break;
+ case ONOT:
+ Bprint(bout, "!");
+ pexpr(l);
+ break;
+ case OLIST:
+ pexpr(l);
+ if(r) {
+ Bprint(bout, ",");
+ pexpr(r);
+ }
+ break;
+ case OCALL:
+ pexpr(l);
+ Bprint(bout, "(");
+ pexpr(r);
+ Bprint(bout, ")");
+ break;
+ case OCTRUCT:
+ Bprint(bout, "{");
+ pexpr(l);
+ Bprint(bout, "}");
+ break;
+ case OHEAD:
+ Bprint(bout, "head ");
+ pexpr(l);
+ break;
+ case OTAIL:
+ Bprint(bout, "tail ");
+ pexpr(l);
+ break;
+ case OAPPEND:
+ Bprint(bout, "append ");
+ pexpr(l);
+ Bprint(bout, ",");
+ pexpr(r);
+ break;
+ case ODELETE:
+ Bprint(bout, "delete ");
+ pexpr(l);
+ Bprint(bout, ",");
+ pexpr(r);
+ break;
+ case ORET:
+ Bprint(bout, "return ");
+ pexpr(l);
+ break;
+ case OINDEX:
+ pexpr(l);
+ Bprint(bout, "[");
+ pexpr(r);
+ Bprint(bout, "]");
+ break;
+ case OINDC:
+ Bprint(bout, "@");
+ pexpr(l);
+ break;
+ case ODOT:
+ pexpr(l);
+ Bprint(bout, ".%s", n->sym->name);
+ break;
+ case OFRAME:
+ Bprint(bout, "%s:%s", n->sym->name, l->sym->name);
+ break;
+ case OCAST:
+ Bprint(bout, "(%s)", n->sym->name);
+ pexpr(l);
+ break;
+ case OFMT:
+ pexpr(l);
+ Bprint(bout, "\\%c", (int)r->ival);
+ break;
+ case OEVAL:
+ Bprint(bout, "eval ");
+ pexpr(l);
+ break;
+ case OWHAT:
+ Bprint(bout, "whatis");
+ if(n->sym)
+ Bprint(bout, " %s", n->sym->name);
+ break;
+ }
+}
+
+void
+pstr(String *s)
+{
+ int i, c;
+
+ Bputc(bout, '"');
+ for(i = 0; i < s->len; i++) {
+ c = s->string[i];
+ switch(c) {
+ case '\0':
+ c = '0';
+ break;
+ case '\n':
+ c = 'n';
+ break;
+ case '\r':
+ c = 'r';
+ break;
+ case '\t':
+ c = 't';
+ break;
+ case '\b':
+ c = 'b';
+ break;
+ case '\f':
+ c = 'f';
+ break;
+ case '\a':
+ c = 'a';
+ break;
+ case '\v':
+ c = 'v';
+ break;
+ case '\\':
+ c = '\\';
+ break;
+ case '"':
+ c = '"';
+ break;
+ default:
+ Bputc(bout, c);
+ continue;
+ }
+ Bputc(bout, '\\');
+ Bputc(bout, c);
+ }
+ Bputc(bout, '"');
+}
diff --git a/sys/src/cmd/acid/proc.c b/sys/src/cmd/acid/proc.c
new file mode 100755
index 000000000..efb06d047
--- /dev/null
+++ b/sys/src/cmd/acid/proc.c
@@ -0,0 +1,279 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ctype.h>
+#include <mach.h>
+#define Extern extern
+#include "acid.h"
+#include "y.tab.h"
+
+static void install(int);
+
+void
+nocore(void)
+{
+ int i;
+
+ if(cormap == 0)
+ return;
+
+ for (i = 0; i < cormap->nsegs; i++)
+ if (cormap->seg[i].inuse && cormap->seg[i].fd >= 0)
+ close(cormap->seg[i].fd);
+ free(cormap);
+ cormap = 0;
+}
+
+void
+sproc(int pid)
+{
+ Lsym *s;
+ char buf[64];
+ int i, fcor;
+
+ if(symmap == 0)
+ error("no map");
+
+ snprint(buf, sizeof(buf), "/proc/%d/mem", pid);
+ fcor = open(buf, ORDWR);
+ if(fcor < 0)
+ error("setproc: open %s: %r", buf);
+
+ checkqid(symmap->seg[0].fd, pid);
+
+ s = look("pid");
+ s->v->ival = pid;
+
+ nocore();
+ cormap = attachproc(pid, kernel, fcor, &fhdr);
+ if (cormap == 0)
+ error("setproc: can't make coremap: %r");
+ i = findseg(cormap, "text");
+ if (i > 0)
+ cormap->seg[i].name = "*text";
+ i = findseg(cormap, "data");
+ if (i > 0)
+ cormap->seg[i].name = "*data";
+ install(pid);
+}
+
+int
+nproc(char **argv)
+{
+ char buf[128];
+ int pid, i, fd;
+
+ pid = fork();
+ switch(pid) {
+ case -1:
+ error("new: fork %r");
+ case 0:
+ rfork(RFNAMEG|RFNOTEG);
+
+ snprint(buf, sizeof(buf), "/proc/%d/ctl", getpid());
+ fd = open(buf, ORDWR);
+ if(fd < 0)
+ fatal("new: open %s: %r", buf);
+ write(fd, "hang", 4);
+ close(fd);
+
+ close(0);
+ close(1);
+ close(2);
+ for(i = 3; i < NFD; i++)
+ close(i);
+
+ open("/dev/cons", OREAD);
+ open("/dev/cons", OWRITE);
+ open("/dev/cons", OWRITE);
+ exec(argv[0], argv);
+ fatal("new: exec %s: %r");
+ default:
+ install(pid);
+ msg(pid, "waitstop");
+ notes(pid);
+ sproc(pid);
+ dostop(pid);
+ break;
+ }
+
+ return pid;
+}
+
+void
+notes(int pid)
+{
+ Lsym *s;
+ Value *v;
+ int i, fd;
+ char buf[128];
+ List *l, **tail;
+
+ s = look("notes");
+ if(s == 0)
+ return;
+ v = s->v;
+
+ snprint(buf, sizeof(buf), "/proc/%d/note", pid);
+ fd = open(buf, OREAD);
+ if(fd < 0)
+ error("pid=%d: open note: %r", pid);
+
+ v->set = 1;
+ v->type = TLIST;
+ v->l = 0;
+ tail = &v->l;
+ for(;;) {
+ i = read(fd, buf, sizeof(buf));
+ if(i <= 0)
+ break;
+ buf[i] = '\0';
+ l = al(TSTRING);
+ l->string = strnode(buf);
+ l->fmt = 's';
+ *tail = l;
+ tail = &l->next;
+ }
+ close(fd);
+}
+
+void
+dostop(int pid)
+{
+ Lsym *s;
+ Node *np, *p;
+
+ s = look("stopped");
+ if(s && s->proc) {
+ np = an(ONAME, ZN, ZN);
+ np->sym = s;
+ np->fmt = 'D';
+ np->type = TINT;
+ p = con(pid);
+ p->fmt = 'D';
+ np = an(OCALL, np, p);
+ execute(np);
+ }
+}
+
+static void
+install(int pid)
+{
+ Lsym *s;
+ List *l;
+ char buf[128];
+ int i, fd, new, p;
+
+ new = -1;
+ for(i = 0; i < Maxproc; i++) {
+ p = ptab[i].pid;
+ if(p == pid)
+ return;
+ if(p == 0 && new == -1)
+ new = i;
+ }
+ if(new == -1)
+ error("no free process slots");
+
+ snprint(buf, sizeof(buf), "/proc/%d/ctl", pid);
+ fd = open(buf, OWRITE);
+ if(fd < 0)
+ error("pid=%d: open ctl: %r", pid);
+ ptab[new].pid = pid;
+ ptab[new].ctl = fd;
+
+ s = look("proclist");
+ l = al(TINT);
+ l->fmt = 'D';
+ l->ival = pid;
+ l->next = s->v->l;
+ s->v->l = l;
+ s->v->set = 1;
+}
+
+void
+deinstall(int pid)
+{
+ int i;
+ Lsym *s;
+ List *f, **d;
+
+ for(i = 0; i < Maxproc; i++) {
+ if(ptab[i].pid == pid) {
+ close(ptab[i].ctl);
+ ptab[i].pid = 0;
+ s = look("proclist");
+ d = &s->v->l;
+ for(f = *d; f; f = f->next) {
+ if(f->ival == pid) {
+ *d = f->next;
+ break;
+ }
+ }
+ s = look("pid");
+ if(s->v->ival == pid)
+ s->v->ival = 0;
+ return;
+ }
+ }
+}
+
+void
+msg(int pid, char *msg)
+{
+ int i;
+ int l;
+ char err[ERRMAX];
+
+ for(i = 0; i < Maxproc; i++) {
+ if(ptab[i].pid == pid) {
+ l = strlen(msg);
+ if(write(ptab[i].ctl, msg, l) != l) {
+ errstr(err, sizeof err);
+ if(strcmp(err, "process exited") == 0)
+ deinstall(pid);
+ error("msg: pid=%d %s: %s", pid, msg, err);
+ }
+ return;
+ }
+ }
+ error("msg: pid=%d: not found for %s", pid, msg);
+}
+
+char *
+getstatus(int pid)
+{
+ int fd, n;
+ char *argv[16], buf[64];
+ static char status[128];
+
+ snprint(buf, sizeof(buf), "/proc/%d/status", pid);
+ fd = open(buf, OREAD);
+ if(fd < 0)
+ error("open %s: %r", buf);
+
+ n = read(fd, status, sizeof(status)-1);
+ close(fd);
+ if(n <= 0)
+ error("read %s: %r", buf);
+ status[n] = '\0';
+
+ if(tokenize(status, argv, nelem(argv)-1) < 3)
+ error("tokenize %s: %r", buf);
+
+ return argv[2];
+}
+
+Waitmsg*
+waitfor(int pid)
+{
+ Waitmsg *w;
+
+ for(;;) {
+ if((w = wait()) == nil)
+ error("wait %r");
+ if(w->pid == pid)
+ return w;
+ free(w);
+ }
+}
diff --git a/sys/src/cmd/acid/util.c b/sys/src/cmd/acid/util.c
new file mode 100755
index 000000000..c861d1994
--- /dev/null
+++ b/sys/src/cmd/acid/util.c
@@ -0,0 +1,304 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ctype.h>
+#include <mach.h>
+#define Extern extern
+#include "acid.h"
+#include "y.tab.h"
+
+static int syren;
+
+Lsym*
+unique(char *buf, Sym *s)
+{
+ Lsym *l;
+ int i, renamed;
+
+ renamed = 0;
+ strcpy(buf, s->name);
+ for(;;) {
+ l = look(buf);
+ if(l == 0 || (l->lexval == Tid && l->v->set == 0))
+ break;
+
+ if(syren == 0 && !quiet) {
+ print("Symbol renames:\n");
+ syren = 1;
+ }
+ i = strlen(buf)+1;
+ memmove(buf+1, buf, i);
+ buf[0] = '$';
+ renamed++;
+ if(renamed > 5 && !quiet) {
+ print("Too many renames; must be X source!\n");
+ break;
+ }
+ }
+ if(renamed && !quiet)
+ print("\t%s=%s %c/%llux\n", s->name, buf, s->type, s->value);
+ if(l == 0)
+ l = enter(buf, Tid);
+ return l;
+}
+
+void
+varsym(void)
+{
+ int i;
+ Sym *s;
+ long n;
+ Lsym *l;
+ uvlong v;
+ char buf[1024];
+ List *list, **tail, *l2, *tl;
+
+ tail = &l2;
+ l2 = 0;
+
+ symbase(&n);
+ for(i = 0; i < n; i++) {
+ s = getsym(i);
+ switch(s->type) {
+ case 'T':
+ case 'L':
+ case 'D':
+ case 'B':
+ case 'b':
+ case 'd':
+ case 'l':
+ case 't':
+ if(s->name[0] == '.')
+ continue;
+
+ v = s->value;
+ tl = al(TLIST);
+ *tail = tl;
+ tail = &tl->next;
+
+ l = unique(buf, s);
+
+ l->v->set = 1;
+ l->v->type = TINT;
+ l->v->ival = v;
+ if(l->v->comt == 0)
+ l->v->fmt = 'X';
+
+ /* Enter as list of { name, type, value } */
+ list = al(TSTRING);
+ tl->l = list;
+ list->string = strnode(buf);
+ list->fmt = 's';
+ list->next = al(TINT);
+ list = list->next;
+ list->fmt = 'c';
+ list->ival = s->type;
+ list->next = al(TINT);
+ list = list->next;
+ list->fmt = 'X';
+ list->ival = v;
+
+ }
+ }
+ l = mkvar("symbols");
+ l->v->set = 1;
+ l->v->type = TLIST;
+ l->v->l = l2;
+ if(l2 == 0)
+ print("no symbol information\n");
+}
+
+void
+varreg(void)
+{
+ Lsym *l;
+ Value *v;
+ Reglist *r;
+ List **tail, *li;
+
+ l = mkvar("registers");
+ v = l->v;
+ v->set = 1;
+ v->type = TLIST;
+ v->l = 0;
+ tail = &v->l;
+
+ for(r = mach->reglist; r->rname; r++) {
+ l = mkvar(r->rname);
+ v = l->v;
+ v->set = 1;
+ v->ival = r->roffs;
+ v->fmt = r->rformat;
+ v->type = TINT;
+
+ li = al(TSTRING);
+ li->string = strnode(r->rname);
+ li->fmt = 's';
+ *tail = li;
+ tail = &li->next;
+ }
+
+ if(machdata == 0)
+ return;
+
+ l = mkvar("bpinst"); /* Breakpoint text */
+ v = l->v;
+ v->type = TSTRING;
+ v->fmt = 's';
+ v->set = 1;
+ v->string = gmalloc(sizeof(String));
+ v->string->len = machdata->bpsize;
+ v->string->string = gmalloc(machdata->bpsize);
+ memmove(v->string->string, machdata->bpinst, machdata->bpsize);
+}
+
+void
+loadvars(void)
+{
+ Lsym *l;
+ Value *v;
+
+ l = mkvar("proc");
+ v = l->v;
+ v->type = TINT;
+ v->fmt = 'X';
+ v->set = 1;
+ v->ival = 0;
+
+ l = mkvar("pid"); /* Current process */
+ v = l->v;
+ v->type = TINT;
+ v->fmt = 'D';
+ v->set = 1;
+ v->ival = 0;
+
+ mkvar("notes"); /* Pending notes */
+
+ l = mkvar("proclist"); /* Attached processes */
+ l->v->type = TLIST;
+}
+
+uvlong
+rget(Map *map, char *reg)
+{
+ Lsym *s;
+ ulong x;
+ uvlong v;
+ int ret;
+
+ s = look(reg);
+ if(s == 0)
+ fatal("rget: %s\n", reg);
+
+ switch(s->v->fmt){
+ default:
+ ret = get4(map, s->v->ival, &x);
+ v = x;
+ break;
+ case 'V':
+ case 'W':
+ case 'Y':
+ case 'Z':
+ ret = get8(map, s->v->ival, &v);
+ break;
+ }
+ if(ret < 0)
+ error("can't get register %s: %r\n", reg);
+ return v;
+}
+
+String*
+strnodlen(char *name, int len)
+{
+ String *s;
+
+ s = gmalloc(sizeof(String)+len+1);
+ s->string = (char*)s+sizeof(String);
+ s->len = len;
+ if(name != 0)
+ memmove(s->string, name, len);
+ s->string[len] = '\0';
+
+ s->gclink = gcl;
+ gcl = s;
+
+ return s;
+}
+
+String*
+strnode(char *name)
+{
+ return strnodlen(name, strlen(name));
+}
+
+String*
+runenode(Rune *name)
+{
+ int len;
+ Rune *p;
+ String *s;
+
+ p = name;
+ for(len = 0; *p; p++)
+ len++;
+
+ len++;
+ len *= sizeof(Rune);
+ s = gmalloc(sizeof(String)+len);
+ s->string = (char*)s+sizeof(String);
+ s->len = len;
+ memmove(s->string, name, len);
+
+ s->gclink = gcl;
+ gcl = s;
+
+ return s;
+}
+
+String*
+stradd(String *l, String *r)
+{
+ int len;
+ String *s;
+
+ len = l->len+r->len;
+ s = gmalloc(sizeof(String)+len+1);
+ s->gclink = gcl;
+ gcl = s;
+ s->len = len;
+ s->string = (char*)s+sizeof(String);
+ memmove(s->string, l->string, l->len);
+ memmove(s->string+l->len, r->string, r->len);
+ s->string[s->len] = 0;
+ return s;
+}
+
+String*
+straddrune(String *l, Rune r)
+{
+ int len;
+ String *s;
+
+ len = l->len+runelen(r);
+ s = gmalloc(sizeof(String)+len+1);
+ s->gclink = gcl;
+ gcl = s;
+ s->len = len;
+ s->string = (char*)s+sizeof(String);
+ memmove(s->string, l->string, l->len);
+ runetochar(s->string+l->len, &r);
+ s->string[s->len] = 0;
+ return s;
+}
+
+int
+scmp(String *sr, String *sl)
+{
+ if(sr->len != sl->len)
+ return 0;
+
+ if(memcmp(sr->string, sl->string, sl->len))
+ return 0;
+
+ return 1;
+}