scc

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

symbol.c (6735B)


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