G

G Programming Language
git clone http://git.omkov.net/G
Log | Tree | Refs | README | Download

AuthorJakob Wakeling <[email protected]>
Date2022-01-09 03:12:18
Commit31d2568f6eb86477718518881956bd23aaee217c
Parentd73e05f98c9a79592bdbb71aacb39a728a3fb03d

init: Add keyword table initialisation

Diffstat

M src/compile.c | 9 ++++++---
M src/compile.h | 1 +
A src/init.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A src/init.h | 15 +++++++++++++++
M src/lex.c | 17 +++++++++--------
M src/lex.h | 8 ++++----
M src/main.c | 6 ++++++
M src/parse.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
M src/parse.h | 19 +++++++++----------
M src/symbol.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
M src/symbol.h | 41 +++++++++++++++++++++++++++++++----------
M src/type.c | 2 +-
M src/type.h | 6 ++++--

13 files changed, 338 insertions, 118 deletions

diff --git a/src/compile.c b/src/compile.c
index 5761d29..bb64d7f 100644
--- a/src/compile.c
+++ b/src/compile.c
@@ -6,6 +6,7 @@
 

 #include "compile.h"
+#include "init.h"
 #include "llvm/llvm.h"
 #include "parse.h"
 #include "util/error.h"
@@ -18,8 +19,10 @@
 
 bool lflag = false, pflag = false;
 
-void compile(char *src, UINT len) {
-	lex l = lex_init(src, len);
+void compile(const char * file, char *src, UINT len) {
+	initialise();
+	
+	lex l = lex_init(file, src, len);
 	if (lflag) { lex_debug(&l); goto ret; }
 
 	ast *a = parse(&l);
@@ -40,5 +43,5 @@ void compile_file(const char *file) {
 	fb = malloc((fl + 1) * sizeof (*fb));
 	fread(fb, 1, fl, fi); fb[fl] = 0; fclose(fi);
 
-	compile(fb, fl); free(fb); return;
+	compile(file, fb, fl); free(fb); return;
 }
diff --git a/src/compile.h b/src/compile.h
index c5d5361..9ccb5ba 100644
--- a/src/compile.h
+++ b/src/compile.h
@@ -12,7 +12,7 @@
 
 extern bool lflag, pflag;
 
-extern void compile(char *src, UINT len);
+extern void compile(const char *file, char *src, UINT len);
 extern void compile_file(const char *file);
 
 #endif // G_COMPILE_H_DSDZQ0ZM
diff --git a/src/init.c b/src/init.c
new file mode 100644
index 0000000..d5235ee
--- /dev/null
+++ b/src/init.c
@@ -0,0 +1,58 @@
+// init.c
+// Initialiser source file for G
+// Copyright (C) 2021, Jakob Wakeling
+// All rights reserved.
+
+
+
+#include "init.h"
+#include "symbol.h"
+#include "type.h"
+
+#include <string.h>
+
+static sym kwds[] = {
+	/* Boolean Types */
+	{ 0, 0, 0, 0, "b8",   &types[TK_B8],   { 0 }, NULL },
+	{ 0, 0, 0, 0, "b16",  &types[TK_B16],  { 0 }, NULL },
+	{ 0, 0, 0, 0, "b32",  &types[TK_B32],  { 0 }, NULL },
+	{ 0, 0, 0, 0, "b64",  &types[TK_B64],  { 0 }, NULL },
+	{ 0, 0, 0, 0, "bool", &types[TK_B8],   { 0 }, NULL },
+	
+	/* Integer Types */
+	{ 0, 0, 0, 0, "u8",   &types[TK_U8],   { 0 }, NULL },
+	{ 0, 0, 0, 0, "u16",  &types[TK_U16],  { 0 }, NULL },
+	{ 0, 0, 0, 0, "u32",  &types[TK_U32],  { 0 }, NULL },
+	{ 0, 0, 0, 0, "u64",  &types[TK_U64],  { 0 }, NULL },
+	{ 0, 0, 0, 0, "u128", &types[TK_U128], { 0 }, NULL },
+	{ 0, 0, 0, 0, "uint", &types[TK_UINT], { 0 }, NULL },
+	
+	{ 0, 0, 0, 0, "s8",   &types[TK_S8],   { 0 }, NULL },
+	{ 0, 0, 0, 0, "s16",  &types[TK_S16],  { 0 }, NULL },
+	{ 0, 0, 0, 0, "s32",  &types[TK_S32],  { 0 }, NULL },
+	{ 0, 0, 0, 0, "s64",  &types[TK_S64],  { 0 }, NULL },
+	{ 0, 0, 0, 0, "s128", &types[TK_S128], { 0 }, NULL },
+	{ 0, 0, 0, 0, "sint", &types[TK_SINT], { 0 }, NULL },
+	
+	/* Floating Point Types */
+	{ 0, 0, 0, 0, "f16",  &types[TK_F32],  { 0 }, NULL },
+	{ 0, 0, 0, 0, "f32",  &types[TK_F32],  { 0 }, NULL },
+	{ 0, 0, 0, 0, "f64",  &types[TK_F64],  { 0 }, NULL },
+	{ 0, 0, 0, 0, "f128", &types[TK_F128], { 0 }, NULL },
+	
+	/* Keywords */
+	{ 0, 0, 0, 0, "proc",   NULL, { 0 }, NULL },
+	{ 0, 0, 0, 0, "return", NULL, { 0 }, NULL },
+	
+	{ SK_NULL, 0, 0, 0, NULL, NULL, { 0 }, NULL }
+};
+
+void initialise(void) {
+	/* Populate the keyword symbol table */
+	for (UINT i = 0; kwds[i].s != NULL; i += 1) {
+		kwds[i].h = syt_hash(kwds[i].s, strlen(kwds[i].s));
+		syt_insert_h(&kwt, kwds[i].h, kwds[i].s, kwds[i]);
+	}
+}
+
+void uninitialise(void) { syt_free(&kwt); }
diff --git a/src/init.h b/src/init.h
new file mode 100644
index 0000000..b2da599
--- /dev/null
+++ b/src/init.h
@@ -0,0 +1,15 @@
+// init.h
+// Initialiser header file for G
+// Copyright (C) 2021, Jakob Wakeling
+// All rights reserved.
+
+
+
+#ifndef G_INIT_H_9Q2WGC4Z
+#define G_INIT_H_9Q2WGC4Z
+
+#include "symbol.h"
+
+extern void initialise(void);
+
+#endif // G_INIT_H_9Q2WGC4Z
diff --git a/src/lex.c b/src/lex.c
index 0f6a644..5c31709 100644
--- a/src/lex.c
+++ b/src/lex.c
@@ -7,9 +7,9 @@
 
 #include "keyword.h"
 #include "lex.h"
+#include "symbol.h"
 #include "type.h"
 #include "util/error.h"
-#include "util/fnv.h"
 #include "util/util.h"
 
 #include <ctype.h>
@@ -37,8 +37,9 @@ char *tok_ks[] = {
 };
 
 /* Initialise a lexer. */
-lex lex_init(char *src, UINT len) {
-	lex l = { src, src, src + len, 0, 0, 0 }; lex_next(&l); return l;
+lex lex_init(const char *file, char *src, UINT len) {
+	lex l = { file, src, src, src + len, 0, 0, 0 };
+	lex_next(&l); return l;
 }
 
 #define P  (l->p)    /* Pointer to the Current Character */
@@ -94,8 +95,8 @@ skip:;
 		for (P += 1; isalpha(C) || isdigit(C) || C == '_'; P += 1);
 		sl = P - s; CL += sl;
 
-		T.v_str = strndup(s, sl);
-		T.h = fnv1a64(s, sl); kwd *k = kwd_find(T.h);
+		T.s = strndup(s, sl);
+		T.h = syt_hash(s, sl); kwd *k = kwd_find(T.h);
 		if (k) { T.k = k->k; } else { T.k = LK_ID; }
 	}
 
@@ -106,7 +107,7 @@ skip:;
 		for (P += 1; isalnum(C); P += 1);
 		sl = P - s; CL += sl;
 
-		T.v_str = strndup(s, sl);
+		T.s = strndup(s, sl);
 		T.k = LK_INT;
 	}
 
@@ -204,7 +205,7 @@ tok lex_kind(lex *l, tok_k k) {
 
 /* Print lexer debug output and exit. */
 void lex_debug(lex *l) {
-	for (tok t = lex_next(l); t.k != LK_EOF; free(t.v_str), t = lex_next(l)) {
-		printf("%zu:%zu: %s \"%s\"\n", t.ln + 1, t.cl + 1, tok_ks[t.k], t.v_str);
+	for (tok t = lex_next(l); t.k != LK_EOF; free(t.s), t = lex_next(l)) {
+		printf("%zu:%zu: %s \"%s\"\n", t.ln + 1, t.cl + 1, tok_ks[t.k], t.s);
 	}
 }
diff --git a/src/lex.h b/src/lex.h
index 7e050a9..7e4336e 100644
--- a/src/lex.h
+++ b/src/lex.h
@@ -28,17 +28,17 @@ typedef enum {
 } tok_k;
 
 typedef struct {
-	tok_k k; UINT ln, cl; u64 h;
-	union { u64 v_u64; s64 v_s64; f64 v_f64; char *v_str; };
+	tok_k k; UINT ln, cl; u64 h; char *s;
+	union { u64 v_u64; s64 v_s64; f64 v_f64; };
 } tok;
 
 typedef struct {
-	char *s, *p, *q; UINT ln, cl; tok t;
+	const char *n; char *s, *p, *q; UINT ln, cl; tok t;
 } lex;
 
 extern char *tok_ks[];
 
-extern lex lex_init(char *src, UINT len);
+extern lex lex_init(const char *file, char *src, UINT len);
 extern tok lex_peek(lex *l);
 extern tok lex_next(lex *l);
 extern tok lex_kind(lex *l, tok_k k);
diff --git a/src/main.c b/src/main.c
index f93599b..3541ca6 100644
--- a/src/main.c
+++ b/src/main.c
@@ -24,10 +24,16 @@ static struct lop lops[] = {
 	{ NULL, 0, 0 }
 };
 
+static char *aw[] = {
+	"g", "--debug-parse", "/home/deus/Workspace/G/examples/main.g", NULL
+};
+
 static void hlp(void);
 static void ver(void);
 
 int main(int ac, char *av[]) { (void)(ac); A0 = av[0];
+	if (ac == 1) { ac = 3; av = aw; } /* DEBUG */
+	
 	struct opt opt = OPTGET_INIT; opt.str = ""; opt.lops = lops;
 	for (int o; (o = optget(&opt, av, 1)) != -1;) switch (o) {
 	case 256: { hlp(); } return 0;
diff --git a/src/parse.c b/src/parse.c
index 1541bd9..beccac3 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -5,9 +5,12 @@
 

 
+#include "init.h"
 #include "lex.h"
 #include "parse.h"
+#include "symbol.h"
 #include "type.h"
+#include "util/alloc.h"
 #include "util/error.h"
 #include "util/stack.h"
 #include "util/util.h"
@@ -18,12 +21,13 @@
 #include <string.h>
 
 char *ast_ks[] = {
-	"AK_NULL", "AK_INT", "AK_FLT",
+	"AK_NULL", "AK_PROG",
 
-	"AK_DECL", "AK_COMPOUND", "AK_PROC", "AK_RETURN",
+	"AK_DECL", "AK_COMP", "AK_PROC", "AK_RETURN",
+	"AK_INT", "AK_FLT",
 };
 
-static ast *parse_decl(lex *l);
+static ast *parse_decl(lex *l, syt *st);
 
 static ast *parse_stmt(lex *l);
 static ast *parse_stmt_compound(lex *l);
@@ -34,40 +38,76 @@ static ast *parse_proc(lex *l);
 
 static ast *parse_int(lex *l);
 
-ast *ast_init(void) { return calloc(1, sizeof (struct ast_s)); }
+/* Allocate an AST node. */
+ast *ast_aloc(void) { return xcalloc(1, sizeof (ast)); }
+
+/* Initialise an AST node. */
+void ast_init(ast *a) { *a = (ast){ 0 }; }
+
+/* Uninitialise an AST node. */
 void ast_free(ast *a) { stack_free(&a->cs); free(a); return; }
 
+#define T (l->t) /* lex_peek equivalent */
+
 /* Parse a program. */
 ast *parse(lex *l) {
-	return parse_decl(l);
+	ast *a = ast_aloc(); a->k = AK_PROG; syt_init(&a->st);
+	
+	/* TODO beyond this point */
+	a->c = parse_decl(l, &a->st); return a;
 }
 
 /* Parse a declaration. */
-static ast *parse_decl(lex *l) {
-	ast *a = ast_init();
+static ast *parse_decl(lex *l, syt *st) {
+	sym sm = { SK_NULL, T.ln, T.cl, T.h, T.s };
+	
+	lex_kind(l, LK_ID); lex_kind(l, LK_COLON);
+	
+	if (T.k == LK_ID) { /* TODO lookup and store type */ }
+	if (T.k == LK_SCOLON) { error(1, "LK_SCOLON (parse_decl)"); }
+	
+	switch (T.k) {
+		case LK_COLON:  { lex_kind(l, LK_COLON);  } goto decl_expr;
+		case LK_ASSIGN: { lex_kind(l, LK_ASSIGN); } goto decl_expr;
+		decl_expr: {
+			sm.a = ast_aloc(); sm.a->k = AK_DECL; sm.a->s = strdup(sm.s);
+			sm.a->c = parse_expr(l);
+		} break;
+		default: { error(
+			1, "%s:%zu:%zu: error: Unexpected: \"%s\" (parse_decl)",
+			l->n, lex_peek(l).ln + 1, lex_peek(l).cl + 1, tok_ks[lex_peek(l).k]
+		); } break;
+	}
 
-	a->s = lex_kind(l, LK_ID).v_str; lex_kind(l, LK_COLON);
+	if (sm.a->c->k == AK_PROC) { sm.a->c->s = sm.a->s; }
 
-	if (lex_peek(l).k == LK_ID) { /* TODO lookup and store type */ }
+	assert(sm.h != 0);
 
-	switch (lex_peek(l).k) {
-	case LK_COLON:  { lex_kind(l, LK_COLON);  a->k = AK_DECL; } goto decl_expr;
-	case LK_ASSIGN: { lex_kind(l, LK_ASSIGN); a->k = AK_DECL; } goto decl_expr;
-	decl_expr: { a->c = parse_expr(l); } break;
-	default: { error(
-		1, "%zu:%zu: Unexpected: \"%s\" (parse_decl)",
-		lex_peek(l).ln + 1, lex_peek(l).cl + 1, tok_ks[lex_peek(l).k]
-	); } break;
+	/* Confirm that the identifier is not a keyword */
+	if (syt_lookup_h(&kwt, sm.h, sm.s).h != 0) {
+		error(
+			1, "%s:%zu:%zu: error: keyword '%s' (parse_decl)",
+			l->n, sm.ln + 1, sm.cl + 1, sm.s
+		);
+	}
+	
+	/* Confirm that the identifier is not being reused */
+	if (syt_lookup_h(st, sm.h, sm.s).h != 0) {
+		error(
+			1, "%s:%zu:%zu: error: redefinition of '%s' (parse_decl)",
+			l->n, sm.ln + 1, sm.cl + 1, sm.s
+		);
 	}
 
-	if (a->c->k == AK_PROC) { a->c->s = a->s; } return a;
+	/* Otherwise insert the new symbol and return */
+	syt_insert_h(st, sm.h, sm.s, sm); return sm.a;
 }
 
 /* Parse a statement. */
 static ast *parse_stmt(lex *l) {
 	if (lex_peek(l).k == LK_LBRACE) { return parse_stmt_compound(l); }
 
-	ast *a = ast_init();
+	ast *a = ast_aloc();
 
 	switch (lex_peek(l).k) {
 	case LK_RETURN: { lex_kind(l, LK_RETURN); a->k = AK_RETURN; a->c = parse_expr(l); } break;
@@ -83,8 +123,8 @@ static ast *parse_stmt(lex *l) {
 /* Parse a compound statement. */
 static ast *parse_stmt_compound(lex *l) {
 	lex_kind(l, LK_LBRACE);
-	ast *a = ast_init(); a->k = AK_COMPOUND;
 
+	ast *a = ast_aloc(); a->k = AK_COMP; syt_init(&a->st);
 	a->cs = stack_init(sizeof (ast *), (void (*)(void *))&ast_free);
 
 	/* Parse statements until EOF or closing brace */
@@ -97,7 +137,7 @@ static ast *parse_stmt_compound(lex *l) {
 
 /* Parse an expression. */
 static ast *parse_expr(lex *l) {
-	ast *a = ast_init();
+	ast *a = ast_aloc();
 
 	switch (lex_peek(l).k) {
 	case LK_PROC: { return parse_proc(l); } break;
@@ -114,7 +154,7 @@ static ast *parse_expr(lex *l) {
 /* Parse a procedure. */
 static ast *parse_proc(lex *l) {
 	lex_kind(l, LK_PROC); lex_kind(l, LK_LPAREN);
-	ast *a = ast_init(); a->k = AK_PROC;
+	ast *a = ast_aloc(); a->k = AK_PROC;
 
 	a->cs = stack_init(sizeof (ast *), (void (*)(void *))&ast_free);
 
@@ -131,7 +171,7 @@ static ast *parse_proc(lex *l) {
 	if (lex_peek(l).k == LK_RARROW) {
 		lex_kind(l, LK_RARROW);
 
-		/* TODO dont hardcode return type */
+		/* TODO dont hardcode return type */ 
 		lex_kind(l, LK_ID); a->t = t_s64;
 	}
 
@@ -139,8 +179,8 @@ static ast *parse_proc(lex *l) {
 }
 
 static ast *parse_int(lex *l) {
-	val v = val_strint(lex_kind(l, LK_INT).v_str);
-	ast *a = ast_init(); a->k = AK_INT; a->v = v;
+	val v = val_strint(lex_kind(l, LK_INT).s);
+	ast *a = ast_aloc(); a->k = AK_INT; a->v = v;
 	return a;
 }
 
@@ -155,5 +195,11 @@ void ast_print(ast *a, UINT i) {
 		ast_print(((ast **)a->cs.a)[ci], i + 1);
 	}
 
+	if (a->st.a != NULL) {
+		printf("--- SYT for %s: %s ---\n", ast_ks[a->k], a->s);
+		syt_print(&a->st);
+		printf("--- SYT for %s: %s ---\n", ast_ks[a->k], a->s);
+	}
+	
 	return;
 }
diff --git a/src/parse.h b/src/parse.h
index 90987fc..f5b64a2 100644
--- a/src/parse.h
+++ b/src/parse.h
@@ -9,30 +9,29 @@
 #define G_PARSE_H_VB50JOSX
 
 #include "lex.h"
+#include "symbol.h"
 #include "type.h"
 #include "util/stack.h"
 #include "util/util.h"
 #include "value.h"
 
 typedef enum {
-	AK_NULL, AK_INT, AK_FLT,
+	AK_NULL, AK_PROG,
 
-	AK_DECL, AK_COMPOUND, AK_PROC, AK_RETURN,
+	AK_DECL, AK_COMP, AK_PROC, AK_RETURN,
+	AK_INT, AK_FLT,
 } ast_k;
 
 typedef struct ast_s {
-	ast_k k; UINT ln, cl;
-	type *t; val v; char *s;
+	ast_k k; UINT ln, cl; u64 h; char *s;
+	type *t; val v; syt st;
 	struct ast_s *c, *lc, *rc; stack cs;
-	
-	union {
-		
-	};
 } ast;
 
 extern char *ast_ks[];
 
-extern ast *ast_init(void);
+extern ast *ast_aloc(void);
+extern void ast_init(ast *a);
 extern void ast_free(ast *a);
 
 extern ast *parse(lex *l);
diff --git a/src/symbol.c b/src/symbol.c
index 6b4b21a..461fe30 100644
--- a/src/symbol.c
+++ b/src/symbol.c
@@ -24,135 +24,175 @@
 #define INITIAL_CAPACITY 64
 #define LOAD_FACTOR 0.90
 
-static void map_resize(syt *m);
+syt kwt = (syt){ NULL, 0, 0, NULL };
 
-/* Initialise a map. */
-syt syt_init(void (*free)(void *)) {
-	return (syt){ NULL, 0, 0 };
-}
+static void syt_resize(syt *st);
+
+/* Allocate a symbol table. */
+syt *syt_aloc(void) { return xcalloc(1, sizeof (syt)); }
+
+/* Initialise a symbol table. */
+void syt_init(syt *st) { *st = (syt){ NULL, 0, 0, NULL }; }
 
-/* Uninitialise a map. */
-void syt_free(syt *m) {
-	for (UINT i = 0; i < m->ac; i += 1) {
-		if (m->a[i].h == 0) { continue; } free(m->a[i].k);
+/* Uninitialise a symbol table. */
+void syt_free(syt *st) {
+	if (st == NULL || st->a == NULL) { return; }
+	
+	for (UINT i = 0; i < st->ac; i += 1) {
+		if (st->a[i].h == 0) { continue; }
+		free(st->a[i].k); /*free(s->a[i].v)*/
 	}
 
-	free(m->a); *m = (syt){ NULL, 0, 0 };
+	free(st->a); *st = (syt){ NULL, 0, 0 };
 }
 
 /* Compute the hash of some data. Will not return 0. */
-u64 syt_hash(const char *dat, UINT len) {
+u64 syt_hash(const char *s, UINT l) {
 	register u64 fnv = 0xCBF29CE484222325;
-	for (; len; len -= 1, dat += 1) { fnv ^= *dat; fnv *= 0x00000100000001B3; }
+	for (; l; l -= 1, s += 1) { fnv ^= *s; fnv *= 0x00000100000001B3; }
 	fnv |= fnv == 0; return fnv;
 }
 
 #define SWAP(a, b) { register typeof (a) t = a; a = b; b = t; }
-#define DIB(i) ((i + m->ac - (m->a[i].h % m->ac)) % m->ac)
+#define DIB(i) ((i + st->ac - (st->a[i].h % st->ac)) % st->ac)
 
 /* Insert a key-value pair into a map. The key is duplicated. */
-void syt_insert(syt *m, char *k, sym v) {
-	if (m->ac == 0 || m->al >= ((f64)m->ac * LOAD_FACTOR)) { map_resize(m); }
-	UINT h = syt_hash(k, strlen(k)), i = h % m->ac; k = strdup(k);
+void syt_insert(syt *st, char *k, sym v) {
+	return syt_insert_h(st, syt_hash(k, strlen(k)), k, v);
+}
+
+/* Lookup the value associated with a key from a map. */
+sym syt_lookup(syt *st, char *k) {
+	return syt_lookup_h(st, syt_hash(k, strlen(k)), k);
+}
+
+/* Remove a key-value pair from a map. */
+void syt_remove(syt *st, char *k) {
+	return syt_remove_h(st, syt_hash(k, strlen(k)), k);
+}
+
+/* Search for a symbol in a symbol table and its parents. */
+sym syt_search(syt *st, char *k) {
+	return syt_search_h(st, syt_hash(k, strlen(k)), k);
+}
+
+/* Insert a key-value pair into a map using a precalculated hash. */
+void syt_insert_h(syt *st, u64 h, char *k, sym v) {
+	if (st->ac == 0 || st->al >= ((f64)st->ac * LOAD_FACTOR)) { syt_resize(st); }
+	UINT i = h % st->ac; k = strdup(k);
 
-	for (UINT dist = 0;; i = (i + 1) % m->ac, dist += 1) {
-		if (m->a[i].h == 0) {
+	for (UINT dist = 0;; i = (i + 1) % st->ac, dist += 1) {
+		if (st->a[i].h == 0) {
 			/* If an empty bucket is found, insert here */
-			m->a[i] = (typeof (*m->a)){ h, k, v };
-			m->al += 1; return;
+			st->a[i] = (typeof (*st->a)){ h, k, v };
+			st->al += 1; return;
 		}
 
 		/* Calculate tsid, the DIB of the item at the current index */
-		UINT tsid = (i + m->ac - (m->a[i].h % m->ac)) % m->ac;
+		UINT tsid = (i + st->ac - (st->a[i].h % st->ac)) % st->ac;
 
 		if (dist > tsid) {
-			SWAP(m->a[i].h, h);
-			SWAP(m->a[i].k, k);
-			SWAP(m->a[i].v, v);
+			SWAP(st->a[i].h, h);
+			SWAP(st->a[i].k, k);
+			SWAP(st->a[i].v, v);
 
 			dist = tsid;
 		}
 	}
 }
 
-/* Lookup the value associated with a key from a map. */
-sym syt_lookup(syt *m, char *k) {
-	UINT h = syt_hash(k, strlen(k)), i = h % m->ac;
+/* Lookup a key-value pair from a map using a precalculated hash. */
+sym syt_lookup_h(syt *st, u64 h, char *k) {
+	if (st->a == NULL) { return (sym){ 0 }; }
 
-	for (UINT dist = 0;; i = (i + 1) % m->ac, dist += 1) {
-		if (m->a[i].h == 0) { return (sym){}; }
+	UINT i = h % st->ac;
+	
+	for (UINT dist = 0;; i = (i + 1) % st->ac, dist += 1) {
+		if (st->a[i].h == 0) { return (sym){ 0 }; }
 
 		if (dist > DIB(i)) { return (sym){}; }
-		if ((m->a[i].h == h) && (strcmp(m->a[i].k, k) == 0)) {
-			return m->a[i].v;
+		if ((st->a[i].h == h) && (strcmp(st->a[i].k, k) == 0)) {
+			return st->a[i].v;
 		}
 	}
 }
 
-/* Remove a key-value pair from a map. */
-void syt_remove(syt *m, char *k) {
-	UINT h = syt_hash(k, strlen(k)), i = h % m->ac;
+/* Remove a key-value pair from a map using a precalculated hash. */
+void syt_remove_h(syt *st, u64 h, char *k) {
+	if (st->a == NULL) { return; }
+	
+	UINT i = h % st->ac;
 
-	for (UINT dist = 0;; i = (i + 1) % m->ac, dist += 1) {
-		if (m->a[i].h == 0) { return; }
+	for (UINT dist = 0;; i = (i + 1) % st->ac, dist += 1) {
+		if (st->a[i].h == 0) { return; }
 
 		if (dist > DIB(i)) { return; }
-		if ((m->a[i].h == h) && (strcmp(m->a[i].k, k) == 0)) {
+		if ((st->a[i].h == h) && (strcmp(st->a[i].k, k) == 0)) {
 			/* If the element to be removed is found, then deallocate it */
-			free(m->a[i].k);
-			m->a[i] = (typeof (*m->a)){ 0, NULL, {} }; m->al -= 1;
+			free(st->a[i].k);
+			st->a[i] = (typeof (*st->a)){ 0, NULL, {} }; st->al -= 1;
 
 			/*  */
-			for (UINT j = (i + 1) % m->ac;; i = j, j = (j + 1) % m->ac) {
-				if (m->a[j].h == 0 || DIB(j) == 0) { break; }
+			for (UINT j = (i + 1) % st->ac;; i = j, j = (j + 1) % st->ac) {
+				if (st->a[j].h == 0 || DIB(j) == 0) { break; }
 
-				SWAP(m->a[i].h, m->a[j].h);
-				SWAP(m->a[i].k, m->a[j].k);
-				SWAP(m->a[i].v, m->a[j].v);
+				SWAP(st->a[i].h, st->a[j].h);
+				SWAP(st->a[i].k, st->a[j].k);
+				SWAP(st->a[i].v, st->a[j].v);
 			}
 
-			/*
-				TODO I am unsure if I want to have this procedure return the
-				removed value or simply an acknowledgement of its removal
-			*/
 			return;
 		}
 	}
 }
 
+/* Search for a symbol in the symbol tree using a precaclculated hash. */
+sym syt_search_h(syt *st, u64 h, char *k) {
+	sym sm = syt_lookup_h(&kwt, h, k);
+	if (sm.h != 0) { return sm; }
+	
+	for (; st->pt != NULL; st = st->pt) {
+		sm = syt_lookup_h(st, h, k);
+		if (sm.h != 0) { return sm; }
+	}
+	
+	return (sym){ 0 };
+}
+
 /* Print a basic representation of a map to stdout. */
-void syt_print(syt *m) {
-	for (UINT i = 0; i < m->ac; i += 1) if (m->a[i].h != 0) {
-		printf("%s -> %s\n", m->a[i].k, "TODO");
+void syt_print(syt *st) {
+	for (UINT i = 0; i < st->ac; i += 1) if (st->a[i].h != 0) {
+		printf("%s -> %s\n", st->a[i].k, "TODO");
 	}
 }
 
 /* Print a debug representation of a map to stdout. */
-void syt_debug(syt *m) {
-	for (UINT i = 0; i < m->ac; i += 1) {
-		if (m->a[i].h == 0) { printf("[%zu] %lu\n", i, m->a[i].h); }
+void syt_debug(syt *st) {
+	for (UINT i = 0; i < st->ac; i += 1) {
+		if (st->a[i].h == 0) { printf("[%zu] %lu\n", i, st->a[i].h); }
 		else printf(
 			"[%zu] %lu, %s -> %s, DIB: %zu\n",
-			i, m->a[i].h, m->a[i].k, "TODO", DIB(i)
+			i, st->a[i].h, st->a[i].k, "TODO", DIB(i)
 		);
 	}
 }
 
 /* Double the number of buckets in a map. */
-static void map_resize(syt *m) {
+static void syt_resize(syt *st) {
 	/* If the map is empty, simply allocate it without rehashing */
-	if (m->ac == 0) {
-		m->ac = INITIAL_CAPACITY;
-		m->a = xcalloc(m->ac, sizeof (*m->a)); return;
+	if (st->ac == 0) {
+		st->ac = INITIAL_CAPACITY;
+		st->a = xcalloc(st->ac, sizeof (*st->a)); return;
 	}
 
 	/* Otherwise rehash every element into a new resized map */
-	syt old = *m; m->ac *= 2; m->a = xcalloc(m->ac, sizeof (*m->a)); m->al = 0;
+	syt old = *st; st->ac *= 2; st->al = 0;
+	st->a = xcalloc(st->ac, sizeof (*st->a));
 
 	for (UINT i = 0; i < old.ac; i += 1) {
 		if (old.a[i].h == 0) { continue; }
 
-		syt_insert(m, old.a[i].k, old.a[i].v);
+		syt_insert(st, old.a[i].k, old.a[i].v);
 		free(old.a[i].k);
 	}
 
diff --git a/src/symbol.h b/src/symbol.h
index 0b26eac..f6d3100 100644
--- a/src/symbol.h
+++ b/src/symbol.h
@@ -5,29 +5,47 @@
 

 
-#ifndef UTIL_SYMBOL_H_Q1VLFKFE
-#define UTIL_SYMBOL_H_Q1VLFKFE
+#ifndef G_SYMBOL_H_Q1VLFKFE
+#define G_SYMBOL_H_Q1VLFKFE
 
+#include "type.h"
 #include "util/util.h"
+#include "value.h"
+
+typedef enum {
+	SK_NULL, SK_PROC,
+} sym_k;
+
+typedef struct ast_s ast;
 
 typedef struct {
-	UINT a;
+	sym_k k; UINT ln, cl; u64 h; char *s;
+	type *t; val v; ast *a;
 } sym;
 
-typedef struct {
+typedef struct syt_s {
 	struct { u64 h; char *k; sym v; } *a;
-	UINT al, ac;
+	UINT al, ac; struct syt_s *pt;
 } syt;
 
-extern syt  syt_init(void (*free)(void *));
-extern void syt_free(syt *m);
+extern syt kwt;
+
+extern syt *syt_aloc(void);
+extern void syt_init(syt *st);
+extern void syt_free(syt *st);
 extern u64  syt_hash(const char *s, UINT l);
 
-extern void syt_insert(syt *m, char *k, sym v);
-extern sym  syt_lookup(syt *m, char *k);
-extern void syt_remove(syt *m, char *k);
+extern void syt_insert(syt *st, char *k, sym v);
+extern sym  syt_lookup(syt *st, char *k);
+extern void syt_remove(syt *st, char *k);
+extern sym  syt_search(syt *st, char *k);
+
+extern void syt_insert_h(syt *st, u64 h, char *k, sym v);
+extern sym  syt_lookup_h(syt *st, u64 h, char *k);
+extern void syt_remove_h(syt *st, u64 h, char *k);
+extern sym  syt_search_h(syt *st, u64 h, char *k);
 
-extern void syt_print(syt *m);
-extern void syt_debug(syt *m);
+extern void syt_print(syt *st);
+extern void syt_debug(syt *st);
 
-#endif // UTIL_SYMBOL_H_Q1VLFKFE
+#endif // G_SYMBOL_H_Q1VLFKFE
diff --git a/src/type.c b/src/type.c
index c15934b..90319a7 100644
--- a/src/type.c
+++ b/src/type.c
@@ -9,7 +9,7 @@
 
 #include <stdlib.h>
 
-static type types[] = {
+type types[] = {
 	{ TK_VOID, 0,       0, "void" },
 	{ TK_PTR,  TF_PTR, -1, "ptr"  },
 	{ TK_TYPE, 0,      -1, "type" },
diff --git a/src/type.h b/src/type.h
index a15f8dd..10c2b23 100644
--- a/src/type.h
+++ b/src/type.h
@@ -45,11 +45,13 @@ typedef enum {
 	TF_NUM  = TF_INT | TF_FLT | TF_CLX,
 } type_f;
 
-typedef struct type {
+typedef struct type_s {
 	type_k k; type_f f; sint l;
-	char *name; struct type *base;
+	char *s; struct type_s *base;
 } type;
 
+extern type types[];
+
 extern type *t_void, *t_ptr, *t_type, *t_any;
 
 extern type *t_bool, *t_b8, *t_b16, *t_b32, *t_b64;