shithub: scc

Download patch

ref: 5029b379b8193ead69618b3e306c9dcd2e1ab296
parent: d56911aa4feb7fb2f32fa38f53c0d74ecf7ea4d8
author: Roberto E. Vargas Caballero <[email protected]>
date: Sat Jan 23 06:09:20 EST 2016

[cc2] Add parser of IR

This is a totally incomplete parser, and it is in a state not thought to be shown,
but it is something to begin to talk.

--- a/cc2/Makefile
+++ b/cc2/Makefile
@@ -2,7 +2,8 @@
 
 include ../config.mk
 
-OBJS = main.o parser.o code.o optm.o peep.o cgen.o
+OBJS = main.o parser.o code.o optm.o peep.o cgen.o \
+       symbol.o node.o arch/$(ARCH)/types.o
 
 all: cc2
 
--- /dev/null
+++ b/cc2/arch/amd64-sysv/arch.h
@@ -1,0 +1,5 @@
+
+#define TINT    long long
+#define TUINT   unsigned long long
+#define TFLOAT  double
+
--- /dev/null
+++ b/cc2/arch/amd64-sysv/types.c
@@ -1,0 +1,89 @@
+
+#include "arch.h"
+#include "../../cc2.h"
+
+
+Type int8type = {
+	.flags  = SIGNF | INTF,
+	.size   = 1,
+	.align  = 1
+};
+
+Type int16type = {
+	.flags  = SIGNF | INTF,
+	.size   = 2,
+	.align  = 2
+};
+
+Type int32type = {
+	.flags  = SIGNF | INTF,
+	.size   = 4,
+	.align  = 4
+};
+
+Type int64type = {
+	.flags  = SIGNF | INTF,
+	.size   = 8,
+	.align  = 8
+};
+
+Type uint8type = {
+	.flags  = INTF,
+	.size   = 1,
+	.align  = 1
+};
+
+Type uint16type = {
+	.flags  = INTF,
+	.size   = 2,
+	.align  = 2
+};
+
+Type uint32type = {
+	.flags  = INTF,
+	.size   = 4,
+	.align  = 2
+};
+
+Type uint64type = {
+	.flags  = INTF,
+	.size   = 8,
+	.align  = 2
+};
+
+Type ptrtype = {
+	.flags  = INTF,
+	.size   = 8,
+	.align  = 8
+};
+
+Type booltype = {
+	.flags  = INTF,
+	.size   = 1,
+	.align  = 1
+};
+
+Type float32type = {
+	.size   = 4,
+	.align  = 4
+};
+
+Type float64type = {
+	.size   = 8,
+	.align  = 8
+};
+
+Type float80type = {
+	.size   = 10,
+	.align  = 12
+};
+
+Type voidtype = {
+	.size = 0,
+	.align = 0
+};
+
+Type elipsistype = {
+	.size = 0,
+	.align = 0
+};
--- /dev/null
+++ b/cc2/arch/i386-sysv/arch.h
@@ -1,0 +1,5 @@
+
+#define TINT    long long
+#define TUINT   unsigned long long
+#define TFLOAT  double
+
--- /dev/null
+++ b/cc2/arch/i386-sysv/types.c
@@ -1,0 +1,89 @@
+
+#include "arch.h"
+#include "../../cc2.h"
+
+
+Type int8type = {
+	.flags  = SIGNF | INTF,
+	.size   = 1,
+	.align  = 1
+};
+
+Type int16type = {
+	.flags  = SIGNF | INTF,
+	.size   = 2,
+	.align  = 2
+};
+
+Type int32type = {
+	.flags  = SIGNF | INTF,
+	.size   = 4,
+	.align  = 4
+};
+
+Type int64type = {
+	.flags  = SIGNF | INTF,
+	.size   = 8,
+	.align  = 8
+};
+
+Type uint8type = {
+	.flags  = INTF,
+	.size   = 1,
+	.align  = 1
+};
+
+Type uint16type = {
+	.flags  = INTF,
+	.size   = 2,
+	.align  = 2
+};
+
+Type uint32type = {
+	.flags  = INTF,
+	.size   = 4,
+	.align  = 2
+};
+
+Type uint64type = {
+	.flags  = INTF,
+	.size   = 8,
+	.align  = 2
+};
+
+Type ptrtype = {
+	.flags  = INTF,
+	.size   = 4,
+	.align  = 4
+};
+
+Type booltype = {
+	.flags  = INTF,
+	.size   = 1,
+	.align  = 1
+};
+
+Type float32type = {
+	.size   = 4,
+	.align  = 4
+};
+
+Type float64type = {
+	.size   = 8,
+	.align  = 8
+};
+
+Type float80type = {
+	.size   = 10,
+	.align  =  4
+};
+
+Type voidtype = {
+	.size = 0,
+	.align = 0
+};
+
+Type elipsistype = {
+	.size = 0,
+	.align = 0
+};
--- /dev/null
+++ b/cc2/arch/z80/arch.h
@@ -1,0 +1,5 @@
+
+#define TINT    long long
+#define TUINT   unsigned long long
+#define TFLOAT  double
+
--- /dev/null
+++ b/cc2/arch/z80/types.c
@@ -1,0 +1,89 @@
+
+#include "arch.h"
+#include "../../cc2.h"
+
+
+Type int8type = {
+	.flags  = SIGNF | INTF,
+	.size   = 1,
+	.align  = 1
+};
+
+Type int16type = {
+	.flags  = SIGNF | INTF,
+	.size   = 2,
+	.align  = 1
+};
+
+Type int32type = {
+	.flags  = SIGNF | INTF,
+	.size   = 4,
+	.align  = 1
+};
+
+Type int64type = {
+	.flags  = SIGNF | INTF,
+	.size   = 8,
+	.align  = 1
+};
+
+Type uint8type = {
+	.flags  = INTF,
+	.size   = 1,
+	.align  = 1
+};
+
+Type uint16type = {
+	.flags  = INTF,
+	.size   = 2,
+	.align  = 1
+};
+
+Type uint32type = {
+	.flags  = INTF,
+	.size   = 4,
+	.align  = 1
+};
+
+Type uint64type = {
+	.flags  = INTF,
+	.size   = 8,
+	.align  = 1
+};
+
+Type ptrtype = {
+	.flags  = INTF,
+	.size   = 2,
+	.align  = 1
+};
+
+Type booltype = {
+	.flags  = INTF,
+	.size   = 1,
+	.align  = 1
+};
+
+Type float32type = {
+	.size   = 4,
+	.align  = 1
+};
+
+Type float64type = {
+	.size   = 4,
+	.align  = 1
+};
+
+Type float80type = {
+	.size   = 4,
+	.align  = 1
+};
+
+Type voidtype = {
+	.size = 0,
+	.align = 0
+};
+
+Type elipsistype = {
+	.size = 0,
+	.align = 0
+};
--- a/cc2/cc2.h
+++ b/cc2/cc2.h
@@ -1,5 +1,102 @@
 
+enum tflags {
+	SIGNF   = 1,
+	INTF    = 2,
+	DEFTYP  = 4,
+	STRUCTF = 8,
+	UNIONF  = 16,
+	FUNCF   = 32,
+	ARYF    = 64
+};
+
+enum op {
+	/* types */
+	ELLIPSIS = 'E',
+	INT8     = 'C',
+	INT16    = 'I',
+	INT32    = 'W',
+	INT64    = 'Q',
+	UINT8    = 'K',
+	UINT16   = 'N',
+	UINT32   = 'Z',
+	UINT64   = 'O',
+	POINTER  = 'P',
+	FUNCTION = 'F',
+	VECTOR   = 'V',
+	UNION    = 'U',
+	STRUCT   = 'S',
+	BOOL     = 'B',
+	FLOAT    = 'J',
+	DOUBLE   = 'D',
+	LDOUBLE  = 'H',
+	VOID     = '0',
+	ONAME    = '"',
+	/* kind of operand */
+	NONE     = 0,
+	MEM      = 'M',
+	AUTO     = 'A',
+	REG      = 'R',
+	/* storage class */
+	GLOB     = 'G',
+	EXTRN    = 'X',
+	PRIVAT   = 'Y',
+	LOCAL    = 'T',
+	MEMBER   = 'M',
+	LABEL    = 'L',
+	/* operands */
+	OADD     = '+',
+	OSUB     = '-',
+	OMUL     = '*',
+	OMOD     = '%',
+	ODIV     = '/',
+	OSHL     = 'l',
+	OSHR     = 'r',
+	OLT      = '<',
+	OGT      = '>',
+	OLE      = '[',
+	OGE      = ']',
+	OEQ      = '=',
+	ONE      = '!',
+	OBAND    = '&',
+	OBOR     = '|',
+	OBXOR    = '^',
+	OCPL     = '~',
+	OASSIG   = ':',
+	ONEG     = '_',
+	OCALL    = 'c',
+	OPAR     = 'p',
+	OFIELD   = '.',
+	OCOMMA   = ',',
+	OASK     = '?',
+	OCOLON   = ' ',
+	OADDR    = '\'',
+	OAND     = 'a',
+	OOR      = 'b',
+	OPTR     = '@',
+	OSYM     = 'y',
+	OCAST    = 'g',
+	OCONST   = '#',
+	OSTRING  = '"',
+	/*statements */
+	OJMP     = 'j',
+	ORET     = 'r',
+	OBLOOP   = 'b',
+	OELOOP   = 'e',
+	OCASE    = 'v',
+	ODEFAULT = 'f',
+	OTABLE   = 't',
+	OSWITCH  = 's',
+	OEPARS   = '\\',
+	OSTMT    = '\t'
+};
+
 enum nerrors {
+	EIDOVER,       /* identifier overflow */
+	EOUTPAR,       /* out pf params */
+	ESYNTAX,       /* syntax error */
+	ESTACKA,       /* stack unaligned */
+	ESTACKO,       /* stack overflow */
+	ESTACKU,       /* stack underflow */
 	ELNLINE,       /* line too long */
 	EFERROR,       /* error reading from file:%s*/
 	ENUMERR
@@ -6,9 +103,34 @@
 };
 
 typedef struct node Node;
+typedef struct type Type;
+typedef struct symbol Symbol;
 
+struct type {
+	unsigned short size;
+	unsigned short align;
+	unsigned short flags;
+};
+
+struct symbol {
+	unsigned short id;
+	char *name;
+	Type type;
+	char kind;
+	union {
+		TUINT i;
+		char *s;
+	} u;
+	Symbol *next;
+	Symbol *h_next;
+};
+
 struct node {
-	unsigned char op;
+	char op;
+	Type type;
+	Symbol *sym;
+	Node *left, *right;
+	Node *stmt;
 };
 
 /* main.c */
@@ -29,3 +151,14 @@
 
 /* code.c */
 extern void writeout(void);
+
+/* node.c */
+extern void cleannodes(void);
+extern void delnode(Node *np);
+extern Node *newnode(void);
+
+/* symbol.c */
+extern Symbol *getsym(int id);
+extern void popctx(void);
+extern void pushctx(void);
+extern void freesym(Symbol *sym);
--- a/cc2/cgen.c
+++ b/cc2/cgen.c
@@ -1,4 +1,5 @@
 
+#include "arch.h"
 #include "cc2.h"
 
 void
--- a/cc2/code.c
+++ b/cc2/code.c
@@ -1,4 +1,5 @@
 
+#include "arch.h"
 #include "cc2.h"
 
 void
--- a/cc2/main.c
+++ b/cc2/main.c
@@ -3,6 +3,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include "arch.h"
 #include "cc2.h"
 #include "error.h"
 
--- /dev/null
+++ b/cc2/node.c
@@ -1,0 +1,64 @@
+
+#include <stdlib.h>
+
+#include "../inc/cc.h"
+
+#include "arch.h"
+#include "cc2.h"
+
+#define NSYMBOLS   32
+
+int inhome;
+
+struct arena {
+	Node *mem;
+	struct arena *next;
+};
+static struct arena *arena;
+static Node *freep;
+
+Node *
+newnode(void)
+{
+	struct arena *ap;
+	Node *np;
+
+	if (!freep) {
+		ap = xmalloc(sizeof(*ap));
+		ap->mem = xcalloc(NSYMBOLS, sizeof(Node));
+		ap->next = arena;
+		arena = ap;
+		for (np = ap->mem; np < &ap->mem[NSYMBOLS-1]; ++np)
+			np->left = np+1;
+		np->left = NULL;
+		freep = np;
+	}
+
+	np = freep;
+	freep = np->left;
+
+	np->right = NULL;
+	np->left = NULL;
+	np->sym = NULL;
+	np->stmt = NULL;
+	return np;
+}
+
+void
+delnode(Node *np)
+{
+	np->left = freep;
+	freep = np;
+}
+
+void
+cleannodes(void)
+{
+	struct arena *ap, *next;
+
+	for (ap = arena; ap; ap = next) {
+		next = ap;
+		free(ap->mem);
+		free(ap);
+	}
+}
--- a/cc2/optm.c
+++ b/cc2/optm.c
@@ -1,4 +1,5 @@
 
+#include "arch.h"
 #include "cc2.h"
 
 void
--- a/cc2/parser.c
+++ b/cc2/parser.c
@@ -1,45 +1,385 @@
 
 #include <errno.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
+#include "../inc/cc.h"
+#include "../inc/sizes.h"
+
+#include "arch.h"
 #include "cc2.h"
 
-#define MAXLINE 200
+#define MAXLINE     200
+#define STACKSIZ     50
 
+extern Type int8type, int16type, int32type, int64type,
+            uint8type, uint16type, uint32type, uint64type,
+            float32type, float64type, float80type,
+            booltype,
+            ptrtype,
+            voidtype,
+            elipsistype;
+
+Type funtype = {
+	.flags = DEFTYP | FUNCF
+};
+
+Type arrtype = {
+	.flags = DEFTYP | ARYF
+};
+
+Type uniontype = {
+	.flags = DEFTYP | UNIONF
+};
+
+Type strtype = {
+	.flags = DEFTYP | STRUCTF
+};
+
+union tokenop {
+	void *arg;
+	int op;
+};
+
+typedef void parsefun(char *, union tokenop);
+static parsefun type, symbol, getname, unary, binary, ternary, call,
+                parameter, constant;
+
+typedef void evalfun(void);
+static evalfun vardecl, beginfun, endfun, endpars, stmt, begininit, endinit;
+
+static struct decoc {
+	void (*eval)(void);
+	void (*parse)(char *token, union tokenop);
+	union tokenop u;
+} optbl[] = {
+	[AUTO]        = {vardecl, symbol, .u.op = AUTO},
+	[REG]         = {vardecl, symbol, .u.op = REG},
+	[GLOB]        = {vardecl, symbol, .u.op = MEM},
+	[EXTRN]       = {vardecl, symbol, .u.op = MEM},
+	[PRIVAT]      = {vardecl, symbol, .u.op = MEM},
+	[LOCAL]       = {vardecl, symbol, .u.op = MEM},
+	[MEMBER]      = {NULL, symbol},
+	[LABEL]       = {NULL, symbol},
+
+	[INT8]        = {NULL, type, .u.arg   = &int8type},
+	[INT16]       = {NULL, type, .u.arg   = &int16type},
+	[INT32]       = {NULL, type, .u.arg   = &int32type},
+	[INT64]       = {NULL, type, .u.arg   = &int64type},
+	[UINT8]       = {NULL, type, .u.arg   = &uint8type},
+	[UINT16]      = {NULL, type, .u.arg   = &uint16type},
+	[UINT32]      = {NULL, type, .u.arg   = &uint32type},
+	[UINT64]      = {NULL, type, .u.arg   = &uint64type},
+	[FLOAT]       = {NULL, type, .u.arg   = &float32type},
+	[DOUBLE]      = {NULL, type, .u.arg   = &float64type},
+	[LDOUBLE]     = {NULL, type, .u.arg   = &float80type},
+	[VOID]        = {NULL, type, .u.arg   = &voidtype},
+	[BOOL]        = {NULL, type, .u.arg   = &booltype},
+	[POINTER]     = {NULL, type, .u.arg   = &ptrtype},
+	[ELLIPSIS]    = {NULL, type, .u.arg   = &elipsistype},
+
+	[FUNCTION]    = {NULL, type, .u.arg = &funtype},
+	[VECTOR]      = {NULL, NULL, .u.arg = &arrtype},
+	[UNION]       = {NULL, NULL, .u.arg = &uniontype},
+	[STRUCT]      = {NULL, NULL, .u.arg = &strtype},
+
+	[ONAME]       = {NULL, getname},
+	['{']         = {beginfun},
+	['}']         = {endfun},
+	['(']         = {begininit},
+	[')']         = {endinit},
+	[OEPARS]      = {endpars},
+	[OSTMT]       = {stmt},
+
+	[OCPL]        = {NULL, unary},
+	[ONEG]        = {NULL, unary},
+	[OFIELD]      = {NULL, unary},
+	[OADDR]       = {NULL, unary},
+	[OAND]        = {NULL, unary},
+	[OOR]         = {NULL, unary},
+	[OPTR]        = {NULL, unary},
+	[OCAST]       = {NULL, unary},
+	[OPAR ]       = {NULL, unary},
+
+	[OADD]        = {NULL, binary},
+	[OSUB]        = {NULL, binary},
+	[OMUL]        = {NULL, binary},
+	[OMOD]        = {NULL, binary},
+	[ODIV]        = {NULL, binary},
+	[OSHL]        = {NULL, binary},
+	[OSHR]        = {NULL, binary},
+	[OLT]         = {NULL, binary},
+	[OGT]         = {NULL, binary},
+	[OLE]         = {NULL, binary},
+	[OGE]         = {NULL, binary},
+	[OEQ]         = {NULL, binary},
+	[ONE]         = {NULL, binary},
+	[OBAND]       = {NULL, binary},
+	[OBOR]        = {NULL, binary},
+	[OBXOR]       = {NULL, binary},
+	[OASSIG]      = {NULL, binary},
+	[OCOMMA]      = {NULL, binary},
+
+	[OASK]        = {NULL, ternary},
+	[OCALL]       = {NULL, call},
+
+	[OCONST]      = NULL, constant,
+
+	[OCASE]       = NULL,
+	[ODEFAULT]    = NULL,
+	[OTABLE]      = NULL,
+	[OSWITCH]     = NULL
+};
+
+static void *stack[STACKSIZ], **sp = stack;
+static Symbol *lastsym, *curfun;
+static Symbol *params[NR_FUNPARAM];
+static int funpars = -1, sclass, callpars, ininit;
+static Node *stmtp, *callp;
+
 static void
-push(Node * np)
+push(void *elem)
 {
+	if (sp == stack[STACKSIZ])
+		error(ESTACKO);
+	*sp++ = elem;
 }
 
-static Node *
+static void *
 pop(void)
 {
+	if (sp == stack)
+		error(ESTACKU);
+	return *--sp;
 }
 
+static unsigned short
+newid(void)
+{
+	static unsigned short id;
+
+	if (++id == 0)
+		error(EIDOVER);
+}
+
 static void
-expr(char *tok)
+type(char *token, union tokenop u)
 {
+	push(u.arg);
 }
 
 static void
-stmt(Node *np)
+getname(char *t, union tokenop u)
 {
+	push((*++t) ? xstrdup(t) : NULL);
 }
 
 static void
-decl(char *tok)
+symbol(char *token, union tokenop u)
 {
+	Node *np;
+
+	sclass = *token++;
+	np = newnode();
+	np->sym = getsym(atoi(token));
+	np->op = u.op;
+	push(np);
 }
 
+static Type *
+gettype(char *token)
+{
+	struct decoc *dp;
+
+	dp = &optbl[*token];
+	if (!dp->parse)
+		error(ESYNTAX);
+	(*dp->parse)(token, dp->u);
+	return pop();
+}
+
+static void
+constant(char *token, union tokenop u)
+{
+	static char letters[] = "0123456789ABCDEF";
+	Node *np = newnode();
+	Symbol *sym = getsym(0);
+	TUINT v;
+	unsigned c;
+
+	np->sym = sym;
+	++token;
+	if (*token == OSTRING) {
+		np->op = OSYM;
+		np->type = ptrtype;
+		sym->id = newid();
+		sym->u.s = xstrdup(++token);
+	} else {
+		np->op = OCONST;
+		np->type = *gettype(token++);
+		for (v = 0; c = *token++; v += c) {
+			v <<= 4;
+			c = strchr(letters, c) - letters;
+		}
+		sym->u.i = v;
+	}
+}
+
+static void
+ternary(char *token, union tokenop u)
+{
+	Node *ask, *colon;
+	Type *tp;
+
+	tp = gettype(++token);
+
+	colon = newnode();
+	colon->op = OCOLON;
+	colon->right = pop();
+	colon->left = pop();
+
+	ask = newnode();
+	ask->op = OASK;
+	ask->type = *tp;
+	ask->left = pop();
+	ask->right = pop();
+	push(ask);
+}
+
+static void
+unary(char *token, union tokenop u)
+{
+	Node *np = newnode();
+
+	np->op = *token++;
+	np->type = *gettype(token);
+	np->left = pop();
+	np->right = NULL;
+	push(np);
+}
+
+static void
+call(char *token, union tokenop u)
+{
+	Node *np, *par, *fun;
+
+	for (par = NULL;; par = np) {
+		np = pop();
+		if (np->op != OPAR)
+			break;
+		np->right = par;
+	}
+	fun = newnode();
+	fun->op = OCALL;
+	fun->type = *gettype(token);
+	fun->left = np;
+	fun->right = par;
+	push(fun);
+}
+
+static void
+binary(char *token, union tokenop u)
+{
+	Node *np = newnode();
+
+	np->op = *token++;
+	np->type = *gettype(token);
+	np->right = pop();
+	np->left = pop();
+	push(np);
+}
+
+static void
+begininit(void)
+{
+	inint = 1;
+}
+
+static void
+endinit(void)
+{
+	ininit = 0;
+}
+
+static void
+beginfun(void)
+{
+	if (curfun)
+		error(ESYNTAX);
+	memset(params, 0, sizeof(params));
+	funpars = 0;
+	curfun = lastsym;
+	pushctx();
+}
+
+static void
+endfun(void)
+{
+	if (!curfun)
+		error(ESYNTAX);
+	popctx();
+	curfun = NULL;
+	funpars = -1;
+}
+
+static void
+endpars(void)
+{
+	if (!curfun || funpars == -1)
+		error(ESYNTAX);
+	funpars = -1;
+}
+
+static void
+vardecl(void)
+{
+	Type *tp;
+	Node *np;
+	Symbol *sym;
+	char *name;
+
+	name = pop();
+	tp = pop();
+	np = pop();
+
+	sym = np->sym;
+	sym->name = name;
+	sym->type = *tp;
+	sym->kind = sclass;
+	lastsym = sym;
+
+	if (funpars >= 0) {
+		if (funpars == NR_FUNPARAM)
+			error(EOUTPAR);
+		params[funpars++] = sym;
+	}
+	delnode(np);
+}
+
+static void
+stmt(void)
+{
+	static Node *lastp;
+	Node *np = pop();
+
+	if (!stmtp)
+		stmtp = np;
+	else
+		lastp->stmt = np;
+	lastp = np;
+}
+
 void
 parse(void)
 {
-	char line[MAXLINE];
+	char line[MAXLINE], *t;
 	size_t len;
+	int c;
+	struct decoc *dp;
 
 	for (;;) {
-		if (fgets(line, sizeof(line), stdin))
+		if (!fgets(line, sizeof(line), stdin))
 			break;
 		if ((len = strlen(line)) == 0 || line[0] == '\n')
 			continue;
@@ -46,15 +386,20 @@
 		if (line[len-1] != '\n')
 			error(ELNLINE);
 		line[len-1] = '\0';
-		switch (*line) {
-		case '\t':
-			expr(strtok(line, "\t"));
-			stmt(pop());
-			break;
-		default:
-			decl(strtok(line, "\t"));
-			break;
+
+		c = *line;
+		for (t = strtok(line, "\t\n"); t; t = strtok(NULL, "\t\n")) {
+			dp = &optbl[*t];
+			if (!dp->parse)
+				break;
+			(*dp->parse)(t, dp->u);
 		}
+
+		(*optbl[c].eval)();
+		if (sp != stack)
+			error(ESTACKA);
+		if (c == '}')
+			break;
 	}
 
 	if (ferror(stdin))
--- a/cc2/peep.c
+++ b/cc2/peep.c
@@ -1,4 +1,5 @@
 
+#include "arch.h"
 #include "cc2.h"
 
 void
--- /dev/null
+++ b/cc2/symbol.c
@@ -1,0 +1,66 @@
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "../inc/cc.h"
+
+#include "arch.h"
+#include "cc2.h"
+
+#define NR_SYMHASH  64
+
+static Symbol *symtab[NR_SYMHASH];
+static Symbol *locals;
+static int infunction;
+
+
+void
+freesym(Symbol *sym)
+{
+	free(sym->name);
+	free(sym);
+}
+
+void
+pushctx(void)
+{
+	infunction = 1;
+}
+
+void
+popctx(void)
+{
+	Symbol *sym, *next;
+
+	infunction = 0;
+	for (sym = locals; sym; sym = next) {
+		next = sym->next;
+		symtab[sym->id & NR_SYMHASH-1] = sym->h_next;
+		freesym(sym);
+	}
+}
+
+Symbol *
+getsym(int id)
+{
+	Symbol **htab, *sym;
+
+	htab = &symtab[id & NR_SYMHASH-1];
+	for (sym = *htab; sym; sym = sym->h_next) {
+		if (sym->id > 0 && sym->id != id)
+			break;
+	}
+	if (!sym) {
+		sym = xcalloc(1, sizeof(*sym));
+		sym->id = id;
+		if (!infunction) {
+			sym->next = NULL;
+		} else {
+			sym->next = locals;
+			locals = sym;
+		}
+		sym->h_next = *htab;
+		*htab = sym;
+	}
+	return sym;
+}