tadd acidtypes - 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 98cd2746cff82ab359de6d6ce2c3f87b2c4166a8
 (DIR) parent 70e24710a84797be0c26fec6b22897ddccbf679c
 (HTM) Author: rsc <devnull@localhost>
       Date:   Mon, 19 Apr 2004 22:41:57 +0000
       
       add acidtypes
       
       Diffstat:
         A src/cmd/acidtypes/dat.h             |      72 +++++++++++++++++++++++++++++++
         A src/cmd/acidtypes/dwarf.c           |     193 +++++++++++++++++++++++++++++++
         A src/cmd/acidtypes/main.c            |      66 +++++++++++++++++++++++++++++++
         A src/cmd/acidtypes/mkfile            |      23 +++++++++++++++++++++++
         A src/cmd/acidtypes/stabs.c           |     775 +++++++++++++++++++++++++++++++
         A src/cmd/acidtypes/type.c            |     571 +++++++++++++++++++++++++++++++
         A src/cmd/acidtypes/util.c            |      63 +++++++++++++++++++++++++++++++
       
       7 files changed, 1763 insertions(+), 0 deletions(-)
       ---
 (DIR) diff --git a/src/cmd/acidtypes/dat.h b/src/cmd/acidtypes/dat.h
       t@@ -0,0 +1,72 @@
       +typedef struct Type Type;
       +typedef struct Typeref Typeref;
       +typedef struct TypeList TypeList;
       +
       +enum
       +{
       +        None,
       +        Base,
       +        Enum,
       +        Aggr,
       +        Function,        
       +        Pointer,
       +        Array,
       +        Range,
       +        Defer,
       +        Typedef,
       +};
       +
       +struct Type
       +{        /* Font Tab 4 */
       +        uint        ty;                        /* None, Struct, ... */
       +        vlong lo;                        /* for range */
       +        char sue;
       +        vlong hi;
       +        uint        gen;
       +        uint        n1;                /* type number (impl dependent) */
       +        uint        n2;                /* another type number */
       +        char        *name;                /* name of type */
       +        char        *suename;        /* name of struct, union, enumeration */
       +        uint        isunion;        /* is this Struct a union? */
       +        uint        printfmt;        /* describes base type */
       +        uint        xsizeof;        /* size of type */
       +        Type        *sub;                /* subtype */
       +        uint        n;                        /* count for t, tname, val */
       +        Type **t;                        /* members of sue, params of function */
       +        char        **tname;        /* associated names */
       +        long        *val;                /* associated offsets or values */
       +        uint        didtypedef;        /* internal flag */
       +        uint        didrange;                /* internal flag */
       +        uint         printed;                /* internal flag */
       +        Type *equiv;                /* internal */
       +};
       +
       +struct TypeList
       +{
       +        Type *hd;
       +        TypeList *tl;
       +};
       +
       +void *erealloc(void*, uint);
       +void *emalloc(uint);
       +char *estrdup(char*);
       +void warn(char*, ...);
       +
       +Type *typebynum(uint n1, uint n2);
       +Type *typebysue(char, char*);
       +void printtypes(Biobuf*);
       +void renumber(TypeList*, uint);
       +void denumber(void);
       +TypeList *mktl(Type*, TypeList*);
       +
       +struct Dwarf;
       +struct Stab;
       +int dwarf2acid(struct Dwarf*, Biobuf*);
       +int stabs2acid(struct Stab*, Biobuf*);
       +
       +Type *newtype(void);
       +char *nameof(Type*, int);
       +void freetypes(void);
       +
       +extern char *prefix;
       +char *fixname(char*);
 (DIR) diff --git a/src/cmd/acidtypes/dwarf.c b/src/cmd/acidtypes/dwarf.c
       t@@ -0,0 +1,193 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include <mach.h>
       +#include <elf.h>
       +#include <dwarf.h>
       +#include "dat.h"
       +
       +static ulong
       +valof(uint ty, DwarfVal *v)
       +{
       +        switch(ty){
       +        default:
       +fmtinstall('H', encodefmt);
       +fprint(2, "valof %d %.*H\n", ty, v->b.len, v->b.data);
       +                return 0;
       +        case TConstant:
       +                return v->c;
       +        }
       +}
       +
       +static Type*
       +xnewtype(uint ty, DwarfSym *s)
       +{
       +        Type *t;
       +
       +        t = typebynum(s->unit+s->uoff, 0);
       +        t->ty = ty;
       +        return t;
       +}
       +
       +int
       +dwarf2acid(Dwarf *d, Biobuf *b)
       +{
       +        char *fn;
       +        DwarfSym s;
       +        Type *t;
       +
       +        /* pass over dwarf section pulling out type info */
       +
       +        if(dwarfenum(d, &s) < 0)
       +                return -1;
       +
       +        while(dwarfnextsym(d, &s, s.depth!=1) == 1){
       +        top:
       +                switch(s.attrs.tag){
       +                case TagSubprogram:
       +                case TagLexDwarfBlock:
       +                        dwarfnextsym(d, &s, 1);
       +                        goto top;
       +
       +                case TagTypedef:
       +                        t = xnewtype(Typedef, &s);
       +                        t->name = s.attrs.name;
       +                        t->sub = typebynum(s.attrs.type, 0);
       +                        break;
       +                case TagBaseType:
       +                        t = xnewtype(Base, &s);
       +                        t->xsizeof = s.attrs.bytesize;
       +                        switch(s.attrs.encoding){
       +                        default:
       +                        case TypeAddress:
       +                                t->printfmt = 'x';
       +                                break;
       +                        case TypeBoolean:
       +                        case TypeUnsigned:
       +                        case TypeSigned:
       +                        case TypeSignedChar:
       +                        case TypeUnsignedChar:
       +                                t->printfmt = 'd';
       +                                break;
       +                        case TypeFloat:
       +                                t->printfmt = 'f';
       +                                break;
       +                        case TypeComplexFloat:
       +                                t->printfmt = 'F';
       +                                break;
       +                        case TypeImaginaryFloat:
       +                                t->printfmt = 'i';
       +                                break;
       +                        }
       +                        break;
       +                case TagPointerType:
       +                        t = xnewtype(Pointer, &s);
       +                        t->sub = typebynum(s.attrs.type, 0);
       +                        break;
       +                case TagStructType:
       +                case TagUnionType:
       +                        t = xnewtype(Aggr, &s);
       +                        t->sue = s.attrs.tag==TagStructType ? 's' : 'u';
       +                        t->xsizeof = s.attrs.bytesize;
       +                        t->suename = s.attrs.name;
       +                        t->isunion = s.attrs.tag==TagUnionType;
       +                        dwarfnextsym(d, &s, 1);
       +                        if(s.depth != 2)
       +                                goto top;
       +                        do{
       +                                if(!s.attrs.have.name || !s.attrs.have.type || s.attrs.tag != TagMember)
       +                                        continue;
       +                                if(t->n%32 == 0){
       +                                        t->tname = erealloc(t->tname, (t->n+32)*sizeof(t->tname[0]));
       +                                        t->val = erealloc(t->val, (t->n+32)*sizeof(t->val[0]));
       +                                        t->t = erealloc(t->t, (t->n+32)*sizeof(t->t[0]));
       +                                }
       +                                t->tname[t->n] = s.attrs.name;
       +                                if(t->isunion)
       +                                        t->val[t->n] = 0;
       +                                else
       +                                        t->val[t->n] = valof(s.attrs.have.datamemberloc, &s.attrs.datamemberloc);
       +                                t->t[t->n] = typebynum(s.attrs.type, 0);
       +                                t->n++;
       +                        }while(dwarfnextsym(d, &s, 1) == 1 && s.depth==2);
       +                        goto top;
       +                        break;
       +                case TagSubroutineType:
       +                        t = xnewtype(Function, &s);
       +                        break;
       +                case TagConstType:
       +                case TagVolatileType:
       +                        t = xnewtype(Defer, &s);
       +                        t->sub = typebynum(s.attrs.type, 0);
       +                        break;
       +                case TagArrayType:
       +                        t = xnewtype(Array, &s);
       +                        t->sub = typebynum(s.attrs.type, 0);
       +                        break;
       +                case TagEnumerationType:
       +                        t = xnewtype(Enum, &s);
       +                        t->sue = 'e';
       +                        t->suename = s.attrs.name;
       +                        t->xsizeof = s.attrs.bytesize;
       +                        dwarfnextsym(d, &s, 1);
       +                        if(s.depth != 2)
       +                                goto top;
       +                        do{
       +                                if(!s.attrs.have.name || !s.attrs.have.constvalue || s.attrs.tag != TagEnumerator)
       +                                        continue;
       +                                if(t->n%32 == 0){
       +                                        t->tname = erealloc(t->tname, (t->n+32)*sizeof(t->tname[0]));
       +                                        t->val = erealloc(t->val, (t->n+32)*sizeof(t->val[0]));
       +                                }
       +                                t->tname[t->n] = s.attrs.name;
       +                                t->val[t->n] = valof(s.attrs.have.constvalue, &s.attrs.constvalue);
       +                                t->n++;
       +                        }while(dwarfnextsym(d, &s, 1) == 1 && s.depth==2);
       +                        goto top;
       +                        break;
       +                }
       +        }
       +
       +        printtypes(b);
       +
       +        /* pass over dwarf section pulling out type definitions */
       +
       +        if(dwarfenum(d, &s) < 0)
       +                goto out;
       +
       +        fn = nil;
       +        while(dwarfnextsym(d, &s, 1) == 1){
       +                if(s.depth == 1)
       +                        fn = nil;
       +                switch(s.attrs.tag){
       +                case TagSubprogram:
       +                        fn = s.attrs.name;
       +                        break;
       +                case TagFormalParameter:
       +                        if(s.depth != 2)
       +                                break;
       +                        /* fall through */
       +                case TagVariable:
       +                        if(s.attrs.name == nil || s.attrs.type == 0)
       +                                continue;
       +                        t = typebynum(s.attrs.type, 0);
       +                        if(t->ty == Pointer){
       +                                t = t->sub;
       +                                if(t && t->equiv)
       +                                        t = t->equiv;
       +                        }
       +                        if(t == nil)
       +                                break;
       +                        if(t->ty != Aggr)
       +                                break;
       +                        Bprint(b, "complex %s %s%s%s;\n", nameof(t, 1),
       +                                fn ? fixname(fn) : "", fn ? ":" : "", fixname(s.attrs.name));
       +                        break;
       +                }
       +        }
       +
       +out:
       +        freetypes();
       +        return 0;
       +}
       +
 (DIR) diff --git a/src/cmd/acidtypes/main.c b/src/cmd/acidtypes/main.c
       t@@ -0,0 +1,66 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include <mach.h>
       +#include "dat.h"
       +
       +void
       +usage(void)
       +{
       +        fprint(2, "usage: acidtypes [-p prefix] executable...\n");
       +        exits("usage");
       +}
       +
       +void
       +main(int argc, char **argv)
       +{
       +        int i;
       +        Fhdr *fp;
       +        Biobuf b;
       +        char err[ERRMAX];
       +
       +        quotefmtinstall();
       +
       +        ARGBEGIN{
       +        case 'p':
       +                prefix = EARGF(usage());
       +                break;
       +        default:
       +                usage();
       +        }ARGEND
       +
       +        if(argc < 1)
       +                usage();
       +
       +        Binit(&b, 1, OWRITE);
       +        for(i=0; i<argc; i++){
       +                Bprint(&b, "\n//\n// symbols for %s\n//\n\n", argv[i]);
       +                if((fp = crackhdr(argv[i], OREAD)) == nil){
       +                        rerrstr(err, sizeof err);
       +                        Bprint(&b, "// open %s: %s\n\n", argv[i], err);
       +                        fprint(2, "open %s: %s\n", argv[i], err);
       +                        continue;
       +                }
       +                if(fp->dwarf){
       +                        if(dwarf2acid(fp->dwarf, &b) < 0){
       +                                rerrstr(err, sizeof err);
       +                                Bprint(&b, "// dwarf2acid %s: %s\n\n", argv[i], err);
       +                                fprint(2, "dwarf2acid %s: %s\n", argv[i], err);
       +                        }
       +                }else if(fp->stabs.stabbase){
       +                        if(stabs2acid(&fp->stabs, &b) < 0){
       +                                rerrstr(err, sizeof err);
       +                                Bprint(&b, "// dwarf2acid %s: %s\n\n", argv[i], err);
       +                                fprint(2, "dwarf2acid %s: %s\n", argv[i], err);
       +                        }
       +                }else{
       +                        Bprint(&b, "// no debugging symbols in %s\n\n", argv[i]);
       +                //        fprint(2, "no debugging symbols in %s\n", argv[i]);
       +                }
       +                uncrackhdr(fp);
       +        }
       +        Bflush(&b);
       +        Bterm(&b);
       +        exits(0);
       +}
       +
 (DIR) diff --git a/src/cmd/acidtypes/mkfile b/src/cmd/acidtypes/mkfile
       t@@ -0,0 +1,23 @@
       +<$PLAN9/src/mkhdr
       +
       +TARG=acidtypes
       +
       +OFILES=\
       +        dwarf.$O\
       +        main.$O\
       +        stabs.$O\
       +        type.$O\
       +        util.$O\
       +
       +HFILES=\
       +        dat.h\
       +        ../../libmach/mach.h\
       +        ../../libmach/elf.h\
       +        ../../libmach/dwarf.h\
       +        ../../libmach/stabs.h\
       +
       +CFLAGS=-I../../libmach $CFLAGS
       +SHORTLIB=mach bio 9
       +
       +<$PLAN9/src/mkone
       +
 (DIR) diff --git a/src/cmd/acidtypes/stabs.c b/src/cmd/acidtypes/stabs.c
       t@@ -0,0 +1,775 @@
       +#include <u.h>
       +#include <errno.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include <mach.h>
       +#include <stabs.h>
       +#include <ctype.h>
       +#include "dat.h"
       +
       +static jmp_buf kaboom;
       +
       +static Type *parsename(char*, char**);
       +static Type *parseinfo(char*, char**);
       +static int parsenum(char*, int*, int*, char**);
       +static int parseattr(char*, char**, char**);
       +static Type *parsedefn(char *p, Type *t, char **pp);
       +static int parsebound(char**);
       +static vlong parsebigint(char**);
       +
       +typedef struct Sym Sym;
       +struct Sym
       +{
       +        char *fn;
       +        char *name;
       +        Type *type;
       +        Sym *next;
       +};
       +
       +typedef struct Ftypes Ftypes;
       +struct Ftypes
       +{
       +        Ftypes *down;
       +        Ftypes *next;
       +        char *file;
       +        TypeList *list;
       +};
       +
       +Ftypes *fstack;
       +Ftypes *allftypes;
       +
       +static Sym*
       +mksym(char *fn, char *name, Type *type)
       +{
       +        Sym *s;
       +
       +        s = emalloc(sizeof *s);
       +        s->fn = fn;
       +        s->name = name;
       +        s->type = type;
       +        return s;
       +}
       +
       +static char*
       +estrndup(char *s, int n)
       +{
       +        char *t;
       +
       +        t = emalloc(n+1);
       +        memmove(t, s, n);
       +        return t;
       +}
       +
       +static char*
       +mkpath(char *dir, char *name)
       +{
       +        char *s;
       +        if(name[0] == '/')
       +                return estrdup(name);
       +        else{
       +                s = emalloc(strlen(dir)+strlen(name)+1);
       +                strcpy(s, dir);
       +                strcat(s, name);
       +                return s;
       +        }
       +}
       +
       +static Ftypes*
       +mkftypes(char *dir, char *name)
       +{
       +        Ftypes *f;
       +
       +        f = emalloc(sizeof(*f));
       +        f->file = mkpath(dir, name);
       +        f->next = allftypes;
       +        allftypes = f;
       +        return f;
       +}
       +
       +static Ftypes*
       +findftypes(char *dir, char *name)
       +{
       +        char *s;
       +        Ftypes *f, *found;
       +
       +        found = nil;
       +        s = mkpath(dir, name);
       +        for(f=allftypes; f; f=f->next)
       +                if(strcmp(f->file, s) == 0)
       +                        found = f;
       +        return found;
       +}
       +
       +static void
       +oops(void)
       +{
       +        longjmp(kaboom, 1);
       +}
       +
       +/* find a : but skip over :: */
       +static char*
       +findcolon(char *p)
       +{
       +        while((p = strchr(p, ':')) != nil && *(p+1) == ':')
       +                p += 2;
       +        if(p == nil)
       +                oops();
       +        return p;
       +}
       +
       +static void
       +semi(char **p)
       +{
       +        if(**p != ';')
       +                oops();
       +        (*p)++;
       +}
       +
       +static void
       +comma(char **p)
       +{
       +        if(**p != ',')
       +                oops();
       +        (*p)++;
       +}
       +
       +static int
       +parseint(char **pp)
       +{
       +        if(!isdigit(**pp))
       +                oops();
       +        return strtol(*pp, pp, 10);
       +}
       +
       +/*
       +        name ::= symbol_opt info
       + */
       +static Type*
       +parsename(char *desc, char **pp)
       +{
       +        if(*desc == 'c')
       +                return nil;
       +
       +        if(isdigit(*desc) || *desc=='-' || *desc=='(')
       +                return parseinfo(desc, pp);
       +        if(*desc == 0)
       +                oops();
       +        return parseinfo(desc+1, pp);
       +}
       +
       +/*
       +        info ::= num | num '=' attr* defn
       + */
       +static Type*
       +parseinfo(char *desc, char **pp)
       +{
       +        int n1, n2;
       +        Type *t;
       +        char *attr;
       +
       +        parsenum(desc, &n1, &n2, &desc);
       +        t = typebynum(n1, n2);
       +        if(*desc != '='){
       +                *pp = desc;
       +                return t;
       +        }
       +        desc++;
       +        if(fstack)
       +                fstack->list = mktl(t, fstack->list);
       +        while(parseattr(desc, &attr, &desc) >= 0){
       +                if(*attr == 's')
       +                        t->xsizeof = atoi(attr+1)/8;
       +        }
       +        return parsedefn(desc, t, pp);
       +}
       +
       +/*
       +        num ::= integer | '(' integer ',' integer ')'
       +*/
       +static int
       +parsenum(char *p, int *n1, int *n2, char **pp)
       +{
       +        if(isdigit(*p)){
       +                *n1 = strtol(p, &p, 10);
       +                *n2 = 0;
       +                *pp = p;
       +                return 0;
       +        }
       +        if(*p == '('){
       +                *n1 = strtol(p+1, &p, 10);
       +                if(*p != ',')
       +                        oops();
       +                *n2 = strtol(p+1, &p, 10);
       +                if(*p != ')')
       +                        oops();
       +                *pp = p+1;
       +                return 0;
       +        }
       +        oops();
       +        return -1;
       +}
       +
       +/*
       +        attr ::= '@' text ';'
       +
       +        text is 
       +                'a' integer (alignment)
       +                'p' integer (pointer class)
       +                'P' (packed type)
       +                's' integer (size of type in bits)
       +                'S' (string instead of array of chars)
       +*/
       +static int
       +parseattr(char *p, char **text, char **pp)
       +{
       +        if(*p != '@')
       +                return -1;
       +        *text = p+1;
       +        if((p = strchr(p, ';')) == nil)
       +                oops();
       +        *pp = p+1;
       +        return 0;
       +}
       +
       +
       +typedef struct Basic Basic;
       +struct Basic
       +{
       +        int size;
       +        int fmt;
       +};
       +
       +static Basic baseints[] =
       +{
       +        0, 0,
       +/*1*/        4, 'd',        /* int32 */
       +/*2*/        1, 'd',        /* char8 */
       +/*3*/        2, 'd',        /* int16 */
       +/*4*/        4, 'd',        /* long int32 */
       +/*5*/        1, 'x',        /* uchar8 */
       +/*6*/        1, 'd',        /* schar8 */
       +/*7*/        2, 'x',        /* uint16 */
       +/*8*/        4, 'x',        /* uint32 */
       +/*9*/        4, 'x',        /* uint32 */
       +/*10*/        4, 'x',        /* ulong32 */
       +/*11*/        0, 0,                /* void */
       +/*12*/        4, 'f',                /* float */
       +/*13*/        8, 'f',                /* double */
       +/*14*/        10, 'f',        /* long double */
       +/*15*/        4, 'd',        /* int32 */
       +/*16*/        4, 'd',        /* bool32 */        
       +/*17*/        2, 'f',                /* short real */
       +/*18*/        4, 'f',                /* real */
       +/*19*/        4, 'x',        /* stringptr */
       +/*20*/        1, 'd',        /* character8 */
       +/*21*/        1, 'x',        /* logical*1 */
       +/*22*/        2, 'x',        /* logical*2 */
       +/*23*/        4, 'X',        /* logical*4 */
       +/*24*/        4, 'X',        /* logical32 */
       +/*25*/        8, 'F',                /* complex (two single) */
       +/*26*/        16, 'F',        /* complex (two double) */
       +/*27*/        1, 'd',        /* integer*1 */
       +/*28*/        2, 'd',        /* integer*2 */
       +/*29*/        4, 'd',        /* integer*4 */
       +/*30*/        2, 'x',        /* wide char */
       +/*31*/        8, 'd',        /* int64 */
       +/*32*/        8, 'x',        /* uint64 */
       +/*33*/        8, 'x',        /* logical*8 */
       +/*34*/        8, 'd',        /* integer*8 */
       +};
       +
       +static Basic basefloats[] =
       +{
       +        0,0,
       +/*1*/        4, 'f',        /* 32-bit */
       +/*2*/        8, 'f',        /* 64-bit */
       +/*3*/        8, 'F',        /* complex */
       +/*4*/        4, 'F',        /* complex16 */
       +/*5*/        8, 'F', /* complex32 */
       +/*6*/        10, 'f',        /* long double */
       +};
       +
       +/*
       +        defn ::= info
       +                | 'b' ('u' | 's') 'c'? width; offset; nbits;                 (builtin, signed/unsigned, char/not, width in bytes, offset & nbits of type)
       +                | 'w'                (aix wide char type, not used)
       +                | 'R' fptype; bytes;                        (fptype 1=32-bit, 2=64-bit, 3=complex, 4=complex16, 5=complex32, 6=long double)
       +                | 'g' typeinfo ';' nbits                 (aix floating, not used)
       +                | 'c' typeinfo ';' nbits                (aix complex, not used)
       +                | 'b' typeinfo ';' bytes                (ibm, no idea)
       +                | 'B' typeinfo                (volatile typref)
       +                | 'd' typeinfo                (file of typeref)
       +                | 'k' typeinfo                (const typeref)
       +                | 'M' typeinfo ';' length                (multiple instance type, fortran)
       +                | 'S' typeinfo                (set, typeref must have small number of values)
       +                | '*' typeinfo                (pointer to typeref)
       +                | 'x' ('s'|'u'|'e') name ':'        (struct, union, enum reference.  name can have '::' in it)
       +                | 'r' typeinfo ';' low ';' high ';'                (subrange.  typeref can be type being defined for base types!)
       +                                low and high are bounds
       +                                if bound is octal power of two, it's a big negative number
       +                | ('a'|'P') indextypedef arraytypeinfo         (array, index should be range type)
       +                                        indextype is type definition not typeinfo (need not say typenum=)
       +                                        P means packed array
       +                | 'A' arraytypeinfo                (open array (no index bounds))
       +                | 'D' dims ';' typeinfo                (dims-dimensional dynamic array)
       +                | 'E' dims ';' typeinfo                (subarray of N-dimensional array)
       +                | 'n' typeinfo ';' bytes                (max length string)
       +                | 'z' typeinfo ';' bytes                (no idea what difference is from 'n')
       +                | 'N'                                        (pascal stringptr)
       +                | 'e' (name ':' bigint ',')* ';'        (enum listing)
       +                | ('s'|'u') bytes (name ':' type ',' bitoffset ',' bitsize ';')* ';'                (struct/union defn)
       +                                                        tag is given as name in stabs entry, with 'T' symbol
       +                | 'f' typeinfo ';'                         (function returning type)
       +                | 'f' rettypeinfo ',' paramcount ';' (typeinfo ',' (0|1) ';')* ';'
       +                | 'p' paramcount ';' (typeinfo ',' (0|1) ';')* ';'
       +                | 'F' rettypeinfo ',' paramcount ';' (name ':' typeinfo ',' (0|1) ';')* ';'
       +                | 'R' paramcount ';' (name ':' typeinfo ',' (0|1) ';')* ';'
       +                                                        (the 0 or 1 is pass-by-reference vs pass-by-value)
       +                                                        (the 0 or 1 is pass-by-reference vs pass-by-value)
       +*/
       +
       +static Type*
       +parsedefn(char *p, Type *t, char **pp)
       +{
       +        char c, *name;
       +        int ischar, namelen, n, wid, offset, bits, sign;
       +        long val;
       +        Type *tt;
       +
       +        if(*p == '(' || isdigit(*p)){
       +                t->ty = Defer;
       +                t->sub = parseinfo(p, pp);
       +                return t;
       +        }
       +
       +        switch(c = *p){
       +        case '-':        /* builtin */
       +                n = strtol(p+1, &p, 10);
       +                if(n >= nelem(baseints) || n < 0)
       +                        n = 0;
       +                t->ty = Base;
       +                t->xsizeof = baseints[n].size;
       +                t->printfmt = baseints[n].fmt;
       +                break;
       +        case 'b':        /* builtin */
       +                p++;
       +                if(*p != 'u' && *p != 's')
       +                        oops();
       +                sign = (*p == 's');
       +                p++;
       +                if(*p == 'c'){
       +                        ischar = 1;
       +                        p++;
       +                }
       +                wid = parseint(&p);
       +                semi(&p);
       +                offset = parseint(&p);
       +                semi(&p);
       +                bits = parseint(&p);
       +                semi(&p);
       +                t->ty = Base;
       +                t->xsizeof = wid;
       +                if(sign == 1)
       +                        t->printfmt = 'd';
       +                else
       +                        t->printfmt = 'x';
       +                break;
       +        case 'R':        /* fp type */
       +                n = parseint(&p);
       +                semi(&p);
       +                wid = parseint(&p);
       +                semi(&p);
       +                t->ty = Base;
       +                t->xsizeof = wid;
       +                if(n < 0 || n >= nelem(basefloats))
       +                        n = 0;
       +                t->xsizeof = basefloats[n].size;
       +                t->printfmt = basefloats[n].fmt;
       +                break;
       +        case 'r':        /* subrange */
       +                t->ty = Range;
       +                t->sub = parseinfo(p+1, &p);
       +                if(*(p-1) == ';' && *p != ';')
       +                        p--;
       +                semi(&p);
       +                t->lo = parsebound(&p);
       +                semi(&p);
       +                t->hi = parsebound(&p);
       +                semi(&p);
       +                break;
       +        case 'B':        /* volatile */
       +        case 'k':        /* const */
       +                t->ty = Defer;
       +                t->sub = parseinfo(p+1, &p);
       +                break;
       +        case '*':        /* pointer */
       +        case 'A':        /* open array */
       +                t->ty = Pointer;
       +                t->sub = parseinfo(p+1, &p);
       +                break;
       +        case 'a':        /* array */                
       +        case 'P':        /* packed array */
       +                t->ty = Pointer;
       +                tt = newtype();
       +                parsedefn(p+1, tt, &p);        /* index type */
       +                if(*p == ';')
       +                        p++;
       +                tt = newtype();
       +                t->sub = tt;
       +                parsedefn(p, tt, &p);        /* element type */
       +                break;
       +        case 'e':        /* enum listing */
       +                p++;
       +                t->sue = 'e';
       +                t->ty = Enum;
       +                while(*p != ';'){
       +                        name = p;
       +                        p = findcolon(p)+1;
       +                        namelen = (p-name)-1;
       +                        val = parsebigint(&p);
       +                        comma(&p);
       +                        if(t->n%32 == 0){
       +                                t->tname = erealloc(t->tname, (t->n+32)*sizeof(t->tname[0]));
       +                                t->val = erealloc(t->val, (t->n+32)*sizeof(t->val[0]));
       +                        }
       +                        t->tname[t->n] = estrndup(name, namelen);
       +                        t->val[t->n] = val;
       +                        t->n++;
       +                }
       +                semi(&p);
       +                break;
       +                
       +        case 's':        /* struct */
       +        case 'u':        /* union */
       +                p++;
       +                t->sue = c;
       +                t->ty = Aggr;
       +                n = parseint(&p);
       +                while(*p != ';'){
       +                        name = p;
       +                        p = findcolon(p)+1;
       +                        namelen = (p-name)-1;
       +                        tt = parseinfo(p, &p);
       +                        comma(&p);
       +                        offset = parseint(&p);
       +                        comma(&p);
       +                        bits = parseint(&p);
       +                        semi(&p);
       +                        if(t->n%32 == 0){
       +                                t->tname = erealloc(t->tname, (t->n+32)*sizeof(t->tname[0]));
       +                                t->val = erealloc(t->val, (t->n+32)*sizeof(t->val[0]));
       +                                t->t = erealloc(t->t, (t->n+32)*sizeof(t->t[0]));
       +                        }
       +                        t->tname[t->n] = estrndup(name, namelen);
       +                        t->val[t->n] = offset;
       +                        t->t[t->n] = tt;
       +                        t->n++;
       +                }
       +                semi(&p);
       +                break;
       +
       +        case 'x':        /* struct, union, enum reference */
       +                p++;
       +                t->ty = Defer;
       +                if(*p != 's' && *p != 'u' && *p != 'e')
       +                        oops();
       +                c = *p;
       +                name = p+1;
       +                p = findcolon(p+1);
       +                name = estrndup(name, p-name);
       +                t->sub = typebysue(c, name);
       +                p++;
       +                break;
       +
       +#if 0        /* AIX */
       +        case 'f':        /* function */
       +        case 'p':        /* procedure */
       +        case 'F':        /* Pascal function */
       +        /* case 'R':        /* Pascal procedure */
       +                /*
       +                 * Even though we don't use the info, we have
       +                 * to parse it in case it is embedded in other descriptions.
       +                 */
       +                t->ty = Function;
       +                p++;
       +                if(c == 'f' || c == 'F'){
       +                        t->sub = parseinfo(p, &p);
       +                        if(*p != ','){
       +                                if(*p == ';')
       +                                        p++;
       +                                break;
       +                        }
       +                        comma(&p);
       +                }
       +                n = parseint(&p);        /* number of params */
       +                semi(&p);
       +                while(*p != ';'){
       +                        if(c == 'F' || c == 'R'){
       +                                name = p;                /* parameter name */
       +                                p = findcolon(p)+1;
       +                        }
       +                        parseinfo(p, &p);        /* param type */
       +                        comma(&p);
       +                        parseint(&p);        /* bool: passed by value? */
       +                        semi(&p);
       +                }
       +                semi(&p);
       +                break;
       +#endif
       +
       +        case 'f':        /* static function */
       +        case 'F':        /* global function */
       +                t->ty = Function;
       +                p++;
       +                t->sub = parseinfo(p, &p);
       +                break;
       +
       +        /*
       +         * We'll never see any of this stuff.
       +         * When we do, we can worry about it.
       +         */
       +        case 'D':        /* n-dimensional array */
       +        case 'E':        /* subarray of n-dimensional array */
       +        case 'M':        /* fortran multiple instance type */
       +        case 'N':        /* pascal string ptr */
       +        case 'S':        /* set */
       +        case 'c':        /* aix complex */
       +        case 'd':        /* file of */
       +        case 'g':        /* aix float */
       +        case 'n':        /* max length string */
       +        case 'w':        /* aix wide char */
       +        case 'z':        /* another max length string */
       +        default:
       +                fprint(2, "unsupported type char %c (%d)\n", *p, *p);
       +                oops();
       +        }
       +        *pp = p;
       +        return t;
       +}
       +
       +/*
       +        bound ::= 
       +                'A' offset                        (bound is on stack by ref at offset offset from arg list)
       +                | 'T' offset                        (bound is on stack by val at offset offset from arg list)
       +                | 'a' regnum                (bound passed by reference in register)
       +                | 't' regnum                (bound passed by value in register)
       +                | 'J'                                (no bound)
       +                | bigint
       +*/
       +static int
       +parsebound(char **pp)
       +{
       +        char *p;
       +        int n;
       +
       +        n = 0;
       +        p = *pp;
       +        switch(*p){
       +        case 'A':        /* bound is on stack by reference at offset n from arg list */
       +        case 'T':        /* bound is on stack by value at offset n from arg list */
       +        case 'a':        /* bound is passed by reference in register n */
       +        case 't':        /* bound is passed by value in register n */
       +                p++;
       +                parseint(&p);
       +                break;
       +        case 'J':        /* no bound */
       +                p++;
       +                break;
       +        default:
       +                n = parsebigint(&p);
       +                break;
       +        }
       +        *pp = p;
       +        return n;
       +}
       +
       +/*
       +        bigint ::= '-'? decimal
       +                | 0 octal
       +                | -1
       + */
       +static vlong
       +parsebigint(char **pp)
       +{
       +        char *p;
       +        int n, neg;
       +
       +        p = *pp;
       +        if(*p == '0'){
       +                errno = 0;
       +                n = strtoll(p, &p, 8);
       +                if(errno)
       +                        n = 0;
       +                goto out;
       +        }
       +        neg = 0;
       +        if(*p == '-'){
       +                neg = 1;
       +                p++;
       +        }
       +        if(!isdigit(*p))
       +                oops();
       +        n = strtol(p, &p, 10);
       +        if(neg)
       +                n = -n;
       +
       +out:
       +        *pp = p;
       +        return n;
       +}
       +
       +int
       +stabs2acid(Stab *stabs, Biobuf *b)
       +{
       +        int fno, i;
       +        char c, *dir, *fn, *file, *name, *desc, *p;
       +        Ftypes *f;
       +        Type *t, *tt;
       +        StabSym sym;
       +        Sym *symbols, *s;
       +        Sym **lsym;
       +
       +        dir = nil;
       +        file = nil;
       +        fno = 0;
       +        fn = nil;
       +        symbols = nil;
       +        lsym = &symbols;
       +        for(i=0; stabsym(stabs, i, &sym)>=0; i++){
       +                switch(sym.type){
       +                case N_SO:
       +                        if(sym.name){
       +                                if(sym.name[0] && sym.name[strlen(sym.name)-1] == '/')
       +                                        dir = sym.name;
       +                                else
       +                                        file = sym.name;
       +                        }
       +                        denumber();
       +                        fstack = nil;
       +                        fno = 0;
       +                        break;
       +                case N_BINCL:
       +                        fno++;
       +                        f = mkftypes(dir, sym.name);
       +                        f->down = fstack;
       +                        fstack = f;
       +                        break;
       +                case N_EINCL:
       +                        if(fstack)
       +                                fstack = fstack->down;
       +                        break;
       +                case N_EXCL:
       +                        fno++;
       +                        if((f = findftypes(dir, sym.name)) == nil){
       +                                fprint(2, "cannot find remembered %s\n", sym.name);
       +                                continue;
       +                        }
       +                        renumber(f->list, fno);
       +                        break;
       +                case N_GSYM:
       +                case N_FUN:
       +                case N_PSYM:
       +                case N_LSYM:
       +                case N_LCSYM:
       +                case N_STSYM:
       +                case N_RSYM:
       +                        name = sym.name;
       +                        if(name == nil){
       +                                if(sym.type==N_FUN)
       +                                        fn = nil;
       +                                continue;
       +                        }
       +                        if((p = strchr(name, ':')) == nil)
       +                                continue;
       +                        name = estrndup(name, p-name);
       +                        desc = ++p;
       +                        c = *desc;
       +                        if(c == 'c'){
       +                                fprint(2, "skip constant %s\n", name);
       +                                continue;
       +                        }
       +                        if(setjmp(kaboom)){
       +                                fprint(2, "cannot parse %s\n", name);
       +                                continue;
       +                        }
       +                        t = parsename(desc, &p);
       +                        if(t == nil)
       +                                continue;
       +                        if(*p != 0)
       +                                fprint(2, "extra desc '%s' in '%s'\n", p, desc);
       +                        /* void is defined as itself */
       +                        if(t->ty==Defer && t->sub==t && strcmp(name, "void")==0){
       +                                t->ty = Base;
       +                                t->xsizeof = 0;
       +                                t->printfmt = '0';
       +                        }
       +                        if(*name==' ' && *(name+1) == 0)
       +                                *name = 0;
       +                        /* attach names to structs, unions, enums */
       +                        if(c=='T' && *name && t->sue){
       +                                t->suename = name;
       +                                if(t->name == nil)
       +                                        t->name = name;
       +                                tt = typebysue(t->sue, name);
       +                                tt->ty = Defer;
       +                                tt->sub = t;
       +                        }
       +                        if(c=='t'){
       +                                tt = newtype();
       +                                tt->ty = Typedef;
       +                                tt->name = name;
       +                                tt->sub = t;
       +                        }
       +                        /* define base c types */
       +                        if(t->ty==None || t->ty==Range){
       +                                if(strcmp(name, "char") == 0){
       +                                        t->ty = Base;
       +                                        t->xsizeof = 1;
       +                                        t->printfmt = 'x';
       +                                }
       +                                if(strcmp(name, "int") == 0){
       +                                        t->ty = Base;
       +                                        t->xsizeof = 4;
       +                                        t->printfmt = 'd';
       +                                }
       +                        }
       +                        /* record declaration in list for later. */
       +                        if(c != 't' && c != 'T')
       +                        switch(sym.type){
       +                        case N_GSYM:
       +                                *lsym = mksym(nil, name, t);
       +                                lsym = &(*lsym)->next;
       +                                break;
       +                        case N_FUN:
       +                                fn = name;
       +                                break;
       +                        case N_PSYM:
       +                        case N_LSYM:
       +                        case N_LCSYM:
       +                        case N_STSYM:
       +                        case N_RSYM:
       +                                *lsym = mksym(fn, name, t);
       +                                lsym = &(*lsym)->next;
       +                                break;
       +                        }
       +                        break;
       +                }
       +        }
       +
       +        printtypes(b);
       +
       +        for(s=symbols; s; s=s->next){
       +                t = s->type;
       +                if(t->ty == Pointer){
       +                        t = t->sub;
       +                        if(t && t->equiv)
       +                                t = t->equiv;
       +                }
       +                if(t == nil || t->ty != Aggr)
       +                        continue;
       +                Bprint(b, "complex %s %s%s%s;\n", nameof(t, 1),
       +                        s->fn ? fixname(s->fn) : "", s->fn ? ":" : "", fixname(s->name));
       +        }
       +
       +        return 0;
       +}
 (DIR) diff --git a/src/cmd/acidtypes/type.c b/src/cmd/acidtypes/type.c
       t@@ -0,0 +1,571 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include <mach.h>
       +#include <ctype.h>
       +#include "dat.h"
       +
       +char *prefix = "";
       +
       +static TypeList *thash[1021];
       +static TypeList *namehash[1021];
       +static TypeList *alltypes;
       +
       +static uint
       +hash(uint num, uint num1)
       +{
       +        return (num*1009 + num1*1013) % nelem(thash);
       +}
       +
       +static uint
       +shash(char *s)
       +{
       +        uint h;
       +
       +        h = 0;
       +        for(; *s; s++)
       +                h = 37*h + *s;
       +        return h%nelem(namehash);
       +}
       +
       +void
       +addnamehash(Type *t)
       +{
       +        uint h;
       +
       +        if(t->name){
       +                h = shash(t->name);
       +                namehash[h] = mktl(t, namehash[h]);
       +        }
       +}
       +
       +static void
       +addhash(Type *t)
       +{
       +        uint h;
       +
       +        if(t->n1 || t->n2){
       +                h = hash(t->n1, t->n2);
       +                thash[h] = mktl(t, thash[h]);
       +        }
       +        if(t->name)
       +                addnamehash(t);
       +}
       +
       +Type*
       +typebysue(char sue, char *name)
       +{
       +        Type *t;
       +        TypeList *tl;
       +
       +        for(tl=namehash[shash(name)]; tl; tl=tl->tl){
       +                t = tl->hd;
       +                if(t->sue==sue && t->suename && strcmp(name, t->suename)==0)
       +                        return t;
       +        }
       +        t = newtype();
       +        if(sue=='e')
       +                t->ty = Enum;
       +        else
       +                t->ty = Aggr;
       +        if(sue=='u')
       +                t->isunion = 1;
       +        t->sue = sue;
       +        t->suename = name;
       +        addnamehash(t);
       +        return t;
       +}
       +
       +Type*
       +typebynum(uint n1, uint n2)
       +{
       +        Type *t;
       +        TypeList *tl;
       +
       +        if(n1 || n2){
       +                for(tl=thash[hash(n1, n2)]; tl; tl=tl->tl){
       +                        t = tl->hd;
       +                        if(t->n1==n1 && t->n2==n2)
       +                                return t;
       +                }
       +        }
       +
       +        t = newtype();
       +        t->n1 = n1;
       +        t->n2 = n2;
       +        addhash(t);
       +        return t;
       +}        
       +
       +Type*
       +newtype(void)
       +{
       +        Type *t;
       +        static int gen;
       +
       +        t = emalloc(sizeof *t);
       +        t->gen = ++gen;
       +        alltypes = mktl(t, alltypes);
       +        return t;
       +}
       +
       +struct {
       +        char *old;
       +        char *new;
       +} fixes[] = { /* Font Tab 4 */
       +        "append",                "$append",
       +        "builtin",                "$builtin",
       +        "complex",                "$complex",
       +        "delete",                "$delete",
       +        "do",                        "$do",
       +        "else",                        "$else",
       +        "eval",                        "$eval",
       +        "fmt",                        "$fmt",
       +        "fn",                        "$fn",
       +        "head",                        "$head",
       +        "if",                        "$if",
       +        "local",                "$local",
       +        "loop",                        "$loop",
       +        "ret",                        "$ret",
       +        "tail",                        "$tail",
       +        "then",                        "$then",
       +        "whatis",                        "$whatis",
       +        "while",                "$while",
       +};
       +
       +char*
       +fixname(char *name)
       +{
       +        int i;
       +
       +        if(name == nil)
       +                return nil;
       +        for(i=0; i<nelem(fixes); i++)
       +                if(name[0]==fixes[i].old[0] && strcmp(name, fixes[i].old)==0)
       +                        return fixes[i].new;
       +        return name;
       +}
       +
       +void
       +denumber(void)
       +{
       +        memset(thash, 0, sizeof thash);
       +        memset(namehash, 0, sizeof namehash);
       +}
       +
       +void
       +renumber(TypeList *tl, uint n1)
       +{
       +        Type *t;
       +
       +        for(; tl; tl=tl->tl){
       +                t = tl->hd;
       +                t->n1 = n1;
       +                addhash(t);
       +        }
       +}
       +
       +static Type*
       +defer(Type *t)
       +{
       +        Type *u, *oldt;
       +        int n;
       +
       +        u = t;
       +        n = 0;
       +        oldt = t;
       +        while(t && (t->ty == Defer || t->ty == Typedef)){
       +                if(n++%2)
       +                        u = u->sub;
       +                t = t->sub;
       +                if(t == u)        /* cycle */
       +                        goto cycle;
       +        }
       +        return t;
       +
       +cycle:
       +        fprint(2, "cycle\n");
       +        t = oldt;
       +        n = 0;
       +        while(t && (t->ty==Defer || t->ty==Typedef)){
       +                fprint(2, "t %p/%d %s\n", t, t->ty, t->name);
       +                if(t == u && n++ == 2)
       +                        break;
       +                t = t->sub;
       +        }
       +        return u;
       +}
       +
       +static void
       +dotypedef(Type *t)
       +{
       +        if(t->ty != Typedef && t->ty != Defer)
       +                return;
       +
       +        if(t->didtypedef)
       +                return;
       +
       +        t->didtypedef = 1;
       +        if(t->sub == nil)
       +                return;
       +
       +        /* push names downward to remove anonymity */
       +        if(t->name && t->sub->name == nil)
       +                t->sub->name = t->name;
       +
       +        dotypedef(t->sub);
       +}
       +
       +static int
       +countbytes(uvlong x)
       +{
       +        int n;
       +
       +        for(n=0; x; n++)
       +                x>>=8;
       +        return n;
       +}
       +
       +static void
       +dorange(Type *t)
       +{
       +        Type *tt;
       +
       +        if(t->ty != Range)
       +                return;
       +        if(t->didrange)
       +                return;
       +        t->didrange = 1;
       +        tt = defer(t->sub);
       +        if(tt == nil)
       +                return;
       +        dorange(tt);
       +        if(t != tt && tt->ty != Base)
       +                return;
       +        t->ty = Base;
       +        t->xsizeof = tt->xsizeof;
       +        if(t->lo == 0)
       +                t->printfmt = 'x';
       +        else
       +                t->printfmt = 'd';
       +        if(t->xsizeof == 0)
       +                t->xsizeof = countbytes(t->hi);
       +}
       +
       +
       +char*
       +nameof(Type *t, int doanon)
       +{
       +        static char buf[1024];
       +        char *p;
       +
       +        if(t->name)
       +                strcpy(buf, fixname(t->name));
       +        else if(t->suename)
       +                snprint(buf, sizeof buf, "%s_%s", t->isunion ? "union" : "struct", t->suename);
       +        else if(doanon)
       +                snprint(buf, sizeof buf, "%s_%lud_", prefix, t->gen);
       +        else
       +                return "";
       +        for(p=buf; *p; p++)
       +                if(isspace(*p))
       +                        *p = '_';
       +        return buf;
       +}
       +
       +static char
       +basecharof(Type *t)        //XXX
       +{
       +        switch(t->xsizeof){
       +        default:
       +                return 'X';
       +        case 1:
       +                return 'b';
       +        case 2:
       +                if(t->printfmt=='d')
       +                        return 'd';
       +                else
       +                        return 'x';
       +        case 4:
       +                if(t->printfmt=='d')
       +                        return 'D';
       +                else if(t->printfmt=='f')
       +                        return 'f';
       +                else
       +                        return 'X';
       +        case 8:
       +                if(t->printfmt=='d')
       +                        return 'V';
       +                else if(t->printfmt=='f')
       +                        return 'F';
       +                else
       +                        return 'Y';
       +        }
       +}
       +
       +static int
       +nilstrcmp(char *a, char *b)
       +{
       +        if(a == b)
       +                return 0;
       +        if(a == nil)
       +                return -1;
       +        if(b == nil)
       +                return 1;
       +        return strcmp(a, b);
       +}
       +
       +static int
       +typecmp(Type *t, Type *u)
       +{
       +        int i;
       +
       +        if(t == u)
       +                return 0;
       +        if(t == nil)
       +                return -1;
       +        if(u == nil)
       +                return 1;
       +
       +        if(t->ty < u->ty)
       +                return -1;
       +        if(t->ty > u->ty)
       +                return 1;
       +
       +        if(t->isunion != u->isunion)
       +                return t->isunion - u->isunion;
       +
       +        i = nilstrcmp(t->name, u->name);
       +        if(i)
       +                return i;
       +
       +        i = nilstrcmp(t->suename, u->suename);
       +        if(i)
       +                return i;
       +
       +        if(t->name || t->suename)
       +                return 0;
       +
       +        if(t->ty==Enum){
       +                if(t->n < u->n)
       +                        return -1;
       +                if(t->n > u->n)
       +                        return 1;
       +                if(t->n == 0)
       +                        return 0;
       +                i = strcmp(t->tname[0], u->tname[0]);
       +                return i;
       +        }
       +        if(t < u)
       +                return -1;
       +        if(t > u)
       +                return 1;
       +        return 0;
       +}
       +
       +static int
       +qtypecmp(const void *va, const void *vb)
       +{
       +        Type *t, *u;
       +
       +        t = *(Type**)va;
       +        u = *(Type**)vb;
       +        return typecmp(t, u);
       +}
       +
       +void
       +printtype(Biobuf *b, Type *t)
       +{
       +        char *name;
       +        int j, nprint;
       +        Type *tt, *ttt;
       +
       +        if(t->printed)
       +                return;
       +        t->printed = 1;
       +        switch(t->ty){
       +        case Aggr:
       +                name = nameof(t, 1);
       +                Bprint(b, "sizeof%s = %lud;\n", name, t->xsizeof);
       +                Bprint(b, "aggr %s {\n", name);
       +                nprint = 0;
       +                for(j=0; j<t->n; j++){
       +                        tt = defer(t->t[j]);
       +                        if(tt && tt->equiv)
       +                                tt = tt->equiv;
       +                        if(tt == nil){
       +                                Bprint(b, "// oops: nil type\n");
       +                                continue;
       +                        }
       +                        switch(tt->ty){
       +                        default:
       +                                Bprint(b, "// oops: unknown type %d for %p/%s (%d,%d; %c,%s; %p)\n",
       +                                        tt->ty, tt, fixname(t->tname[j]),
       +                                        tt->n1, tt->n2, tt->sue ? tt->sue : '.', tt->suename, tt->sub);
       +Bprint(b, "// t->t[j] = %p\n", ttt=t->t[j]);
       +while(ttt){
       +Bprint(b, "// %s %d (%d,%d) sub %p\n", ttt->name, ttt->ty, ttt->n1, ttt->n2, ttt->sub);
       +ttt=ttt->sub;
       +}
       +                        case Base:
       +                        case Pointer:
       +                        case Enum:
       +                        case Array:
       +                        case Function:
       +                                nprint++;
       +                                Bprint(b, "\t'%c' %lud %s;\n", basecharof(tt), t->val[j], fixname(t->tname[j]));
       +                                break;
       +                        case Aggr:
       +                                nprint++;
       +                                Bprint(b, "\t%s %lud %s;\n", nameof(tt, 1), t->val[j], fixname(t->tname[j]));
       +                                break;
       +                        }
       +                }
       +                if(nprint == 0)
       +                        Bprint(b, "\t'X' 0 __dummy;\n");
       +                Bprint(b, "};\n\n");
       +        
       +                name = nameof(t, 1);        /* might have smashed it */
       +                Bprint(b, "defn %s(addr) { indent_%s(addr, \"\"); }\n", name, name);
       +                Bprint(b, "defn\nindent_%s(addr, indent) {\n", name);
       +                Bprint(b, "\tcomplex %s addr;\n", name);
       +                for(j=0; j<t->n; j++){
       +                        name = fixname(t->tname[j]);
       +                        tt = defer(t->t[j]);
       +                        if(tt == nil){
       +                                Bprint(b, "// oops nil %s\n", name);
       +                                continue;
       +                        }
       +                        switch(tt->ty){
       +                        case Base:
       +                        base:
       +                                Bprint(b, "\tprint(indent, \"%s\t\", addr.%s, \"\\n\");\n",
       +                                        name, name);
       +                                break;
       +                        case Pointer:
       +                                ttt = defer(tt->sub);
       +                                if(ttt && ttt->ty == Aggr)
       +                                        Bprint(b, "\tprint(indent, \"%s\t%s(\", addr.%s, \")\\n\");\n",
       +                                                name, nameof(ttt, 1), name);
       +                                else
       +                                        goto base;
       +                                break;
       +                        case Array:
       +                                Bprint(b, "\tprint(indent, \"%s\t\", addr.%s\\X, \"\\n\");\n",
       +                                        name, name);
       +                                break;
       +                        case Enum:
       +                                Bprint(b, "\tprint(indent, \"%s\t\", addr.%s, \" \", %s(addr.%s), \"\\n\");\n",
       +                                        name, name, nameof(tt, 1), name);
       +                                break;
       +                        case Aggr:
       +                                Bprint(b, "\tprint(indent, \"%s\t%s{\\n\");\n",
       +                                        name, nameof(tt, 0));
       +                                Bprint(b, "\tindent_%s(addr+%lud, indent+\"  \");\n",
       +                                        nameof(tt, 1), t->val[j]);
       +                                Bprint(b, "\tprint(indent, \"\t}\\n\");\n");
       +                                break;
       +                        }
       +                }
       +                Bprint(b, "};\n\n");
       +                break;
       +        
       +        case Enum:
       +                name = nameof(t, 1);
       +                Bprint(b, "// enum %s\n", name);
       +                for(j=0; j<t->n; j++)
       +                        Bprint(b, "%s = %ld;\n", fixname(t->tname[j]), t->val[j]);
       +        
       +                Bprint(b, "vals_%s = {\n", name);
       +                for(j=0; j<t->n; j++)
       +                        Bprint(b, "\t%lud,\n", t->val[j]);
       +                Bprint(b, "};\n");
       +                Bprint(b, "names_%s = {\n", name);
       +                for(j=0; j<t->n; j++)
       +                        Bprint(b, "\t\"%s\",\n", fixname(t->tname[j]));
       +                Bprint(b, "};\n");
       +                Bprint(b, "defn\n%s(val) {\n", name);
       +                Bprint(b, "\tlocal i;\n");
       +                Bprint(b, "\ti = match(val, vals_%s);\n", name);
       +                Bprint(b, "\tif i >= 0 then return names_%s[i];\n", name);
       +                Bprint(b, "\treturn \"???\";\n");
       +                Bprint(b, "};\n");
       +                break;
       +        }
       +}
       +
       +void
       +printtypes(Biobuf *b)
       +{
       +        int i, n, nn;
       +        Type *t, *tt, **all;
       +        TypeList *tl;
       +
       +        /* check that pointer resolved */
       +        for(tl=alltypes; tl; tl=tl->tl){
       +                t = tl->hd;
       +                if(t->ty==None){
       +                        if(t->n1 || t->n2)
       +                                warn("type %d,%d referenced but not defined", t->n1, t->n2);
       +                        else if(t->sue && t->suename)
       +                                warn("%s %s referenced but not defined",
       +                                        t->sue=='s' ? "struct" :
       +                                        t->sue=='u' ? "union" :
       +                                        t->sue=='e' ? "enum" : "???", t->suename);
       +                }
       +        }
       +
       +        /* push typedefs down, base types up */
       +        n = 0;
       +        for(tl=alltypes; tl; tl=tl->tl){
       +                n++;
       +                t = tl->hd;
       +                if(t->ty == Typedef || t->ty == Defer)
       +                        dotypedef(t);
       +        }
       +
       +        /* push ranges around */
       +        for(tl=alltypes; tl; tl=tl->tl)
       +                dorange(tl->hd);
       +
       +        /*
       +         * only take one type of a given name; acid is going to do this anyway,
       +         * and this will reduce the amount of code we output considerably.
       +         * we could run a DFA equivalence relaxation sort of algorithm
       +         * to find the actual equivalence classes, and then rename types 
       +         * appropriately, but this will do for now.
       +         */
       +        all = emalloc(n*sizeof(all[0]));
       +        n = 0;
       +        for(tl=alltypes; tl; tl=tl->tl)
       +                all[n++] = tl->hd;
       +
       +        qsort(all, n, sizeof(all[0]), qtypecmp);
       +
       +        nn = 0;
       +        for(i=0; i<n; i++){
       +                if(i==0 || typecmp(all[i-1], all[i]) != 0)
       +                        all[nn++] = all[i];
       +                else
       +                        all[i]->equiv = all[nn-1];
       +        }
       +
       +        for(tl=alltypes; tl; tl=tl->tl){
       +                t = tl->hd;
       +                tt = defer(t);
       +                if(tt && tt->equiv)
       +                        t->equiv = tt->equiv;
       +        }
       +
       +        for(i=0; i<nn; i++)
       +                printtype(b, all[i]);
       +
       +        free(all);
       +}
       +
       +void
       +freetypes(void)
       +{
       +        memset(thash, 0, sizeof(thash));
       +        memset(namehash, 0, sizeof namehash);
       +}
 (DIR) diff --git a/src/cmd/acidtypes/util.c b/src/cmd/acidtypes/util.c
       t@@ -0,0 +1,63 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include <mach.h>
       +#include "dat.h"
       +
       +static int nwarn;
       +
       +void
       +warn(char *fmt, ...)
       +{
       +        va_list arg;
       +
       +        if(++nwarn < 5){
       +                va_start(arg, fmt);
       +                fprint(2, "warning: ");
       +                vfprint(2, fmt, arg);
       +                fprint(2, "\n");
       +                va_end(arg);
       +        }else if(nwarn == 5)
       +                fprint(2, "[additional warnings elided...]\n");
       +}
       +
       +void*
       +erealloc(void *v, uint n)
       +{
       +        v = realloc(v, n);
       +        if(v == nil)
       +                sysfatal("realloc: %r");
       +        return v;
       +}
       +
       +void*
       +emalloc(uint n)
       +{
       +        void *v;
       +
       +        v = mallocz(n, 1);
       +        if(v == nil)
       +                sysfatal("malloc: %r");
       +        return v;
       +}
       +
       +char*
       +estrdup(char *s)
       +{
       +        s = strdup(s);
       +        if(s == nil)
       +                sysfatal("strdup: %r");
       +        return s;
       +}
       +
       +TypeList*
       +mktl(Type *hd, TypeList *tail)
       +{
       +        TypeList *tl;
       +
       +        tl = emalloc(sizeof(*tl));
       +        tl->hd = hd;
       +        tl->tl = tail;
       +        return tl;
       +}
       +