1#include <assert.h>2#include <limits.h>3#include <stdio.h>4#include <stdlib.h>5#include <string.h>67#include <scc/cstd.h>8#include <scc/scc.h>9#include "cc1.h"1011#define NR_SYM_HASH 6412#define NR_CPP_HASH 3213#define NR_LBL_HASH 161415struct keyword {16 char *str;17 unsigned char token, value;18};1920unsigned curctx;21static unsigned short counterid;2223static Symbol *head, *labels;24static Symbol *htab[NR_SYM_HASH];25static Symbol *htabcpp[NR_CPP_HASH];26static Symbol *htablbl[NR_LBL_HASH];2728#ifndef NDEBUG29void30dumpstab(Symbol **tbl, char *msg)31{32 Symbol **bp, *sym;33 unsigned size;3435 fprintf(stderr, "Symbol Table dump at ctx=%u\n%s\n", curctx, msg);36 if (tbl == htab)37 size = NR_SYM_HASH;38 else if (tbl == htabcpp)39 size = NR_CPP_HASH;40 else if (tbl == htablbl)41 size = NR_LBL_HASH;42 else43 abort();4445 for (bp = tbl; bp < &tbl[size]; ++bp) {46 if (*bp == NULL)47 continue;48 fprintf(stderr, "%d", (int) (bp - htab));49 for (sym = *bp; sym; sym = sym->hash)50 fprintf(stderr, "->[%d,%d:'%s'=%p]",51 sym->ns, sym->ctx, sym->name, (void *) sym);52 putc('\n', stderr);53 }54 fputs("head:", stderr);55 for (sym = head; sym; sym = sym->next) {56 fprintf(stderr, "->[%d,%d:'%s'=%p]",57 sym->ns, sym->ctx,58 (sym->name) ? sym->name : "", (void *) sym);59 }60 fputs("\nlabels:", stderr);61 for (sym = labels; sym; sym = sym->next) {62 fprintf(stderr, "->[%d,%d:'%s'=%p]",63 sym->ns, sym->ctx,64 (sym->name) ? sym->name : "", (void *) sym);65 }66 putc('\n', stderr);67}68#endif6970static Symbol **71hash(char *s, int ns)72{73 unsigned h, size;74 Symbol **tab;7576 h = genhash(s);7778 switch (ns) {79 case NS_CPP:80 tab = htabcpp;81 size = NR_CPP_HASH-1;82 break;83 case NS_LABEL:84 tab = htablbl;85 size = NR_LBL_HASH-1;86 break;87 default:88 tab = htab;89 size = NR_SYM_HASH-1;90 break;91 }92 return &tab[h & size];93}9495static void96unlinkhash(Symbol *sym)97{98 Symbol **h;99100 if ((sym->flags & SDECLARED) == 0)101 return;102 h = hash(sym->name, sym->ns);103 assert(sym->ns == NS_CPP || *h == sym);104 while (*h != sym)105 h = &(*h)->hash;106 *h = sym->hash;107}108109void110pushctx(void)111{112 DBG("SYM: pushed context %d", curctx+1);113 if (++curctx == NR_BLOCK+1)114 error("too many nested blocks");115}116117void118killsym(Symbol *sym)119{120 short f;121 char *name;122123 if (!sym)124 return;125 f = sym->flags;126 if (f & SSTRING)127 free(sym->u.s);128 if (sym->ns == NS_TAG)129 sym->type->prop &= ~TDEFINED;130 unlinkhash(sym);131 if ((name = sym->name) != NULL) {132 switch (sym->ns) {133 case NS_LABEL:134 if ((f & SDEFINED) == 0)135 errorp("label '%s' is not defined", name);136 case NS_IDEN:137 if ((f & (SUSED|SGLOBAL|SDECLARED)) == SDECLARED)138 warn("'%s' defined but not used", name);139 break;140 }141 }142 free(name);143 free(sym);144}145146void147popctx(void)148{149 Symbol *next, *sym;150 int ns, dangling = 0;151152 DBG("SYM: popped context %d", curctx);153 /*154 * we have to be careful before popping the current155 * context, because since the parser is one token156 * ahead it may already have read an identifier at157 * this point, and yylval.sym is a pointer to158 * the symbol associated to such token. If that159 * symbol is from the context that we are popping160 * then we are going to generate a dangling pointer.161 * We can detect this situation and call again to162 * lookup.163 */164 if ((yytoken == IDEN || yytoken == TYPEIDEN) &&165 yylval.sym->ctx == curctx) {166 ns = yylval.sym->ns;167 dangling = 1;168 }169170 for (sym = head; sym && sym->ctx == curctx; sym = next) {171 /*172 * Since we are unlinking them in the inverse order173 * we do know that sym is always the head of the174 * collision list175 */176 next = sym->next;177 killsym(sym);178 }179 head = sym;180181 if (--curctx == GLOBALCTX) {182 for (sym = labels; sym; sym = next) {183 next = sym->next;184 killsym(sym);185 }186 labels = NULL;187 }188189 if (dangling) {190 yylval.sym = lookup(ns, yytext, ALLOC);191 yytoken = yylval.sym->token;192 }193}194195unsigned196newid(void)197{198 unsigned short id;199200 if (lexmode == CPPMODE)201 return 0;202 id = ++counterid;203 if (id == 0) {204 die("cc1: overflow in %s identifiers",205 (curctx) ? "internal" : "external");206 }207 return id;208}209210Symbol *211newsym(int ns, char *name)212{213 Symbol *sym;214215 sym = xmalloc(sizeof(*sym));216 if (name)217 name = xstrdup(name);218 sym->name = name;219 sym->id = 0;220 sym->hide = 0;221 sym->ns = ns;222 sym->ctx = curctx;223 sym->token = IDEN;224 sym->flags = 0;225 sym->u.s = NULL;226 sym->type = NULL;227 sym->hash = NULL;228229 if (ns == NS_LABEL) {230 sym->next = labels;231 labels = sym;232 } else if (ns != NS_CPP) {233 sym->next = head;234 head = sym;235 }236 return sym;237}238239static Symbol *240linkhash(Symbol *sym)241{242 Symbol **h;243244 h = hash(sym->name, sym->ns);245 sym->hash = *h;246 *h = sym;247248 if (sym->ns != NS_CPP)249 sym->id = newid();250 sym->flags |= SDECLARED;251 return sym;252}253254Symbol *255newrstring(Rune *rs, size_t len)256{257 Symbol *sym = newsym(NS_IDEN, NULL);258259 if (lexmode != CPPMODE)260 sym->type = mktype(wchartype, ARY, len, NULL);261 sym->id = newid();262 sym->flags |= SRSTRING | SCONSTANT | SPRIVATE;263 sym->u.rs = xcalloc(len, sizeof(Rune));264 if (rs)265 memcpy(sym->u.rs, rs, len * sizeof(Rune));266267 return sym;268}269270Symbol *271newstring(char *s, size_t len)272{273 Symbol *sym = newsym(NS_IDEN, NULL);274275 if (lexmode != CPPMODE)276 sym->type = mktype(chartype, ARY, len, NULL);277 sym->id = newid();278 sym->flags |= SSTRING | SCONSTANT | SPRIVATE;279 sym->u.s = xmalloc(len);280 if (s)281 memcpy(sym->u.s, s, len);282283 return sym;284}285286Symbol *287newlabel(void)288{289 Symbol *sym = newsym(NS_LABEL, NULL);290 sym->id = newid();291 return sym;292}293294Symbol *295lookup(int ns, char *name, int alloc)296{297 Symbol *sym;298 int sns, c;299 char *t;300301 c = *name;302 for (sym = *hash(name, ns); sym; sym = sym->hash) {303 t = sym->name;304 if (*t != c || strcmp(t, name))305 continue;306 sns = sym->ns;307 if (sns == ns)308 return sym;309 /*310 * When a lookup is done in a namespace associated311 * to a struct we also want symbols of NS_IDEN which312 * are typedef, because in other case we cannot declare313 * fields of such types.314 */315 if (sns == NS_KEYWORD && ns != NS_MACROPAR && ns != NS_CPP ||316 (sym->flags & STYPEDEF) && ns >= NS_STRUCTS) {317 return sym;318 }319 }320 return (alloc == ALLOC) ? newsym(ns, name) : NULL;321}322323Symbol *324install(int ns, Symbol *sym)325{326 if (sym->flags & SDECLARED || sym->ctx != curctx) {327 if (sym->ctx == curctx && ns == sym->ns)328 return NULL;329 sym = newsym(ns, sym->name);330 }331 return linkhash(sym);332}333334void335keywords(struct keyword *key, int ns)336{337 Symbol *sym;338339 for ( ; key->str; ++key) {340 sym = linkhash(newsym(ns, key->str));341 sym->token = key->token;342 sym->u.token = key->value;343 }344}345346void347builtins(struct builtin *built)348{349 Symbol *sym;350 struct builtin *bp;351352 for (bp = built; bp->str; ++bp) {353 sym = linkhash(newsym(NS_KEYWORD, bp->str));354 sym->token = BUILTIN;355 sym->u.fun = bp->fun;356 }357}358359void360isyms(void)361{362 static struct keyword cppoper[] = {363 {"defined", DEFINED, DEFINED},364 {NULL, 0, 0}365 };366 static struct keyword cppkeys[] = {367 {"define", DEFINE, DEFINE},368 {"include", INCLUDE, INCLUDE},369 {"line", LINE, LINE},370 {"ifdef", IFDEF, IFDEF},371 {"if", IF, IF},372 {"elif", ELIF, ELIF},373 {"else", ELSE, ELSE},374 {"ifndef", IFNDEF, IFNDEF},375 {"endif", ENDIF, ENDIF},376 {"undef", UNDEF, UNDEF},377 {"pragma", PRAGMA, PRAGMA},378 {"error", ERROR, ERROR},379 {NULL, 0, 0}380 };381 static struct keyword lexkeys[] = {382 {"auto", SCLASS, AUTO},383 {"break", BREAK, BREAK},384 {"_Bool", TYPE, BOOL},385 {"__builtin_va_list", TYPE, VA_LIST},386 {"case", CASE, CASE},387 {"char", TYPE, CHAR},388 {"const", TQUALIFIER, CONST},389 {"continue", CONTINUE, CONTINUE},390 {"default", DEFAULT, DEFAULT},391 {"do", DO, DO},392 {"double", TYPE, DOUBLE},393 {"else", ELSE, ELSE},394 {"enum", TYPE, ENUM},395 {"extern", SCLASS, EXTERN},396 {"float", TYPE, FLOAT},397 {"for", FOR, FOR},398 {"goto", GOTO, GOTO},399 {"if", IF, IF},400 {"inline", TQUALIFIER, INLINE},401 {"int", TYPE, INT},402 {"long", TYPE, LONG},403 {"register", SCLASS, REGISTER},404 {"restrict", TQUALIFIER, RESTRICT},405 {"return", RETURN, RETURN},406 {"short", TYPE, SHORT},407 {"signed", TYPE, SIGNED},408 {"sizeof", SIZEOF, SIZEOF},409 {"static", SCLASS, STATIC},410 {"struct", TYPE, STRUCT},411 {"switch", SWITCH, SWITCH},412 {"typedef", SCLASS, TYPEDEF},413 {"union", TYPE, UNION},414 {"unsigned", TYPE, UNSIGNED},415 {"void", TYPE, VOID},416 {"volatile", TQUALIFIER, VOLATILE},417 {"while", WHILE, WHILE},418 {NULL, 0, 0},419 };420421 keywords(lexkeys, NS_KEYWORD);422 keywords(cppkeys, NS_CPPCLAUSES);423 keywords(cppoper, NS_CPP);424 ibuilts();425426 /*427 * Remove all the predefined symbols from * the symbol list. It428 * will make faster some operations. There is no problem of memory429 * leakeage because this memory is not ever freed430 */431 counterid = 0;432 head = NULL;433}