Author | Jakob Wakeling <[email protected]> |
Date | 2022-04-12 13:18:27 |
Commit | a47f6532e4d1c1d6af1d4c443e4e0d28f2bbd5d9 |
Parent | 895c21f5f5943231651252c3093f5f4aebc78753 |
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); } } }