Home
       symbol.c - scc - simple c99 compiler
  HTML git clone git://git.simple-cc.org/scc
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
   DIR README
   DIR LICENSE
       ---
       symbol.c (8242B)
       ---
            1 #include <assert.h>
            2 #include <limits.h>
            3 #include <stdio.h>
            4 #include <stdlib.h>
            5 #include <string.h>
            6 
            7 #include <scc/cstd.h>
            8 #include <scc/scc.h>
            9 #include "cc1.h"
           10 
           11 #define NR_SYM_HASH 64
           12 #define NR_CPP_HASH 32
           13 #define NR_LBL_HASH 16
           14 
           15 struct keyword {
           16         char *str;
           17         unsigned char token, value;
           18 };
           19 
           20 unsigned curctx;
           21 static unsigned short counterid;
           22 
           23 static Symbol *head, *labels;
           24 static Symbol *htab[NR_SYM_HASH];
           25 static Symbol *htabcpp[NR_CPP_HASH];
           26 static Symbol *htablbl[NR_LBL_HASH];
           27 
           28 #ifndef NDEBUG
           29 void
           30 dumpstab(Symbol **tbl, char *msg)
           31 {
           32         Symbol **bp, *sym;
           33         unsigned size;
           34 
           35         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         else
           43                 abort();
           44 
           45         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 #endif
           69 
           70 static Symbol **
           71 hash(char *s, int ns)
           72 {
           73         unsigned h, size;
           74         Symbol **tab;
           75 
           76         h = genhash(s);
           77 
           78         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 }
           94 
           95 static void
           96 unlinkhash(Symbol *sym)
           97 {
           98         Symbol **h;
           99 
          100         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 }
          108 
          109 void
          110 pushctx(void)
          111 {
          112         DBG("SYM: pushed context %d", curctx+1);
          113         if (++curctx == NR_BLOCK+1)
          114                 error("too many nested blocks");
          115 }
          116 
          117 void
          118 killsym(Symbol *sym)
          119 {
          120         short f;
          121         char *name;
          122 
          123         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 }
          145 
          146 void
          147 popctx(void)
          148 {
          149         Symbol *next, *sym;
          150         int ns, dangling = 0;
          151 
          152         DBG("SYM: popped context %d", curctx);
          153         /*
          154          * we have to be careful before popping the current
          155          * context, because since the parser is one token
          156          * ahead it may already have read an identifier at
          157          * this point, and yylval.sym is a pointer to
          158          * the symbol associated to such token. If that
          159          * symbol is from the context that we are popping
          160          * then we are going to generate a dangling pointer.
          161          * We can detect this situation and call again to
          162          * lookup.
          163          */
          164         if ((yytoken == IDEN || yytoken == TYPEIDEN) &&
          165             yylval.sym->ctx == curctx) {
          166                 ns = yylval.sym->ns;
          167                 dangling = 1;
          168         }
          169 
          170         for (sym = head; sym && sym->ctx == curctx; sym = next) {
          171                 /*
          172                  * Since we are unlinking them in the inverse order
          173                  * we do know that sym is always the head of the
          174                  * collision list
          175                  */
          176                 next = sym->next;
          177                 killsym(sym);
          178         }
          179         head = sym;
          180 
          181         if (--curctx == GLOBALCTX) {
          182                 for (sym = labels; sym; sym = next) {
          183                         next = sym->next;
          184                         killsym(sym);
          185                 }
          186                 labels = NULL;
          187         }
          188 
          189         if (dangling) {
          190                 yylval.sym = lookup(ns, yytext, ALLOC);
          191                 yytoken = yylval.sym->token;
          192         }
          193 }
          194 
          195 unsigned
          196 newid(void)
          197 {
          198         unsigned short id;
          199 
          200         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 }
          209 
          210 Symbol *
          211 newsym(int ns, char *name)
          212 {
          213         Symbol *sym;
          214 
          215         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;
          228 
          229         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 }
          238 
          239 static Symbol *
          240 linkhash(Symbol *sym)
          241 {
          242         Symbol **h;
          243 
          244         h = hash(sym->name, sym->ns);
          245         sym->hash = *h;
          246         *h = sym;
          247 
          248         if (sym->ns != NS_CPP)
          249                 sym->id = newid();
          250         sym->flags |= SDECLARED;
          251         return sym;
          252 }
          253 
          254 Symbol *
          255 newstring(char *s, size_t len)
          256 {
          257         Symbol *sym = newsym(NS_IDEN, NULL);
          258 
          259         if (lexmode != CPPMODE)
          260                 sym->type = mktype(chartype, ARY, len, NULL);
          261         sym->id = newid();
          262         sym->flags |= SSTRING | SCONSTANT | SPRIVATE;
          263         sym->u.s = xmalloc(len);
          264         if (s)
          265                 memcpy(sym->u.s, s, len);
          266 
          267         return sym;
          268 }
          269 
          270 Symbol *
          271 newlabel(void)
          272 {
          273         Symbol *sym = newsym(NS_LABEL, NULL);
          274         sym->id = newid();
          275         return sym;
          276 }
          277 
          278 Symbol *
          279 lookup(int ns, char *name, int alloc)
          280 {
          281         Symbol *sym;
          282         int sns, c;
          283         char *t;
          284 
          285         c = *name;
          286         for (sym = *hash(name, ns); sym; sym = sym->hash) {
          287                 t = sym->name;
          288                 if (*t != c || strcmp(t, name))
          289                         continue;
          290                 sns = sym->ns;
          291                 if (sns == ns)
          292                         return sym;
          293                 /*
          294                  * When a lookup is done in a namespace associated
          295                  * to a struct we also want symbols of NS_IDEN which
          296                  * are typedef, because in other case we cannot declare
          297                  * fields of such types.
          298                  * TODO: Remove this trick
          299                  */
          300                 if (sns == NS_KEYWORD ||
          301                     (sym->flags & STYPEDEF) && ns >= NS_STRUCTS) {
          302                         return sym;
          303                 }
          304         }
          305         return (alloc == ALLOC) ? newsym(ns, name) : NULL;
          306 }
          307 
          308 Symbol *
          309 install(int ns, Symbol *sym)
          310 {
          311         if (sym->flags & SDECLARED || sym->ctx != curctx) {
          312                 if (sym->ctx == curctx && ns == sym->ns)
          313                         return NULL;
          314                 sym = newsym(ns, sym->name);
          315         }
          316         return linkhash(sym);
          317 }
          318 
          319 void
          320 keywords(struct keyword *key, int ns)
          321 {
          322         Symbol *sym;
          323 
          324         for ( ; key->str; ++key) {
          325                 sym = linkhash(newsym(ns, key->str));
          326                 sym->token = key->token;
          327                 sym->u.token = key->value;
          328         }
          329 }
          330 
          331 void
          332 builtins(struct builtin *built)
          333 {
          334         Symbol *sym;
          335         struct builtin *bp;
          336 
          337         for (bp = built; bp->str; ++bp) {
          338                 sym = linkhash(newsym(NS_KEYWORD, bp->str));
          339                 sym->token = BUILTIN;
          340                 sym->u.fun = bp->fun;
          341         }
          342 }
          343 
          344 void
          345 isyms(void)
          346 {
          347         static struct keyword cppoper[] = {
          348                 {"defined", DEFINED, DEFINED},
          349                 {NULL, 0, 0}
          350         };
          351         static struct keyword cppkeys[] = {
          352                 {"define", DEFINE, DEFINE},
          353                 {"include", INCLUDE, INCLUDE},
          354                 {"line", LINE, LINE},
          355                 {"ifdef", IFDEF, IFDEF},
          356                 {"if", IF, IF},
          357                 {"elif", ELIF, ELIF},
          358                 {"else", ELSE, ELSE},
          359                 {"ifndef", IFNDEF, IFNDEF},
          360                 {"endif", ENDIF, ENDIF},
          361                 {"undef", UNDEF, UNDEF},
          362                 {"pragma", PRAGMA, PRAGMA},
          363                 {"error", ERROR, ERROR},
          364                 {NULL, 0, 0}
          365         };
          366         static struct keyword lexkeys[] = {
          367                 {"auto", SCLASS, AUTO},
          368                 {"break", BREAK, BREAK},
          369                 {"_Bool", TYPE, BOOL},
          370                 {"__builtin_va_list", TYPE, VA_LIST},
          371                 {"case", CASE, CASE},
          372                 {"char", TYPE, CHAR},
          373                 {"const", TQUALIFIER, CONST},
          374                 {"continue", CONTINUE, CONTINUE},
          375                 {"default", DEFAULT, DEFAULT},
          376                 {"do", DO, DO},
          377                 {"double", TYPE, DOUBLE},
          378                 {"else", ELSE, ELSE},
          379                 {"enum", TYPE, ENUM},
          380                 {"extern", SCLASS, EXTERN},
          381                 {"float", TYPE, FLOAT},
          382                 {"for", FOR, FOR},
          383                 {"goto", GOTO, GOTO},
          384                 {"if", IF, IF},
          385                 {"inline", TQUALIFIER, INLINE},
          386                 {"int", TYPE, INT},
          387                 {"long", TYPE, LONG},
          388                 {"register", SCLASS, REGISTER},
          389                 {"restrict", TQUALIFIER, RESTRICT},
          390                 {"return", RETURN, RETURN},
          391                 {"short", TYPE, SHORT},
          392                 {"signed", TYPE, SIGNED},
          393                 {"sizeof", SIZEOF, SIZEOF},
          394                 {"static", SCLASS, STATIC},
          395                 {"struct", TYPE, STRUCT},
          396                 {"switch", SWITCH, SWITCH},
          397                 {"typedef", SCLASS, TYPEDEF},
          398                 {"union", TYPE, UNION},
          399                 {"unsigned", TYPE, UNSIGNED},
          400                 {"void", TYPE, VOID},
          401                 {"volatile", TQUALIFIER, VOLATILE},
          402                 {"while", WHILE, WHILE},
          403                 {NULL, 0, 0},
          404         };
          405 
          406         keywords(lexkeys, NS_KEYWORD);
          407         keywords(cppkeys, NS_CPPCLAUSES);
          408         keywords(cppoper, NS_CPP);
          409         ibuilts();
          410 
          411         /*
          412          * Remove all the predefined symbols from * the symbol list. It
          413          * will make faster some operations. There is no problem of memory
          414          * leakeage because this memory is not ever freed
          415          */
          416         counterid = 0;
          417         head = NULL;
          418 }