Author | Jakob Wakeling <[email protected]> |
Date | 2023-06-22 03:15:33 |
Commit | 09e2c5c89f7c6842d18b03f11e2be6f0d859a54b |
Parent | e91c41c67b91e52b496da535c5e020965e7c19b5 |
Implement the bitwise not unary operator
Diffstat
D | doc/ast.md | | | 6 | ------ |
R | examples/hello_rudimentary.g -> examples/hello.g | | | 0 | |
M | examples/main.g | | | 7 | ++++--- |
M | src/analyse.c | | | 21 | +++++++++++---------- |
M | src/lex.c | | | 4 | ++-- |
M | src/llvm.c | | | 57 | ++++++++++++++++++++++++++++++++++++++++----------------- |
M | src/parse.c | | | 6 | ++++-- |
M | src/parse.h | | | 4 | ++-- |
8 files changed, 63 insertions, 42 deletions
diff --git a/doc/ast.md b/doc/ast.md deleted file mode 100644 index 3e65c48..0000000 --- a/doc/ast.md +++ /dev/null @@ -1,6 +0,0 @@ -# AST Structures - -## AK_DECL - -If an AST node of kind AK_DECL has a child, it shall be an expression representing the -initialisation value. diff --git a/examples/hello_rudimentary.g b/examples/hello.g similarity index 100% rename from examples/hello_rudimentary.g rename to examples/hello.g diff --git a/examples/main.g b/examples/main.g index ffc53d8..5cfdb4f 100644 --- a/examples/main.g +++ b/examples/main.g @@ -1,4 +1,5 @@ -main :: proc() -> u64 { - var := true; - return u64(var); +main :: proc() -> u8 { + var : u8 = u8(0b11111101); + inv : u8 = ~var; + return inv; } diff --git a/src/analyse.c b/src/analyse.c index 56683a6..6d5ba1d 100644 --- a/src/analyse.c +++ b/src/analyse.c @@ -45,13 +45,13 @@ static void analyse_stmt(ast *a, syt *st) { /* Analyse a compound statement. */ static inline void analyse_stmt_comp(ast *a, syt *st) { - for (UINT i = 0; i < A.c.al; i += 1) { analyse_stmt(A.c.a[i], st); } + for (UINT i = 0; i < A.c.al; i += 1) { analyse_stmt(A.c.a[i], &A.st); } } /* Analyse a declaration statement. */ static void analyse_stmt_decl(ast *a, syt *st) { assert(A.c.al == 0 || A.c.al == 1); - if (A.c.al == 0) { assert(a->t != NULL); return; } + if (A.c.al == 0) { assert(A.t != NULL); return; } analyse_expr(C[0], st); type *value_type = ast_type(C[0], st); @@ -59,7 +59,7 @@ static void analyse_stmt_decl(ast *a, syt *st) { if (C[0]->k == AK_PROC) { return; /* TODO */ } else if (is_bool(value_type)) { /* If a type has not been specified, set the type based on the value */ - if (a->t == NULL) { a->t = C[0]->t; } + if (A.t == NULL) { A.t = C[0]->t; } /* If the type has been specified, check that the value is compatible */ else { @@ -68,19 +68,19 @@ static void analyse_stmt_decl(ast *a, syt *st) { } else if (is_int(value_type)) { /* If a type has not been specified, set the type based on the value */ - if (a->t == NULL) { - a->t = C[0]->t; + if (A.t == NULL) { + A.t = C[0]->t; /* If the value type is smaller than 32 bit, upgrade it */ - if (a->t->l < 4) { - if (is_sign(a->t)) { a->t = &TYPE(TY_S32); } - else { a->t = &TYPE(TY_U32); } + if (A.t->l < 4) { + if (is_sign(A.t)) { A.t = &TYPE(TY_S32); } + else { A.t = &TYPE(TY_U32); } /* Insert a type cast node between parent and child */ /* FIXME this behaviour is incorrect, should only implicitely cast for literals, not all expressions */ ast *cast = ast_init(); cast->k = AK_CAST; cast->ln = C[0]->ln; cast->cl = C[0]->cl; - cast->t = a->t; + cast->t = A.t; ast *child = C[0]; @@ -97,7 +97,7 @@ static void analyse_stmt_decl(ast *a, syt *st) { } else if (is_flt(value_type)) { /* If a type has not been specified, set the type based on the value */ - if (a->t == NULL) { a->t = a->c.a[0]->t; } + if (A.t == NULL) { A.t = A.c.a[0]->t; } /* If the type has been specified, check that the value is compatible */ else { diff --git a/src/lex.c b/src/lex.c index a558be8..aac8c2c 100644 --- a/src/lex.c +++ b/src/lex.c @@ -75,7 +75,7 @@ tok lex_peek(lex *l) { return T; } /* Lex the next token, and return the current one. */ tok lex_next(lex *l) { - redo:; if (T.k == TK_EOF) { return T; } + reset:; if (T.k == TK_EOF) { return T; } tok t = T; T = (tok){ 0 }; /* Skip null characters and whitespace */ @@ -139,7 +139,7 @@ tok lex_next(lex *l) { for (P += 1; is_alpha(C) || is_digit_dec(C) || C == '_'; P += 1); sl = P - s; CL += sl; - if (sl <= 1) { note(l->n, T.ln, T.cl, 0, "A hash must be followed by an identifier"); goto redo; } + if (sl <= 1) { note(l->n, T.ln, T.cl, 0, "A hash must be followed by an identifier"); goto reset; } T.k = TK_HASH; T.h = syt_hash(s, sl); if (!(T.s = strndup(s, sl))) { error(1, SERR); } } diff --git a/src/llvm.c b/src/llvm.c index 416afa6..14bed4d 100644 --- a/src/llvm.c +++ b/src/llvm.c @@ -236,7 +236,7 @@ static LLVMValueRef llvm_stmt_for(ast *a, syt *st) { /* Generate IR for an expression. */ static LLVMValueRef llvm_expr(ast *a, syt *st) { - switch (A.k) { + reset:; switch (A.k) { case AK_PROC: { return llvm_expr_proc(a, st); } break; case AK_CAST: { return llvm_expr_cast(a, st); } break; case AK_BOOL: { return llvm_bool(a); } break; @@ -256,28 +256,44 @@ static LLVMValueRef llvm_expr(ast *a, syt *st) { return LLVMBuildCall2(llvm_builder, v->llvm_t, v->llvm_v, NULL, 0, ""); } break; + case AK_OP_POS: { a = C[0]; goto reset; /* no-op */ } + case AK_OP_NEG: { + 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(C[0], st), "neg"); } + else if (is_flt(t)) { return LLVMBuildFNeg(llvm_builder, llvm_expr(C[0], st), "neg"); } + else { note(file_name, A.ln, A.cl, -1, "Expression cannot be made negative (llvm:llvm_expr)"); } + } break; + case AK_BW_NOT: { + 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 LLVMBuildXor(llvm_builder, llvm_expr(C[0], st), LLVMConstInt(llvm_type(t), -1, false), ""); + } + else if (is_flt(t)) { + /* TODO should floating point numbers be invertable? */ + LLVMValueRef bc = LLVMBuildBitCast(llvm_builder, llvm_expr(C[0], st), LLVMIntType(t->l * 8), ""); + LLVMValueRef vr = LLVMBuildXor(llvm_builder, bc, LLVMConstInt(LLVMIntType(t->l * 8), -1, false), ""); + return LLVMBuildBitCast(llvm_builder, vr, llvm_type(t), ""); + } + else { note(file_name, A.ln, A.cl, -1, "Expression cannot be inverted (llvm:llvm_expr)"); } + } break; case AK_OP_ADD: { - return LLVMBuildAdd(llvm_builder, llvm_expr(A.c.a[0], st), llvm_expr(A.c.a[1], st), "add"); + return LLVMBuildAdd(llvm_builder, llvm_expr(C[0], st), llvm_expr(C[1], st), "add"); } break; case AK_OP_SUB: { - return LLVMBuildSub(llvm_builder, llvm_expr(A.c.a[0], st), llvm_expr(A.c.a[1], st), "sub"); + return LLVMBuildSub(llvm_builder, llvm_expr(C[0], st), llvm_expr(C[1], st), "sub"); } break; case AK_OP_MUL: { - return LLVMBuildMul(llvm_builder, llvm_expr(A.c.a[0], st), llvm_expr(A.c.a[1], st), "mul"); + return LLVMBuildMul(llvm_builder, llvm_expr(C[0], st), llvm_expr(C[1], st), "mul"); } break; case AK_OP_DIV: { - return LLVMBuildSDiv(llvm_builder, llvm_expr(A.c.a[0], st), llvm_expr(A.c.a[1], st), "div"); + return LLVMBuildSDiv(llvm_builder, llvm_expr(C[0], st), llvm_expr(C[1], st), "div"); } break; case AK_OP_MOD: { - 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(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(file_name, A.ln, A.cl, -1, "Expression cannot be made negative (LLVM Failsafe)"); } + return LLVMBuildSRem(llvm_builder, llvm_expr(C[0], st), llvm_expr(C[1], st), "mod"); } break; case AK_OP_ADO: { ast *v = syt_search(st, C[0]->s); diff --git a/src/parse.c b/src/parse.c index c800c0d..039c5ab 100644 --- a/src/parse.c +++ b/src/parse.c @@ -19,9 +19,9 @@ char *ast_ks[] = { "AK_VOID", "AK_PROG", "AK_PROC", "AK_TYPE", "AK_CAST", - "AK_STMT", "AK_COMP", "AK_DECL", "AK_RETURN", "AK_IF", "AK_FOR", + "AK_COMP", "AK_DECL", "AK_RETURN", "AK_IF", "AK_FOR", - "AK_OP_POS", "AK_OP_NEG", "AK_OP_ADO", "AK_OP_DRF", + "AK_OP_POS", "AK_OP_NEG", "AK_BW_NOT", "AK_OP_ADO", "AK_OP_DRF", "AK_OP_ADD", "AK_OP_SUB", "AK_OP_MUL", "AK_OP_DIV", "AK_OP_MOD", "AK_ASSIGN", "AK_AS_ADD", "AK_AS_SUB", "AK_AS_MUL", "AK_AS_DIV", "AK_AS_MOD", @@ -300,6 +300,7 @@ static ast *parse_expr(lex *l, syt *st, s32 o) { case TK_LPAREN: { lex_next(l); left = parse_expr(l, st, 0); lex_kind(l, TK_RPAREN); } break; case TK_OP_ADD: { left = ast_kind(AK_OP_POS); } goto prefix; case TK_OP_SUB: { left = ast_kind(AK_OP_NEG); } goto prefix; + case TK_BW_NOT: { left = ast_kind(AK_BW_NOT); } goto prefix; case TK_BW_AND: { left = ast_kind(AK_OP_ADO); } goto prefix; case TK_OP_MUL: { left = ast_kind(AK_OP_DRF); } goto prefix; prefix: { lex_next(l); ast_push(left, parse_expr(l, st, ast_precedence(left->k))); } break; diff --git a/src/parse.h b/src/parse.h index 25b2675..96f30af 100644 --- a/src/parse.h +++ b/src/parse.h @@ -18,9 +18,9 @@ typedef enum { AK_VOID, AK_PROG, AK_PROC, AK_TYPE, AK_CAST, - AK_STMT, AK_COMP, AK_DECL, AK_RETURN, AK_IF, AK_FOR, + AK_COMP, AK_DECL, AK_RETURN, AK_IF, AK_FOR, - AK_OP_POS, AK_OP_NEG, AK_OP_ADO, AK_OP_DRF, + AK_OP_POS, AK_OP_NEG, AK_BW_NOT, AK_OP_ADO, AK_OP_DRF, AK_OP_ADD, AK_OP_SUB, AK_OP_MUL, AK_OP_DIV, AK_OP_MOD, AK_ASSIGN, AK_AS_ADD, AK_AS_SUB, AK_AS_MUL, AK_AS_DIV, AK_AS_MOD,