| #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", |
| "var", "$var", |
| "whatis", "$whatis", |
| "while", "$while", |
| |
| /* register names! */ |
| /* generic */ |
| "PC", "$PC", |
| "SP", "$SP", |
| "LR", "$LR", |
| "R0", "$R0", |
| "R1", "$R1", |
| "R2", "$R2", |
| "R3", "$R3", |
| "R4", "$R4", |
| "R5", "$R5", |
| "R6", "$R6", |
| "R7", "$R7", |
| "R8", "$R8", |
| "R9", "$R9", |
| "R10", "$R10", |
| "R11", "$R11", |
| "R12", "$R12", |
| "R13", "$R13", |
| "R14", "$R14", |
| "R15", "$R15", |
| "R16", "$R16", |
| "R17", "$R17", |
| "R18", "$R18", |
| "R19", "$R19", |
| "R20", "$R20", |
| "R21", "$R21", |
| "R22", "$R22", |
| "R23", "$R23", |
| "R24", "$R24", |
| "R25", "$R25", |
| "R26", "$R26", |
| "R27", "$R27", |
| "R28", "$R28", |
| "R29", "$R29", |
| "R30", "$R30", |
| "R31", "$R31", |
| "E0", "$E0", |
| "E1", "$E1", |
| "E2", "$E2", |
| "E3", "$E3", |
| "E4", "$E4", |
| "E5", "$E5", |
| "E6", "$E6", |
| "F0", "$F0", |
| "F1", "$F1", |
| "F2", "$F2", |
| "F3", "$F3", |
| "F4", "$F4", |
| "F5", "$F5", |
| "F6", "$F6", |
| "F7", "$F7", |
| "F8", "$F8", |
| "F9", "$F9", |
| "F10", "$F10", |
| "F11", "$F11", |
| "F12", "$F12", |
| "F13", "$F13", |
| "F14", "$F14", |
| "F15", "$F15", |
| "F16", "$F16", |
| "F17", "$F17", |
| "F18", "$F18", |
| "F19", "$F19", |
| "F20", "$F20", |
| "F21", "$F21", |
| "F22", "$F22", |
| "F23", "$F23", |
| "F24", "$F24", |
| "F25", "$F25", |
| "F26", "$F26", |
| "F27", "$F27", |
| "F28", "$F28", |
| "F29", "$F29", |
| "F30", "$F30", |
| "F31", "$F31", |
| |
| /* 386 */ |
| "DI", "$DI", |
| "SI", "$SI", |
| "BP", "$BP", |
| "BX", "$BX", |
| "DX", "$DX", |
| "CX", "$CX", |
| "AX", "$AX", |
| "GS", "$GS", |
| "FS", "$FS", |
| "ES", "$ES", |
| "DS", "$DS", |
| "TRAP", "$TRAP", |
| "ECODE", "$ECODE", |
| "CS", "$CS", |
| "EFLAGS", "$EFLAGS", |
| "SS", "$SS", |
| |
| /* power */ |
| "CAUSE", "$CAUSE", |
| "SRR1", "$SRR1", |
| "CR", "$CR", |
| "XER", "$XER", |
| "CTR", "$CTR", |
| "VRSAVE", "$VRSAVE", |
| "FPSCR", "$FPSCR", |
| }; |
| |
| char* |
| nonempty(char *name) |
| { |
| if(name[0] == '\0') |
| return "__empty__name__"; |
| return name; |
| } |
| |
| char* |
| cleanstl(char *name) |
| { |
| char *b, *p; |
| static char buf[65536]; /* These can be huge. */ |
| |
| if(strchr(name, '<') == nil) |
| return nonempty(name); |
| |
| b = buf; |
| for(p = name; *p != 0; p++){ |
| switch(*p){ |
| case '<': |
| strcpy(b, "_L_"); |
| b += 3; |
| break; |
| case '>': |
| strcpy(b, "_R_"); |
| b += 3; |
| break; |
| case '*': |
| strcpy(b, "_A_"); |
| b += 3; |
| break; |
| case ',': |
| strcpy(b, "_C_"); |
| b += 3; |
| break; |
| case '.': |
| strcpy(b, "_D_"); |
| b += 3; |
| break; |
| default: |
| *b++ = *p; |
| break; |
| } |
| } |
| *b = 0; |
| return buf; |
| } |
| |
| char* |
| fixname(char *name) |
| { |
| int i; |
| char *s; |
| static int nbuf; |
| static char buf[8][65536]; |
| |
| if(name == nil) |
| return nil; |
| s = demangle(name, buf[nbuf], 1); |
| if(s != name){ |
| if(++nbuf == nelem(buf)) |
| nbuf = 0; |
| name = s; |
| } |
| for(i=0; i<nelem(fixes); i++) |
| if(name[0]==fixes[i].old[0] && strcmp(name, fixes[i].old)==0) |
| return nonempty(fixes[i].new); |
| return nonempty(name); |
| } |
| |
| void |
| denumber(void) |
| { |
| memset(thash, 0, sizeof thash); |
| memset(namehash, 0, sizeof namehash); |
| } |
| |
| void |
| renumber(TypeList *tl, uint n1) |
| { |
| int n; |
| Type *t, *tt; |
| |
| for(; tl; tl=tl->tl){ |
| t = tl->hd; |
| tt = typebynum(n1, t->n2); |
| *tt = *t; |
| tt->n1 = n1; |
| if(tt->n){ |
| n = (tt->n+31)&~31; |
| if(tt->tname){ |
| tt->tname = emalloc(n*sizeof tt->tname[0]); |
| memmove(tt->tname, t->tname, n*sizeof tt->tname[0]); |
| } |
| if(tt->val){ |
| tt->val = emalloc(n*sizeof tt->val[0]); |
| memmove(tt->val, t->val, n*sizeof tt->val[0]); |
| } |
| if(tt->t){ |
| tt->t = emalloc(n*sizeof tt->t[0]); |
| memmove(tt->t, t->t, n*sizeof tt->t[0]); |
| } |
| } |
| addhash(tt); |
| } |
| } |
| |
| Type* |
| defer(Type *t) |
| { |
| Type *u, *oldt; |
| int n; |
| |
| if(t == nil) |
| return nil; |
| |
| /* XXX rob has return t; here */ |
| 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; |
| } |
| if(oldt != t) |
| oldt->sub = t; |
| 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* |
| mkname(char *prefix, char *name) |
| { |
| static char buf[65536]; |
| |
| snprint(buf, sizeof buf, "%s%s", prefix, name); |
| return buf; |
| } |
| |
| char* |
| nameof(Type *t, int doanon) |
| { |
| static char buf[65536]; |
| 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((uchar)*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); |
| } |
| |
| int careaboutaggrcount; |
| |
| 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(careaboutaggrcount && t->ty == Aggr){ |
| if(t->n > u->n) |
| return -1; |
| if(t->n < u->n) |
| return 1; |
| } |
| |
| 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, "%B = %lud;\n", mkname("sizeof", name), t->xsizeof); |
| Bprint(b, "aggr %B {\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); |
| if(0){ |
| 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 %B;\n", basecharof(tt), t->val[j], fixname(t->tname[j])); |
| break; |
| case Aggr: |
| nprint++; |
| Bprint(b, "\t%B %lud %B;\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 %B(addr) { %B(addr, \"\"); }\n", name, mkname("indent_", name)); |
| Bprint(b, "defn %B(addr, indent) {\n", mkname("indent_", name)); |
| Bprint(b, "\tcomplex %B 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.%B, \"\\n\");\n", |
| name, name); |
| break; |
| case Pointer: |
| ttt = defer(tt->sub); |
| if(ttt && ttt->ty == Aggr) |
| Bprint(b, "\tprint(indent, \"%s\t(%s)\", addr.%B, \"\\n\");\n", |
| name, nameof(ttt, 1), name); |
| else |
| goto base; |
| break; |
| case Array: |
| Bprint(b, "\tprint(indent, \"%s\t\", addr.%B\\X, \"\\n\");\n", |
| name, name); |
| break; |
| case Enum: |
| Bprint(b, "\tprint(indent, \"%s\t\", addr.%B, \" \", %B(addr.%B), \"\\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, "\t%B(addr+%lud, indent+\" \");\n", |
| mkname("indent_", nameof(tt, 1)), t->val[j]); |
| Bprint(b, "\tprint(indent, \"}\\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, "%B = %ld;\n", fixname(t->tname[j]), t->val[j]); |
| |
| Bprint(b, "%B = {\n", mkname("vals_", name)); |
| for(j=0; j<t->n; j++) |
| Bprint(b, "\t%lud,\n", t->val[j]); |
| Bprint(b, "};\n"); |
| Bprint(b, "%B = {\n", mkname("names_", name)); |
| for(j=0; j<t->n; j++) |
| Bprint(b, "\t\"%s\",\n", fixname(t->tname[j])); |
| Bprint(b, "};\n"); |
| Bprint(b, "defn %B(val) {\n", name); |
| Bprint(b, "\tlocal i;\n"); |
| Bprint(b, "\ti = match(val, %B);\n", mkname("vals_", name)); |
| Bprint(b, "\tif i >= 0 then return %B[i];\n", mkname("names_", 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 - %p", t->n1, t->n2, t); |
| 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; |
| |
| careaboutaggrcount = 1; |
| qsort(all, n, sizeof(all[0]), qtypecmp); |
| careaboutaggrcount = 0; |
| |
| 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); |
| } |