scc

A fork of https://git.simple-cc.org/scc/ for Qute

git clone https://git.8pit.net/scc.git

  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
 15struct keyword {
 16	char *str;
 17	unsigned char token, value;
 18};
 19
 20unsigned curctx;
 21static unsigned short counterid;
 22
 23static Symbol *head, *labels;
 24static Symbol *htab[NR_SYM_HASH];
 25static Symbol *htabcpp[NR_CPP_HASH];
 26static Symbol *htablbl[NR_LBL_HASH];
 27
 28#ifndef NDEBUG
 29void
 30dumpstab(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
 70static Symbol **
 71hash(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
 95static void
 96unlinkhash(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
109void
110pushctx(void)
111{
112	DBG("SYM: pushed context %d", curctx+1);
113	if (++curctx == NR_BLOCK+1)
114		error("too many nested blocks");
115}
116
117void
118killsym(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
146void
147popctx(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
195unsigned
196newid(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
210Symbol *
211newsym(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
239static Symbol *
240linkhash(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
254Symbol *
255newrstring(Rune *rs, size_t len)
256{
257	Symbol *sym = newsym(NS_IDEN, NULL);
258
259	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));
266
267	return sym;
268}
269
270Symbol *
271newstring(char *s, size_t len)
272{
273	Symbol *sym = newsym(NS_IDEN, NULL);
274
275	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);
282
283	return sym;
284}
285
286Symbol *
287newlabel(void)
288{
289	Symbol *sym = newsym(NS_LABEL, NULL);
290	sym->id = newid();
291	return sym;
292}
293
294Symbol *
295lookup(int ns, char *name, int alloc)
296{
297	Symbol *sym;
298	int sns, c;
299	char *t;
300
301	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 associated
311		 * to a struct we also want symbols of NS_IDEN which
312		 * are typedef, because in other case we cannot declare
313		 * 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}
322
323Symbol *
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}
333
334void
335keywords(struct keyword *key, int ns)
336{
337	Symbol *sym;
338
339	for ( ; key->str; ++key) {
340		sym = linkhash(newsym(ns, key->str));
341		sym->token = key->token;
342		sym->u.token = key->value;
343	}
344}
345
346void
347builtins(struct builtin *built)
348{
349	Symbol *sym;
350	struct builtin *bp;
351
352	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}
358
359void
360isyms(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	};
420
421	keywords(lexkeys, NS_KEYWORD);
422	keywords(cppkeys, NS_CPPCLAUSES);
423	keywords(cppoper, NS_CPP);
424	ibuilts();
425
426	/*
427	 * Remove all the predefined symbols from * the symbol list. It
428	 * will make faster some operations. There is no problem of memory
429	 * leakeage because this memory is not ever freed
430	 */
431	counterid = 0;
432	head = NULL;
433}