diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/acid |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/acid')
-rwxr-xr-x | sys/src/cmd/acid/acid.h | 298 | ||||
-rwxr-xr-x | sys/src/cmd/acid/builtin.c | 1315 | ||||
-rwxr-xr-x | sys/src/cmd/acid/dbg.y | 411 | ||||
-rwxr-xr-x | sys/src/cmd/acid/dot.c | 153 | ||||
-rwxr-xr-x | sys/src/cmd/acid/exec.c | 498 | ||||
-rwxr-xr-x | sys/src/cmd/acid/expr.c | 1041 | ||||
-rwxr-xr-x | sys/src/cmd/acid/lex.c | 609 | ||||
-rwxr-xr-x | sys/src/cmd/acid/list.c | 277 | ||||
-rwxr-xr-x | sys/src/cmd/acid/main.c | 595 | ||||
-rwxr-xr-x | sys/src/cmd/acid/mkfile | 33 | ||||
-rwxr-xr-x | sys/src/cmd/acid/print.c | 445 | ||||
-rwxr-xr-x | sys/src/cmd/acid/proc.c | 279 | ||||
-rwxr-xr-x | sys/src/cmd/acid/util.c | 304 |
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; +} |