shithub: scc

ref: 7a2a1f936d8ca77484fa4ddb3b1244ecd350a8b5
dir: /cc1/symbol.c/

View raw version

#include <inttypes.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "../inc/cc.h"
#include "../inc/sizes.h"
#include "cc1.h"

#define NR_SYM_HASH 64

unsigned curctx;
static short localcnt;
static short globalcnt;

static Symbol *head, *labels;
static Symbol *htab[NR_SYM_HASH];

#ifndef NDEBUG
void
dumpstab(char *msg)
{
	Symbol **bp, *sym;

	fprintf(stderr, "Symbol Table dump at ctx=%u\n%s\n", curctx, msg);
	for (bp = htab; bp < &htab[NR_SYM_HASH]; ++bp) {
		if (*bp == NULL)
			continue;
		fprintf(stderr, "%d", (int) (bp - htab));
		for (sym = *bp; sym; sym = sym->hash)
			fprintf(stderr, "->[%d,%d:%s]",
			        sym->ns, sym->ctx, sym->name);
		putc('\n', stderr);
	}
	fputs("head:", stderr);
	for (sym = head; sym; sym = sym->next) {
		fprintf(stderr, "->[%d,%d:'%s']",
		        sym->ns, sym->ctx,
		        (sym->name) ? sym->name : "");
	}
	putc('\n', stderr);
}
#endif

static unsigned
hash(const char *s)
{
	unsigned c, h;

	for (h = 0; c = *s; ++s)
		h ^= 33 * c;
	return h & NR_SYM_HASH-1;
}

static Symbol *
linkhash(Symbol *sym, char *name)
{
	Symbol **h, *p, *prev;

	sym->name = xstrdup(name);
	h = &htab[hash(name)];

	for (prev = p = *h; p; prev = p, p = p->hash) {
		if (p->ctx <= sym->ctx)
			break;
	}
	if (p == prev) {
		sym->hash = *h;
		*h = sym;
	} else {
		p = prev->hash;
		prev->hash = sym;
		sym->hash = p;
	}

	return sym;
}

static void
unlinkhash(Symbol *sym)
{
	Symbol **h, *p, *prev;

	h = &htab[hash(sym->name)];
	for (prev = p = *h; p != sym; prev = p, p = p->hash)
		/* nothing */;
	if (prev == p)
		*h = sym->hash;
	else
		prev->hash = sym->hash;
}

void
pushctx(void)
{
	if (++curctx == NR_BLOCK+1)
		error("too much nested blocks");
}

void
popctx(void)
{
	Symbol *next, *sym;
	short f;

	if (--curctx == GLOBALCTX) {
		localcnt = 0;
		for (sym = labels; sym; sym = next) {
			next = sym->next;
			if ((f & (ISUSED|ISDECLARED)) == ISDECLARED)
				warn("'%s' defined but not used", sym->name);
			if ((sym->flags & ISDECLARED) == 0)
				printerr("label '%s' is not defined", sym->name);
			free(sym->name);
			free(sym);
		}
		labels = NULL;
	}

	for (sym = head; sym && sym->ctx > curctx; sym = next) {
		next = sym->next;
		if (sym->ns == NS_TAG)
			sym->type->defined = 0;
		if (sym->name) {
			f = sym->flags;
			unlinkhash(sym);
			if ((f & (ISUSED|ISGLOBAL|ISDECLARED)) == ISDECLARED)
				warn("'%s' defined but not used", sym->name);
		}
		free(sym->name);
		// TODO: There is a memory leak with sym->u.s
		free(sym);
	}
	head = sym;
}

Type *
duptype(Type *base)
{
	Type *tp = xmalloc(sizeof(*tp));

	*tp = *base;
	tp->id = (curctx) ? ++localcnt : ++globalcnt;
	return tp;
}

Symbol *
newsym(unsigned ns)
{
	Symbol *sym, *p, *prev;

	sym = malloc(sizeof(*sym));
	sym->id = 0;
	sym->ns = ns;
	sym->ctx = (ns == NS_CPP) ? UCHAR_MAX : curctx;
	sym->token = IDEN;
	sym->flags = ISDECLARED;
	sym->u.s = sym->name = NULL;
	sym->type = NULL;
	sym->next = sym->hash = NULL;

	if (ns == NS_CPP)
		return sym;
	if (ns == NS_LABEL) {
		sym->next = labels;
		return labels = sym;
	}

	for (prev = p = head; p; prev = p, p = p->next) {
		if (p->ctx <= sym->ctx)
			break;
	}
	if (p == prev) {
		sym->next = head;
		head = sym;
	} else {
		p = prev->next;
		prev->next = sym;
		sym->next = p;
	}

	return sym;
}

Symbol *
lookup(unsigned ns)
{
	Symbol *sym, **h;
	unsigned sns;
	char *t, c;

	h = &htab[hash(yytext)];
	c = *yytext;
	for (sym = *h; sym; sym = sym->hash) {
		t = sym->name;
		if (*t != c || strcmp(t, yytext))
			continue;
		sns = sym->ns;
		if (sns == NS_KEYWORD || sns == NS_CPP)
			return sym;
		if (sns != ns)
			continue;
		return sym;
	}
	sym = linkhash(newsym(ns), yytext);
	sym->flags &= ~ISDECLARED;

	return sym;
}

void
delmacro(Symbol *sym)
{
	unlinkhash(sym);
	free(sym->name);
	free(sym->u.s);
	free(sym);
}

Symbol *
nextsym(Symbol *sym, unsigned ns)
{
	char *s, *t, c;
	Symbol *new, *p;

	/*
	 * This function is only called when a macro with parameters
	 * is called without them.
	 *      #define x(y) ((y) + 1)
	 *      int x = x(y);
	 */
	s = sym->name;
	c = *s;
	for (p = sym->hash; p; p = p->hash) {
		t = p->name;
		if (c == *t && !strcmp(s, t))
			return sym;
	}
	new = linkhash(newsym(ns), s);
	new->flags &= ~ISDECLARED;
	return new;
}

Symbol *
install(unsigned ns, Symbol *sym)
{
	if (sym->ctx == curctx) {
		if (sym->flags & ISDECLARED) {
			if (ns == sym->ns)
				return NULL;
		} else {
			sym->flags |= ISDECLARED;
			sym->ns = ns;
			goto assign_id;
		}
	}
	sym = linkhash(newsym(ns), sym->name);

assign_id:
	if (sym->ns != NS_CPP)
		sym->id = (curctx) ? ++localcnt : ++globalcnt;

	return sym;
}

void
ikeywords(void)
{
	static struct {
		char *str;
		unsigned char token, value;
	} *bp, keywords[] = {
		{"auto", SCLASS, AUTO},
		{"break", BREAK, BREAK},
		{"_Bool", TYPE, BOOL},
		{"case", CASE, CASE},
		{"char", TYPE, CHAR},
		{"const", TQUALIFIER, CONST},
		{"continue", CONTINUE, CONTINUE},
		{"default", DEFAULT, DEFAULT},
		{"do", DO, DO},
		{"double", TYPE, DOUBLE},
		{"else", ELSE, ELSE},
		{"enum", TYPE, ENUM},
		{"extern", SCLASS, EXTERN},
		{"float", TYPE, FLOAT},
		{"for", FOR, FOR},
		{"goto", GOTO, GOTO},
		{"if", IF, IF},
		{"int", TYPE, INT},
		{"long", TYPE, LONG},
		{"register", SCLASS, REGISTER},
		{"restrict", TQUALIFIER, RESTRICT},
		{"return", RETURN, RETURN},
		{"short", TYPE, SHORT},
		{"signed", TYPE, SIGNED},
		{"sizeof", SIZEOF, SIZEOF},
		{"static", SCLASS, STATIC},
		{"struct", TYPE, STRUCT},
		{"switch", SWITCH, SWITCH},
		{"typedef", SCLASS, TYPEDEF},
		{"union", TYPE, UNION},
		{"unsigned", TYPE, UNSIGNED},
		{"void", TYPE, VOID},
		{"volatile", TQUALIFIER, VOLATILE},
		{"while", WHILE, WHILE},
		{NULL, 0, 0},
	}, cppclauses[] = {
		{"define", DEFINE, DEFINE},
		{"include", INCLUDE, INCLUDE},
		{"line", LINE, LINE},
		{"ifdef", IFDEF, IFDEF},
		{"if", IF, IF},
		{"elif", ELIF, ELIF},
		{"else", ELSE, ELSE},
		{"ifndef", IFNDEF, IFNDEF},
		{"endif", ENDIF, ENDIF},
		{"undef", UNDEF, UNDEF},
		{"pragma", PRAGMA, PRAGMA},
		{"error", ERROR, ERROR},
		{NULL, 0, 0}
	}, *list[] = {
		keywords,
		cppclauses,
		NULL
	}, **lp;
	Symbol *sym;
	int ns = NS_KEYWORD;

	for (lp = list; *lp; ++lp) {
		for (bp = *lp; bp->str; ++bp) {
			strcpy(yytext, bp->str);
			sym = lookup(ns);
			sym->token = bp->token;
			sym->u.token = bp->value;
		}
		ns = NS_CPPCLAUSES;
	}
	/*
	 * Remove all the predefined symbols from * the symbol list. It
	 * will make faster someoperations. There is no problem of memory
	 * leakeage because this memory is not ever freed
	 */
	head = NULL;
}