G

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

AuthorJakob Wakeling <[email protected]>
Date2022-04-12 13:18:27
Commita47f6532e4d1c1d6af1d4c443e4e0d28f2bbd5d9
Parent895c21f5f5943231651252c3093f5f4aebc78753

Implment a semantic analysis stage

Diffstat

A src/analyse.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A src/analyse.h | 14 ++++++++++++++
M src/compile.c | 10 +++++++---
M src/compile.h | 2 +-
M src/main.c | 24 ++++++++++++++----------
M src/symbol.c | 6 ++----

6 files changed, 138 insertions, 18 deletions

diff --git a/src/analyse.c b/src/analyse.c
new file mode 100644
index 0000000..d1a0e1f
--- /dev/null
+++ b/src/analyse.c
@@ -0,0 +1,100 @@
+// analyse.c
+// Semantic analyser source file for G
+// Copyright (C) 2022, Jakob Wakeling
+// All rights reserved.
+
+#include "analyse.h"
+#include "parse.h"
+#include "symbol.h"
+#include "type.h"
+#include "util/error.h"
+#include "util/util.h"
+
+#include <assert.h>
+
+static void analyse_stmt(ast *a, syt *st);
+static void analyse_stmt_comp(ast *a, syt *st);
+static void analyse_stmt_decl(ast *a, syt *st);
+static void analyse_stmt_expr(ast *a, syt *st);
+
+static void analyse_expr(ast *a, syt *st);
+static void analyse_expr_proc(ast *a, syt *st);
+
+static type *type_expr(ast *a, syt *st);
+
+#define A  (*a)
+#define ST (*st)
+
+/* Analyse a program. */
+void analyse(ast *a) {
+	assert(A.k == AK_PROG);
+	
+	/* Analyse all child nodes */
+	for (UINT i = 0; i < A.c.al; i += 1) { analyse_stmt_decl(A.c.a[i], &A.st); }
+}
+
+/* Analyse a statement. */
+static void analyse_stmt(ast *a, syt *st) {
+	switch (A.k) {
+	case AK_COMP: { analyse_stmt_comp(a, st); } break;
+	case AK_DECL: { analyse_stmt_decl(a, st); } break;
+	default:      { analyse_stmt_expr(a, st); } break;
+	}
+}
+
+/* Analyse a compound statement. */
+static void analyse_stmt_comp(ast *a, syt *st) {
+	assert(A.k == AK_COMP);
+	
+	/* Analyse all child nodes */
+	for (UINT i = 0; i < A.c.al; i += 1) { analyse_stmt(A.c.a[i], st); }
+}
+
+/* Analyse a declaration statement. */
+static void analyse_stmt_decl(ast *a, syt *st) {
+	assert(A.c.al == 0 || A.c.al == 1);
+	
+	/* If an initialisation value is present, then find its type */
+	type *t = NULL; if (A.c.al == 1) {
+		analyse_expr(A.c.a[0], st);
+		t = type_expr(A.c.a[0], st);
+	}
+	
+	/* If the declaration is already typed, then ensure that it matches */
+	if (A.t) { if (A.t != t) {
+		error(1, "%s:%zu:%zu: error: incorrect type", "", A.ln + 1, A.cl + 1);
+	}}
+	
+	/* Otherwise store the initialisation type */
+	else { A.t = t; }
+}
+
+/* Analyse an expression statement. */
+static void analyse_stmt_expr(ast *a, syt *st) {
+	analyse_expr(a, st);
+}
+
+/* Analyse an expression. */
+static void analyse_expr(ast *a, syt *st) {
+	if (A.k == AK_PROC) { analyse_expr_proc(a, st); }
+}
+
+/* Analyse a procedure expression. */
+static void analyse_expr_proc(ast *a, syt *st) {
+	assert(A.k == AK_PROC);
+	
+	/* Analyse the procedure body */
+	analyse_stmt_comp(A.c.a[0], st);
+}
+
+/* Find the ultimate type of an expression. */
+static type *type_expr(ast *a, syt *st) {
+	/* If the given node has a type, then return that */
+	if (A.t) { return A.t; }
+	
+	/* Otherwise recurse down the first child */
+	if (A.c.al) { return type_expr(A.c.a[0], st); }
+	
+	/* If no type is found, return NULL */
+	return NULL;
+}
diff --git a/src/analyse.h b/src/analyse.h
new file mode 100644
index 0000000..8d32bbf
--- /dev/null
+++ b/src/analyse.h
@@ -0,0 +1,14 @@
+// analyse.h
+// Semantic analyser header file for G
+// Copyright (C) 2022, Jakob Wakeling
+// All rights reserved.
+
+#ifndef G_ANALYSE_H_N80HV3K4
+#define G_ANALYSE_H_N80HV3K4
+
+#include "parse.h"
+#include "util/util.h"
+
+extern void analyse(ast *a);
+
+#endif // G_ANALYSE_H_N80HV3K4
diff --git a/src/compile.c b/src/compile.c
index 0c88ced..4f31c03 100644
--- a/src/compile.c
+++ b/src/compile.c
@@ -3,6 +3,7 @@
 // Copyright (C) 2021, Jakob Wakeling
 // All rights reserved.
 
+#include "analyse.h"
 #include "compile.h"
 #include "init.h"
 #include "llvm.h"
@@ -13,16 +14,19 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-bool lflag = false, pflag = false;
+bool dlflag = false, dpflag = false, daflag = false;
 
 void compile(const char * file, char *src, UINT len) {
 	initialise();
 
 	lex l = lex_init(file, src, len);
-	if (lflag) { lex_debug(&l); goto end; }
+	if (dlflag) { lex_debug(&l); goto end; }
 
 	ast *a = parse(&l);
-	if (pflag) { ast_print(a, 0); goto end; }
+	if (dpflag) { ast_print(a, 0); goto end; }
+	
+	analyse(a);
+	if (daflag) { ast_print(a, 0); goto end; }
 
 	llvm(a);
 
diff --git a/src/compile.h b/src/compile.h
index 58c7808..b029b58 100644
--- a/src/compile.h
+++ b/src/compile.h
@@ -8,7 +8,7 @@
 
 #include "util/util.h"
 
-extern bool lflag, pflag;
+extern bool dlflag, dpflag, daflag;
 
 extern void compile(const char *file, char *src, UINT len);
 extern void compile_file(const char *file);
diff --git a/src/main.c b/src/main.c
index 73e325f..ab65b93 100644
--- a/src/main.c
+++ b/src/main.c
@@ -14,15 +14,16 @@
 #include <stdlib.h>
 
 static struct lop lops[] = {
-	{ "help",        ARG_NUL, 256 },
-	{ "version",     ARG_NUL, 257 },
-	{ "debug-lex",   ARG_NUL, 258 },
-	{ "debug-parse", ARG_NUL, 259 },
+	{ "help",          ARG_NUL, 256 },
+	{ "version",       ARG_NUL, 257 },
+	{ "debug-lex",     ARG_NUL, 258 },
+	{ "debug-parse",   ARG_NUL, 259 },
+	{ "debug-analyse", ARG_NUL, 260 },
 	{ NULL, 0, 0 }
 };
 
 static char *aw[] = {
-	"g", "--debug-parse", "/home/deus/Workspace/G/examples/dual.g", NULL
+	"g", "--debug-analyse", "/home/deus/Workspace/G/examples/dual.g", NULL
 };
 
 static void hlp(void);
@@ -36,8 +37,9 @@ int main(int ac, char *av[]) { A0 = av[0];
 	for (int o; (o = optget(&opt, av, 1)) != -1;) switch (o) {
 	case 256: { hlp(); } return 0;
 	case 257: { ver(); } return 0;
-	case 258: { lflag = true; } break;
-	case 259: { pflag = true; } break;
+	case 258: { dlflag = true; } break;
+	case 259: { dpflag = true; } break;
+	case 260: { daflag = true; } break;
 	default: {} return 1;
 	}
 
@@ -52,10 +54,11 @@ static void hlp(void) {
 	puts("G - G Programming Language\n");
 	puts("Usage: g\n");
 	puts("Options:");
-	puts("  --help        Display help information");
-	puts("  --version     Display version information");
-	puts("  --debug-lex   Print lexer debug output and exit");
-	puts("  --debug-parse Print parser debug output and exit");
+	puts("  --help          Display help information");
+	puts("  --version       Display version information");
+	puts("  --debug-lex     Print lexer debug output and exit");
+	puts("  --debug-parse   Print parser debug output and exit");
+	puts("  --debug-analyse Print analysis debug output and exit");
 }
 
 /* Print version information. */
diff --git a/src/symbol.c b/src/symbol.c
index dfbc25b..e3bb6bd 100644
--- a/src/symbol.c
+++ b/src/symbol.c
@@ -160,10 +160,8 @@ ast *syt_search_h(syt *st, u64 h, char *k) {
 /* Print a basic representation of a map to stdout. */
 void syt_print(syt *st) {
 	for (UINT i = 0; i < st->ac; i += 1) if (st->a[i].h != 0) {
-		if (st->a[i].v->c.a[0]->t) {
-			printf("%s -> %s\n", st->a[i].k, st->a[i].v->c.a[0]->t->s);
-		}
-		else { printf("%s -> unknown type\n", st->a[i].k); }
+		if (st->a[i].v->t) { printf("%s -> %s\n", st->a[i].k, st->a[i].v->t->s); }
+		else { printf("%s -> (null)\n", st->a[i].k); }
 	}
 }