scc

simple C compiler
git clone git@git.2f30.org/scc.git
Log | Files | Refs | README | LICENSE

symbol.c (6803B)


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