| #include "c.h" |
| #include <stdio.h> |
| |
| static char rcsid[] = "$Id: sym.c 355 2007-02-18 22:08:49Z drh $"; |
| |
| #define equalp(x) v.x == p->sym.u.c.v.x |
| |
| struct table { |
| int level; |
| Table previous; |
| struct entry { |
| struct symbol sym; |
| struct entry *link; |
| } *buckets[256]; |
| Symbol all; |
| }; |
| #define HASHSIZE NELEMS(((Table)0)->buckets) |
| static struct table |
| cns = { CONSTANTS }, |
| ext = { GLOBAL }, |
| ids = { GLOBAL }, |
| tys = { GLOBAL }; |
| Table constants = &cns; |
| Table externals = &ext; |
| Table identifiers = &ids; |
| Table globals = &ids; |
| Table types = &tys; |
| Table labels; |
| int level = GLOBAL; |
| static int tempid; |
| List loci, symbols; |
| |
| Table newtable(int arena) { |
| Table new; |
| |
| NEW0(new, arena); |
| return new; |
| } |
| |
| Table table(Table tp, int level) { |
| Table new = newtable(FUNC); |
| new->previous = tp; |
| new->level = level; |
| if (tp) |
| new->all = tp->all; |
| return new; |
| } |
| void foreach(Table tp, int lev, void (*apply)(Symbol, void *), void *cl) { |
| assert(tp); |
| while (tp && tp->level > lev) |
| tp = tp->previous; |
| if (tp && tp->level == lev) { |
| Symbol p; |
| Coordinate sav; |
| sav = src; |
| for (p = tp->all; p && p->scope == lev; p = p->up) { |
| src = p->src; |
| (*apply)(p, cl); |
| } |
| src = sav; |
| } |
| } |
| void enterscope(void) { |
| if (++level == LOCAL) |
| tempid = 0; |
| } |
| void exitscope(void) { |
| rmtypes(level); |
| if (types->level == level) |
| types = types->previous; |
| if (identifiers->level == level) { |
| if (Aflag >= 2) { |
| int n = 0; |
| Symbol p; |
| for (p = identifiers->all; p && p->scope == level; p = p->up) |
| if (++n > 127) { |
| warning("more than 127 identifiers declared in a block\n"); |
| break; |
| } |
| } |
| identifiers = identifiers->previous; |
| } |
| assert(level >= GLOBAL); |
| --level; |
| } |
| Symbol install(const char *name, Table *tpp, int level, int arena) { |
| Table tp = *tpp; |
| struct entry *p; |
| unsigned h = (unsigned long)name&(HASHSIZE-1); |
| |
| assert(level == 0 || level >= tp->level); |
| if (level > 0 && tp->level < level) |
| tp = *tpp = table(tp, level); |
| NEW0(p, arena); |
| p->sym.name = (char *)name; |
| p->sym.scope = level; |
| p->sym.up = tp->all; |
| tp->all = &p->sym; |
| p->link = tp->buckets[h]; |
| tp->buckets[h] = p; |
| return &p->sym; |
| } |
| Symbol relocate(const char *name, Table src, Table dst) { |
| struct entry *p, **q; |
| Symbol *r; |
| unsigned h = (unsigned long)name&(HASHSIZE-1); |
| |
| for (q = &src->buckets[h]; *q; q = &(*q)->link) |
| if (name == (*q)->sym.name) |
| break; |
| assert(*q); |
| /* |
| Remove the entry from src's hash chain |
| and from its list of all symbols. |
| */ |
| p = *q; |
| *q = (*q)->link; |
| for (r = &src->all; *r && *r != &p->sym; r = &(*r)->up) |
| ; |
| assert(*r == &p->sym); |
| *r = p->sym.up; |
| /* |
| Insert the entry into dst's hash chain |
| and into its list of all symbols. |
| Return the symbol-table entry. |
| */ |
| p->link = dst->buckets[h]; |
| dst->buckets[h] = p; |
| p->sym.up = dst->all; |
| dst->all = &p->sym; |
| return &p->sym; |
| } |
| Symbol lookup(const char *name, Table tp) { |
| struct entry *p; |
| unsigned h = (unsigned long)name&(HASHSIZE-1); |
| |
| assert(tp); |
| do |
| for (p = tp->buckets[h]; p; p = p->link) |
| if (name == p->sym.name) |
| return &p->sym; |
| while ((tp = tp->previous) != NULL); |
| return NULL; |
| } |
| int genlabel(int n) { |
| static int label = 1; |
| |
| label += n; |
| return label - n; |
| } |
| Symbol findlabel(int lab) { |
| struct entry *p; |
| unsigned h = lab&(HASHSIZE-1); |
| |
| for (p = labels->buckets[h]; p; p = p->link) |
| if (lab == p->sym.u.l.label) |
| return &p->sym; |
| NEW0(p, FUNC); |
| p->sym.name = stringd(lab); |
| p->sym.scope = LABELS; |
| p->sym.up = labels->all; |
| labels->all = &p->sym; |
| p->link = labels->buckets[h]; |
| labels->buckets[h] = p; |
| p->sym.generated = 1; |
| p->sym.u.l.label = lab; |
| (*IR->defsymbol)(&p->sym); |
| return &p->sym; |
| } |
| Symbol constant(Type ty, Value v) { |
| struct entry *p; |
| unsigned h = v.u&(HASHSIZE-1); |
| static union { int x; char endian; } little = { 1 }; |
| |
| ty = unqual(ty); |
| for (p = constants->buckets[h]; p; p = p->link) |
| if (eqtype(ty, p->sym.type, 1)) |
| switch (ty->op) { |
| case INT: if (equalp(i)) return &p->sym; break; |
| case UNSIGNED: if (equalp(u)) return &p->sym; break; |
| case FLOAT: |
| if (v.d == 0.0) { |
| float z1 = v.d, z2 = p->sym.u.c.v.d; |
| char *b1 = (char *)&z1, *b2 = (char *)&z2; |
| if (z1 == z2 |
| && (!little.endian && b1[0] == b2[0] |
| || little.endian && b1[sizeof (z1)-1] == b2[sizeof (z2)-1])) |
| return &p->sym; |
| } else if (equalp(d)) |
| return &p->sym; |
| break; |
| case FUNCTION: if (equalp(g)) return &p->sym; break; |
| case ARRAY: |
| case POINTER: if (equalp(p)) return &p->sym; break; |
| default: assert(0); |
| } |
| NEW0(p, PERM); |
| p->sym.name = vtoa(ty, v); |
| p->sym.scope = CONSTANTS; |
| p->sym.type = ty; |
| p->sym.sclass = STATIC; |
| p->sym.u.c.v = v; |
| p->link = constants->buckets[h]; |
| p->sym.up = constants->all; |
| constants->all = &p->sym; |
| constants->buckets[h] = p; |
| if (ty->u.sym && !ty->u.sym->addressed) |
| (*IR->defsymbol)(&p->sym); |
| p->sym.defined = 1; |
| return &p->sym; |
| } |
| Symbol intconst(int n) { |
| Value v; |
| |
| v.i = n; |
| return constant(inttype, v); |
| } |
| Symbol genident(int scls, Type ty, int lev) { |
| Symbol p; |
| |
| NEW0(p, lev >= LOCAL ? FUNC : PERM); |
| p->name = stringd(genlabel(1)); |
| p->scope = lev; |
| p->sclass = scls; |
| p->type = ty; |
| p->generated = 1; |
| if (lev == GLOBAL) |
| (*IR->defsymbol)(p); |
| return p; |
| } |
| |
| Symbol temporary(int scls, Type ty) { |
| Symbol p; |
| |
| NEW0(p, FUNC); |
| p->name = stringd(++tempid); |
| p->scope = level < LOCAL ? LOCAL : level; |
| p->sclass = scls; |
| p->type = ty; |
| p->temporary = 1; |
| p->generated = 1; |
| return p; |
| } |
| Symbol newtemp(int sclass, int tc, int size) { |
| Symbol p = temporary(sclass, btot(tc, size)); |
| |
| (*IR->local)(p); |
| p->defined = 1; |
| return p; |
| } |
| |
| Symbol allsymbols(Table tp) { |
| return tp->all; |
| } |
| |
| void locus(Table tp, Coordinate *cp) { |
| loci = append(cp, loci); |
| symbols = append(allsymbols(tp), symbols); |
| } |
| |
| void use(Symbol p, Coordinate src) { |
| Coordinate *cp; |
| |
| NEW(cp, PERM); |
| *cp = src; |
| p->uses = append(cp, p->uses); |
| } |
| /* findtype - find type ty in identifiers */ |
| Symbol findtype(Type ty) { |
| Table tp = identifiers; |
| int i; |
| struct entry *p; |
| |
| assert(tp); |
| do |
| for (i = 0; i < HASHSIZE; i++) |
| for (p = tp->buckets[i]; p; p = p->link) |
| if (p->sym.type == ty && p->sym.sclass == TYPEDEF) |
| return &p->sym; |
| while ((tp = tp->previous) != NULL); |
| return NULL; |
| } |
| |
| /* mkstr - make a string constant */ |
| Symbol mkstr(char *str) { |
| Value v; |
| Symbol p; |
| |
| v.p = str; |
| p = constant(array(chartype, strlen(v.p) + 1, 0), v); |
| if (p->u.c.loc == NULL) |
| p->u.c.loc = genident(STATIC, p->type, GLOBAL); |
| return p; |
| } |
| |
| /* mksymbol - make a symbol for name, install in &globals if sclass==EXTERN */ |
| Symbol mksymbol(int sclass, const char *name, Type ty) { |
| Symbol p; |
| |
| if (sclass == EXTERN) |
| p = install(string(name), &globals, GLOBAL, PERM); |
| else { |
| NEW0(p, PERM); |
| p->name = string(name); |
| p->scope = GLOBAL; |
| } |
| p->sclass = sclass; |
| p->type = ty; |
| (*IR->defsymbol)(p); |
| p->defined = 1; |
| return p; |
| } |
| |
| /* vtoa - return string for the constant v of type ty */ |
| char *vtoa(Type ty, Value v) { |
| char buf[50]; |
| |
| ty = unqual(ty); |
| switch (ty->op) { |
| case INT: return stringd(v.i); |
| case UNSIGNED: return stringf((v.u&~0x7FFF) ? "0x%X" : "%U", v.u); |
| case FLOAT: return stringf("%g", (double)v.d); |
| case ARRAY: |
| if (ty->type == chartype || ty->type == signedchar |
| || ty->type == unsignedchar) |
| return v.p; |
| return stringf("%p", v.p); |
| case POINTER: return stringf("%p", v.p); |
| case FUNCTION: return stringf("%p", v.g); |
| } |
| assert(0); return NULL; |
| } |