ref: a993e8c13722106027d20e89369be1cc02753083
dir: /cc1/symbol.c/
#include <inttypes.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "../inc/cc.h" #include "../inc/sizes.h" #include "cc1.h" #define NR_SYM_HASH 64 unsigned curctx; static short localcnt; static short globalcnt; static Symbol *head, *labels; static Symbol *htab[NR_SYM_HASH]; #ifndef NDEBUG void dumpstab(char *msg) { Symbol **bp, *sym; fprintf(stderr, "Symbol Table dump at ctx=%u\n%s\n", curctx, msg); for (bp = htab; bp < &htab[NR_SYM_HASH]; ++bp) { if (*bp == NULL) continue; fprintf(stderr, "%d", (int) (bp - htab)); for (sym = *bp; sym; sym = sym->hash) fprintf(stderr, "->[%d,%d:%s]", sym->ns, sym->ctx, sym->name); putc('\n', stderr); } fputs("head:", stderr); for (sym = head; sym; sym = sym->next) { fprintf(stderr, "->[%d,%d:'%s']", sym->ns, sym->ctx, (sym->name) ? sym->name : ""); } putc('\n', stderr); } #endif static unsigned hash(const char *s) { unsigned c, h; for (h = 0; c = *s; ++s) h ^= 33 * c; return h & NR_SYM_HASH-1; } static Symbol * linkhash(Symbol *sym, char *name) { Symbol **h, *p, *prev; sym->name = xstrdup(name); h = &htab[hash(name)]; for (prev = p = *h; p; prev = p, p = p->hash) { if (p->ctx <= sym->ctx) break; } if (p == prev) { sym->hash = *h; *h = sym; } else { p = prev->hash; prev->hash = sym; sym->hash = p; } return sym; } static void unlinkhash(Symbol *sym) { Symbol **h, *p, *prev; h = &htab[hash(sym->name)]; for (prev = p = *h; p != sym; prev = p, p = p->hash) /* nothing */; if (prev == p) *h = sym->hash; else prev->hash = sym->hash; } void pushctx(void) { if (++curctx == NR_BLOCK+1) error("too much nested blocks"); } void popctx(void) { Symbol *next, *sym; short f; if (--curctx == GLOBALCTX) { localcnt = 0; for (sym = labels; sym; sym = next) { next = sym->next; if ((f & (ISUSED|ISDECLARED)) == ISDECLARED) warn("'%s' defined but not used", sym->name); if ((sym->flags & ISDECLARED) == 0) printerr("label '%s' is not defined", sym->name); free(sym->name); free(sym); } labels = NULL; } for (sym = head; sym && sym->ctx > curctx; sym = next) { next = sym->next; if (sym->ns == NS_TAG) sym->type->defined = 0; if (sym->name) { f = sym->flags; unlinkhash(sym); if ((f & (ISUSED|ISGLOBAL|ISDECLARED)) == ISDECLARED) warn("'%s' defined but not used", sym->name); } free(sym->name); if (sym->flags & ISSTRING) free(sym->u.s); free(sym); } head = sym; } Type * duptype(Type *base) { Type *tp = xmalloc(sizeof(*tp)); *tp = *base; tp->id = (curctx) ? ++localcnt : ++globalcnt; return tp; } Symbol * newsym(unsigned ns) { Symbol *sym, *p, *prev; sym = malloc(sizeof(*sym)); sym->id = 0; sym->ns = ns; sym->ctx = (ns == NS_CPP) ? UCHAR_MAX : curctx; sym->token = IDEN; sym->flags = ISDECLARED; sym->u.s = sym->name = NULL; sym->type = NULL; sym->next = sym->hash = NULL; if (ns == NS_CPP) return sym; if (ns == NS_LABEL) { sym->next = labels; sym->id = ++localcnt; return labels = sym; } for (prev = p = head; p; prev = p, p = p->next) { if (p->ctx <= sym->ctx) break; } if (p == prev) { sym->next = head; head = sym; } else { p = prev->next; prev->next = sym; sym->next = p; } return sym; } Symbol * lookup(unsigned ns) { Symbol *sym, **h; unsigned sns; char *t, c; h = &htab[hash(yytext)]; c = *yytext; for (sym = *h; sym; sym = sym->hash) { t = sym->name; if (*t != c || strcmp(t, yytext)) continue; sns = sym->ns; if (sns == NS_KEYWORD || sns == NS_CPP) return sym; if (sns != ns) continue; return sym; } sym = linkhash(newsym(ns), yytext); sym->flags &= ~ISDECLARED; return sym; } void delmacro(Symbol *sym) { unlinkhash(sym); free(sym->name); free(sym->u.s); free(sym); } Symbol * nextsym(Symbol *sym, unsigned ns) { char *s, *t, c; Symbol *new, *p; /* * This function is only called when a macro with parameters * is called without them. * #define x(y) ((y) + 1) * int x = x(y); */ s = sym->name; c = *s; for (p = sym->hash; p; p = p->hash) { t = p->name; if (c == *t && !strcmp(s, t)) return sym; } new = linkhash(newsym(ns), s); new->flags &= ~ISDECLARED; return new; } Symbol * install(unsigned ns, Symbol *sym) { if (sym->ctx == curctx) { if (sym->flags & ISDECLARED) { if (ns == sym->ns) return NULL; } else { sym->flags |= ISDECLARED; sym->ns = ns; goto assign_id; } } sym = linkhash(newsym(ns), sym->name); assign_id: if (sym->ns != NS_CPP || sym->ns != NS_LABEL) sym->id = (curctx) ? ++localcnt : ++globalcnt; return sym; } void ikeywords(void) { static struct { char *str; unsigned char token, value; } *bp, keywords[] = { {"auto", SCLASS, AUTO}, {"break", BREAK, BREAK}, {"_Bool", TYPE, BOOL}, {"case", CASE, CASE}, {"char", TYPE, CHAR}, {"const", TQUALIFIER, CONST}, {"continue", CONTINUE, CONTINUE}, {"default", DEFAULT, DEFAULT}, {"do", DO, DO}, {"double", TYPE, DOUBLE}, {"else", ELSE, ELSE}, {"enum", TYPE, ENUM}, {"extern", SCLASS, EXTERN}, {"float", TYPE, FLOAT}, {"for", FOR, FOR}, {"goto", GOTO, GOTO}, {"if", IF, IF}, {"int", TYPE, INT}, {"long", TYPE, LONG}, {"register", SCLASS, REGISTER}, {"restrict", TQUALIFIER, RESTRICT}, {"return", RETURN, RETURN}, {"short", TYPE, SHORT}, {"signed", TYPE, SIGNED}, {"sizeof", SIZEOF, SIZEOF}, {"static", SCLASS, STATIC}, {"struct", TYPE, STRUCT}, {"switch", SWITCH, SWITCH}, {"typedef", SCLASS, TYPEDEF}, {"union", TYPE, UNION}, {"unsigned", TYPE, UNSIGNED}, {"void", TYPE, VOID}, {"volatile", TQUALIFIER, VOLATILE}, {"while", WHILE, WHILE}, {NULL, 0, 0}, }, cppclauses[] = { {"define", DEFINE, DEFINE}, {"include", INCLUDE, INCLUDE}, {"line", LINE, LINE}, {"ifdef", IFDEF, IFDEF}, {"if", IF, IF}, {"elif", ELIF, ELIF}, {"else", ELSE, ELSE}, {"ifndef", IFNDEF, IFNDEF}, {"endif", ENDIF, ENDIF}, {"undef", UNDEF, UNDEF}, {"pragma", PRAGMA, PRAGMA}, {"error", ERROR, ERROR}, {NULL, 0, 0} }, *list[] = { keywords, cppclauses, NULL }, **lp; Symbol *sym; int ns = NS_KEYWORD; for (lp = list; *lp; ++lp) { for (bp = *lp; bp->str; ++bp) { strcpy(yytext, bp->str); sym = lookup(ns); sym->token = bp->token; sym->u.token = bp->value; } ns = NS_CPPCLAUSES; } /* * Remove all the predefined symbols from * the symbol list. It * will make faster someoperations. There is no problem of memory * leakeage because this memory is not ever freed */ head = NULL; }