Author | Jakob Wakeling <[email protected]> |
Date | 2023-06-20 12:35:52 |
Commit | 861312df2e6595ce69883e19124fd938e76939d4 |
Parent | f782ab77f3815498c6a66fa186799d604ac01196 |
Implement address of and dereference code gen
Diffstat
M | examples/main.g | | | 7 | ++++--- |
M | src/analyse.c | | | 14 | ++++++-------- |
M | src/llvm.c | | | 77 | +++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------ |
M | src/llvm.h | | | 5 | +++-- |
M | src/log.c | | | 3 | +++ |
M | src/log.h | | | 1 | + |
M | src/main.c | | | 8 | +++++--- |
M | src/parse.c | | | 43 | +++++++++++++++++-------------------------- |
M | src/parse.h | | | 2 | ++ |
M | src/type.c | | | 4 | ++++ |
M | src/type.h | | | 4 | +++- |
11 files changed, 101 insertions, 67 deletions
diff --git a/examples/main.g b/examples/main.g index bb04a56..ca0c6c4 100644 --- a/examples/main.g +++ b/examples/main.g @@ -1,4 +1,5 @@ -main :: proc() -> u32 { - var : *u32 = &u32(4); - return *var; +pepo :: proc() -> u64 { + var1 : f32 = f32(1.0); + var2 : *f32 = &var1; + return u64(var2); } diff --git a/src/analyse.c b/src/analyse.c index 5ee38bc..e77bd8e 100644 --- a/src/analyse.c +++ b/src/analyse.c @@ -16,7 +16,6 @@ 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_stmt_return(ast *a, syt *st); static void analyse_expr(ast *a, syt *st); @@ -39,7 +38,7 @@ static void analyse_stmt(ast *a, syt *st) { case AK_COMP: { analyse_stmt_comp(a, st); } break; case AK_DECL: { analyse_stmt_decl(a, st); } break; case AK_RETURN: { analyse_stmt_return(a, st); } break; - default: { analyse_stmt_expr(a, st); } break; + default: { analyse_expr(a, st); } break; } } @@ -102,19 +101,18 @@ static void analyse_stmt_decl(ast *a, syt *st) { else { note("TODO", a->ln, a->cl, -1, "unhandled value kind %s", ast_ks[a->c.a[0]->k]); } } -/* Analyse an expression statement. */ -static void analyse_stmt_expr(ast *a, syt *st) { - analyse_expr(a, st); -} - /* Analyse a return statement. */ static void analyse_stmt_return(ast *a, syt *st) { /* TODO Check if the return type matches or is compatible with the given value */ + analyse_expr(C[0], st); } /* Analyse an expression. */ static void analyse_expr(ast *a, syt *st) { if (A.k == AK_PROC) { analyse_expr_proc(a, st); } + if (A.k == AK_OP_DRF) { A.t = ast_type(C[0], st)->base; } + + for (UINT i = 0; i < A.c.al; i += 1) { analyse_expr(C[i], st); } } /* Analyse a procedure expression. */ diff --git a/src/llvm.c b/src/llvm.c index b3cb5fb..2b315a5 100644 --- a/src/llvm.c +++ b/src/llvm.c @@ -22,6 +22,7 @@ #include <stdlib.h> #include <string.h> +static char *file_name = NULL, *module_name = NULL; static LLVMContextRef llvm_context = NULL; static LLVMModuleRef llvm_module = NULL; static LLVMBuilderRef llvm_builder = NULL; @@ -44,7 +45,7 @@ static LLVMValueRef llvm_flt(ast *a); static LLVMValueRef llvm_hash(ast *a, syt *st); -static inline void llvm_init(void); +static inline void llvm_init(char *file); static inline void llvm_free(void); static LLVMTypeRef llvm_type(type *t); static LLVMValueRef llvm_ival(type *t); @@ -53,8 +54,8 @@ static LLVMValueRef llvm_ival(type *t); #define C (a->c.a) /* AST child shorthand "C[i]" */ /* Generate IR from an AST with LLVM. */ -void llvm(ast *a) { - llvm_init(); +void llvm(ast *a, char *file) { + llvm_init(file); /* Generate IR for all child nodes */ for (UINT i = 0; i < a->c.al; i += 1) { llvm_stmt_decl(a->c.a[i], &a->st); } @@ -85,8 +86,8 @@ void llvm(ast *a) { LLVMDisposeTargetMachine(machine); llvm_free(); } -void llvm_bitcode(ast *a) { - llvm_init(); +void llvm_bitcode(ast *a, char *file) { + llvm_init(file); /* Generate IR for all child nodes */ for (UINT i = 0; i < a->c.al; i += 1) { llvm_stmt_decl(a->c.a[i], &a->st); } @@ -100,8 +101,8 @@ void llvm_bitcode(ast *a) { LLVMDisposeMessage(err); llvm_free(); } -void llvm_ir(ast *a) { - llvm_init(); +void llvm_ir(ast *a, char *file) { + llvm_init(file); /* Generate IR for all child nodes */ for (UINT i = 0; i < a->c.al; i += 1) { llvm_stmt_decl(a->c.a[i], &a->st); } @@ -126,7 +127,7 @@ static LLVMValueRef llvm_stmt(ast *a, syt *st) { case AK_FOR: { return llvm_stmt_for(a, st); } break; case AK_HASH_SYSCALL: { return llvm_hash(a, st); } break; - default: { error(2, "llvm_stmt: Unhandled AST kind %s", ast_ks[a->k]); } break; + default: { note(file_name, a->ln, a->cl, -1, "Unhandled AST kind %s (llvm:llvm_stmt)", ast_ks[a->k]); } break; } } @@ -155,12 +156,12 @@ static LLVMValueRef llvm_stmt_decl(ast *a, syt *st) { } else { if (a->p->k == AK_PROG) { /* Global */ - LLVMValueRef v = LLVMAddGlobal(llvm_module, llvm_type(A.t), a->s); + LLVMValueRef v = LLVMAddGlobal(llvm_module, llvm_type(A.t), ""); LLVMSetInitializer(v, a->c.al ? llvm_expr(C[0], st) : llvm_ival(a->t)); a->llvm_v = v; } else { /* Local */ - LLVMValueRef v = LLVMBuildAlloca(llvm_builder, llvm_type(A.t), a->s); + LLVMValueRef v = LLVMBuildAlloca(llvm_builder, llvm_type(A.t), ""); LLVMBuildStore(llvm_builder, a->c.al ? llvm_expr(C[0], st) : llvm_ival(a->t), v); a->llvm_v = v; } @@ -181,7 +182,7 @@ static LLVMValueRef llvm_stmt_assn(ast *a, syt *st) { ); ast *v = syt_search(st, a->s); - if (v == NULL) { error(2, "llvm_expr: Undefined variable %s", a->s); } + if (v == NULL) { note(file_name, a->ln, a->cl, 0, "Undefined variable %s (LLVM Failsafe)", a->s); } switch (a->k) { case AK_ASSIGN: { @@ -244,9 +245,9 @@ static LLVMValueRef llvm_expr(ast *a, syt *st) { case AK_FLT: { return llvm_flt(a); } break; case AK_ID_VAR: { ast *v = syt_search(st, a->s); - if (v == NULL) { error(2, "llvm_expr: Undefined variable %s", a->s); } + if (v == NULL) { note(file_name, A.ln, A.cl, 0, "Undefined variable %s", A.s); } - return LLVMBuildLoad2(llvm_builder, llvm_type(v->t), v->llvm_v, v->s); + return LLVMBuildLoad2(llvm_builder, llvm_type(v->t), v->llvm_v, ""); } break; case AK_CALL: { ast *v = syt_search(st, a->s); @@ -254,7 +255,7 @@ static LLVMValueRef llvm_expr(ast *a, syt *st) { if (!v->llvm_v) { error(2, "llvm_expr: Procedure follows"); } - return LLVMBuildCall2(llvm_builder, v->llvm_t, v->llvm_v, NULL, 0, v->s); + return LLVMBuildCall2(llvm_builder, v->llvm_t, v->llvm_v, NULL, 0, ""); } break; case AK_OP_ADD: { return LLVMBuildAdd(llvm_builder, llvm_expr(A.c.a[0], st), llvm_expr(A.c.a[1], st), "add"); @@ -272,14 +273,27 @@ static LLVMValueRef llvm_expr(ast *a, syt *st) { return LLVMBuildSRem(llvm_builder, llvm_expr(A.c.a[0], st), llvm_expr(A.c.a[1], st), "mod"); } break; case AK_OP_NEG: { - type *t = ast_type(A.c.a[0], st); - if (t == NULL) { note("TODO", A.ln, A.cl, -1, "Subtree is missing a type"); } + type *t = ast_type(C[0], st); + if (t == NULL) { note(file_name, A.ln, A.cl, -1, "Subtree is missing a type (llvm:llvm_expr)"); } if (is_int(t)) { return LLVMBuildNeg(llvm_builder, llvm_expr(A.c.a[0], st), "neg"); } else if (is_flt(t)) { return LLVMBuildFNeg(llvm_builder, llvm_expr(A.c.a[0], st), "neg"); } - else { note("TODO", A.ln, A.cl, -1, "Expression cannot be made negative (LLVM Failsafe)"); } + else { note(file_name, A.ln, A.cl, -1, "Expression cannot be made negative (LLVM Failsafe)"); } + } break; + case AK_OP_ADO: { + ast *v = syt_search(st, C[0]->s); + if (v == NULL) { note(file_name, A.ln, A.cl, -1, "Undefined variable (llvm:llvm_expr)"); } + if (v->llvm_v == NULL) { note(file_name, A.ln, A.cl, -1, "Variable follows (llvm:llvm_expr)"); } + + return v->llvm_v; /* TODO handle non-variables (?) */ + } break; + case AK_OP_DRF: { + if (C[0]->t == NULL) { note(file_name, A.ln, A.cl, -1, "Child is missing a type (llvm:llvm_expr)"); } + if (C[0]->t->base == NULL) { note(file_name, A.ln, A.cl, -1, "Cannot be dereferenced (llvm:llvm_expr)"); } + + return LLVMBuildLoad2(llvm_builder, llvm_type(C[0]->t->base), llvm_expr(C[0], st), ""); } - default: { error(2, "llvm_expr unknown kind %s", ast_ks[a->k]); } break; + default: { note(file_name, A.ln, A.cl, -1, "Unhandled AST kind %s (llvm:llvm_expr)", ast_ks[a->k]); } break; } } @@ -294,7 +308,12 @@ static LLVMValueRef llvm_expr_cast(ast *a, syt *st) { type *expr_type = ast_type(C[0], st); - if (is_int(expr_type)) { + if (is_ptr(expr_type)) { + if (is_int(a->t)) { + return LLVMBuildPtrToInt(llvm_builder, llvm_expr(C[0], st), llvm_type(a->t), ""); + } + } + else if (is_int(expr_type)) { if (is_int(a->t)) { return LLVMBuildIntCast2(llvm_builder, llvm_expr(C[0], st), llvm_type(a->t), is_sign(a->t), "cast"); } @@ -321,7 +340,7 @@ static LLVMValueRef llvm_expr_cast(ast *a, syt *st) { } } - note("TODO", a->ln, a->cl, -1, "llvm_expr_cast unhandled type %s or %s", expr_type->s, a->t->s); + note(file_name, A.ln, A.cl, -1, "unhandled type %s or %s (llvm:llvm_expr_cast)", expr_type->s, a->t->s); } /* Generate IR for an integer. */ @@ -377,9 +396,10 @@ static LLVMValueRef llvm_hash(ast *a, syt *st) { } /* Initialise LLVM. */ -static inline void llvm_init(void) { +static inline void llvm_init(char *file) { + file_name = file; llvm_context = LLVMGetGlobalContext(); - llvm_module = LLVMModuleCreateWithName("G"); + llvm_module = LLVMModuleCreateWithName(file_name); llvm_builder = LLVMCreateBuilder(); } @@ -393,7 +413,8 @@ static inline void llvm_free(void) { /* Return the appropriate LLVMTypeRef for a G type. */ static LLVMTypeRef llvm_type(type *t) { switch (t->k) { - case TY_ZERO: { return LLVMVoidType(); } break; + case TY_VOID: { return LLVMVoidType(); } break; + case TY_PTR: { return LLVMPointerType(llvm_type(t->base), 0); } break; case TY_B8: { return LLVMIntType(8); } break; case TY_B16: { return LLVMIntType(16); } break; case TY_B32: { return LLVMIntType(32); } break; @@ -417,6 +438,7 @@ static LLVMTypeRef llvm_type(type *t) { /* Return the default value for a G type. */ static LLVMValueRef llvm_ival(type *t) { switch (t->k) { + case TY_PTR: { return LLVMConstNull(llvm_type(t->base)); } break; case TY_B8: { return LLVMConstInt(LLVMIntType(8), 0, false); } break; case TY_B16: { return LLVMConstInt(LLVMIntType(16), 0, false); } break; case TY_B32: { return LLVMConstInt(LLVMIntType(32), 0, false); } break; diff --git a/src/llvm.h b/src/llvm.h index c35ad06..3349152 100644 --- a/src/llvm.h +++ b/src/llvm.h @@ -8,8 +8,8 @@ #include "parse.h" -extern void llvm(ast *a); -extern void llvm_bitcode(ast *a); -extern void llvm_ir(ast *a); +extern void llvm(ast *a, char *file); +extern void llvm_bitcode(ast *a, char *file); +extern void llvm_ir(ast *a, char *file); #endif // G_LLVM_H_CZUMSHFW diff --git a/src/log.c b/src/log.c index b32eb2e..8166eff 100644 --- a/src/log.c +++ b/src/log.c @@ -29,3 +29,6 @@ void note(const char *file, UINT ln, UINT cl, sint level, const char *format, .. if (level == 0 && (log_count += 1) == log_limit) { fprintf(stderr, "fatal: error limit reached"); exit(1); } } + +/* Check if there has been an error. */ +bool has_error(void) { return log_count > 0; } diff --git a/src/log.h b/src/log.h index e469f35..bfb69d5 100644 --- a/src/log.h +++ b/src/log.h @@ -12,5 +12,6 @@ extern bool log_waerr; extern sint log_level, log_limit; extern void note(const char *file, UINT ln, UINT cl, sint level, const char *format, ...); +extern bool has_error(void); #endif // G_LOG_H_1RPM5P9E diff --git a/src/main.c b/src/main.c index 4e412fd..21552d4 100644 --- a/src/main.c +++ b/src/main.c @@ -77,12 +77,14 @@ static void compile(const char * file, char *src, UINT len) { ast *a = parse(&l); if (pflag) { if (!qflag) { ast_print(a, 0); } goto end; } + if (has_error()) { exit(1); } + analyse(a); if (Pflag) { if (!qflag) { ast_print(a, 0); } goto end; } - if (bflag) { llvm_ir(a); } - else if (Bflag) { llvm_bitcode(a); } - else { llvm(a); } + if (bflag) { llvm_ir(a, strdup(file)); } + else if (Bflag) { llvm_bitcode(a, strdup(file)); } + else { llvm(a, strdup(file)); } end:; return; } diff --git a/src/parse.c b/src/parse.c index 3274d20..ae3c65d 100644 --- a/src/parse.c +++ b/src/parse.c @@ -56,6 +56,10 @@ inline ast *ast_init(void) { if (!a) { error(1, SERR); } return a; } +inline void ast_free(ast **a) { + fprintf(stderr, "ast_free() NOT IMPLEMENTED\n"); /* TODO */ +} + /* Initialise an AST node of a specific kind. */ inline ast *ast_kind(ast_k kind) { ast *a = ast_init(); a->k = kind; return a; @@ -123,8 +127,8 @@ ast *parse(lex *l) { /* Parse and append all child nodes */ for (ast *c; T.k != TK_EOF;) { - if ((c = parse_stmt_decl(l, &a->st, NULL))) { ast_push(a, c); } - else { error(1, "NULL AST (parse:parse_stmt_decl)"); } + if ((c = parse_stmt_decl(l, &a->st, NULL)) != NULL) { ast_push(a, c); } + else { note(l->n, T.ln, T.cl, -1, "NULL AST (parse:parse_stmt_decl)"); } } return a; @@ -176,24 +180,18 @@ static ast *parse_stmt_decl(lex *l, syt *st, ast *a) { if (T.k == TK_ID) { ast *s = syt_search_h(st, T.h, T.s); - if (s == NULL) { error( /* ERROR */ - 1, "%s:%zu:%zu: error: use of undeclared identifier \"%s\"", - l->n, T.ln + 1, T.cl + 1, T.s - ); } - if (s->k != AK_TYPE) { error( /* ERROR */ - 1, "%s:%zu:%zu: error: expected type identifier", - l->n, T.ln + 1, T.cl + 1 - ); } + if (s == NULL) { note(l->n, T.ln, T.cl, 0, "Use of undeclared identifier \"%s\"", T.s); } + if (s->k != AK_TYPE) { note(l->n, T.ln, T.cl, 0, "Expected type identifier"); } a->t = type_ptrc(s->t, pn); lex_next(l); if (T.k == TK_SCOLON) { lex_next(l); goto end; } } - else if (pn != 0) { note(l->n, T.ln, T.cl, 1, "Expected a type identifier for pointer type"); } - else if (T.k == TK_SCOLON) { note(l->n, T.ln, T.cl, 1, "A declaration without a type is invalid"); } + else if (pn != 0) { note(l->n, T.ln, T.cl, 0, "Expected a type identifier for pointer type"); } + else if (T.k == TK_SCOLON) { note(l->n, T.ln, T.cl, 0, "A declaration without a type is invalid"); } /* Assign a constant or variable value */ if (T.k == TK_COLON || T.k == TK_ASSIGN) { lex_next(l); ast_push(a, parse_expr(l, st, 0)); } - else { error(1, "%s:%zu:%zu: error: expected ':' or '='", l->n, T.ln + 1, T.cl + 1); } + else { note(l->n, T.ln, T.cl, 0, "expected ':' or '='"); } /* Parse a semicolon if one is required */ if (a->c.a[0]->k != AK_PROC) { lex_kind(l, TK_SCOLON); } @@ -212,7 +210,7 @@ static ast *parse_stmt_assn(lex *l, syt *st, ast *a) { case TK_AS_DIV: { a->k = AK_AS_DIV; } goto expr; case TK_AS_MOD: { a->k = AK_AS_MOD; } goto expr; expr: { lex_next(l); ast_push(a, parse_expr(l, st, 0)); } break; - default: { error(1, "%s:%zu:%zu: error: expected assignment operator", l->n, T.ln + 1, T.cl + 1); } break; + default: { note(l->n, T.ln, T.cl, 0, "Expected assignment operator"); } break; } lex_kind(l, TK_SCOLON); return a; @@ -348,18 +346,12 @@ static ast *parse_expr_proc(lex *l, syt *st) { lex_next(l); tok t = lex_kind(l, TK_ID); ast *s = syt_search_h(st, t.h, t.s); - if (s == NULL) { error( /* ERROR */ - 1, "%s:%zu:%zu: error: use of undefined identifier \"%s\"", - l->n, T.ln + 1, T.cl + 1, t.s - ); } - if (s->k != AK_TYPE) { error( /* ERROR */ - 1, "%s:%zu:%zu: error: expected type identifier", - l->n, T.ln + 1, T.cl + 1 - ); } + if (s == NULL) { note(l->n, T.ln, T.cl, 0, "use of undefined identifier \"%s\"", t.s); } + if (s->k != AK_TYPE) { note(l->n, T.ln, T.cl, 0, "expected type identifier"); } a->t = s->t; } - else { a->t = &TYPE(TY_ZERO); } + else { a->t = &TYPE(TY_VOID); } ast_push(a, parse_stmt_compound(l, st)); return a; } @@ -447,7 +439,7 @@ void ast_print(ast *a, UINT i) { switch (a->k) { case AK_DECL: { if (a->t == NULL) { break; }} - case AK_PROC: case AK_CAST: case AK_INT: case AK_FLT: { + case AK_PROC: case AK_CAST: case AK_INT: case AK_FLT: case AK_OP_DRF: { printf(" -> %s", a->t != NULL ? a->t->s : "untyped"); if (a->t != NULL) for (type *t = a->t->base; t != NULL; t = t->base) { printf(" -> %s", t->s); diff --git a/src/parse.h b/src/parse.h index 203db0c..f5f6697 100644 --- a/src/parse.h +++ b/src/parse.h @@ -46,7 +46,9 @@ typedef struct { ast **a; UINT al; } ast_a; extern char *ast_ks[]; extern ast *ast_init(void); +extern void ast_free(ast **a); extern ast *ast_kind(ast_k kind); + extern void ast_push(ast *a, ast *c); extern void ast_displace(ast *a, ast *c); extern type *ast_type(ast *a, syt *st); diff --git a/src/type.c b/src/type.c index f5b7a4d..5f53617 100644 --- a/src/type.c +++ b/src/type.c @@ -9,7 +9,7 @@ #include <stdlib.h> type types[] = { - { TY_ZERO, 0, 0, "void" }, + { TY_VOID, 0, 0, "void" }, { TY_TYPE, 0, -1, "type" }, { TY_PTR, TF_PTR, -1, "ptr" }, { TY_AUTO, 0, -1, "auto" }, @@ -136,6 +136,9 @@ type *type_ptrc(type *base, u64 n) { return r; } +/* Check if a type is a pointer. */ +inline bool is_ptr(type *t) { return (t->f & TF_PTR); } + /* Check if a type is numerical. */ inline bool is_num(type *t) { return (t->f & TF_NUM); } diff --git a/src/type.h b/src/type.h index fc07919..afd19ce 100644 --- a/src/type.h +++ b/src/type.h @@ -11,7 +11,7 @@ #define TYPE(a) (types[a]) typedef enum { - TY_ZERO, TY_TYPE, TY_PTR, TY_AUTO, + TY_VOID, TY_TYPE, TY_PTR, TY_AUTO, TY_BOOL, TY_B8, TY_B16, TY_B32, TY_B64, @@ -65,6 +65,7 @@ extern type_a types_a; extern type *type_ptrc(type *base, u64 n); +extern bool is_ptr(type *t); extern bool is_num(type *t); extern bool is_int(type *t); extern bool is_flt(type *t);