Author | Jakob Wakeling <[email protected]> |
Date | 2023-07-14 08:49:59 |
Commit | 3c485fcedc4c3a106c6ebe5103abe4db86c2b2f2 |
Parent | 1544347804b7a223b8dc012a622ed61ae77eb068 |
Implicity cast procedure arguments if safe
Diffstat
A | examples/Test.sh | | | 16 | ++++++++++++++++ |
M | examples/io.g | | | 8 | ++++---- |
M | examples/main.g | | | 4 | ++-- |
R | examples/map.g -> examples/map.g.theoretical | | | 0 | |
M | src/analyse.c | | | 75 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- |
M | src/init.c | | | 5 | +++++ |
M | src/llvm.c | | | 54 | +++++++++++++++++++++++------------------------------- |
M | src/main.c | | | 1 | + |
M | src/parse.c | | | 114 | ++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------- |
M | src/parse.h | | | 10 | +++++++--- |
M | src/type.c | | | 6 | +++--- |
M | src/type.h | | | 4 | +++- |
12 files changed, 203 insertions, 94 deletions
diff --git a/examples/Test.sh b/examples/Test.sh new file mode 100755 index 0000000..bf47ccb --- /dev/null +++ b/examples/Test.sh @@ -0,0 +1,16 @@ +#!/bin/sh +# Shell script to compile all example programs and report on failure + +DIR="$(dirname "$(realpath "$0")")"; cd "$DIR" + +for f in *.g; do + [ -f "$f" ] || break + ../bin/g "$f" > /dev/null 2>&1 + if [ $? -eq 0 ]; then + printf "\e[1;32m[OKAY]\e[0m $f\n" + else + printf "\e[1;31m[FAIL]\e[0m $f\n" + fi +done + +rm *.o diff --git a/examples/io.g b/examples/io.g index a8bfe87..9427d7a 100644 --- a/examples/io.g +++ b/examples/io.g @@ -1,10 +1,10 @@ main :: proc() -> sint { - file : [6]u8 = { 'g', '.', 't', 'x', 't', '\0' }; - buf : [7]u8 = { 'O', 'u', 't', 'p', 'u', 't', '\n' }; + file : string = "g.txt"; + body : string = "Output\n"; /* Open file with O_WRONLY and O_CREAT flags */ - fd : sint = #syscall(uint(2), ptr(file), s32(0b1000010), u16(0o644)); - r : sint = #syscall(uint(1), fd, ptr(buf), uint(7)); + fd : sint = #syscall(uint(2), cstring(file), s32(0b1000010), u16(0o644)); + r : sint = #syscall(uint(1), fd, cstring(body), len(body)); #syscall(uint(3), fd); return r; diff --git a/examples/main.g b/examples/main.g index 61553d8..4ae7e76 100644 --- a/examples/main.g +++ b/examples/main.g @@ -1,7 +1,7 @@ -add3 :: proc(x: u8, y: u8, z: u8) -> u8 { +add3 :: proc(x: uint, y: uint, z: uint) -> uint { return x + y + z; } -main :: proc() -> u8 { +main :: proc() -> uint { return add3(1, 2, 3); } diff --git a/examples/map.g b/examples/map.g.theoretical similarity index 100% rename from examples/map.g rename to examples/map.g.theoretical diff --git a/src/analyse.c b/src/analyse.c index 0178a82..21647a8 100644 --- a/src/analyse.c +++ b/src/analyse.c @@ -31,7 +31,7 @@ static void analyse_expr_hash(ast *a, syt *st); /* Analyse a program. */ void analyse(ast *a) { - for (UINT i = 0; i < A.c.al; i += 1) { analyse_stmt_decl(C[i], &A.st); } + for (UINT i = 0; i < CL; i += 1) { analyse_stmt_decl(C[i], &A.st); } } /* Analyse a statement. */ @@ -50,7 +50,7 @@ static void analyse_stmt(ast *a, syt *st) { static inline void analyse_stmt_comp(ast *a, syt *st) { assert(A.k == AK_COMP); - for (UINT i = 0; i < A.c.al; i += 1) { analyse_stmt(C[i], &A.st); } + for (UINT i = 0; i < CL; i += 1) { analyse_stmt(C[i], &A.st); } } /* Analyse a declaration statement. */ @@ -61,7 +61,10 @@ static void analyse_stmt_decl(ast *a, syt *st) { analyse_expr(C[0], st); type *value_type = ast_type(C[0], st); - if (C[0]->k == AK_PROC) { return; /* TODO */ } + if (C[0]->k == AK_PROC) { + A.t = &TYPE(TY_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; } @@ -153,12 +156,21 @@ static void analyse_stmt_for(ast *a, syt *st) { /* Analyse an expression. */ static void analyse_expr(ast *a, syt *st) { switch (A.k) { + case AK_ID: { + ast *sy = syt_search_h(st, A.h, A.s); + if (sy == NULL) { note("TODO", A.ln, A.cl, 0, "Use of undeclared identifier \"%s\"", A.s); } + else { A.t = sy->t; } + } break; + case AK_PROC: { analyse_expr_proc(a, st); } break; + case AK_HASH: { analyse_expr_hash(a, st); } break; case AK_CALL: { assert(CL >= 1); assert(C[0]->k == AK_ID); assert(C[0]->h != 0); assert(C[0]->s != NULL); + analyse_expr(C[0], st); type *t = C[0]->t; + ast *sym = syt_search_h(st, C[0]->h, C[0]->s); if (sym == NULL) { note("TODO", A.ln, A.cl, 0, "Use of undeclared identifier \"%s\"", C[0]->s); } @@ -167,7 +179,37 @@ static void analyse_expr(ast *a, syt *st) { if (CL > 2) { note("TODO", A.ln, A.cl, 0, "Type casts must only have a single argument"); } } else if (sym->k == AK_PROC) { A.k = AK_BUILTIN; A.t = sym->t; } - } goto childs; + + for (UINT i = 1; i < CL; i += 1) { analyse_expr(C[i], st); } + + if (is_proc(t)) { + register ast **av = sym->c.a[0]->c.a; register UINT ac = sym->c.a[0]->c.al; + for (UINT i = 0; i < ac - 1; i += 1) { + if (is_equal(C[i + 1]->t, av[i]->t)) { /* Ignored */ } + else if (is_com(C[i + 1]->t, av[i]->t)) { + if (C[i + 1]->t->l <= av[i]->t->l) { + ast *cast = ast_init(AK_CAST, C[i + 1]->ln, C[i + 1]->cl); cast->t = av[i]->t; + ast *child = C[i + 1]; + + ast_wrap(a, child, cast); + } + else { + note( + "TODO", C[i + 1]->ln, C[i + 1]->cl, 0, + "Implicit cast from %s to %s would cause loss of information", + C[i + 1]->t->s, av[i]->t->s + ); + } + } + else { + note( + "TODO", C[i + 1]->ln, C[i + 1]->cl, 0, "Explicit cast required from %s to %s", + C[i + 1]->t->s, av[i]->t->s + ); + } + } + } + } break; case AK_SUBS: { assert(CL == 2); @@ -175,15 +217,25 @@ static void analyse_expr(ast *a, syt *st) { note("TODO", A.ln, A.cl, 0, "Expression must have integral type"); } } break; - case AK_PROC: { analyse_expr_proc(a, st); } break; - case AK_HASH: { analyse_expr_hash(a, st); } break; - case AK_OP_ADO: { A.t = type_ptr(ast_type(C[0], st), 1); } goto childs; - case AK_OP_DRF: { A.t = ast_type(C[0], st)->base; } goto childs; - childs: default: { for (UINT i = 0; i < CL; i += 1) { analyse_expr(C[i], st); }} break; + case AK_POS: case AK_NEG: case AK_LO_NOT: case AK_BW_NOT: { + analyse_expr(C[0], st); A.t = ast_type(C[0], st); + } break; + case AK_ADO: { analyse_expr(C[0], st); A.t = type_ptr(ast_type(C[0], st), 1); } break; + case AK_DRF: { analyse_expr(C[0], st); A.t = ast_type(C[0], st)->base; } break; + case AK_ASSIGN: case AK_AS_ADD: case AK_AS_SUB: case AK_AS_MUL: case AK_AS_DIV: case AK_AS_MOD: { + for (UINT i = 0; i < CL; i += 1) { analyse_expr(C[i], st); } A.t = ast_type(C[0], st); + } break; + case AK_ADD: case AK_SUB: case AK_MUL: case AK_DIV: case AK_MOD: { + for (UINT i = 0; i < CL; i += 1) { analyse_expr(C[i], st); } A.t = ast_type(C[0], st); + } break; + case AK_EQ: case AK_NE: case AK_LT: case AK_LE: case AK_GT: case AK_GE: { + for (UINT i = 0; i < CL; i += 1) { analyse_expr(C[i], st); } A.t = &TYPE(TY_BOOL); + } break; + default: { for (UINT i = 0; i < CL; i += 1) { analyse_expr(C[i], st); }} break; } } -/* Analyse a procedure expression. */ +/* Analyse a procedure expression. AK_PROC has a scope. */ static void analyse_expr_proc(ast *a, syt *st) { assert(A.k == AK_PROC); @@ -193,7 +245,7 @@ static void analyse_expr_proc(ast *a, syt *st) { } /* Analyse the procedure body */ - analyse_stmt_comp(C[CL - 1], st); + analyse_stmt_comp(C[CL - 1], &A.st); } /* Analyse a hash expression. */ diff --git a/src/init.c b/src/init.c index c3a0dc1..f6832d7 100644 --- a/src/init.c +++ b/src/init.c @@ -59,6 +59,11 @@ void initialise(void) { kwds[i].h = syt_hash(kwds[i].s, strlen(kwds[i].s)); syt_insert_h(&kwt, kwds[i].h, kwds[i].s, &kwds[i]); } + + /* Set the size of word sized types */ + /* TODO don't hardcode */ + TYPE(TY_UINT).l = 8; + TYPE(TY_SINT).l = 8; } void uninitialise(void) { syt_free(&kwt); } diff --git a/src/llvm.c b/src/llvm.c index 6522299..0d61033 100644 --- a/src/llvm.c +++ b/src/llvm.c @@ -68,7 +68,7 @@ void llvm(ast *a, char *file, llvm_action action) { switch (action) { case llvm_obj: case llvm_asm: { - // if (failed) { break; } /* Don't compile after failure */ + if (failed) { exit(2); } /* Don't compile after failure */ char *triple = LLVMGetDefaultTargetTriple(); printf("Target: %s\n", triple); @@ -167,15 +167,7 @@ static LLVMValueRef llvm_stmt_decl(ast *a, syt *st) { } else /* Local */ { LLVMValueRef v = LLVMBuildAlloca(llvm_builder, llvm_type(A.t), ""); - - if (A.t->k == TY_STRING) { - LLVMBuildMemCpy( - llvm_builder, v, 8, CL ? llvm_expr(C[0], st, true) : llvm_ival(A.t), 8, - LLVMConstInt(LLVMIntType(64), 16, false) - ); - } - else { LLVMBuildStore(llvm_builder, CL ? llvm_expr(C[0], st, true) : llvm_ival(A.t), v); } - + LLVMBuildStore(llvm_builder, CL ? llvm_expr(C[0], st, true) : llvm_ival(A.t), v); A.llvm_v = v; } } @@ -286,8 +278,8 @@ static LLVMValueRef llvm_expr(ast *a, syt *st, bool load) { else { return LLVMBuildLoad2(llvm_builder, llvm_type(ast_type(C[0], st)->base), vr, ""); } } - case AK_OP_POS: { a = C[0]; goto reset; /* no-op */ } break; - case AK_OP_NEG: { + case AK_POS: { a = C[0]; goto reset; /* no-op */ } break; + case AK_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)"); } @@ -295,8 +287,8 @@ static LLVMValueRef llvm_expr(ast *a, syt *st, bool load) { else if (is_flt(t)) { return LLVMBuildFNeg(llvm_builder, llvm_expr(C[0], st, true), "neg"); } else { note(file_name, A.ln, A.cl, -1, "Expression cannot be made negative (llvm:llvm_expr)"); } } break; - case AK_OP_ADO: { return llvm_expr(C[0], st, false); } break; - case AK_OP_DRF: { + case AK_ADO: { return llvm_expr(C[0], st, false); } break; + case AK_DRF: { type *t = ast_type(C[0], st); if (t == NULL) { note(file_name, A.ln, A.cl, -1, "Child is missing a type (llvm:llvm_expr)"); } if (t->base == NULL) { note(file_name, A.ln, A.cl, -1, "Cannot be dereferenced (llvm:llvm_expr)"); } @@ -305,19 +297,19 @@ static LLVMValueRef llvm_expr(ast *a, syt *st, bool load) { else { return LLVMBuildLoad2(llvm_builder, llvm_type(t->base), llvm_expr(C[0], st, true), ""); } } - case AK_OP_ADD: { + case AK_ADD: { if (is_int(ast_type(C[0], st))) { return LLVMBuildAdd(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); } else if (is_flt(ast_type(C[0], st))) { return LLVMBuildFAdd(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); } } break; - case AK_OP_SUB: { + case AK_SUB: { if (is_int(ast_type(C[0], st))) { return LLVMBuildSub(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); } else if (is_flt(ast_type(C[0], st))) { return LLVMBuildFSub(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); } } break; - case AK_OP_MUL: { + case AK_MUL: { if (is_int(ast_type(C[0], st))) { return LLVMBuildMul(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); } else if (is_flt(ast_type(C[0], st))) { return LLVMBuildFMul(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); } } break; - case AK_OP_DIV: { + case AK_DIV: { register type *t = ast_type(C[0], st); if (is_int(t)) { if (is_sign(t)) { return LLVMBuildSDiv(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); } @@ -325,7 +317,7 @@ static LLVMValueRef llvm_expr(ast *a, syt *st, bool load) { } else if (is_flt(t)) { return LLVMBuildFDiv(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); } } break; - case AK_OP_MOD: { + case AK_MOD: { register type *t = ast_type(C[0], st); if (is_int(t)) { if (is_sign(t)) { return LLVMBuildSRem(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); } @@ -445,36 +437,37 @@ static LLVMValueRef llvm_expr_proc(ast *a, syt *st) { /* Generate IR for a type cast. */ static LLVMValueRef llvm_expr_cast(ast *a, syt *st) { assert(A.t != NULL); - assert(CL == 2); + assert(CL == 1 || CL == 2); - type *expr_type = ast_type(C[1], st); + ast *c = CL == 1 ? C[0] : C[1]; + type *expr_type = ast_type(c, st); if (is_ptr(expr_type)) { - if (is_int(a->t)) { return LLVMBuildPtrToInt(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), ""); } + if (is_int(a->t)) { return LLVMBuildPtrToInt(llvm_builder, llvm_expr(c, st, true), llvm_type(a->t), ""); } } else if (is_bool(expr_type)) { - if (is_int(a->t)) { return LLVMBuildIntCast2(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), is_sign(a->t), ""); } + if (is_int(a->t)) { return LLVMBuildIntCast2(llvm_builder, llvm_expr(c, st, true), llvm_type(a->t), is_sign(a->t), ""); } } else if (is_int(expr_type)) { if (is_bool(a->t) || is_int(a->t)) { - return LLVMBuildIntCast2(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), is_sign(a->t), ""); + return LLVMBuildIntCast2(llvm_builder, llvm_expr(c, st, true), llvm_type(a->t), is_sign(a->t), ""); } else if (is_flt(a->t)) { - if (is_sign(expr_type)) { return LLVMBuildSIToFP(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), "stof"); } - else { return LLVMBuildUIToFP(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), "utof"); } + if (is_sign(expr_type)) { return LLVMBuildSIToFP(llvm_builder, llvm_expr(c, st, true), llvm_type(a->t), "stof"); } + else { return LLVMBuildUIToFP(llvm_builder, llvm_expr(c, st, true), llvm_type(a->t), "utof"); } } } else if (is_flt(expr_type)) { if (is_int(a->t)) { - if (is_sign(a->t)) { return LLVMBuildFPToSI(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), "ftos"); } - else { return LLVMBuildFPToUI(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), "ftou"); } + if (is_sign(a->t)) { return LLVMBuildFPToSI(llvm_builder, llvm_expr(c, st, true), llvm_type(a->t), "ftos"); } + else { return LLVMBuildFPToUI(llvm_builder, llvm_expr(c, st, true), llvm_type(a->t), "ftou"); } } - else if (is_flt(a->t)) { return LLVMBuildFPCast(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), "cast"); } + else if (is_flt(a->t)) { return LLVMBuildFPCast(llvm_builder, llvm_expr(c, st, true), llvm_type(a->t), "cast"); } } else if (expr_type->k == TY_ARR) { if (is_ptr(a->t)) { a->t->base = expr_type->base; - return LLVMBuildBitCast(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), ""); + return LLVMBuildBitCast(llvm_builder, llvm_expr(c, st, true), llvm_type(a->t), ""); } } diff --git a/src/main.c b/src/main.c index d51477b..cfa2372 100644 --- a/src/main.c +++ b/src/main.c @@ -84,6 +84,7 @@ static void compile(const char * file, char *src, UINT len) { else if (Bflag) { llvm(a, strdup(file), llvm_bc); } else if (Sflag) { llvm(a, strdup(file), llvm_asm); } else { llvm(a, strdup(file), llvm_obj); } + if (has_error()) { exit(1); } end:; return; } diff --git a/src/parse.c b/src/parse.c index 71035ca..cd94f54 100644 --- a/src/parse.c +++ b/src/parse.c @@ -19,7 +19,9 @@ typedef struct { type *t; ast *a; } ta_pair; char *ast_ks[] = { - "AK_VOID", "AK_PROG", "AK_PROC", "AK_TYPE", "AK_CAST", + "AK_VOID", "AK_PROG", "AK_ID", "AK_BOOL", "AK_INT", "AK_FLT", "AK_STR", + + "AK_PROC", "AK_TYPE", "AK_CAST", "AK_COMP", "AK_DECL", "AK_RETURN", "AK_IF", "AK_FOR", @@ -33,7 +35,7 @@ char *ast_ks[] = { "AK_ASSIGN", "AK_AS_ADD", "AK_AS_SUB", "AK_AS_MUL", "AK_AS_DIV", "AK_AS_MOD", - "AK_ID", "AK_CALL", "AK_BOOL", "AK_INT", "AK_FLT", "AK_ARR", "AK_SUBS", "AK_STR", + "AK_CALL", "AK_ARR", "AK_SUBS", "AK_HASH", "AK_HASH_SYSCALL", "AK_BUILTIN" }; @@ -53,8 +55,8 @@ static ast *parse_expr_proc(lex *l, syt *st); static inline ta_pair parse_type(lex *l, syt *st); -static ast *parse_int(lex *l, syt *st); -static ast *parse_flt(lex *l, syt *st); +static inline ast *parse_int(lex *l, syt *st); +static inline ast *parse_flt(lex *l, syt *st); static s32 tok_precedence(tok_k tk); static s32 ast_precedence(ast_k ak); @@ -63,7 +65,7 @@ static inline char *strdup_or_fail(const char *s); /* Initialise an AST node. */ inline ast *ast_init(ast_k kind, UINT ln, UINT cl) { - ast *a = calloc(1, sizeof (*a)); if (a == NULL) { error(1, SERR); } + ast *a = calloc(1, sizeof (*a)); if (a == NULL) { panic(SERR); } a->k = kind; a->ln = ln; a->cl = cl; return a; } @@ -79,7 +81,7 @@ void ast_push(ast *a, ast *c) { assert(a != NULL); assert(c != NULL); ast **ca = realloc(a->c.a, (a->c.al += 1) * sizeof (ast *)); - if (!ca) { error(1, SERR); } else { a->c.a = ca; ca = NULL; } + if (!ca) { panic(SERR); } else { a->c.a = ca; ca = NULL; } /* Store pointer from parent to child and vice versa */ assert(c->p == NULL); @@ -91,10 +93,10 @@ void ast_displace(ast *a, ast *c) { ast **oa = a->c.a; UINT ol = a->c.al; bool found = false; for (UINT i = 0; i < ol; i += 1) { if (oa[i] == c) { found = true; break; }} - if (found == false) { return; } + if (!found) { return; } ast **ca = calloc((a->c.al -= 1), sizeof (ast *)); - if (!ca) { error(1, SERR); } else { a->c.a = ca; ca = NULL; } + if (!ca) { panic(SERR); } else { a->c.a = ca; ca = NULL; } for (UINT i = 0, j = 0; i < ol && j < a->c.al; i += 1) { if (oa[i] == c) { continue; } a->c.a[j] = oa[i]; j += 1; @@ -103,7 +105,22 @@ void ast_displace(ast *a, ast *c) { c->p = NULL; free(oa); } +/* Insert a wrapper AST node between a child and its parent. */ +void ast_wrap(ast *const a, ast *const c, ast *const w) { + assert(a != NULL); assert(c != NULL); assert(w != NULL); + ast **oa = a->c.a; UINT ol = a->c.al, ifound; bool found = false; + + for (UINT i = 0; i < ol; i += 1) { if (oa[i] == c) { found = true; ifound = i; break; }} + if (!found) { panic("ast_wrap called with an unrelated parent and child"); } + + w->p = a; a->c.a[ifound] = w; c->p = NULL; ast_push(w, c); +} + +/* Get the type of an AST node. */ type *ast_type(ast *a, syt *st) { + /* If the given node has a type, then return that */ + if (a->t && !is_proc(a->t)) { return a->t; } + /* Search the symbol table for a type first */ if (a->s) { ast *sym = syt_search(st, a->s); @@ -113,9 +130,6 @@ type *ast_type(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) { type *rt = ast_type(a->c.a[0], st); @@ -139,6 +153,8 @@ ast *ast_a_pop(ast_a *aa) { } #define T (l->t) /* lex_peek equivalent */ +#define C(ast) (ast->c.a) /* AST child shorthand "C(a)[i]" */ +#define CL(ast) (ast->c.al) /* AST child array length shorthand */ /* Parse a program. */ ast *parse(lex *l) { @@ -196,7 +212,7 @@ static ast *parse_stmt_compound(lex *l, syt *st) { /* Parse a declaration statement. */ static ast *parse_stmt_decl(lex *l, syt *st, bool scolon) { ast *a = ast_init(AK_DECL, T.ln, T.cl); a->h = T.h; a->s = T.s; - assert(T.k == TK_ID); lex_next(l); assert(T.k == TK_COLON); lex_next(l); + lex_kind(l, TK_ID); lex_kind(l, TK_COLON); /* Store the declaration's type if one is specified */ if (T.k == TK_ID || T.k == TK_MUL || T.k == TK_LBRACK) { @@ -208,8 +224,8 @@ static ast *parse_stmt_decl(lex *l, syt *st, bool scolon) { if (T.k == TK_COLON || T.k == TK_ASSIGN) { lex_next(l); ast_push(a, parse_expr(l, st, 0)); } /* Ensure that a type is known and consume a semicolon if one is required */ - if (a->t == NULL && a->c.al == 0) { note(l->n, T.ln, T.cl, 0, "A declaration without a type is invalid"); } - if (scolon && (a->c.al < 1 || a->c.a[0]->k != AK_PROC)) { lex_kind(l, TK_SCOLON); } + if (a->t == NULL && CL(a) == 0) { note(l->n, T.ln, T.cl, 0, "A declaration without a type is invalid"); } + if (scolon && (CL(a) < 1 || C(a)[0]->k != AK_PROC)) { lex_kind(l, TK_SCOLON); } /* Insert the new symbol and return */ syt_insert_h(st, a->h, a->s, a); return a; @@ -302,11 +318,16 @@ static ast *parse_expr(lex *l, syt *st, s32 o) { left = ast_init(AK_ID, T.ln, T.cl); left->h = T.h; left->s = strdup_or_fail(T.s); lex_next(l); } break; - case TK_TRUE: { left = ast_init(AK_BOOL, T.ln, T.cl); left->v_bool = true; } goto boolean; - case TK_FALSE: { left = ast_init(AK_BOOL, T.ln, T.cl); left->v_bool = false; } goto boolean; - boolean: { left->t = &TYPE(TY_BOOL); lex_next(l); } break; - case TK_INT: { left = parse_int(l, st); } break; - case TK_FLT: { left = parse_flt(l, st); } break; + case TK_TRUE: { + left = ast_init(AK_BOOL, T.ln, T.cl); + left->t = &TYPE(TY_BOOL); left->v_bool = true; lex_next(l); + } break; + case TK_FALSE: { + left = ast_init(AK_BOOL, T.ln, T.cl); + left->t = &TYPE(TY_BOOL); left->v_bool = false; lex_next(l); + } break; + case TK_INT: { left = parse_int(l, st); } break; + case TK_FLT: { left = parse_flt(l, st); } break; case TK_STR: { left = ast_init(AK_STR, T.ln, T.cl); left->h = T.h; left->s = strdup_or_fail(T.s); left->t = &TYPE(TY_STRING); lex_next(l); @@ -318,12 +339,12 @@ static ast *parse_expr(lex *l, syt *st, s32 o) { left->h = T.h; left->s = strdup_or_fail(T.s); lex_kind(l, TK_ID); } break; case TK_LPAREN: { lex_next(l); left = parse_expr(l, st, 0); lex_kind(l, TK_RPAREN); } break; - case TK_ADD: { left = ast_init(AK_OP_POS, T.ln, T.cl); } goto prefix; - case TK_SUB: { left = ast_init(AK_OP_NEG, T.ln, T.cl); } goto prefix; + case TK_ADD: { left = ast_init(AK_POS, T.ln, T.cl); } goto prefix; + case TK_SUB: { left = ast_init(AK_NEG, T.ln, T.cl); } goto prefix; case TK_EMARK: { left = ast_init(AK_LO_NOT, T.ln, T.cl); } goto prefix; case TK_TILDE: { left = ast_init(AK_BW_NOT, T.ln, T.cl); } goto prefix; - case TK_BW_AND: { left = ast_init(AK_OP_ADO, T.ln, T.cl); } goto prefix; - case TK_MUL: { left = ast_init(AK_OP_DRF, T.ln, T.cl); } goto prefix; + case TK_BW_AND: { left = ast_init(AK_ADO, T.ln, T.cl); } goto prefix; + case TK_MUL: { left = ast_init(AK_DRF, T.ln, T.cl); } goto prefix; prefix: { lex_next(l); ast_push(left, parse_expr(l, st, ast_precedence(left->k))); } break; default: { note(l->n, T.ln, T.cl, 0, "Unexpected \"%s\", was expecting an expression", tok_ks[T.k]); } break; } @@ -357,17 +378,17 @@ static ast *parse_expr(lex *l, syt *st, s32 o) { case TK_AS_MUL: { a = ast_init(AK_AS_MUL, T.ln, T.cl); } goto infix; case TK_AS_DIV: { a = ast_init(AK_AS_DIV, T.ln, T.cl); } goto infix; case TK_AS_MOD: { a = ast_init(AK_AS_MOD, T.ln, T.cl); } goto infix; - case TK_ADD: { a = ast_init(AK_OP_ADD, T.ln, T.cl); } goto infix; - case TK_SUB: { a = ast_init(AK_OP_SUB, T.ln, T.cl); } goto infix; - case TK_MUL: { a = ast_init(AK_OP_MUL, T.ln, T.cl); } goto infix; - case TK_DIV: { a = ast_init(AK_OP_DIV, T.ln, T.cl); } goto infix; - case TK_MOD: { a = ast_init(AK_OP_MOD, T.ln, T.cl); } goto infix; - case TK_EQ: { a = ast_init(AK_EQ, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; - case TK_NE: { a = ast_init(AK_NE, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; - case TK_LT: { a = ast_init(AK_LT, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; - case TK_LE: { a = ast_init(AK_LE, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; - case TK_GT: { a = ast_init(AK_GT, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; - case TK_GE: { a = ast_init(AK_GE, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; + case TK_ADD: { a = ast_init(AK_ADD, T.ln, T.cl); } goto infix; + case TK_SUB: { a = ast_init(AK_SUB, T.ln, T.cl); } goto infix; + case TK_MUL: { a = ast_init(AK_MUL, T.ln, T.cl); } goto infix; + case TK_DIV: { a = ast_init(AK_DIV, T.ln, T.cl); } goto infix; + case TK_MOD: { a = ast_init(AK_MOD, T.ln, T.cl); } goto infix; + case TK_EQ: { a = ast_init(AK_EQ, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; + case TK_NE: { a = ast_init(AK_NE, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; + case TK_LT: { a = ast_init(AK_LT, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; + case TK_LE: { a = ast_init(AK_LE, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; + case TK_GT: { a = ast_init(AK_GT, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; + case TK_GE: { a = ast_init(AK_GE, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; case TK_LO_AND: { a = ast_init(AK_LO_AND, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; case TK_LO_OR: { a = ast_init(AK_LO_OR, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; infix: { lex_next(l); ast_push(a, left); ast_push(a, parse_expr(l, st, ast_precedence(a->k))); } break; @@ -459,8 +480,8 @@ static inline ta_pair parse_type(lex *l, syt *st) { if (r == NULL) { return (ta_pair){ s->t, a }; } else { c->base = s->t; return (ta_pair){ r, a }; } } -/* Parse an integer. */ -static ast *parse_int(lex *l, syt *st) { +/* Parse an integer. AK_INT is terminal. */ +static inline ast *parse_int(lex *l, syt *st) { assert(T.k == TK_INT); tok t = lex_next(l); @@ -479,8 +500,8 @@ static ast *parse_int(lex *l, syt *st) { return a; } -/* Parse a floating-point number. */ -static ast *parse_flt(lex *l, syt *st) { +/* Parse a floating-point number. AK_FLT is terminal. */ +static inline ast *parse_flt(lex *l, syt *st) { assert(T.k == TK_FLT); tok t = lex_next(l); @@ -527,9 +548,9 @@ static s32 tok_precedence(tok_k tk) { static s32 ast_precedence(ast_k ak) { switch (ak) { case AK_CALL: case AK_SUBS: { return 8; } - case AK_OP_POS: case AK_OP_NEG: case AK_LO_NOT: case AK_BW_NOT: case AK_OP_ADO: case AK_OP_DRF: { return 7; } - case AK_OP_MUL: case AK_OP_DIV: case AK_OP_MOD: { return 6; } - case AK_OP_ADD: case AK_OP_SUB: { return 5; } + case AK_POS: case AK_NEG: case AK_LO_NOT: case AK_BW_NOT: case AK_ADO: case AK_DRF: { return 7; } + case AK_MUL: case AK_DIV: case AK_MOD: { return 6; } + case AK_ADD: case AK_SUB: { return 5; } case AK_EQ: case AK_NE: case AK_LT: case AK_LE: case AK_GT: case AK_GE: { return 4; } case AK_LO_AND: { return 3; } case AK_LO_OR: { return 2; } @@ -584,9 +605,9 @@ void ast_print(ast *a, UINT indent) { for (UINT i = 0; i < a->c.al; i += 1) { ast_print(a->c.a[i], indent + 1); } if (a->st.a != NULL) { - printf("--- SYT for %s \"%s\" ---\n", ast_ks[a->k], a->s); + printf("--- SYT for %s \"%s\"%s ---\n", ast_ks[a->k], a->s, a->st.pt == NULL ? " NO PARENT" : ""); syt_print(&a->st); - printf("--- SYT for %s \"%s\" ---\n", ast_ks[a->k], a->s); + printf("--- SYT for %s \"%s\"%s ---\n", ast_ks[a->k], a->s, a->st.pt == NULL ? " NO PARENT" : ""); } return; diff --git a/src/parse.h b/src/parse.h index fc75a35..0e4716c 100644 --- a/src/parse.h +++ b/src/parse.h @@ -15,12 +15,14 @@ /* Remember to update ast_ks in parse.c */ typedef enum { - AK_VOID, AK_PROG, AK_PROC, AK_TYPE, AK_CAST, + AK_VOID, AK_PROG, AK_ID, AK_BOOL, AK_INT, AK_FLT, AK_STR, + + AK_PROC, AK_TYPE, AK_CAST, AK_COMP, AK_DECL, AK_RETURN, AK_IF, AK_FOR, - AK_OP_POS, AK_OP_NEG, AK_OP_ADO, AK_OP_DRF, - AK_OP_ADD, AK_OP_SUB, AK_OP_MUL, AK_OP_DIV, AK_OP_MOD, + AK_POS, AK_NEG, AK_ADO, AK_DRF, + AK_ADD, AK_SUB, AK_MUL, AK_DIV, AK_MOD, AK_EQ, AK_NE, AK_LT, AK_LE, AK_GT, AK_GE, @@ -29,7 +31,7 @@ typedef enum { AK_ASSIGN, AK_AS_ADD, AK_AS_SUB, AK_AS_MUL, AK_AS_DIV, AK_AS_MOD, - AK_ID, AK_CALL, AK_BOOL, AK_INT, AK_FLT, AK_ARR, AK_SUBS, AK_STR, + AK_CALL, AK_ARR, AK_SUBS, AK_HASH, AK_HASH_SYSCALL, AK_BUILTIN } ast_k; @@ -56,6 +58,7 @@ extern void ast_free(ast **a); extern void ast_push(ast *a, ast *c); extern void ast_displace(ast *a, ast *c); +extern void ast_wrap(ast *const a, ast *const c, ast *const w); extern type *ast_type(ast *a, syt *st); extern void ast_a_push(ast_a *aa, ast *a); diff --git a/src/type.c b/src/type.c index 0bf3f62..3d44c1a 100644 --- a/src/type.c +++ b/src/type.c @@ -13,7 +13,7 @@ type types[] = { { TY_PTR, TF_PTR, -1, "ptr" }, { TY_ARR, 0, -1, "arr" }, { TY_TYPE, 0, -1, "type" }, - { TY_ANY, 0, -1, "any" }, + { TY_PROC, 0, -1, "proc" }, { TY_BOOL, TF_BOOL, 1, "bool" }, { TY_B8, TF_BOOL, 1, "b8" }, @@ -21,14 +21,14 @@ type types[] = { { TY_B32, TF_BOOL, 4, "b32" }, { TY_B64, TF_BOOL, 8, "b64" }, - { TY_UINT, TF_INT, -1, "uint" }, + { TY_UINT, TF_INT, -2, "uint" }, { TY_U8, TF_INT, 1, "u8" }, { TY_U16, TF_INT, 2, "u16" }, { TY_U32, TF_INT, 4, "u32" }, { TY_U64, TF_INT, 8, "u64" }, { TY_U128, TF_INT, 16, "u128" }, - { TY_SINT, TF_INT | TF_SIGN, -1, "sint" }, + { TY_SINT, TF_INT | TF_SIGN, -2, "sint" }, { TY_S8, TF_INT | TF_SIGN, 1, "s8" }, { TY_S16, TF_INT | TF_SIGN, 2, "s16" }, { TY_S32, TF_INT | TF_SIGN, 4, "s32" }, diff --git a/src/type.h b/src/type.h index 32d8296..93eeb5f 100644 --- a/src/type.h +++ b/src/type.h @@ -11,7 +11,7 @@ #define TYPE(a) (types[a]) typedef enum { - TY_VOID, TY_PTR, TY_ARR, TY_TYPE, TY_ANY, + TY_VOID, TY_PTR, TY_ARR, TY_TYPE, TY_PROC, TY_BOOL, TY_B8, TY_B16, TY_B32, TY_B64, @@ -71,4 +71,6 @@ extern bool is_sign(type *t); extern bool is_equal(type *t1, type *t2); extern bool is_com(type *t1, type *t2); +#define is_proc(t) (t->k == TY_PROC) + #endif // G_TYPE_H_QHH0TJJQ