scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | README | LICENSE

symbol.c (6781B)


      1 static char sccsid[] = "@(#) ./cc1/symbol.c";
      2 #include <assert.h>
      3 #include <limits.h>
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <string.h>
      7 
      8 #include <scc/cstd.h>
      9 #include <scc/scc.h>
     10 #include "cc1.h"
     11 
     12 #define NR_SYM_HASH 64
     13 #define NR_CPP_HASH 32
     14 #define NR_LBL_HASH 16
     15 
     16 unsigned curctx;
     17 static unsigned short counterid;
     18 
     19 static Symbol *head, *labels;
     20 static Symbol *htab[NR_SYM_HASH];
     21 static Symbol *htabcpp[NR_CPP_HASH];
     22 static Symbol *htablbl[NR_LBL_HASH];
     23 
     24 #ifndef NDEBUG
     25 void
     26 dumpstab(Symbol **tbl, char *msg)
     27 {
     28 	Symbol **bp, *sym;
     29 	unsigned size;
     30 
     31 	fprintf(stderr, "Symbol Table dump at ctx=%u\n%s\n", curctx, msg);
     32 	if (tbl == htab)
     33 		size = NR_SYM_HASH;
     34 	else if (tbl == htabcpp)
     35 		size = NR_CPP_HASH;
     36 	else if (tbl == htablbl)
     37 		size = NR_LBL_HASH;
     38 	else
     39 		abort();
     40 
     41 	for (bp = tbl; bp < &tbl[size]; ++bp) {
     42 		if (*bp == NULL)
     43 			continue;
     44 		fprintf(stderr, "%d", (int) (bp - htab));
     45 		for (sym = *bp; sym; sym = sym->hash)
     46 			fprintf(stderr, "->[%d,%d:'%s'=%p]",
     47 			        sym->ns, sym->ctx, sym->name, (void *) sym);
     48 		putc('\n', stderr);
     49 	}
     50 	fputs("head:", stderr);
     51 	for (sym = head; sym; sym = sym->next) {
     52 		fprintf(stderr, "->[%d,%d:'%s'=%p]",
     53 		        sym->ns, sym->ctx,
     54 		        (sym->name) ? sym->name : "", (void *) sym);
     55 	}
     56 	fputs("\nlabels:", stderr);
     57 	for (sym = labels; sym; sym = sym->next) {
     58 		fprintf(stderr, "->[%d,%d:'%s'=%p]",
     59 		        sym->ns, sym->ctx,
     60 		        (sym->name) ? sym->name : "", (void *) sym);
     61 	}
     62 	putc('\n', stderr);
     63 }
     64 #endif
     65 
     66 static Symbol **
     67 hash(char *s, int ns)
     68 {
     69 	unsigned h, size;
     70 	Symbol **tab;
     71 
     72 	h = genhash(s);
     73 
     74 	switch (ns) {
     75 	case NS_CPP:
     76 		tab = htabcpp;
     77 		size = NR_CPP_HASH-1;
     78 		break;
     79 	case NS_LABEL:
     80 		tab = htablbl;
     81 		size = NR_LBL_HASH-1;
     82 		break;
     83 	default:
     84 		tab = htab;
     85 		size = NR_SYM_HASH-1;
     86 		break;
     87 	}
     88 	return &tab[h & size];
     89 }
     90 
     91 static void
     92 unlinkhash(Symbol *sym)
     93 {
     94 	Symbol **h;
     95 
     96 	if ((sym->flags & SDECLARED) == 0)
     97 		return;
     98 	h = hash(sym->name, sym->ns);
     99 	assert(sym->ns == NS_CPP || *h == sym);
    100 	while (*h != sym)
    101 		h = &(*h)->hash;
    102 	*h = sym->hash;
    103 }
    104 
    105 void
    106 pushctx(void)
    107 {
    108 	DBG("SYM: pushed context %d", curctx+1);
    109 	if (++curctx == NR_BLOCK+1)
    110 		error("too many nested blocks");
    111 }
    112 
    113 void
    114 killsym(Symbol *sym)
    115 {
    116 	short f;
    117 	char *name;
    118 
    119 	if (!sym)
    120 		return;
    121 	f = sym->flags;
    122 	if (f & SSTRING)
    123 		free(sym->u.s);
    124 	if (sym->ns == NS_TAG)
    125 		sym->type->prop &= ~TDEFINED;
    126 	unlinkhash(sym);
    127 	if ((name = sym->name) != NULL) {
    128 		switch (sym->ns) {
    129 		case NS_LABEL:
    130 			if ((f & SDEFINED) == 0)
    131 				errorp("label '%s' is not defined", name);
    132 		case NS_IDEN:
    133 			if ((f & (SUSED|SGLOBAL|SDECLARED)) == SDECLARED)
    134 				warn("'%s' defined but not used", name);
    135 			break;
    136 		}
    137 	}
    138 	free(name);
    139 	free(sym);
    140 }
    141 
    142 void
    143 popctx(void)
    144 {
    145 	Symbol *next, *sym;
    146 	int ns, dangling = 0;
    147 
    148 	DBG("SYM: poped context %d", curctx);
    149 	/*
    150 	 * we have to be careful before popping the current
    151 	 * context, because since the parser is one token
    152 	 * ahead it may already have read an identifier at
    153 	 * this point, and yylval.sym is a pointer to
    154 	 * the symbol associated to such token. If that
    155 	 * symbol is from the context that we are popping
    156 	 * then we are going to generate a dangling pointer.
    157 	 * We can detect this situation and call again to
    158 	 * lookup.
    159 	 */
    160 	if ((yytoken == IDEN || yytoken == TYPEIDEN) &&
    161 	    yylval.sym->ctx == curctx) {
    162 		ns = yylval.sym->ns;
    163 		dangling = 1;
    164 	}
    165 
    166 	for (sym = head; sym && sym->ctx == curctx; sym = next) {
    167 		/*
    168 		 * Since we are unlinking them in the inverse order
    169 		 * we do know that sym is always the head of the
    170 		 * collision list
    171 		 */
    172 		next = sym->next;
    173 		killsym(sym);
    174 	}
    175 	head = sym;
    176 
    177 	if (--curctx == GLOBALCTX) {
    178 		for (sym = labels; sym; sym = next) {
    179 			next = sym->next;
    180 			killsym(sym);
    181 		}
    182 		labels = NULL;
    183 	}
    184 
    185 	if (dangling) {
    186 		yylval.sym = lookup(ns, yytext, ALLOC);
    187 		yytoken = yylval.sym->token;
    188 	}
    189 }
    190 
    191 unsigned
    192 newid(void)
    193 {
    194 	unsigned short id;
    195 
    196 	if (lexmode == CPPMODE)
    197 		return 0;
    198 	id = ++counterid;
    199 	if (id == 0) {
    200 		die("cc1: overflow in %s identifiers",
    201 		    (curctx) ? "internal" : "external");
    202 	}
    203 	return id;
    204 }
    205 
    206 Symbol *
    207 newsym(int ns, char *name)
    208 {
    209 	Symbol *sym;
    210 
    211 	sym = xmalloc(sizeof(*sym));
    212 	if (name)
    213 		name = xstrdup(name);
    214 	sym->name = name;
    215 	sym->id = 0;
    216 	sym->hide = 0;
    217 	sym->ns = ns;
    218 	sym->ctx = curctx;
    219 	sym->token = IDEN;
    220 	sym->flags = 0;
    221 	sym->u.s = NULL;
    222 	sym->type = NULL;
    223 	sym->hash = NULL;
    224 
    225 	if (ns == NS_LABEL) {
    226 		sym->next = labels;
    227 		labels = sym;
    228 	} else if (ns != NS_CPP) {
    229 		sym->next = head;
    230 		head = sym;
    231 	}
    232 	return sym;
    233 }
    234 
    235 static Symbol *
    236 linkhash(Symbol *sym)
    237 {
    238 	Symbol **h;
    239 
    240 	h = hash(sym->name, sym->ns);
    241 	sym->hash = *h;
    242 	*h = sym;
    243 
    244 	if (sym->ns != NS_CPP)
    245 		sym->id = newid();
    246 	sym->flags |= SDECLARED;
    247 	return sym;
    248 }
    249 
    250 Symbol *
    251 newstring(char *s, size_t len)
    252 {
    253 	Symbol *sym = newsym(NS_IDEN, NULL);
    254 
    255 	if (lexmode != CPPMODE)
    256 		sym->type = mktype(chartype, ARY, len, NULL);
    257 	sym->id = newid();
    258 	sym->flags |= SSTRING | SCONSTANT | SPRIVATE;
    259 	sym->u.s = xmalloc(len);
    260 	if (s)
    261 		memcpy(sym->u.s, s, len);
    262 
    263 	return sym;
    264 }
    265 
    266 Symbol *
    267 newlabel(void)
    268 {
    269 	Symbol *sym = newsym(NS_LABEL, NULL);
    270 	sym->id = newid();
    271 	return sym;
    272 }
    273 
    274 Symbol *
    275 lookup(int ns, char *name, int alloc)
    276 {
    277 	Symbol *sym;
    278 	int sns, c;
    279 	char *t;
    280 
    281 	c = *name;
    282 	for (sym = *hash(name, ns); sym; sym = sym->hash) {
    283 		t = sym->name;
    284 		if (*t != c || strcmp(t, name))
    285 			continue;
    286 		sns = sym->ns;
    287 		if (sns == ns)
    288 			return sym;
    289 		/*
    290 		 * When a lookup is done in a namespace associated
    291 		 * to a struct we also want symbols of NS_IDEN which
    292 		 * are typedef, because in other case we cannot declare
    293 		 * fields of such types.
    294 		 * TODO: Remove this trick
    295 		 */
    296 		if (sns == NS_KEYWORD ||
    297 		    (sym->flags & STYPEDEF) && ns >= NS_STRUCTS) {
    298 			return sym;
    299 		}
    300 	}
    301 	return (alloc == ALLOC) ? newsym(ns, name) : NULL;
    302 }
    303 
    304 Symbol *
    305 install(int ns, Symbol *sym)
    306 {
    307 	if (sym->flags & SDECLARED || sym->ctx != curctx) {
    308 		if (sym->ctx == curctx && ns == sym->ns)
    309 			return NULL;
    310 		sym = newsym(ns, sym->name);
    311 	}
    312 	return linkhash(sym);
    313 }
    314 
    315 void
    316 keywords(struct keyword *key, int ns)
    317 {
    318 	Symbol *sym;
    319 
    320 	for ( ; key->str; ++key) {
    321 		sym = linkhash(newsym(ns, key->str));
    322 		sym->token = key->token;
    323 		sym->u.token = key->value;
    324 	}
    325 	/*
    326 	 * Remove all the predefined symbols from * the symbol list. It
    327 	 * will make faster some operations. There is no problem of memory
    328 	 * leakeage because this memory is not ever freed
    329 	 */
    330 	counterid = 0;
    331 	head = NULL;
    332 }
    333 
    334 void
    335 builtins(struct builtin *built)
    336 {
    337 	Symbol *sym;
    338 	struct builtin *bp;
    339 
    340 	for (bp = built; bp->str; ++bp) {
    341 		sym = linkhash(newsym(NS_KEYWORD, bp->str));
    342 		sym->token = BUILTIN;
    343 		sym->u.fun = bp->fun;
    344 	}
    345 	/*
    346 	 * Remove all the predefined symbols from * the symbol list. It
    347 	 * will make faster some operations. There is no problem of memory
    348 	 * leakeage because this memory is not ever freed
    349 	 */
    350 	counterid = 0;
    351 	head = NULL;
    352 }