tacid - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 564ca709d0e20d4fc46744bd858f14cff94ab382
 (DIR) parent 22a7368ef24d5c530a275dd0db0bd4f23b1c3ce3
 (HTM) Author: rsc <devnull@localhost>
       Date:   Mon, 19 Apr 2004 19:32:07 +0000
       
       acid
       
       Diffstat:
         A src/cmd/acid/Notes                  |      49 +++++++++++++++++++++++++++++++
         A src/cmd/acid/acid.h                 |     313 +++++++++++++++++++++++++++++++
         A src/cmd/acid/builtin.c              |    1460 +++++++++++++++++++++++++++++++
         A src/cmd/acid/dbg.y                  |     413 +++++++++++++++++++++++++++++++
         A src/cmd/acid/dot.c                  |     153 +++++++++++++++++++++++++++++++
         A src/cmd/acid/exec.c                 |     538 +++++++++++++++++++++++++++++++
         A src/cmd/acid/expr.c                 |    1018 +++++++++++++++++++++++++++++++
         A src/cmd/acid/lex.c                  |     661 +++++++++++++++++++++++++++++++
         A src/cmd/acid/list.c                 |     270 +++++++++++++++++++++++++++++++
         A src/cmd/acid/main.c                 |     630 +++++++++++++++++++++++++++++++
         A src/cmd/acid/mkfile                 |      32 +++++++++++++++++++++++++++++++
         A src/cmd/acid/print.c                |     446 ++++++++++++++++++++++++++++++
         A src/cmd/acid/proc.c                 |     251 +++++++++++++++++++++++++++++++
         A src/cmd/acid/util.c                 |     344 ++++++++++++++++++++++++++++++
       
       14 files changed, 6578 insertions(+), 0 deletions(-)
       ---
 (DIR) diff --git a/src/cmd/acid/Notes b/src/cmd/acid/Notes
       t@@ -0,0 +1,49 @@
       +Changes from the Plan 9 acid (beyond the 
       +obvious changes necessary to compile without
       +Ken's compiler and with the new libmach interface).
       +========================================
       +
       +the input-line print verb is %Z, so that %L can be for locations
       +
       +the register block is explicitly "mapped" at 0 by xget1, xget2, ...
       +        for compatibility with old acid, even though libmach
       +        doesn't participate in this lie anymore.
       +
       +main accepts pid, file, and core in any order
       +
       +the ptab only records pids (no ctl fd anymore).
       +
       +new builtin sysstop(pid) runs pid until the next syscall
       +
       +map() returns 5-tuples: (name, filename, base, end, offset)
       +        filename is new
       +
       +map() expects a 5-tuple too
       +
       +strace expects a list of register names and values like
       +        {"PC", *PC, "SP", *SP}
       +
       +strace returns 5-tuples now:
       +        {fn, pc, callerpc, paramlist, locallist}
       +
       +new builtin includepipe(cmd) includes the standard output
       +        of running cmd.
       +
       +symbols returns 4-tuples now: {name, type, addr, file}
       +
       +new builtin textfile() returns the current set of open text files
       +        as a list of {file, base} pairs.
       +
       +new builtin textfile({file, base}) adds a new file's symbols and text
       +        offset by base for relocatables.
       +
       +new builtin deltextfile(file) removes a file from the set of open text files.
       +
       +both textfile and deltextfile update symbols.
       +
       +====
       +
       +yet to be done:
       +
       +elflink has the linking info for elf on linux
       +
 (DIR) diff --git a/src/cmd/acid/acid.h b/src/cmd/acid/acid.h
       t@@ -0,0 +1,313 @@
       +/* 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 nlcount;
       +Extern int        remote;
       +Extern int        text;
       +Extern int cor;
       +Extern int        silent;
       +Extern Fhdr        *fhdr;
       +Extern Fhdr        *chdr;
       +Extern int        line;
       +Extern Biobuf*        bout;
       +Extern Biobuf*        io[32];
       +Extern int        iop;
       +Extern int pid;
       +Extern char        symbol[Strsize];
       +Extern int        interactive;
       +Extern Node*        code;
       +Extern int        na;
       +Extern int        wtflag;
       +Extern Regs*        correg;
       +Extern Map*        cormap;
       +Extern Map*        symmap;
       +Extern Lsym*        hash[Hashsize];
       +Extern long        dogc;
       +Extern Rplace*        ret;
       +Extern char*        symfil;
       +Extern char*        corfil;
       +Extern int        gotint;
       +Extern long        flen;
       +Extern Gc*        gcl;
       +Extern int        stacked;
       +Extern jmp_buf        err;
       +Extern Node*        prnt;
       +Extern Node*        fomt;
       +Extern List*        tracelist;
       +Extern int        initialising;
       +Extern int        quiet;
       +Extern Fhdr*        corhdr;
       +Extern Fhdr*        symhdr;
       +
       +extern void        (*expop[])(Node*, Node*);
       +#define expr(n, r) (r)->store.comt=0; (*expop[(unsigned char)((n)->op)])(n, r);
       +
       +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;
       +        } u;
       +};
       +
       +struct List
       +{
       +        Gc gc;
       +        List*        next;
       +        char        type;
       +        Store store;
       +};
       +
       +struct Value
       +{
       +        char        set;
       +        char        type;
       +        Store 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 gc;
       +        char        op;
       +        char        type;
       +        Node*        left;
       +        Node*        right;
       +        Lsym*        sym;
       +        int        builtin;
       +        Store store;
       +};
       +#define ZN        (Node*)0
       +
       +struct String
       +{
       +        Gc gc;
       +        char        *string;
       +        int        len;
       +};
       +
       +List*        addlist(List*, List*);
       +void        addvarsym(Fhdr*);
       +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(int);
       +List*        construct(Node*);
       +void        ctrace(int);
       +void        decl(Node*);
       +void        defcomplex(Node*, Node*);
       +void        deinstall(int);
       +void        delete(List*, int n, Node*);
       +void        delvarsym(char*);
       +void        dostop(int);
       +Lsym*        enter(char*, int);
       +void        error(char*, ...);
       +void        execute(Node*);
       +void        fatal(char*, ...);
       +ulong        findframe(ulong);
       +void        flatten(Node**, Node*);
       +void        gc(void);
       +char*        getstatus(int);
       +void*        gmalloc(long);
       +void        indir(Map*, ulong, char, Node*);
       +void        installbuiltin(void);
       +void        kinit(void);
       +int        Zfmt(Fmt*);
       +int        listcmp(List*, List*);
       +int        listlen(List*);
       +List*        listvar(char*, long);
       +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        pushfd(int);
       +void        pushfile(char*);
       +void        pushstr(Node*);
       +ulong        raddr(char*);
       +void        readtext(char*);
       +void        readcore(void);
       +void        restartio(void);
       +String        *runenode(Rune*);
       +int        scmp(String*, String*);
       +void        sproc(int);
       +String*        stradd(String*, String*);
       +String*        strnode(char*);
       +String*        strnodlen(char*, int);
       +#define system acidsystem
       +char*        system(void);
       +int        trlist(Map*, Regs*, ulong, ulong, Symbol*, int);
       +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,
       +};
 (DIR) diff --git a/src/cmd/acid/builtin.c b/src/cmd/acid/builtin.c
       t@@ -0,0 +1,1460 @@
       +#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        xkill(Node*,Node*);
       +void        waitstop(Node*, Node*);
       +void sysstop(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        includepipe(Node*, Node*);
       +void        regexp(Node*, Node*);
       +void textfile(Node*, Node*);
       +void deltextfile(Node*, Node*);
       +
       +typedef struct Btab Btab;
       +struct Btab
       +{
       +        char        *name;
       +        void        (*fn)(Node*, Node*);
       +} tab[] =
       +{
       +        "atof",                cvtatof,
       +        "atoi",                cvtatoi,
       +        "deltextfile",        deltextfile,
       +        "error",        doerror,
       +        "file",                getfile,
       +        "readfile",        readfile,
       +        "access",        doaccess,
       +        "filepc",        filepc,
       +        "fnbound",        funcbound,
       +        "fmt",                fmt,
       +        "follow",        follow,
       +        "include",        include,
       +        "includepipe",        includepipe,
       +        "interpret",        interpret,
       +        "itoa",                cvtitoa,
       +        "kill",                xkill,
       +        "map",                map,
       +        "match",        match,
       +        "newproc",        newproc,
       +        "pcfile",        pcfile,
       +        "pcline",        pcline,
       +        "print",        bprint,
       +        "printto",        printto,
       +        "rc",                rc,
       +        "reason",        reason,
       +        "regexp",        regexp,
       +        "setproc",        setproc,
       +        "start",        start,
       +        "startstop",        startstop,
       +        "status",        status,
       +        "stop",                stop,
       +        "strace",        strace,
       +        "sysstop",                sysstop,
       +        "textfile",        textfile,
       +        "waitstop",        waitstop,
       +        0
       +};
       +
       +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
       +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->store.fmt = 'D';
       +        r->store.u.ival = -1;
       +
       +        i = 0;
       +        for(f = resl.store.u.l; f; f = f->next) {
       +                if(resi.type == f->type) {
       +                        switch(resi.type) {
       +                        case TINT:
       +                                if(resi.store.u.ival == f->store.u.ival) {
       +                                        r->store.u.ival = i;
       +                                        return;
       +                                }
       +                                break;
       +                        case TFLOAT:
       +                                if(resi.store.u.fval == f->store.u.fval) {
       +                                        r->store.u.ival = i;
       +                                        return;
       +                                }
       +                                break;
       +                        case TSTRING:
       +                                if(scmp(resi.store.u.string, f->store.u.string)) {
       +                                        r->store.u.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] = symfil;
       +
       +        if(args) {
       +                expr(args, &res);
       +                if(res.type != TSTRING)
       +                        error("newproc(): arg not string");
       +                if(res.store.u.string->len >= sizeof(buf))
       +                        error("newproc(): too many arguments");
       +                memmove(buf, res.store.u.string->string, res.store.u.string->len);
       +                buf[res.store.u.string->len] = '\0';
       +                p = buf;
       +                e = buf+res.store.u.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->store.fmt = 'D';
       +        r->store.u.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.store.u.ival, "startstop");
       +        notes(res.store.u.ival);
       +        dostop(res.store.u.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.store.u.ival, "waitstop");
       +        notes(res.store.u.ival);
       +        dostop(res.store.u.ival);
       +}
       +
       +void
       +sysstop(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.store.u.ival, "sysstop");
       +        notes(res.store.u.ival);
       +        dostop(res.store.u.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.store.u.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.store.u.ival, "stop");
       +        notes(res.store.u.ival);
       +        dostop(res.store.u.ival);
       +}
       +
       +void
       +xkill(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.store.u.ival, "kill");
       +        deinstall(res.store.u.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.store.u.ival);
       +        r->store.u.string = strnode(p);
       +        r->op = OCONST;
       +        r->store.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->store.fmt = 's';
       +        r->store.u.string = strnode((*mach->exc)(cormap, correg));
       +}
       +
       +void
       +follow(Node *r, Node *args)
       +{
       +        int n, i;
       +        Node res;
       +        ulong 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 = (*mach->foll)(cormap, correg, res.store.u.ival, f);
       +        if (n < 0)
       +                error("follow(addr): %r");
       +        tail = &r->store.u.l;
       +        for(i = 0; i < n; i++) {
       +                l = al(TINT);
       +                l->store.u.ival = f[i];
       +                l->store.fmt = 'X';
       +                *tail = l;
       +                tail = &l->next;
       +        }
       +}
       +
       +void
       +funcbound(Node *r, Node *args)
       +{
       +        int n;
       +        Node res;
       +        ulong 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.store.u.ival, bounds);
       +        if (n != 0) {
       +                r->store.u.l = al(TINT);
       +                l = r->store.u.l;
       +                l->store.u.ival = bounds[0];
       +                l->store.fmt = 'X';
       +                l->next = al(TINT);
       +                l = l->next;
       +                l->store.u.ival = bounds[1];
       +                l->store.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.store.u.ival);
       +}
       +
       +void
       +filepc(Node *r, Node *args)
       +{
       +        int i;
       +        Node res;
       +        char *p, c;
       +        ulong v;
       +
       +        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.store.u.string->string, ':');
       +        if(p == 0)
       +                error("filepc(filename:line): bad arg format");
       +
       +        c = *p;
       +        *p++ = '\0';
       +        i = file2pc(res.store.u.string->string, atoi(p), &v);
       +        p[-1] = c;
       +        if(i < 0)
       +                error("filepc(filename:line): can't find address");
       +
       +        r->op = OCONST;
       +        r->type = TINT;
       +        r->store.fmt = 'D';
       +        r->store.u.ival = 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->store.u.ival = yyparse();
       +        interactive = isave;
       +        popio();
       +        r->op = OCONST;
       +        r->type = TINT;
       +        r->store.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");
       +
       +        Bflush(bout);
       +        pushfile(res.store.u.string->string);
       +
       +        isave = interactive;
       +        interactive = 0;
       +        r->store.u.ival = yyparse();
       +        interactive = isave;
       +        popio();
       +        r->op = OCONST;
       +        r->type = TINT;
       +        r->store.fmt = 'D';
       +}
       +
       +void
       +includepipe(Node *r, Node *args)
       +{
       +        Node res;
       +        int i, isave, pid, pip[2];
       +        char *argv[4];
       +        Waitmsg *w;
       +
       +        USED(r);
       +        if(args == 0)
       +                error("includepipe(string): arg count");
       +        expr(args, &res);
       +        if(res.type != TSTRING)
       +                error("includepipe(string): arg type");
       +
       +        Bflush(bout);
       +
       +        argv[0] = "rc";
       +        argv[1] = "-c";
       +        argv[2] = res.store.u.string->string;
       +        argv[3] = 0;
       +
       +        if(pipe(pip) < 0)
       +                error("pipe: %r");
       +                
       +        pid = fork();
       +        switch(pid) {
       +        case -1:
       +                close(pip[0]);
       +                close(pip[1]);
       +                error("fork: %r");
       +        case 0:
       +                close(pip[0]);
       +                close(0);
       +                open("/dev/null", OREAD);
       +                dup(pip[1], 1);
       +                if(pip[1] > 1)
       +                        close(pip[1]);
       +                for(i=3; i<100; i++)
       +                        close(i);
       +                exec("rc", argv);
       +                sysfatal("exec rc: %r");
       +        }
       +
       +        close(pip[1]);
       +        pushfd(pip[0]);
       +        
       +        isave = interactive;
       +        interactive = 0;
       +        r->store.u.ival = yyparse();
       +        interactive = isave;
       +        popio();
       +        r->op = OCONST;
       +        r->type = TINT;
       +        r->store.fmt = 'D';
       +
       +        w = waitfor(pid);
       +        if(w->msg && w->msg[0])
       +                error("includepipe(\"%s\"): %s", argv[2], w->msg);        /* leaks w */
       +        free(w);
       +}
       +
       +void
       +rc(Node *r, Node *args)
       +{
       +        Node res;
       +        int pid;
       +        char *p, *q, *argv[4];
       +        Waitmsg *w;
       +
       +        USED(r);
       +        if(args == 0)
       +                error("rc(string): arg count");
       +        expr(args, &res);
       +        if(res.type != TSTRING)
       +                error("rc(string): arg type");
       +
       +        argv[0] = "rc";
       +        argv[1] = "-c";
       +        argv[2] = res.store.u.string->string;
       +        argv[3] = 0;
       +
       +        pid = fork();
       +        switch(pid) {
       +        case -1:
       +                error("fork %r");
       +        case 0:
       +                exec("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->store.u.string = strnode(p);
       +        free(w);
       +        r->store.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.store.u.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->store.u.ival = 0;                
       +        if(access(res.store.u.string->string, 4) == 0)
       +                r->store.u.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.store.u.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->store.u.string = strnodlen(buf, n);
       +                r->store.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->store.u.l = 0;
       +
       +        p = res.store.u.string->string;
       +        bp = Bopen(p, OREAD);
       +        if(bp == 0)
       +                return;
       +
       +        l = &r->store.u.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->store.u.string = s;
       +                new->store.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->store.u.fval = atof(res.store.u.string->string);
       +        r->store.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->store.u.ival = strtoul(res.store.u.string->string, 0, 0);
       +        r->store.fmt = 'D';
       +}
       +
       +void
       +cvtitoa(Node *r, Node *args)
       +{
       +        Node res;
       +        Node *av[Maxarg];
       +        int ival;
       +        char buf[128], *fmt;
       +
       +        if(args == 0)
       +err:
       +                error("itoa(number [, printformat]): arg count");
       +        na = 0;
       +        flatten(av, args);
       +        if(na == 0 || na > 2)
       +                goto err;
       +        expr(av[0], &res);
       +        if(res.type != TINT)
       +                error("itoa(integer): arg type");
       +        ival = (int)res.store.u.ival;
       +        fmt = "%d";
       +        if(na == 2){
       +                expr(av[1], &res);
       +                if(res.type != TSTRING)
       +                        error("itoa(integer, string): arg type");
       +                fmt = res.store.u.string->string;
       +        }
       +
       +        sprint(buf, fmt, ival);
       +        r->op = OCONST;
       +        r->type = TSTRING;
       +        r->store.u.string = strnode(buf);
       +        r->store.fmt = 's';
       +}
       +
       +List*
       +mapent(Map *m)
       +{
       +        int i;
       +        List *l, *n, **t, *h;
       +
       +        h = 0;
       +        t = &h;
       +        for(i = 0; i < m->nseg; i++) {
       +                l = al(TSTRING);
       +                n = al(TLIST);
       +                n->store.u.l = l;
       +                *t = n;
       +                t = &n->next;
       +                l->store.u.string = strnode(m->seg[i].name);
       +                l->store.fmt = 's';
       +                l->next = al(TSTRING);
       +                l = l->next;
       +                l->store.u.string = strnode(m->seg[i].file ? m->seg[i].file : "");
       +                l->store.fmt = 's';
       +                l->next = al(TINT);
       +                l = l->next;
       +                l->store.u.ival = m->seg[i].base;
       +                l->store.fmt = 'X';
       +                l->next = al(TINT);
       +                l = l->next;
       +                l->store.u.ival = m->seg[i].base + m->seg[i].size;
       +                l->store.fmt = 'X';
       +                l->next = al(TINT);
       +                l = l->next;
       +                l->store.u.ival = m->seg[i].offset;
       +                l->store.fmt = 'X';
       +        }
       +        return h;
       +}
       +
       +void
       +map(Node *r, Node *args)
       +{
       +        int i;
       +        Map *m;
       +        List *l;
       +        char *nam, *fil;
       +        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.store.u.l) != 5)
       +                        error("map(list): list must have 5 entries");
       +
       +                l = res.store.u.l;
       +                if(l->type != TSTRING)
       +                        error("map name must be a string");
       +                nam = l->store.u.string->string;
       +                l = l->next;
       +                if(l->type != TSTRING)
       +                        error("map file must be a string");
       +                fil = l->store.u.string->string;
       +                m = symmap;
       +                i = findseg(m, nam, fil);
       +                if(i < 0) {
       +                        m = cormap;
       +                        i = findseg(m, nam, fil);
       +                }
       +                if(i < 0)
       +                        error("%s %s is not a map entry", nam, fil);        
       +                l = l->next;
       +                if(l->type != TINT)
       +                        error("map entry not int");
       +                m->seg[i].base = l->store.u.ival;
       +/*
       +                if (strcmp(ent, "text") == 0)
       +                        textseg(l->store.u.ival, &fhdr);
       +*/
       +                l = l->next;
       +                if(l->type != TINT)
       +                        error("map entry not int");
       +                m->seg[i].size = l->store.u.ival - m->seg[i].base;
       +                l = l->next;
       +                if(l->type != TINT)
       +                        error("map entry not int");
       +                m->seg[i].offset = l->store.u.ival;
       +        }
       +
       +        r->type = TLIST;
       +        r->store.u.l = 0;
       +        if(symmap)
       +                r->store.u.l = mapent(symmap);
       +        if(cormap) {
       +                if(r->store.u.l == 0)
       +                        r->store.u.l = mapent(cormap);
       +                else {
       +                        for(l = r->store.u.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;
       +        }
       +}
       +
       +static struct
       +{
       +        char *name;
       +        ulong val;
       +} sregs[Maxarg/2];
       +static int nsregs;
       +
       +static int
       +straceregrw(Regs *regs, char *name, ulong *val, int isr)
       +{
       +        int i;
       +
       +        if(!isr){
       +                werrstr("saved registers cannot be written");
       +                return -1;
       +        }
       +        for(i=0; i<nsregs; i++)
       +                if(strcmp(sregs[i].name, name) == 0){
       +                        *val = sregs[i].val;
       +                        return 0;
       +                }
       +        return rget(correg, name, val);
       +}
       +
       +void
       +strace(Node *r, Node *args)
       +{
       +        Node *av[Maxarg], res;
       +        List *l;
       +        Regs regs;
       +
       +        na = 0;
       +        flatten(av, args);
       +
       +        if(na != 1)
       +                error("strace(list): want one arg");
       +
       +        expr(av[0], &res);
       +        if(res.type != TLIST)
       +                error("strace(list): strace needs a list");
       +        l = res.store.u.l;
       +        if(listlen(l)%2)
       +                error("strace(list): strace needs an even-length list");
       +        for(nsregs=0; l; nsregs++){
       +                if(l->type != TSTRING)
       +                        error("strace({r,v,r,v,...}): non-string name");
       +                sregs[nsregs].name = l->store.u.string->string;
       +                if(regdesc(sregs[nsregs].name) == nil)
       +                        error("strace: bad register '%s'", sregs[nsregs].name);
       +                l = l->next;
       +
       +                if(l == nil)
       +                        error("cannot happen in strace");
       +                if(l->type != TINT)
       +                        error("strace: non-int value for %s", sregs[nsregs].name);
       +                sregs[nsregs].val = l->store.u.ival;
       +                l = l->next;
       +        }
       +        regs.rw = straceregrw;
       +        
       +        tracelist = 0;
       +        if(stacktrace(cormap, &regs, trlist) <= 0)
       +                error("no stack frame");
       +        r->type = TLIST;
       +        r->store.u.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.store.u.string->string);
       +        if(rp == 0)
       +                return;
       +
       +        expr(av[1], &res);
       +        if(res.type != TSTRING)
       +                error("regexp(pattern, string): bad string");
       +
       +        r->store.fmt = 'D';
       +        r->type = TINT;
       +        r->store.u.ival = regexec(rp, res.store.u.string->string, 0, 0);
       +        free(rp);
       +}
       +
       +char vfmt[] = "aBbcCdDfFgGiIoOqQrRsSuUVxXYZ";
       +
       +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.store.u.ival) == 0)
       +                error("fmt(obj, fmt): bad format '%c'", (char)res.store.u.ival);
       +        expr(av[0], r);
       +        r->store.fmt = res.store.u.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->u.ival);
       +                break;
       +        case 'C':
       +                if(res->u.ival < ' ' || res->u.ival >= 0x7f)
       +                        Bprint(bout, "%3d", (int)res->u.ival&0xff);
       +                else
       +                        Bprint(bout, "%3c", (int)res->u.ival);
       +                break;
       +        case 'r':
       +                Bprint(bout, "%C", (int)res->u.ival);
       +                break;
       +        case 'B':
       +                memset(buf, '0', 34);
       +                buf[1] = 'b';
       +                for(i = 0; i < 32; i++) {
       +                        if(res->u.ival & (1<<i))
       +                                buf[33-i] = '1';
       +                }
       +                buf[35] = '\0';
       +                Bprint(bout, "%s", buf);
       +                break;
       +        case 'b':
       +                Bprint(bout, "%.2x", (int)res->u.ival&0xff);
       +                break;
       +        case 'X':
       +                Bprint(bout, "%.8lux", (ulong)res->u.ival);
       +                break;
       +        case 'x':
       +                Bprint(bout, "%.4lux", (ulong)res->u.ival&0xffff);
       +                break;
       +        case 'W':
       +                Bprint(bout, "%.16llux", res->u.ival);
       +                break;
       +        case 'D':
       +                Bprint(bout, "%d", (int)res->u.ival);
       +                break;
       +        case 'd':
       +                Bprint(bout, "%d", (ushort)res->u.ival);
       +                break;
       +        case 'u':
       +                Bprint(bout, "%d", (int)res->u.ival&0xffff);
       +                break;
       +        case 'U':
       +                Bprint(bout, "%lud", (ulong)res->u.ival);
       +                break;
       +        case 'Z':
       +                Bprint(bout, "%llud", res->u.ival);
       +                break;
       +        case 'V':
       +                Bprint(bout, "%lld", res->u.ival);
       +                break;
       +        case 'Y':
       +                Bprint(bout, "%.16llux", res->u.ival);
       +                break;
       +        case 'o':
       +                Bprint(bout, "0%.11uo", (int)res->u.ival&0xffff);
       +                break;
       +        case 'O':
       +                Bprint(bout, "0%.6uo", (int)res->u.ival);
       +                break;
       +        case 'q':
       +                Bprint(bout, "0%.11o", (short)(res->u.ival&0xffff));
       +                break;
       +        case 'Q':
       +                Bprint(bout, "0%.6o", (int)res->u.ival);
       +                break;
       +        case 'f':
       +        case 'F':
       +                if(type != TFLOAT)
       +                        Bprint(bout, "*%c<%s>*", res->fmt, typenames[(uchar)type]);
       +                else
       +                        Bprint(bout, "%g", res->u.fval);
       +                break;
       +        case 's':
       +        case 'g':
       +        case 'G':
       +                if(type != TSTRING)
       +                        Bprint(bout, "*%c<%s>*", res->fmt, typenames[(uchar)type]);
       +                else
       +                        Bwrite(bout, res->u.string->string, res->u.string->len);
       +                break;
       +        case 'R':
       +                if(type != TSTRING)
       +                        Bprint(bout, "*%c<%s>*", res->fmt, typenames[(uchar)type]);
       +                else
       +                        Bprint(bout, "%S", (Rune*)res->u.string->string);
       +                break;
       +        case 'a':
       +        case 'A':
       +                symoff(buf, sizeof(buf), res->u.ival, CANY);
       +                Bprint(bout, "%s", buf);
       +                break;
       +        case 'I':
       +        case 'i':
       +                if(type != TINT)
       +                        Bprint(bout, "*%c<%s>*", res->fmt, typenames[(uchar)type]);
       +                else {
       +                        if (symmap == nil || (*mach->das)(symmap, res->u.ival, res->fmt, buf, sizeof(buf)) < 0)
       +                                Bprint(bout, "no instruction");
       +                        else
       +                                Bprint(bout, "%s", buf);
       +                }
       +                break;
       +        }
       +}
       +
       +void
       +blprint(List *l)
       +{
       +        Store *res;
       +
       +        Bprint(bout, "{");
       +        while(l) {
       +                switch(l->type) {
       +                case TINT:
       +                        res = &l->store;
       +                        if(res->fmt == 'c'){
       +                                Bprint(bout, "\'%c\'", (int)res->u.ival);
       +                                break;
       +                        }else if(res->fmt == 'r'){
       +                                Bprint(bout, "\'%C\'", (int)res->u.ival);
       +                                break;
       +                        }
       +                        /* fall through */
       +                default:
       +                        patom(l->type, &l->store);
       +                        break;
       +                case TSTRING:
       +                        Bputc(bout, '"');
       +                        patom(l->type, &l->store);
       +                        Bputc(bout, '"');
       +                        break;
       +                case TLIST:
       +                        blprint(l->store.u.l);
       +                        break;
       +                case TCODE:
       +                        pcode(l->store.u.cc, 0);
       +                        break;
       +                }
       +                l = l->next;
       +                if(l)
       +                        Bprint(bout, ", ");
       +        }
       +        Bprint(bout, "}");
       +}
       +
       +int
       +comx(Node res)
       +{
       +        Lsym *sl;
       +        Node *n, xx;
       +
       +        if(res.store.fmt != 'a' && res.store.fmt != 'A')
       +                return 0;
       +
       +        if(res.store.comt == 0 || res.store.comt->base == 0)
       +                return 0;
       +
       +        sl = res.store.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.store.u.cc, 0);
       +                        break;
       +                case TLIST:
       +                        blprint(res.store.u.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.store.u.string->string, OWRITE, 0666);
       +        if(fd < 0)
       +                fd = open(res.store.u.string->string, OWRITE);
       +        if(fd < 0)
       +                error("printto: open %s: %r", res.store.u.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.store.u.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->store.fmt = 's';
       +        if(fileline(res.store.u.ival, buf, sizeof(buf)) < 0) {
       +                r->store.u.string = strnode("?file?");
       +                return;
       +        }
       +        p = strrchr(buf, ':');
       +        if(p == 0)
       +                error("pcfile(addr): funny file %s", buf);
       +        *p = '\0';
       +        r->store.u.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->store.fmt = 'D';
       +        if(fileline(res.store.u.ival, buf, sizeof(buf)) < 0) {
       +                r->store.u.ival = 0;
       +                return;
       +        }
       +
       +        p = strrchr(buf, ':');
       +        if(p == 0)
       +                error("pcline(addr): funny file %s", buf);
       +        r->store.u.ival = atoi(p+1);        
       +}
       +
       +void
       +textfile(Node *r, Node *args)
       +{
       +        char *file;
       +        long base;
       +        Fhdr *fp;
       +        Node res, *av[Maxarg];
       +        List *l, *l2, **tail, *list, *tl;
       +
       +        na = 0;
       +        flatten(av, args);
       +
       +        if(na != 0) {
       +                expr(av[0], &res);
       +                if(res.type != TLIST)
       +                        error("textfile(list): textfile needs a list");
       +                if(listlen(res.store.u.l) != 2)
       +                        error("textfile(list): list must have 2 entries");
       +
       +                l = res.store.u.l;
       +                if(l->type != TSTRING)
       +                        error("textfile name must be a string");
       +                file = l->store.u.string->string;
       +
       +                l = l->next;
       +                if(l->type != TINT)
       +                        error("textfile base must be an int");
       +                base = l->store.u.ival;
       +
       +                if((fp = crackhdr(file, OREAD)) == nil)
       +                        error("crackhdr %s: %r", file);
       +                Bflush(bout);
       +                fp->base = base;
       +                fprint(2, "%s: %s %s %s\n", file, fp->aname, fp->mname, fp->fname);
       +                if(mapfile(fp, base, symmap, nil) < 0)
       +                        fprint(2, "mapping %s: %r\n", file);
       +                if(corhdr){
       +                        unmapfile(corhdr, cormap);
       +                        mapfile(fp, base, cormap, nil);
       +                        free(correg);
       +                        mapfile(corhdr, 0, cormap, &correg);
       +                }
       +                if(syminit(fp) < 0)
       +                        fprint(2, "syminit %s: %r\n", file);
       +                else
       +                        addvarsym(fp);
       +                return;
       +        }
       +
       +        l2 = nil;
       +        tail = &l2;
       +        for(fp=fhdrlist; fp; fp=fp->next){
       +                if(fp->ftype == FCORE)
       +                        continue;
       +                tl = al(TLIST);
       +                *tail = tl;
       +                tail = &tl->next;
       +
       +                list = al(TSTRING);
       +                tl->store.u.l = list;
       +                list->store.u.string = strnode(fp->filename);
       +                list->store.fmt = 's';
       +                list->next = al(TINT);
       +                list = list->next;
       +                list->store.fmt = 'X';
       +                list->store.u.ival = fp->base;
       +        }
       +
       +        r->type = TLIST;
       +        r->store.u.l = l2;
       +}
       +
       +void
       +deltextfile(Node *r, Node *args)
       +{
       +        int did;
       +        char *file;
       +        Fhdr *fp, *fpnext;
       +        Node res, *av[Maxarg];
       +
       +        na = 0;
       +        flatten(av, args);
       +
       +        if(na != 1)
       +                error("deltextfile(string): arg count");
       +
       +        expr(av[0], &res);
       +        if(res.type != TSTRING)
       +                error("deltextfile(string): arg type");
       +        file = res.store.u.string->string;
       +
       +        did = 0;
       +        for(fp=fhdrlist; fp; fp=fpnext){
       +                fpnext = fp->next;
       +                if(fp->ftype == FCORE)
       +                        continue;
       +                if(strcmp(file, fp->filename) == 0){
       +                        did = 1;
       +                        if(fp == symhdr)
       +                                error("cannot remove symbols from main text file");
       +                        unmapfile(fp, symmap);
       +                        uncrackhdr(fp);
       +                }
       +        }
       +
       +        delvarsym(file);
       +        if(!did)
       +                error("symbol file %s not open", file);
       +}
       +
 (DIR) diff --git a/src/cmd/acid/dbg.y b/src/cmd/acid/dbg.y
       t@@ -0,0 +1,413 @@
       +%{
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include <mach.h>
       +#define Extern extern
       +#include "acid.h"
       +%}
       +
       +%union
       +{
       +        Node        *node;
       +        Lsym        *sym;
       +        ulong        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
       +                {
       +                        /* hold on to current command for gc */
       +                        mkvar("_thiscmd")->proc = $1;
       +                        execute($1);
       +                        gc();
       +                        if(interactive && nlcount){
       +                                Bprint(bout, "acid; ");
       +                                nlcount = 0;
       +                        }
       +                }
       +                | 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->store.u.ival = $2;
       +                        $3->store.fmt = $1;
       +                        $$ = $3;
       +                }
       +                | Tconst mname Tconst mname ';'
       +                {
       +                        $4->store.u.ival = $3;
       +                        $4->store.fmt = $1;
       +                        $4->right = $2;
       +                        $$ = $4;
       +                }
       +                | mname Tconst mname ';'
       +                {
       +                        $3->store.u.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
       +                {
       +                        $$ = con(0);
       +                        $$ = an(OADD, $2, $$);
       +                }
       +                | '-' 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;
       +                        $$->store.fmt = 'f';
       +                        $$->store.u.fval = $1;
       +                }
       +                | Tstring
       +                {
       +                        $$ = an(OCONST, ZN, ZN);
       +                        $$->type = TSTRING;
       +                        $$->store.u.string = $1;
       +                        $$->store.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);
       +                }
       +                ;
 (DIR) diff --git a/src/cmd/acid/dot.c b/src/cmd/acid/dot.c
       t@@ -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;
       +        ulong addr;
       +
       +        s = n->sym->name;
       +        if(s == 0)
       +                fatal("dodot: no tag");
       +
       +        expr(n->left, &res);
       +        if(res.store.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.store.comt, s);
       +        if(t == 0)
       +                error("no tag for (expr).%s", s);
       +
       +        /* Propagate types */
       +        if(t->type) 
       +                r->store.comt = t->type->lt;
       +        
       +        addr = res.store.u.ival+t->offset;
       +        if(t->fmt == 'a') {
       +                r->op = OCONST;
       +                r->store.fmt = 'a';
       +                r->type = TINT;
       +                r->store.u.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->store.u.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->store.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->store.comt = type->lt;
       +                v->store.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;
       +}
 (DIR) diff --git a/src/cmd/acid/exec.c b/src/cmd/acid/exec.c
       t@@ -0,0 +1,538 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include <ctype.h>
       +#include <mach.h>
       +#define Extern extern
       +#include "acid.h"
       +
       +void
       +error(char *fmt, ...)
       +{
       +        int i;
       +        char buf[2048];
       +        va_list arg;
       +
       +        /* Unstack io channels */
       +        if(iop != 0) {
       +                for(i = 1; i < iop; i++)
       +                        Bterm(io[i]);
       +                bout = io[0];
       +                iop = 0;
       +        }
       +
       +        ret = 0;
       +        gotint = 0;
       +        Bflush(bout);
       +        if(silent)
       +                silent = 0;
       +        else {
       +                va_start(arg, fmt);
       +                vseprint(buf, buf+sizeof(buf), fmt, arg);
       +                va_end(arg);
       +                fprint(2, "%Z: (error) %s\n", buf);
       +        }
       +        while(popio())
       +                ;
       +        interactive = 1;
       +        longjmp(err, 1);
       +}
       +
       +void
       +unwind(void)
       +{
       +        int i;
       +        Lsym *s;
       +        Value *v;
       +
       +        for(i = 0; i < Hashsize; i++) {
       +                for(s = hash[i]; s; s = s->hash) {
       +                        while(s->v->pop) {
       +                                v = s->v->pop;
       +                                free(s->v);
       +                                s->v = v;
       +                        }
       +                }
       +        }
       +}
       +
       +void
       +execute(Node *n)
       +{
       +        Value *v;
       +        Lsym *sl;
       +        Node *l, *r;
       +        int i, s, e;
       +        Node res, xx;
       +        static int stmnt;
       +
       +        gc();
       +        if(gotint)
       +                error("interrupted");
       +
       +        if(n == 0)
       +                return;
       +
       +        if(stmnt++ > 5000) {
       +                Bflush(bout);
       +                stmnt = 0;
       +        }
       +
       +        l = n->left;
       +        r = n->right;
       +
       +        switch(n->op) {
       +        default:
       +                expr(n, &res);
       +                if(ret || (res.type == TLIST && res.store.u.l == 0))
       +                        break;
       +                prnt->right = &res;
       +                expr(prnt, &xx);
       +                break;
       +        case OASGN:
       +        case OCALL:
       +                expr(n, &res);
       +                break;
       +        case OCOMPLEX:
       +                decl(n);
       +                break;
       +        case OLOCAL:
       +                for(n = n->left; n; n = n->left) {
       +                        if(ret == 0)
       +                                error("local not in function");
       +                        sl = n->sym;
       +                        if(sl->v->ret == ret)
       +                                error("%s declared twice", sl->name);
       +                        v = gmalloc(sizeof(Value));
       +                        v->ret = ret;
       +                        v->pop = sl->v;
       +                        sl->v = v;
       +                        v->scope = 0;
       +                        *(ret->tail) = sl;
       +                        ret->tail = &v->scope;
       +                        v->set = 0;
       +                }
       +                break;
       +        case ORET:
       +                if(ret == 0)
       +                        error("return not in function");
       +                expr(n->left, ret->val);
       +                longjmp(ret->rlab, 1);
       +        case OLIST:
       +                execute(n->left);
       +                execute(n->right);
       +                break;
       +        case OIF:
       +                expr(l, &res);
       +                if(r && r->op == OELSE) {
       +                        if(bool(&res))
       +                                execute(r->left);
       +                        else
       +                                execute(r->right);
       +                }
       +                else if(bool(&res))
       +                        execute(r);
       +                break;
       +        case OWHILE:
       +                for(;;) {
       +                        expr(l, &res);
       +                        if(!bool(&res))
       +                                break;
       +                        execute(r);
       +                }
       +                break;
       +        case ODO:
       +                expr(l->left, &res);
       +                if(res.type != TINT)
       +                        error("loop must have integer start");
       +                s = res.store.u.ival;
       +                expr(l->right, &res);
       +                if(res.type != TINT)
       +                        error("loop must have integer end");
       +                e = res.store.u.ival;
       +                for(i = s; i <= e; i++)
       +                        execute(r);
       +                break;
       +        }
       +}
       +
       +int
       +bool(Node *n)
       +{
       +        int true = 0;
       +
       +        if(n->op != OCONST)
       +                fatal("bool: not const");
       +
       +        switch(n->type) {
       +        case TINT:
       +                if(n->store.u.ival != 0)
       +                        true = 1;
       +                break;
       +        case TFLOAT:
       +                if(n->store.u.fval != 0.0)
       +                        true = 1;
       +                break;
       +        case TSTRING:
       +                if(n->store.u.string->len)
       +                        true = 1;
       +                break;
       +        case TLIST:
       +                if(n->store.u.l)
       +                        true = 1;
       +                break;
       +        }
       +        return true;
       +}
       +
       +void
       +convflt(Node *r, char *flt)
       +{
       +        char c;
       +
       +        c = flt[0];
       +        if(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) {
       +                r->type = TSTRING;
       +                r->store.fmt = 's';
       +                r->store.u.string = strnode(flt);
       +        }
       +        else {
       +                r->type = TFLOAT;
       +                r->store.u.fval = atof(flt);
       +        }
       +}
       +
       +static char*
       +regbyoff(ulong addr)
       +{
       +        Regdesc *r;
       +
       +        if(mach == nil)
       +                error("no mach, no registers");
       +        for(r=mach->reglist; r->name; r++)
       +                if(r->offset == addr)
       +                        return r->name;
       +        error("no register at %#lux", addr);
       +        return nil;
       +}
       +
       +int
       +xget1(Map *m, ulong addr, u8int *a, int n)
       +{
       +        if(addr < 0x100)
       +                return lget1(m, correg, locreg(regbyoff(addr)), a, n);
       +        else
       +                return get1(m, addr, a, n);
       +}
       +
       +int
       +xget2(Map *m, ulong addr, u16int *a)
       +{
       +        if(addr < 0x100)
       +                return lget2(m, correg, locreg(regbyoff(addr)), a);
       +        else
       +                return get2(m, addr, a);
       +}
       +
       +int
       +xget4(Map *m, ulong addr, u32int *a)
       +{
       +        if(addr < 0x100)
       +                return lget4(m, correg, locreg(regbyoff(addr)), a);
       +        else
       +                return get4(m, addr, a);
       +}
       +
       +int
       +xget8(Map *m, ulong addr, u64int *a)
       +{
       +        if(addr < 0x100)
       +                return lget8(m, correg, locreg(regbyoff(addr)), a);
       +        else
       +                return get8(m, addr, a);
       +}
       +
       +void
       +indir(Map *m, ulong addr, char fmt, Node *r)
       +{
       +        int i;
       +        u32int ival;
       +        u64int vval;
       +        int ret;
       +        u8int cval;
       +        u16int sval;
       +        char buf[512], reg[12];
       +
       +        r->op = OCONST;
       +        r->store.fmt = fmt;
       +        switch(fmt) {
       +        default:
       +                error("bad pointer format '%c' for *", fmt);
       +        case 'c':
       +        case 'C':
       +        case 'b':
       +                r->type = TINT;
       +                ret = xget1(m, addr, &cval, 1);
       +                if (ret < 0)
       +                        error("indir: %r");
       +                r->store.u.ival = cval;
       +                break;
       +        case 'x':
       +        case 'd':
       +        case 'u':
       +        case 'o':
       +        case 'q':
       +        case 'r':
       +                r->type = TINT;
       +                ret = xget2(m, addr, &sval);
       +                if (ret < 0)
       +                        error("indir: %r");
       +                r->store.u.ival = sval;
       +                break;
       +        case 'a':
       +        case 'A':
       +        case 'B':
       +        case 'X':
       +        case 'D':
       +        case 'U':
       +        case 'O':
       +        case 'Q':
       +                r->type = TINT;
       +                ret = xget4(m, addr, &ival);
       +                if (ret < 0)
       +                        error("indir: %r");
       +                r->store.u.ival = ival;
       +                break;
       +        case 'V':
       +        case 'W':
       +        case 'Y':
       +        case 'Z':
       +                r->type = TINT;
       +                ret = xget8(m, addr, &vval);
       +                if (ret < 0)
       +                        error("indir: %r");
       +                r->store.u.ival = vval;
       +                break;
       +        case 's':
       +                r->type = TSTRING;
       +                for(i = 0; i < sizeof(buf)-1; i++) {
       +                        ret = xget1(m, addr, (uchar*)&buf[i], 1);
       +                        if (ret < 0)
       +                                error("indir: %r");
       +                        addr++;
       +                        if(buf[i] == '\0')
       +                                break;
       +                }
       +                buf[i] = 0;
       +                if(i == 0)
       +                        strcpy(buf, "(null)");
       +                r->store.u.string = strnode(buf);
       +                break;
       +        case 'R':
       +                r->type = TSTRING;
       +                for(i = 0; i < sizeof(buf)-2; i += 2) {
       +                        ret = xget1(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->store.u.string = runenode((Rune*)buf);
       +                break;
       +        case 'i':
       +        case 'I':
       +                if ((*mach->das)(m, addr, fmt, buf, sizeof(buf)) < 0)
       +                        error("indir: %r");
       +                r->type = TSTRING;
       +                r->store.fmt = 's';
       +                r->store.u.string = strnode(buf);
       +                break;
       +        case 'f':
       +                ret = xget1(m, addr, (uchar*)buf, mach->szfloat);
       +                if (ret < 0)
       +                        error("indir: %r");
       +                mach->ftoa32(buf, sizeof(buf), (void*) buf);
       +                convflt(r, buf);
       +                break;
       +        case 'g':
       +                ret = xget1(m, addr, (uchar*)buf, mach->szfloat);
       +                if (ret < 0)
       +                        error("indir: %r");
       +                mach->ftoa32(buf, sizeof(buf), (void*) buf);
       +                r->type = TSTRING;
       +                r->store.u.string = strnode(buf);
       +                break;
       +        case 'F':
       +                ret = xget1(m, addr, (uchar*)buf, mach->szdouble);
       +                if (ret < 0)
       +                        error("indir: %r");
       +                mach->ftoa64(buf, sizeof(buf), (void*) buf);
       +                convflt(r, buf);
       +                break;
       +        case '3':        /* little endian ieee 80 with hole in bytes 8&9 */
       +                ret = xget1(m, addr, (uchar*)reg, 10);
       +                if (ret < 0)
       +                        error("indir: %r");
       +                memmove(reg+10, reg+8, 2);        /* open hole */
       +                memset(reg+8, 0, 2);                /* fill it */
       +                leieeeftoa80(buf, sizeof(buf), reg);
       +                convflt(r, buf);
       +                break;
       +        case '8':        /* big-endian ieee 80 */
       +                ret = xget1(m, addr, (uchar*)reg, 10);
       +                if (ret < 0)
       +                        error("indir: %r");
       +                beieeeftoa80(buf, sizeof(buf), reg);
       +                convflt(r, buf);
       +                break;
       +        case 'G':
       +                ret = xget1(m, addr, (uchar*)buf, mach->szdouble);
       +                if (ret < 0)
       +                        error("indir: %r");
       +                mach->ftoa64(buf, sizeof(buf), (void*) buf);
       +                r->type = TSTRING;
       +                r->store.u.string = strnode(buf);
       +                break;
       +        }
       +}
       +
       +void
       +windir(Map *m, Node *addr, Node *rval, Node *r)
       +{
       +        uchar cval;
       +        ushort sval;
       +        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->store.fmt = res.store.fmt;
       +        r->store = res.store;
       +
       +        switch(res.store.fmt) {
       +        default:
       +                error("bad pointer format '%c' for */@=", res.store.fmt);
       +        case 'c':
       +        case 'C':
       +        case 'b':
       +                cval = res.store.u.ival;
       +                ret = put1(m, aes.store.u.ival, &cval, 1);
       +                break;
       +        case 'r':
       +        case 'x':
       +        case 'd':
       +        case 'u':
       +        case 'o':
       +                sval = res.store.u.ival;
       +                ret = put2(m, aes.store.u.ival, sval);
       +                r->store.u.ival = sval;
       +                break;
       +        case 'a':
       +        case 'A':
       +        case 'B':
       +        case 'X':
       +        case 'D':
       +        case 'U':
       +        case 'O':
       +                ret = put4(m, aes.store.u.ival, res.store.u.ival);
       +                break;
       +        case 'V':
       +        case 'W':
       +        case 'Y':
       +        case 'Z':
       +                ret = put8(m, aes.store.u.ival, res.store.u.ival);
       +                break;
       +        case 's':
       +        case 'R':
       +                ret = put1(m, aes.store.u.ival, (uchar*)res.store.u.string->string, res.store.u.string->len);
       +                break;
       +        }
       +        if (ret < 0)
       +                error("windir: %r");
       +}
       +
       +void
       +call(char *fn, Node *parameters, Node *local, Node *body, Node *retexp)
       +{
       +        int np, i;
       +        Rplace rlab;
       +        Node *n, res;
       +        Value *v, *f;
       +        Lsym *s, *next;
       +        Node *avp[Maxarg], *ava[Maxarg];
       +
       +        rlab.local = 0;
       +
       +        na = 0;
       +        flatten(avp, parameters);
       +        np = na;
       +        na = 0;
       +        flatten(ava, local);
       +        if(np != na) {
       +                if(np < na)
       +                        error("%s: too few arguments", fn);
       +                error("%s: too many arguments", fn);
       +        }
       +
       +        rlab.tail = &rlab.local;
       +
       +        ret = &rlab;
       +        for(i = 0; i < np; i++) {
       +                n = ava[i];
       +                switch(n->op) {
       +                default:
       +                        error("%s: %d formal not a name", fn, i);
       +                case ONAME:
       +                        expr(avp[i], &res);
       +                        s = n->sym;
       +                        break;
       +                case OINDM:
       +                        res.store.u.cc = avp[i];
       +                        res.type = TCODE;
       +                        res.store.comt = 0;
       +                        if(n->left->op != ONAME)
       +                                error("%s: %d formal not a name", fn, i);
       +                        s = n->left->sym;
       +                        break;
       +                }
       +                if(s->v->ret == ret)
       +                        error("%s already declared at this scope", s->name);
       +
       +                v = gmalloc(sizeof(Value));
       +                v->ret = ret;
       +                v->pop = s->v;
       +                s->v = v;
       +                v->scope = 0;
       +                *(rlab.tail) = s;
       +                rlab.tail = &v->scope;
       +
       +                v->store = res.store;
       +                v->type = res.type;
       +                v->set = 1;
       +        }
       +
       +        ret->val = retexp;
       +        if(setjmp(rlab.rlab) == 0)
       +                execute(body);
       +
       +        for(s = rlab.local; s; s = next) {
       +                f = s->v;
       +                next = f->scope;
       +                s->v = f->pop;
       +                free(f);
       +        }
       +}
 (DIR) diff --git a/src/cmd/acid/expr.c b/src/cmd/acid/expr.c
       t@@ -0,0 +1,1018 @@
       +#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,
       +        ['X'] 4,
       +        ['Y'] 8,
       +        ['W'] 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,
       +};
       +
       +int
       +fmtsize(Value *v)
       +{
       +        int ret;
       +
       +        switch(v->store.fmt) {
       +        default:
       +                return  fsize[(unsigned char)v->store.fmt];
       +        case 'i':
       +        case 'I':
       +                if(v->type != TINT || mach == 0)
       +                        error("no size for i fmt pointer ++/--");
       +                ret = (*mach->instsize)(symmap, v->store.u.ival);
       +                if(ret < 0) {
       +                        ret = (*mach->instsize)(symmap, v->store.u.ival);
       +                        if(ret < 0)
       +                                error("%r");
       +                }
       +                return ret;
       +        }
       +}
       +
       +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->store.u.cc, res);
       +}
       +
       +void
       +ocast(Node *n, Node *res)
       +{
       +        if(n->sym->lt == 0)
       +                error("%s is not a complex type", n->sym->name);
       +
       +        expr(n->left, res);
       +        res->store.comt = n->sym->lt;
       +        res->store.fmt = 'a';
       +}
       +
       +void
       +oindm(Node *n, Node *res)
       +{
       +        Map *m;
       +        Node l;
       +
       +        m = cormap;
       +        if(m == 0)
       +                m = symmap;
       +        expr(n->left, &l);
       +        if(l.type != TINT)
       +                error("bad type for *");
       +        if(m == 0)
       +                error("no map for *");
       +        indir(m, l.store.u.ival, l.store.fmt, res);
       +        res->store.comt = l.store.comt;
       +}
       +
       +void
       +oindc(Node *n, Node *res)
       +{
       +        Map *m;
       +        Node l;
       +
       +        m = symmap;
       +        if(m == 0)
       +                m = cormap;
       +        expr(n->left, &l);
       +        if(l.type != TINT)
       +                error("bad type for @");
       +        if(m == 0)
       +                error("no map for @");
       +        indir(m, l.store.u.ival, l.store.fmt, res);
       +        res->store.comt = l.store.comt;
       +}
       +
       +void
       +oframe(Node *n, Node *res)
       +{
       +        char *p;
       +        Node *lp;
       +        ulong ival;
       +        Frtype *f;
       +
       +        p = n->sym->name;
       +        while(*p && *p == '$')
       +                p++;
       +        lp = n->left;
       +        if(localaddr(cormap, correg, p, lp->sym->name, &ival) < 0)
       +                error("colon: %r");
       +                
       +        res->store.u.ival = ival;
       +        res->op = OCONST;
       +        res->store.fmt = 'X';
       +        res->type = TINT;
       +
       +        /* Try and set comt */
       +        for(f = n->sym->local; f; f = f->next) {
       +                if(f->var == lp->sym) {
       +                        res->store.comt = f->type;
       +                        res->store.fmt = 'a';
       +                        break;
       +                }
       +        }
       +}
       +
       +void
       +oindex(Node *n, Node *res)
       +{
       +        Node l, r;
       +
       +        expr(n->left, &l);
       +        expr(n->right, &r);
       +
       +        if(r.type != TINT)
       +                error("bad type for []");
       +
       +        switch(l.type) {
       +        default:
       +                error("lhs[] has bad type");
       +        case TINT:
       +                indir(cormap, l.store.u.ival+(r.store.u.ival*fsize[(unsigned char)l.store.fmt]), l.store.fmt, res);
       +                res->store.comt = l.store.comt;
       +                res->store.fmt = l.store.fmt;
       +                break;
       +        case TLIST:
       +                nthelem(l.store.u.l, r.store.u.ival, res);
       +                break;
       +        case TSTRING:
       +                res->store.u.ival = 0;
       +                if(r.store.u.ival >= 0 && r.store.u.ival < l.store.u.string->len) {
       +                        int xx8;        /* to get around bug in vc */
       +                        xx8 = r.store.u.ival;
       +                        res->store.u.ival = l.store.u.string->string[xx8];
       +                }
       +                res->op = OCONST;
       +                res->type = TINT;
       +                res->store.fmt = 'c';
       +                break;
       +        }
       +}
       +
       +void
       +oappend(Node *n, Node *res)
       +{
       +        Node r, l;
       +
       +        expr(n->left, &l);
       +        expr(n->right, &r);
       +        if(l.type != TLIST)
       +                error("must append to list");
       +        append(res, &l, &r);
       +}
       +
       +void
       +odelete(Node *n, Node *res)
       +{
       +        Node l, r;
       +
       +        expr(n->left, &l);
       +        expr(n->right, &r);
       +        if(l.type != TLIST)
       +                error("must delete from list");
       +        if(r.type != TINT)
       +                error("delete index must be integer");
       +
       +        delete(l.store.u.l, r.store.u.ival, res);
       +}
       +
       +void
       +ohead(Node *n, Node *res)
       +{
       +        Node l;
       +
       +        expr(n->left, &l);
       +        if(l.type != TLIST)
       +                error("head needs list");
       +        res->op = OCONST;
       +        if(l.store.u.l) {
       +                res->type = l.store.u.l->type;
       +                res->store = l.store.u.l->store;
       +        }
       +        else {
       +                res->type = TLIST;
       +                res->store.u.l = 0;
       +        }
       +}
       +
       +void
       +otail(Node *n, Node *res)
       +{
       +        Node l;
       +
       +        expr(n->left, &l);
       +        if(l.type != TLIST)
       +                error("tail needs list");
       +        res->op = OCONST;
       +        res->type = TLIST;
       +        if(l.store.u.l)
       +                res->store.u.l = l.store.u.l->next;
       +        else
       +                res->store.u.l = 0;
       +}
       +
       +void
       +oconst(Node *n, Node *res)
       +{
       +        res->op = OCONST;
       +        res->type = n->type;
       +        res->store = n->store;
       +        res->store.comt = n->store.comt;
       +}
       +
       +void
       +oname(Node *n, Node *res)
       +{
       +        Value *v;
       +
       +        v = n->sym->v;
       +        if(v->set == 0)
       +                error("%s used but not set", n->sym->name);
       +        res->op = OCONST;
       +        res->type = v->type;
       +        res->store = v->store;
       +        res->store.comt = v->store.comt;
       +}
       +
       +void
       +octruct(Node *n, Node *res)
       +{
       +        res->op = OCONST;
       +        res->type = TLIST;
       +        res->store.u.l = construct(n->left);
       +}
       +
       +void
       +oasgn(Node *n, Node *res)
       +{
       +        Node *lp, r;
       +        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->store.comt = v->store.comt;
       +        }
       +}
       +
       +void
       +oadd(Node *n, Node *res)
       +{
       +        Node l, r;
       +
       +        expr(n->left, &l);
       +        expr(n->right, &r);
       +        res->store.fmt = l.store.fmt;
       +        res->op = OCONST;
       +        res->type = TFLOAT;
       +        switch(l.type) {
       +        default:
       +                error("bad lhs type +");
       +        case TINT:
       +                switch(r.type) {
       +                case TINT:
       +                        res->type = TINT;
       +                        res->store.u.ival = l.store.u.ival+r.store.u.ival;
       +                        break;
       +                case TFLOAT:
       +                        res->store.u.fval = l.store.u.ival+r.store.u.fval;
       +                        break;
       +                default:
       +                        error("bad rhs type +");
       +                }
       +                break;
       +        case TFLOAT:
       +                switch(r.type) {
       +                case TINT:
       +                        res->store.u.fval = l.store.u.fval+r.store.u.ival;
       +                        break;
       +                case TFLOAT:
       +                        res->store.u.fval = l.store.u.fval+r.store.u.fval;
       +                        break;
       +                default:
       +                        error("bad rhs type +");
       +                }
       +                break;
       +        case TSTRING:
       +                if(r.type == TSTRING) {
       +                        res->type = TSTRING;
       +                        res->store.fmt = 's';
       +                        res->store.u.string = stradd(l.store.u.string, r.store.u.string); 
       +                        break;
       +                }
       +                error("bad rhs for +");
       +        case TLIST:
       +                res->type = TLIST;
       +                switch(r.type) {
       +                case TLIST:
       +                        res->store.u.l = addlist(l.store.u.l, r.store.u.l);
       +                        break;
       +                default:
       +                        r.left = 0;
       +                        r.right = 0;
       +                        res->store.u.l = addlist(l.store.u.l, construct(&r));
       +                        break;
       +                }
       +        }
       +}
       +
       +void
       +osub(Node *n, Node *res)
       +{
       +        Node l, r;
       +
       +        expr(n->left, &l);
       +        expr(n->right, &r);
       +        res->store.fmt = l.store.fmt;
       +        res->op = OCONST;
       +        res->type = TFLOAT;
       +        switch(l.type) {
       +        default:
       +                error("bad lhs type -");
       +        case TINT:
       +                switch(r.type) {
       +                case TINT:
       +                        res->type = TINT;
       +                        res->store.u.ival = l.store.u.ival-r.store.u.ival;
       +                        break;
       +                case TFLOAT:
       +                        res->store.u.fval = l.store.u.ival-r.store.u.fval;
       +                        break;
       +                default:
       +                        error("bad rhs type -");
       +                }
       +                break;
       +        case TFLOAT:
       +                switch(r.type) {
       +                case TINT:
       +                        res->store.u.fval = l.store.u.fval-r.store.u.ival;
       +                        break;
       +                case TFLOAT:
       +                        res->store.u.fval = l.store.u.fval-r.store.u.fval;
       +                        break;
       +                default:
       +                        error("bad rhs type -");
       +                }
       +                break;
       +        }
       +}
       +
       +void
       +omul(Node *n, Node *res)
       +{
       +        Node l, r;
       +
       +        expr(n->left, &l);
       +        expr(n->right, &r);
       +        res->store.fmt = l.store.fmt;
       +        res->op = OCONST;
       +        res->type = TFLOAT;
       +        switch(l.type) {
       +        default:
       +                error("bad lhs type *");
       +        case TINT:
       +                switch(r.type) {
       +                case TINT:
       +                        res->type = TINT;
       +                        res->store.u.ival = l.store.u.ival*r.store.u.ival;
       +                        break;
       +                case TFLOAT:
       +                        res->store.u.fval = l.store.u.ival*r.store.u.fval;
       +                        break;
       +                default:
       +                        error("bad rhs type *");
       +                }
       +                break;
       +        case TFLOAT:
       +                switch(r.type) {
       +                case TINT:
       +                        res->store.u.fval = l.store.u.fval*r.store.u.ival;
       +                        break;
       +                case TFLOAT:
       +                        res->store.u.fval = l.store.u.fval*r.store.u.fval;
       +                        break;
       +                default:
       +                        error("bad rhs type *");
       +                }
       +                break;
       +        }
       +}
       +
       +void
       +odiv(Node *n, Node *res)
       +{
       +        Node l, r;
       +
       +        expr(n->left, &l);
       +        expr(n->right, &r);
       +        res->store.fmt = l.store.fmt;
       +        res->op = OCONST;
       +        res->type = TFLOAT;
       +        switch(l.type) {
       +        default:
       +                error("bad lhs type /");
       +        case TINT:
       +                switch(r.type) {
       +                case TINT:
       +                        res->type = TINT;
       +                        if(r.store.u.ival == 0)
       +                                error("zero divide");
       +                        res->store.u.ival = l.store.u.ival/r.store.u.ival;
       +                        break;
       +                case TFLOAT:
       +                        if(r.store.u.fval == 0)
       +                                error("zero divide");
       +                        res->store.u.fval = l.store.u.ival/r.store.u.fval;
       +                        break;
       +                default:
       +                        error("bad rhs type /");
       +                }
       +                break;
       +        case TFLOAT:
       +                switch(r.type) {
       +                case TINT:
       +                        res->store.u.fval = l.store.u.fval/r.store.u.ival;
       +                        break;
       +                case TFLOAT:
       +                        res->store.u.fval = l.store.u.fval/r.store.u.fval;
       +                        break;
       +                default:
       +                        error("bad rhs type /");
       +                }
       +                break;
       +        }
       +}
       +
       +void
       +omod(Node *n, Node *res)
       +{
       +        Node l, r;
       +
       +        expr(n->left, &l);
       +        expr(n->right, &r);
       +        res->store.fmt = l.store.fmt;
       +        res->op = OCONST;
       +        res->type = TINT;
       +        if(l.type != TINT || r.type != TINT)
       +                error("bad expr type %");
       +        res->store.u.ival = l.store.u.ival%r.store.u.ival;
       +}
       +
       +void
       +olsh(Node *n, Node *res)
       +{
       +        Node l, r;
       +
       +        expr(n->left, &l);
       +        expr(n->right, &r);
       +        res->store.fmt = l.store.fmt;
       +        res->op = OCONST;
       +        res->type = TINT;
       +        if(l.type != TINT || r.type != TINT)
       +                error("bad expr type <<");
       +        res->store.u.ival = l.store.u.ival<<r.store.u.ival;
       +}
       +
       +void
       +orsh(Node *n, Node *res)
       +{
       +        Node l, r;
       +
       +        expr(n->left, &l);
       +        expr(n->right, &r);
       +        res->store.fmt = l.store.fmt;
       +        res->op = OCONST;
       +        res->type = TINT;
       +        if(l.type != TINT || r.type != TINT)
       +                error("bad expr type >>");
       +        res->store.u.ival = (unsigned)l.store.u.ival>>r.store.u.ival;
       +}
       +
       +void
       +olt(Node *n, Node *res)
       +{
       +        Node l, r;
       +
       +        expr(n->left, &l);
       +        expr(n->right, &r);
       +
       +        res->store.fmt = l.store.fmt;
       +        res->op = OCONST;
       +        res->type = TINT;
       +        switch(l.type) {
       +        default:
       +                error("bad lhs type <");
       +        case TINT:
       +                switch(r.type) {
       +                case TINT:
       +                        res->store.u.ival = l.store.u.ival < r.store.u.ival;
       +                        break;
       +                case TFLOAT:
       +                        res->store.u.ival = l.store.u.ival < r.store.u.fval;
       +                        break;
       +                default:
       +                        error("bad rhs type <");
       +                }
       +                break;
       +        case TFLOAT:
       +                switch(r.type) {
       +                case TINT:
       +                        res->store.u.ival = l.store.u.fval < r.store.u.ival;
       +                        break;
       +                case TFLOAT:
       +                        res->store.u.ival = l.store.u.fval < r.store.u.fval;
       +                        break;
       +                default:
       +                        error("bad rhs type <");
       +                }
       +                break;
       +        }
       +}
       +
       +void
       +ogt(Node *n, Node *res)
       +{
       +        Node l, r;
       +
       +        expr(n->left, &l);
       +        expr(n->right, &r);
       +        res->store.fmt = 'D';
       +        res->op = OCONST;
       +        res->type = TINT;
       +        switch(l.type) {
       +        default:
       +                error("bad lhs type >");
       +        case TINT:
       +                switch(r.type) {
       +                case TINT:
       +                        res->store.u.ival = l.store.u.ival > r.store.u.ival;
       +                        break;
       +                case TFLOAT:
       +                        res->store.u.ival = l.store.u.ival > r.store.u.fval;
       +                        break;
       +                default:
       +                        error("bad rhs type >");
       +                }
       +                break;
       +        case TFLOAT:
       +                switch(r.type) {
       +                case TINT:
       +                        res->store.u.ival = l.store.u.fval > r.store.u.ival;
       +                        break;
       +                case TFLOAT:
       +                        res->store.u.ival = l.store.u.fval > r.store.u.fval;
       +                        break;
       +                default:
       +                        error("bad rhs type >");
       +                }
       +                break;
       +        }
       +}
       +
       +void
       +oleq(Node *n, Node *res)
       +{
       +        Node l, r;
       +
       +        expr(n->left, &l);
       +        expr(n->right, &r);
       +        res->store.fmt = 'D';
       +        res->op = OCONST;
       +        res->type = TINT;
       +        switch(l.type) {
       +        default:
       +                error("bad expr type <=");
       +        case TINT:
       +                switch(r.type) {
       +                case TINT:
       +                        res->store.u.ival = l.store.u.ival <= r.store.u.ival;
       +                        break;
       +                case TFLOAT:
       +                        res->store.u.ival = l.store.u.ival <= r.store.u.fval;
       +                        break;
       +                default:
       +                        error("bad expr type <=");
       +                }
       +                break;
       +        case TFLOAT:
       +                switch(r.type) {
       +                case TINT:
       +                        res->store.u.ival = l.store.u.fval <= r.store.u.ival;
       +                        break;
       +                case TFLOAT:
       +                        res->store.u.ival = l.store.u.fval <= r.store.u.fval;
       +                        break;
       +                default:
       +                        error("bad expr type <=");
       +                }
       +                break;
       +        }
       +}
       +
       +void
       +ogeq(Node *n, Node *res)
       +{
       +        Node l, r;
       +
       +        expr(n->left, &l);
       +        expr(n->right, &r);
       +        res->store.fmt = 'D';
       +        res->op = OCONST;
       +        res->type = TINT;
       +        switch(l.type) {
       +        default:
       +                error("bad lhs type >=");
       +        case TINT:
       +                switch(r.type) {
       +                case TINT:
       +                        res->store.u.ival = l.store.u.ival >= r.store.u.ival;
       +                        break;
       +                case TFLOAT:
       +                        res->store.u.ival = l.store.u.ival >= r.store.u.fval;
       +                        break;
       +                default:
       +                        error("bad rhs type >=");
       +                }
       +                break;
       +        case TFLOAT:
       +                switch(r.type) {
       +                case TINT:
       +                        res->store.u.ival = l.store.u.fval >= r.store.u.ival;
       +                        break;
       +                case TFLOAT:
       +                        res->store.u.ival = l.store.u.fval >= r.store.u.fval;
       +                        break;
       +                default:
       +                        error("bad rhs type >=");
       +                }
       +                break;
       +        }
       +}
       +
       +void
       +oeq(Node *n, Node *res)
       +{
       +        Node l, r;
       +
       +        expr(n->left, &l);
       +        expr(n->right, &r);
       +        res->store.fmt = 'D';
       +        res->op = OCONST;
       +        res->type = TINT;
       +        res->store.u.ival = 0;
       +        switch(l.type) {
       +        default:
       +                break;
       +        case TINT:
       +                switch(r.type) {
       +                case TINT:
       +                        res->store.u.ival = l.store.u.ival == r.store.u.ival;
       +                        break;
       +                case TFLOAT:
       +                        res->store.u.ival = l.store.u.ival == r.store.u.fval;
       +                        break;
       +                default:
       +                        break;
       +                }
       +                break;
       +        case TFLOAT:
       +                switch(r.type) {
       +                case TINT:
       +                        res->store.u.ival = l.store.u.fval == r.store.u.ival;
       +                        break;
       +                case TFLOAT:
       +                        res->store.u.ival = l.store.u.fval == r.store.u.fval;
       +                        break;
       +                default:
       +                        break;
       +                }
       +                break;
       +        case TSTRING:
       +                if(r.type == TSTRING) {
       +                        res->store.u.ival = scmp(r.store.u.string, l.store.u.string);
       +                        break;
       +                }
       +                break;
       +        case TLIST:
       +                if(r.type == TLIST) {
       +                        res->store.u.ival = listcmp(l.store.u.l, r.store.u.l);
       +                        break;
       +                }
       +                break;
       +        }
       +        if(n->op == ONEQ)
       +                res->store.u.ival = !res->store.u.ival;
       +}
       +
       +
       +void
       +oland(Node *n, Node *res)
       +{
       +        Node l, r;
       +
       +        expr(n->left, &l);
       +        expr(n->right, &r);
       +        res->store.fmt = l.store.fmt;
       +        res->op = OCONST;
       +        res->type = TINT;
       +        if(l.type != TINT || r.type != TINT)
       +                error("bad expr type &");
       +        res->store.u.ival = l.store.u.ival&r.store.u.ival;
       +}
       +
       +void
       +oxor(Node *n, Node *res)
       +{
       +        Node l, r;
       +
       +        expr(n->left, &l);
       +        expr(n->right, &r);
       +        res->store.fmt = l.store.fmt;
       +        res->op = OCONST;
       +        res->type = TINT;
       +        if(l.type != TINT || r.type != TINT)
       +                error("bad expr type ^");
       +        res->store.u.ival = l.store.u.ival^r.store.u.ival;
       +}
       +
       +void
       +olor(Node *n, Node *res)
       +{
       +        Node l, r;
       +
       +        expr(n->left, &l);
       +        expr(n->right, &r);
       +        res->store.fmt = l.store.fmt;
       +        res->op = OCONST;
       +        res->type = TINT;
       +        if(l.type != TINT || r.type != TINT)
       +                error("bad expr type |");
       +        res->store.u.ival = l.store.u.ival|r.store.u.ival;
       +}
       +
       +void
       +ocand(Node *n, Node *res)
       +{
       +        Node l, r;
       +
       +        res->store.fmt = l.store.fmt;
       +        res->op = OCONST;
       +        res->type = TINT;
       +        res->store.u.ival = 0;
       +        expr(n->left, &l);
       +        if(bool(&l) == 0)
       +                return;
       +        expr(n->right, &r);
       +        if(bool(&r) == 0)
       +                return;
       +        res->store.u.ival = 1;
       +}
       +
       +void
       +onot(Node *n, Node *res)
       +{
       +        Node l;
       +
       +        res->op = OCONST;
       +        res->type = TINT;
       +        res->store.u.ival = 0;
       +        expr(n->left, &l);
       +        if(bool(&l) == 0)
       +                res->store.u.ival = 1;
       +}
       +
       +void
       +ocor(Node *n, Node *res)
       +{
       +        Node l, r;
       +
       +        res->op = OCONST;
       +        res->type = TINT;
       +        res->store.u.ival = 0;
       +        expr(n->left, &l);
       +        if(bool(&l)) {
       +                res->store.u.ival = 1;
       +                return;
       +        }
       +        expr(n->right, &r);
       +        if(bool(&r)) {
       +                res->store.u.ival = 1;
       +                return;
       +        }
       +}
       +
       +void
       +oeinc(Node *n, Node *res)
       +{
       +        Value *v;
       +
       +        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->store.u.ival -= fmtsize(v);
       +                else
       +                        v->store.u.ival += fmtsize(v);
       +                break;                        
       +        case TFLOAT:
       +                if(n->op == OEDEC)
       +                        v->store.u.fval--;
       +                else
       +                        v->store.u.fval++;
       +                break;
       +        default:
       +                error("bad type for pre --/++");
       +        }
       +        res->store = v->store;
       +}
       +
       +void
       +opinc(Node *n, Node *res)
       +{
       +        Value *v;
       +
       +        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->store.u.ival -= fmtsize(v);
       +                else
       +                        v->store.u.ival += fmtsize(v);
       +                break;                        
       +        case TFLOAT:
       +                if(n->op == OPDEC)
       +                        v->store.u.fval--;
       +                else
       +                        v->store.u.fval++;
       +                break;
       +        default:
       +                error("bad type for post --/++");
       +        }
       +}
       +
       +void
       +ocall(Node *n, Node *res)
       +{
       +        Lsym *s;
       +        Rplace *rsav;
       +
       +        res->op = OCONST;                /* Default return value */
       +        res->type = TLIST;
       +        res->store.u.l = 0;
       +
       +        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->store.fmt = n->right->store.u.ival;
       +}
       +
       +void
       +owhat(Node *n, Node *res)
       +{
       +        res->op = OCONST;                /* Default return value */
       +        res->type = TLIST;
       +        res->store.u.l = 0;
       +        whatis(n->sym);
       +}
       +
       +void (*expop[])(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,
       +};
 (DIR) diff --git a/src/cmd/acid/lex.c b/src/cmd/acid/lex.c
       t@@ -0,0 +1,661 @@
       +#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
       +setacidfile(void)
       +{
       +        char *name;
       +        Lsym *l;
       +
       +        if(lexio)
       +                name = lexio->name;
       +        else
       +                name = "";
       +        l = mkvar("acidfile");
       +        l->v->set = 1;
       +        l->v->store.fmt = 's';
       +        l->v->type = TSTRING;
       +        l->v->store.u.string = strnode(name);
       +}
       +
       +void
       +pushfile(char *file)
       +{
       +        Biobuf *b;
       +        IOstack *io;
       +
       +        if(file)
       +                b = Bopen(file, OREAD);
       +        else{
       +                b = Bopen(unsharp("#d/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;
       +        setacidfile();
       +}
       +
       +void
       +pushfd(int fd)
       +{
       +        pushfile("/dev/null");
       +        close(lexio->fin->fid);
       +        free(lexio->name);
       +        lexio->name = smprint("<fd#d>", fd);
       +        lexio->fin->fid = fd;
       +}
       +
       +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->store.u.string->string);
       +        if(io->text == 0)
       +                fatal("no memory");
       +        io->ip = io->text;
       +        io->fin = 0;
       +        io->prev = lexio;
       +        lexio = io;
       +        setacidfile();
       +}
       +
       +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);
       +        setacidfile();
       +        return 1;
       +}
       +
       +int
       +Zfmt(Fmt *f)
       +{
       +        int i;
       +        char buf[1024];
       +        IOstack *e;
       +
       +        e = lexio;
       +        if(e) {
       +                i = sprint(buf, "%s:%d", e->name, line);
       +                while(e->prev) {
       +                        e = e->prev;
       +                        if(initialising && e->prev == 0)
       +                                break;
       +                        i += sprint(buf+i, " [%s:%d]", e->name, e->line);
       +                }
       +        } else
       +                sprint(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;
       +                        }
       +                        buf[n++] = c;
       +                }
       +                buf[n] = '\0';
       +                return strtol(buf, 0, 0);
       +        }
       +
       +        n = cmap[(unsigned char)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;
       +                }
       +                nlcount++;
       +                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 = strtoul(symbol+2, 0, 2);
       +                else
       +                        yylval.ival = strtoul(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;
       +        ulong 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->store.fmt = 'X';
       +        v->type = TINT;
       +        memset(v, 0, sizeof(Value));
       +
       +        return s;
       +}
       +
       +void
       +delsym(Lsym *s)
       +{
       +        char *q;
       +        ulong h;
       +        Lsym *p;
       +
       +        h = 0;
       +        for(q = s->name; *q; q++)
       +                h = h*3 + *q;
       +        h %= Hashsize;
       +        
       +        if(hash[h] == s)
       +                hash[h] = s->hash;
       +        else{
       +                for(p=hash[h]; p && p->hash != s; p=p->hash)
       +                        ;
       +                if(p)
       +                        p->hash = s->hash;
       +        }
       +        s->hash = nil;
       +}
       +
       +Lsym*
       +look(char *name)
       +{
       +        Lsym *s;
       +        ulong 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;
       +}
 (DIR) diff --git a/src/cmd/acid/list.c b/src/cmd/acid/list.c
       t@@ -0,0 +1,270 @@
       +#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->store.u.l == 0) {
       +                list->store.u.l = l;
       +                r->store.u.l = l;
       +                return;
       +        }
       +        for(f = list->store.u.l; f->next; f = f->next)
       +                ;
       +        f->next = l;
       +        r->store.u.l = list->store.u.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->store.u.ival != r->store.u.ival)
       +                                return 0;
       +                        break;
       +                case TFLOAT:
       +                        if(l->store.u.fval != r->store.u.fval)
       +                                return 0;
       +                        break;
       +                case TSTRING:
       +                        if(scmp(l->store.u.string, r->store.u.string) == 0)
       +                                return 0;
       +                        break;
       +                case TLIST:
       +                        if(listcmp(l->store.u.l, r->store.u.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->store.u.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->store.u.l = l;
       +
       +        for(tl = &res->store.u.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, long v)
       +{
       +        List *l, *tl;
       +
       +        tl = al(TLIST);
       +
       +        l = al(TSTRING);
       +        tl->store.u.l = l;
       +        l->store.fmt = 's';
       +        l->store.u.string = strnode(s);
       +        l->next = al(TINT);
       +        l = l->next;
       +        l->store.fmt = 'X';
       +        l->store.u.ival = v;
       +
       +        return tl;
       +}
       +
       +static List*
       +listlocals(Map *map, Regs *regs, Symbol *fn, int class)
       +{
       +        int i;
       +        u32int val;
       +        Symbol s;
       +        List **tail, *l2;
       +
       +        l2 = 0;
       +        tail = &l2;
       +        if(fn == nil)
       +                return l2;
       +        for(i = 0; indexlsym(fn, i, &s)>=0; i++) {
       +                if(s.class != class)
       +                        continue;
       +                if(class == CAUTO && s.name[0] == '.')
       +                        continue;
       +                if(lget4(map, regs, s.loc, &val) < 0)
       +                        continue;
       +                *tail = listvar(s.name, val);
       +                tail = &(*tail)->next;
       +        }
       +        return l2;
       +}
       +
       +static List*
       +listparams(Map *map, Regs *regs, Symbol *fn)
       +{
       +        return listlocals(map, regs, fn, CPARAM);
       +}
       +
       +static List*
       +listautos(Map *map, Regs *regs, Symbol *fn)
       +{
       +        return listlocals(map, regs, fn, CAUTO);
       +}
       +
       +int
       +trlist(Map *map, Regs *regs, ulong pc, ulong callerpc, Symbol *sym, int depth)
       +{
       +        List *q, *l;
       +        static List **tail;
       +
       +        if (tracelist == 0)                /* first time */
       +                tail = &tracelist;
       +
       +        q = al(TLIST);
       +        *tail = q;
       +        tail = &q->next;
       +
       +        l = al(TINT);                        /* Function address */
       +        q->store.u.l = l;
       +        l->store.u.ival = sym ? sym->loc.addr : pc;
       +        l->store.fmt = 'X';
       +
       +        l->next = al(TINT);                /* actual pc address */
       +        l = l->next;
       +        l->store.u.ival = pc;
       +        l->store.fmt = 'X';
       +
       +        l->next = al(TINT);                /* called from address */
       +        l = l->next;
       +        l->store.u.ival = callerpc;
       +        l->store.fmt = 'X';
       +
       +        l->next = al(TLIST);                /* make list of params */
       +        l = l->next;
       +        if(sym)
       +                l->store.u.l = listparams(map, regs, sym);
       +
       +        l->next = al(TLIST);                /* make list of locals */
       +        l = l->next;
       +        if(sym)
       +                l->store.u.l = listautos(map, regs, sym);
       +
       +        return depth<40;
       +}
 (DIR) diff --git a/src/cmd/acid/main.c b/src/cmd/acid/main.c
       t@@ -0,0 +1,630 @@
       +#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*        lm[16];
       +static int        nlm;
       +static char*        mtype;
       +
       +static        int attachfiles(int, char**);
       +int        xfmt(Fmt*);
       +int        isnumeric(char*);
       +void        die(void);
       +void        setcore(Fhdr*);
       +
       +void
       +usage(void)
       +{
       +        fprint(2, "usage: acid [-c core] [-l module] [-m machine] [-qrw] [-k] [pid] [file]\n");
       +        exits("usage");
       +}
       +
       +void
       +main(int argc, char *argv[])
       +{
       +        Lsym *l;
       +        Node *n;
       +        char buf[128], *s;
       +        int pid, i;
       +
       +        argv0 = argv[0];
       +        pid = 0;
       +        quiet = 1;
       +
       +        mtype = 0;
       +        ARGBEGIN{
       +        case 'A':
       +                abort();
       +                break;
       +        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
       +
       +        fmtinstall('x', xfmt);
       +        fmtinstall('Z', Zfmt);
       +        fmtinstall('L', locfmt);
       +        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(argc, argv) < 0)
       +                varreg();                /* use default register set on error */
       +        if(mach == nil)
       +                mach = machcpu;
       +
       +        symhdr = nil;        /* not supposed to use this anymore */
       +
       +        l = mkvar("acid");
       +        l->v->set = 1;
       +        l->v->type = TLIST;
       +        l->v->store.u.l = nil;
       +
       +        loadmodule("/usr/local/plan9/acid/port");
       +        for(i = 0; i < nlm; i++) {
       +                if(access(lm[i], AREAD) >= 0)
       +                        loadmodule(lm[i]);
       +                else {
       +                        sprint(buf, "/usr/local/plan9/acid/%s", lm[i]);
       +                        loadmodule(buf);
       +                }
       +        }
       +
       +        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();
       +        }
       +        Bputc(bout, '\n');
       +        exits(0);
       +}
       +
       +static int
       +attachfiles(int argc, char **argv)
       +{
       +        char *s;
       +        int i, omode;
       +        Fhdr *hdr;
       +        Lsym *l;
       +        Value *v;
       +
       +        interactive = 0;
       +        if(setjmp(err))
       +                return -1;
       +
       +        /*
       +         * Unix and Plan 9 differ on what the right order of pid, text, and core is.
       +         * I never remember anyway.  Let's just accept them in any order.
       +         */
       +        omode = wtflag ? ORDWR : OREAD;
       +        for(i=0; i<argc; i++){
       +                if(isnumeric(argv[i])){
       +                        if(pid){
       +                                fprint(2, "already have pid %d; ignoring pid %d\n", pid, argv[i]);
       +                                continue;
       +                        }
       +                        if(corhdr){
       +                                fprint(2, "already have core %s; ignoring pid %d\n", corfil, pid);
       +                                continue;
       +                        }
       +                        pid = atoi(argv[i]);
       +                        continue;
       +                }
       +                if((hdr = crackhdr(argv[i], omode)) == nil){
       +                        fprint(2, "crackhdr %s: %r\n", argv[i]);
       +                        continue;
       +                }
       +                fprint(2, "%s: %s %s %s\n", argv[i], hdr->aname, hdr->mname, hdr->fname);
       +                if(hdr->ftype == FCORE){
       +                        if(pid){
       +                                fprint(2, "already have pid %d; ignoring core %s\n", pid, argv[i]);
       +                                uncrackhdr(hdr);
       +                                continue;
       +                        }
       +                        if(corhdr){
       +                                fprint(2, "already have core %s; ignoring core %s\n", corfil, argv[i]);
       +                                uncrackhdr(hdr);
       +                                continue;
       +                        }
       +                        corhdr = hdr;
       +                        corfil = argv[i];
       +                }else{
       +                        if(symhdr){
       +                                fprint(2, "already have text %s; ignoring text %s\n", symfil, argv[i]);
       +                                uncrackhdr(hdr);
       +                                continue;
       +                        }
       +                        symhdr = hdr;
       +                        symfil = argv[i];
       +                }
       +        }
       +
       +        if(symhdr==nil){
       +                symfil = "a.out";
       +                if(pid){
       +                        if((s = proctextfile(pid)) != nil){
       +                                fprint(2, "pid %d: text %s\n", pid, s);
       +                                symfil = s;
       +                        }
       +                }
       +                /* XXX pull command from core */
       +
       +                if((hdr = crackhdr(symfil, omode)) == nil){
       +                        fprint(2, "crackhdr %s: %r\n", symfil);
       +                        symfil = nil;
       +                }
       +        }
       +
       +        if(symhdr)
       +                syminit(symhdr);
       +
       +        if(!mach)
       +                mach = machcpu;
       +
       +        /*
       +         * Set up maps.
       +         */
       +        symmap = allocmap();
       +        cormap = allocmap();
       +        if(symmap == nil || cormap == nil)
       +                sysfatal("allocating maps: %r");
       +
       +        if(symhdr){
       +                if(mapfile(symhdr, 0, symmap, nil) < 0)
       +                        fprint(2, "mapping %s: %r\n", symfil);
       +                mapfile(symhdr, 0, cormap, nil);
       +        }
       +
       +        l = mkvar("objtype");
       +        v = l->v;
       +        v->store.fmt = 's';
       +        v->set = 1;
       +        v->store.u.string = strnode(mach->name);
       +        v->type = TSTRING;
       +
       +        l = mkvar("textfile");
       +        v = l->v;
       +        v->store.fmt = 's';
       +        v->set = 1;
       +        v->store.u.string = strnode(symfil ? symfil : "");
       +        v->type = TSTRING;
       +
       +        l = mkvar("systype");
       +        v = l->v;
       +        v->store.fmt = 's';
       +        v->set = 1;
       +        v->store.u.string = strnode(symhdr ? symhdr->aname : "");
       +        v->type = TSTRING;
       +
       +        l = mkvar("corefile");
       +        v = l->v;
       +        v->store.fmt = 's';
       +        v->set = 1;
       +        v->store.u.string = strnode(corfil ? corfil : "");
       +        v->type = TSTRING;
       +
       +        if(pid)
       +                sproc(pid);
       +        if(corhdr)
       +                setcore(corhdr);
       +        varreg();
       +        return 0;
       +}
       +
       +void
       +setcore(Fhdr *hdr)
       +{
       +        unmapproc(cormap);
       +        unmapfile(corhdr, cormap);
       +        free(correg);
       +        correg = nil;
       +
       +        if(hdr == nil)
       +                error("no core");
       +        if(mapfile(hdr, 0, cormap, &correg) < 0)
       +                error("mapfile %s: %r", hdr->filename);
       +        corhdr = hdr;
       +        corfil = hdr->filename;
       +}
       +
       +void
       +die(void)
       +{
       +        Lsym *s;
       +        List *f;
       +
       +        Bprint(bout, "\n");
       +
       +        s = look("proclist");
       +        if(s && s->v->type == TLIST) {
       +                for(f = s->v->store.u.l; f; f = f->next){
       +                        detachproc((int)f->store.u.ival);
       +                        Bprint(bout, "/bin/kill -9 %d\n", (int)f->store.u.ival);
       +                }
       +        }
       +        exits(0);
       +}
       +
       +void
       +userinit(void)
       +{
       +        Lsym *l;
       +        Node *n;
       +        char buf[128], *p;
       +
       +        sprint(buf, "/usr/local/plan9/acid/%s", mach->name);
       +        loadmodule(buf);
       +        p = getenv("home");
       +        if(p != 0) {
       +                sprint(buf, "%s/lib/acid", p);
       +                silent = 1;
       +                loadmodule(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;
       +}
       +
       +Node*
       +an(int op, Node *l, Node *r)
       +{
       +        Node *n;
       +
       +        n = gmalloc(sizeof(Node));
       +        memset(n, 0, sizeof(Node));
       +        n->gc.gclink = gcl;
       +        gcl = (Gc*)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->gc.gclink = gcl;
       +        gcl = (Gc*)l;
       +        return l;
       +}
       +
       +Node*
       +con(int v)
       +{
       +        Node *n;
       +
       +        n = an(OCONST, ZN, ZN);
       +        n->store.u.ival = v;
       +        n->store.fmt = 'X';
       +        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: %Z (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("%Z: %s\n", buf);
       +}
       +
       +void
       +marktree(Node *n)
       +{
       +
       +        if(n == 0)
       +                return;
       +
       +        marktree(n->left);
       +        marktree(n->right);
       +
       +        n->gc.gcmark = 1;
       +        if(n->op != OCONST)
       +                return;
       +
       +        switch(n->type) {
       +        case TSTRING:
       +                n->store.u.string->gc.gcmark = 1;
       +                break;
       +        case TLIST:
       +                marklist(n->store.u.l);
       +                break;
       +        case TCODE:
       +                marktree(n->store.u.cc);
       +                break;
       +        }
       +}
       +
       +void
       +marklist(List *l)
       +{
       +        while(l) {
       +                l->gc.gcmark = 1;
       +                switch(l->type) {
       +                case TSTRING:
       +                        l->store.u.string->gc.gcmark = 1;
       +                        break;
       +                case TLIST:
       +                        marklist(l->store.u.l);
       +                        break;
       +                case TCODE:
       +                        marktree(l->store.u.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->store.u.string->gc.gcmark = 1;
       +                                        break;
       +                                case TLIST:
       +                                        marklist(v->store.u.l);
       +                                        break;
       +                                case TCODE:
       +                                        marktree(v->store.u.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;
       +        }
       +
       +        sprint(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);
       +        }
       +        if(strstr(s, "child"))
       +                noted(NCONT);
       +fprint(2, "note: %s\n", s);
       +        noted(NDFLT);
       +}
       +
       +char*
       +system(void)
       +{
       +        char *cpu, *p, *q;
       +        static char kernel[128];
       +
       +        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 = "9power";
       +                print("missing or bad $terminal; assuming %s\n", p);
       +        }
       +        else{
       +                p++;
       +                q = strchr(p, ' ');
       +                if(q)
       +                        *q = 0;
       +                sprint(kernel, "/%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);
       +}
 (DIR) diff --git a/src/cmd/acid/mkfile b/src/cmd/acid/mkfile
       t@@ -0,0 +1,32 @@
       +<$PLAN9/src/mkhdr
       +
       +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=/home/rsc/bin
       +
       +SHORTLIB=mach2 regexp9 bio 9
       +
       +<$PLAN9/src/mkone
       +
       +CFLAGS=$CFLAGS -I../libmach2
       +
       +lex.$O:                y.tab.h
       +util.$O:        y.tab.h
       +builtin.$O:        y.tab.h
       +main.$O:        y.tab.h
 (DIR) diff --git a/src/cmd/acid/print.c b/src/cmd/acid/print.c
       t@@ -0,0 +1,446 @@
       +#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(const void *va, const void *vb)
       +{
       +        char **a = (char**)va;
       +        char **b = (char**)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->store.fmt);
       +                if(l->v->store.comt)
       +                        Bprint(bout, " complex %s",
       +                                                l->v->store.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, "%d", (int)n->store.u.ival);
       +                        break;
       +                case TFLOAT:
       +                        Bprint(bout, "%g", n->store.u.fval);
       +                        break;
       +                case TSTRING:
       +                        pstr(n->store.u.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[(uchar)n->op]);
       +                pexpr(r);
       +                Bputc(bout, ')');
       +                break;
       +        case OASGN:
       +                pexpr(l);
       +                Bprint(bout, binop[(uchar)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->store.u.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, '"');
       +}
 (DIR) diff --git a/src/cmd/acid/proc.c b/src/cmd/acid/proc.c
       t@@ -0,0 +1,251 @@
       +#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
       +sproc(int xpid)
       +{
       +        Lsym *s;
       +        int i;
       +
       +        if(symmap == 0)
       +                error("no map");
       +
       +        if(pid == xpid)
       +                return;
       +
       +        if(xpid <= 0)
       +                error("bad pid");
       +
       +        unmapproc(cormap);
       +        unmapfile(corhdr, cormap);
       +        free(correg);
       +        correg = nil;
       +
       +        if(mapproc(xpid, cormap, &correg) < 0)
       +                error("setproc %d: %r", pid);
       +
       +        /* XXX check text file here? */
       +
       +        pid = xpid;
       +        s = look("pid");
       +        s->v->store.u.ival = pid;
       +
       +        for(i=0; i<cormap->nseg; i++)
       +                if(cormap->seg[i].file == nil){
       +                        if(strcmp(cormap->seg[i].name, "data") == 0)
       +                                cormap->seg[i].name = "*data";
       +                        if(strcmp(cormap->seg[i].name, "text") == 0)
       +                                cormap->seg[i].name = "*text";
       +                }
       +        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);
       +                if(ctlproc(getpid(), "hang") < 0)
       +                        fatal("new: hang %d: %r", getpid());
       +
       +                close(0);
       +                close(1);
       +                close(2);
       +                for(i = 3; i < NFD; i++)
       +                        close(i);
       +
       +                open("/dev/tty", OREAD);
       +                open("/dev/tty", OWRITE);
       +                open("/dev/tty", 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, n;
       +        char **notes;
       +        List *l, **tail;
       +
       +        s = look("notes");
       +        if(s == 0)
       +                return;
       +
       +        v = s->v;
       +        n = procnotes(pid, &notes);
       +        if(n < 0)
       +                error("procnotes pid=%d: %r", pid);
       +
       +        v->set = 1;
       +        v->type = TLIST;
       +        v->store.u.l = 0;
       +        tail = &v->store.u.l;
       +        for(i=0; i<n; i++) {
       +                l = al(TSTRING);
       +                l->store.u.string = strnode(notes[i]);
       +                l->store.fmt = 's';
       +                *tail = l;
       +                tail = &l->next;
       +        }
       +        free(notes);
       +}
       +
       +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->store.fmt = 'D';
       +                np->type = TINT;
       +                p = con(pid);
       +                p->store.fmt = 'D';
       +                np = an(OCALL, np, p);
       +                execute(np);
       +        }
       +}
       +
       +static void
       +install(int pid)
       +{
       +        Lsym *s;
       +        List *l;
       +        int i, 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");
       +
       +        ptab[new].pid = pid;
       +
       +        s = look("proclist");
       +        l = al(TINT);
       +        l->store.fmt = 'D';
       +        l->store.u.ival = pid;
       +        l->next = s->v->store.u.l;
       +        s->v->store.u.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) {
       +                        detachproc(pid);
       +                        // close(ptab[i].ctl);
       +                        ptab[i].pid = 0;
       +                        s = look("proclist");
       +                        d = &s->v->store.u.l;
       +                        for(f = *d; f; f = f->next) {
       +                                if(f->store.u.ival == pid) {
       +                                        *d = f->next;
       +                                        break;
       +                                }
       +                        }
       +                        s = look("pid");
       +                        if(s->v->store.u.ival == pid)
       +                                s->v->store.u.ival = 0;
       +                        return;
       +                }
       +        }
       +}
       +
       +void
       +msg(int pid, char *msg)
       +{
       +        int i;
       +        char err[ERRMAX];
       +
       +        for(i = 0; i < Maxproc; i++) {
       +                if(ptab[i].pid == pid) {
       +                        if(ctlproc(pid, msg) < 0){
       +                                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;
       +        char *p;
       +
       +        static char buf[128];
       +
       +        sprint(buf, "/proc/%d/status", pid);
       +        fd = open(buf, OREAD);
       +        if(fd < 0)
       +                error("open %s: %r", buf);
       +        read(fd, buf, sizeof(buf));
       +        close(fd);
       +        p = buf+56+12;                        /* Do better! */
       +        while(*p == ' ')
       +                p--;
       +        p[1] = '\0';
       +        return buf+56;                        /* ditto */
       +}
       +
       +Waitmsg*
       +waitfor(int pid)
       +{
       +        Waitmsg *w;
       +
       +        for(;;) {
       +                if((w = wait()) == nil)
       +                        error("wait %r");
       +                if(w->pid == pid)
       +                        return w;
       +                free(w);
       +        }
       +        return nil;        /* ken */
       +}
 (DIR) diff --git a/src/cmd/acid/util.c b/src/cmd/acid/util.c
       t@@ -0,0 +1,344 @@
       +#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, Symbol *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/%Z\n", s->name, buf, s->type, s->loc);
       +        if(l == 0)
       +                l = enter(buf, Tid);
       +        return l;        
       +}
       +
       +void
       +varsym(void)
       +{
       +        Lsym *l;
       +        Fhdr *fp;
       +
       +        l = mkvar("symbols");
       +        if(l->v->set)
       +                return;
       +
       +        l->v->set = 1;
       +        l->v->type = TLIST;
       +        l->v->store.u.l = nil;
       +
       +        for(fp=fhdrlist; fp; fp=fp->next){
       +                if(fp->ftype == FCORE)
       +                        continue;
       +                addvarsym(fp);
       +        }
       +
       +        if(l->v->store.u.l == nil)
       +                print("no debugging symbols\n");
       +}
       +
       +void
       +addvarsym(Fhdr *fp)
       +{
       +        int i;
       +        Symbol s;
       +        Lsym *l;
       +        String *file;
       +        ulong v;
       +        char buf[1024];
       +        List *list, **tail, *tl;
       +
       +        if(fp == nil)
       +                return;
       +
       +        l = look("symbols");
       +        if(l == nil)
       +                return;
       +
       +        l->v->set = 1;
       +        l->v->type = TLIST;
       +        tail = &l->v->store.u.l;
       +        while(*tail)
       +                tail = &(*tail)->next;
       +
       +        file = strnode(fp->filename);
       +        for(i=0; findexsym(fp, i, &s)>=0; 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;
       +                        if(s.loc.type != LADDR)
       +                                continue;
       +                        v = s.loc.addr;
       +                        tl = al(TLIST);
       +                        *tail = tl;
       +                        tail = &tl->next;
       +
       +                        l = unique(buf, &s);
       +                        l->v->set = 1;
       +                        l->v->type = TINT;
       +                        l->v->store.u.ival = v;
       +                        if(l->v->store.comt == 0)
       +                                l->v->store.fmt = 'X';
       +
       +                        /* Enter as list of { name, type, value, file } */
       +                        list = al(TSTRING);
       +                        tl->store.u.l = list;
       +                        list->store.u.string = strnode(buf);
       +                        list->store.fmt = 's';
       +                        list->next = al(TINT);
       +                        list = list->next;
       +                        list->store.fmt = 'c';
       +                        list->store.u.ival = s.type;
       +                        list->next = al(TINT);
       +                        list = list->next;
       +                        list->store.fmt = 'X';
       +                        list->store.u.ival = v;
       +                        list->next = al(TSTRING);
       +                        list = list->next;
       +                        list->store.fmt = 's';
       +                        list->store.u.string = file;
       +                }
       +        }
       +        *tail = nil;
       +}
       +
       +static int
       +infile(List *list, char *file, char **name)
       +{
       +        /* name */
       +        if(list->type != TSTRING)
       +                return 0;
       +        *name = list->store.u.string->string;
       +        if(list->next == nil)
       +                return 0;
       +        list = list->next;
       +
       +        /* type character */
       +        if(list->next == nil)
       +                return 0;
       +        list = list->next;
       +
       +        /* address */
       +        if(list->next == nil)
       +                return 0;
       +        list = list->next;
       +
       +        /* file */
       +        if(list->type != TSTRING)
       +                return 0;
       +        return strcmp(list->store.u.string->string, file) == 0;
       +}
       +
       +void
       +delvarsym(char *file)
       +{
       +        char *name;
       +        Lsym *l;
       +        List **lp, *p;
       +
       +        l = look("symbols");
       +        if(l == nil)
       +                return;
       +
       +        if(l->v->type != TLIST)
       +                return;
       +
       +        for(lp=&l->v->store.u.l; *lp; lp=&(*lp)->next){
       +                while(*lp){
       +                        p = *lp;
       +                        if(p->type != TLIST)
       +                                break;
       +                        if(!infile(p->store.u.l, file, &name))
       +                                break;
       +                        *lp = p->next;
       +                        /* XXX remove from hash tables */
       +                }
       +                if(*lp == nil)
       +                        break;
       +        }
       +}
       +
       +void
       +varreg(void)
       +{
       +        Lsym *l;
       +        Value *v;
       +        Regdesc *r;
       +        List **tail, *li;
       +
       +        l = mkvar("registers");
       +        v = l->v;
       +        v->set = 1;
       +        v->type = TLIST;
       +        v->store.u.l = 0;
       +        tail = &v->store.u.l;
       +
       +        if(mach == nil)
       +                return;
       +
       +        for(r = mach->reglist; r->name; r++) {
       +                l = mkvar(r->name);
       +                v = l->v;
       +                v->set = 1;
       +                v->store.u.ival = r->offset;
       +                v->store.fmt = r->format;
       +                v->type = TINT;
       +
       +                li = al(TSTRING);
       +                li->store.u.string = strnode(r->name);
       +                li->store.fmt = 's';
       +                *tail = li;
       +                tail = &li->next;
       +        }
       +
       +        l = mkvar("bpinst");        /* Breakpoint text */
       +        v = l->v;
       +        v->type = TSTRING;
       +        v->store.fmt = 's';
       +        v->set = 1;
       +        v->store.u.string = gmalloc(sizeof(String));
       +        v->store.u.string->len = mach->bpsize;
       +        v->store.u.string->string = gmalloc(mach->bpsize);
       +        memmove(v->store.u.string->string, mach->bpinst, mach->bpsize);
       +}
       +
       +void
       +loadvars(void)
       +{
       +        Lsym *l;
       +        Value *v;
       +
       +        l =  mkvar("proc");
       +        v = l->v;
       +        v->type = TINT;
       +        v->store.fmt = 'X';
       +        v->set = 1;
       +        v->store.u.ival = 0;
       +
       +        l = mkvar("pid");                /* Current process */
       +        v = l->v;
       +        v->type = TINT;
       +        v->store.fmt = 'D';
       +        v->set = 1;
       +        v->store.u.ival = 0;
       +
       +        mkvar("notes");                        /* Pending notes */
       +
       +        l = mkvar("proclist");                /* Attached processes */
       +        l->v->type = TLIST;
       +}
       +
       +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->gc.gclink = gcl;
       +        gcl = (Gc*)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->gc.gclink = gcl;
       +        gcl = (Gc*)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->gc.gclink = gcl;
       +        gcl = (Gc*)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;
       +}
       +
       +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;
       +}