Author | Jakob Wakeling <[email protected]> |
Date | 2023-07-01 07:14:24 |
Commit | 3f9a543df8693f7ebeb7492e4077a716ed3cfdc0 |
Parent | 828da145ae807f2023e1ef42127b5650c80e40c3 |
Implement array subscripting
Diffstat
M | examples/main.g | | | 6 | +++--- |
M | src/analyse.c | | | 8 | ++++++++ |
M | src/llvm.c | | | 156 | +++++++++++++++++++++++++++++++++++-------------------------------------------- |
M | src/parse.c | | | 22 | ++++++++++++++++------ |
M | src/parse.h | | | 2 | +- |
5 files changed, 98 insertions, 96 deletions
diff --git a/examples/main.g b/examples/main.g index 5cfdb4f..b4c85f3 100644 --- a/examples/main.g +++ b/examples/main.g @@ -1,5 +1,5 @@ main :: proc() -> u8 { - var : u8 = u8(0b11111101); - inv : u8 = ~var; - return inv; + var : [1]u8; + var[0] = 1; + return var[0]; } diff --git a/src/analyse.c b/src/analyse.c index 2f275d6..4f2a4a9 100644 --- a/src/analyse.c +++ b/src/analyse.c @@ -143,6 +143,7 @@ static void analyse_stmt_for(ast *a, syt *st) { static void analyse_expr(ast *a, syt *st) { switch (A.k) { case AK_CALL: { + assert(CL >= 1); assert(C[0]->k == AK_ID); assert(C[0]->h != 0); assert(C[0]->s != NULL); @@ -155,6 +156,13 @@ 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"); } } } break; + case AK_SUBS: { + assert(CL == 2); + + if (!is_int(ast_type(C[1], 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_OP_DRF: { A.t = ast_type(C[0], st)->base; } break; default: { for (UINT i = 0; i < CL; i += 1) { analyse_expr(C[i], st); }} break; diff --git a/src/llvm.c b/src/llvm.c index 01b71a3..77096a3 100644 --- a/src/llvm.c +++ b/src/llvm.c @@ -30,13 +30,12 @@ static LLVMBuilderRef llvm_builder = NULL; static LLVMValueRef llvm_stmt(ast *a, syt *st); static LLVMValueRef llvm_stmt_compound(ast *a, syt *st); static LLVMValueRef llvm_stmt_decl(ast *a, syt *st); -static LLVMValueRef llvm_stmt_assn(ast *a, syt *st); static LLVMValueRef llvm_stmt_expr(ast *a, syt *st); static LLVMValueRef llvm_stmt_return(ast *a, syt *st); static LLVMValueRef llvm_stmt_if(ast *a, syt *st); static LLVMValueRef llvm_stmt_for(ast *a, syt *st); -static LLVMValueRef llvm_expr(ast *a, syt *st); +static LLVMValueRef llvm_expr(ast *a, syt *st, bool load); static LLVMValueRef llvm_expr_proc(ast *a, syt *st); static LLVMValueRef llvm_expr_cast(ast *a, syt *st); @@ -123,11 +122,8 @@ static LLVMValueRef llvm_stmt(ast *a, syt *st) { case AK_RETURN: { return llvm_stmt_return(a, st); } break; case AK_IF: { return llvm_stmt_if(a, st); } break; case AK_FOR: { return llvm_stmt_for(a, st); } break; - case AK_ASSIGN: case AK_AS_ADD: case AK_AS_SUB: case AK_AS_MUL: case AK_AS_DIV: case AK_AS_MOD: - { return llvm_stmt_assn(a, st); } break; - case AK_HASH_SYSCALL: - { return llvm_hash(a, st); } break; - default: { return llvm_expr(a, st); } break; + case AK_HASH_SYSCALL: { return llvm_hash(a, st); } break; + default: { return llvm_expr(a, st, true); } break; } } @@ -154,12 +150,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), ""); - LLVMSetInitializer(v, CL ? llvm_expr(C[0], st) : llvm_ival(A.t)); + LLVMSetInitializer(v, CL ? llvm_expr(C[0], st, true) : llvm_ival(A.t)); A.llvm_v = v; } else { /* Local */ LLVMValueRef v = LLVMBuildAlloca(llvm_builder, llvm_type(A.t), ""); - LLVMBuildStore(llvm_builder, CL ? llvm_expr(C[0], st) : llvm_ival(A.t), v); + LLVMBuildStore(llvm_builder, CL ? llvm_expr(C[0], st, true) : llvm_ival(A.t), v); A.llvm_v = v; } } @@ -167,48 +163,6 @@ static LLVMValueRef llvm_stmt_decl(ast *a, syt *st) { return NULL; } -/* Generate IR for an assignment statement. */ -static LLVMValueRef llvm_stmt_assn(ast *a, syt *st) { - assert( - a->k == AK_ASSIGN || a->k == AK_AS_ADD || a->k == AK_AS_SUB || - a->k == AK_AS_MUL || a->k == AK_AS_DIV || a->k == AK_AS_MOD - ); - - ast *v = syt_search(st, C[0]->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: { - return LLVMBuildStore(llvm_builder, llvm_expr(C[1], st), v->llvm_v); - } break; - case AK_AS_ADD: { - LLVMValueRef vr = LLVMBuildLoad2(llvm_builder, llvm_type(v->t), v->llvm_v, v->s); - LLVMValueRef rr = LLVMBuildAdd(llvm_builder, vr, llvm_expr(C[1], st), "as_add"); - return LLVMBuildStore(llvm_builder, rr, v->llvm_v); - } break; - case AK_AS_SUB: { - LLVMValueRef vr = LLVMBuildLoad2(llvm_builder, llvm_type(v->t), v->llvm_v, v->s); - LLVMValueRef rr = LLVMBuildSub(llvm_builder, vr, llvm_expr(C[1], st), "as_sub"); - return LLVMBuildStore(llvm_builder, rr, v->llvm_v); - } break; - case AK_AS_MUL: { - LLVMValueRef vr = LLVMBuildLoad2(llvm_builder, llvm_type(v->t), v->llvm_v, v->s); - LLVMValueRef rr = LLVMBuildMul(llvm_builder, vr, llvm_expr(C[1], st), "as_mul"); - return LLVMBuildStore(llvm_builder, rr, v->llvm_v); - } break; - case AK_AS_DIV: { - LLVMValueRef vr = LLVMBuildLoad2(llvm_builder, llvm_type(v->t), v->llvm_v, v->s); - LLVMValueRef rr = LLVMBuildSDiv(llvm_builder, vr, llvm_expr(C[1], st), "as_div"); - return LLVMBuildStore(llvm_builder, rr, v->llvm_v); - } break; - case AK_AS_MOD: { - LLVMValueRef vr = LLVMBuildLoad2(llvm_builder, llvm_type(v->t), v->llvm_v, v->s); - LLVMValueRef rr = LLVMBuildSRem(llvm_builder, vr, llvm_expr(C[1], st), "as_mod"); - return LLVMBuildStore(llvm_builder, rr, v->llvm_v); - } break; - } -} - /* Generate IR for an expression statement. */ static LLVMValueRef llvm_stmt_expr(ast *a, syt *st) { @@ -216,7 +170,7 @@ static LLVMValueRef llvm_stmt_expr(ast *a, syt *st) { /* Generate IR for a return statement. */ static LLVMValueRef llvm_stmt_return(ast *a, syt *st) { - return LLVMBuildRet(llvm_builder, a->c.al > 0 ? llvm_expr(C[0], st) : NULL); + return LLVMBuildRet(llvm_builder, a->c.al > 0 ? llvm_expr(C[0], st, true) : NULL); } /* Generate IR for an if statement. */ @@ -230,7 +184,7 @@ static LLVMValueRef llvm_stmt_for(ast *a, syt *st) { } /* Generate IR for an expression. */ -static LLVMValueRef llvm_expr(ast *a, syt *st) { +static LLVMValueRef llvm_expr(ast *a, syt *st, bool load) { reset:; switch (A.k) { case AK_BOOL: { return LLVMConstInt(llvm_type(a->t), a->v_bool, false); } break; case AK_INT: { return LLVMConstInt(llvm_type(a->t), a->v_int, false); } break; @@ -240,29 +194,40 @@ static LLVMValueRef llvm_expr(ast *a, syt *st) { case AK_CAST: { return llvm_expr_cast(a, st); } break; case AK_ID: { ast *sym = syt_search(st, a->s); - if (sym == NULL) { note(file_name, A.ln, A.cl, 0, "Undefined variable %s", A.s); } + if (sym == NULL) { note(file_name, A.ln, A.cl, -1, "Undefined variable \"%s\"", A.s); } + if (!sym->llvm_v) { note(file_name, A.ln, A.cl, -1, "Variable \"%s\" follows (llvm:llvm_expr)", A.s); } - if (sym->t->k == TY_ARR) { return sym->llvm_v; } - - return LLVMBuildLoad2(llvm_builder, llvm_type(sym->t), sym->llvm_v, ""); + if (!load || sym->t->k == TY_ARR) { return sym->llvm_v; } + else { return LLVMBuildLoad2(llvm_builder, llvm_type(sym->t), sym->llvm_v, ""); } } break; case AK_CALL: { ast *sym = syt_search_h(st, C[0]->h, C[0]->s); if (sym == NULL) { note(file_name, A.ln, A.cl, -1, "Undefined procedure \"%s\" (llvm:llvm_expr)", C[0]->s); } - if (!sym->llvm_v) { note(file_name, A.ln, A.cl, -1, "Procedure \"%s\" follows (llvm:llvm_expr)", C[0]->s); } /* TODO procedure call arguments */ return LLVMBuildCall2(llvm_builder, sym->llvm_t, sym->llvm_v, NULL, 0, ""); } break; + case AK_SUBS: { + ast *sym = syt_search_h(st, C[0]->h, C[0]->s); + if (sym == NULL) { note(file_name, A.ln, A.cl, 0, "Undefined variable \"%s\"", C[0]->s); } + + if (!sym->llvm_v) { note(file_name, A.ln, A.cl, -1, "Variable \"%s\" follows (llvm:llvm_expr)", A.s); } + + LLVMValueRef idc[1] = { llvm_expr(C[1], st, true) }; + LLVMValueRef vr = LLVMBuildGEP2(llvm_builder, llvm_type(sym->t), sym->llvm_v, idc, 1, ""); + + if (!load) { return vr; } + else { return LLVMBuildLoad2(llvm_builder, llvm_type(sym->t->base), vr, ""); } + } 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"); } + if (is_int(t)) { return LLVMBuildNeg(llvm_builder, llvm_expr(C[0], st, true), "neg"); } + 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_BW_NOT: { @@ -270,30 +235,30 @@ static LLVMValueRef llvm_expr(ast *a, syt *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), ""); + return LLVMBuildXor(llvm_builder, llvm_expr(C[0], st, true), 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 bc = LLVMBuildBitCast(llvm_builder, llvm_expr(C[0], st, true), 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(C[0], st), llvm_expr(C[1], st), "add"); + return LLVMBuildAdd(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), "add"); } break; case AK_OP_SUB: { - return LLVMBuildSub(llvm_builder, llvm_expr(C[0], st), llvm_expr(C[1], st), "sub"); + return LLVMBuildSub(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), "sub"); } break; case AK_OP_MUL: { - return LLVMBuildMul(llvm_builder, llvm_expr(C[0], st), llvm_expr(C[1], st), "mul"); + return LLVMBuildMul(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), "mul"); } break; case AK_OP_DIV: { - return LLVMBuildSDiv(llvm_builder, llvm_expr(C[0], st), llvm_expr(C[1], st), "div"); + return LLVMBuildSDiv(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), "div"); } break; case AK_OP_MOD: { - return LLVMBuildSRem(llvm_builder, llvm_expr(C[0], st), llvm_expr(C[1], st), "mod"); + return LLVMBuildSRem(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), "mod"); } break; case AK_OP_ADO: { ast *v = syt_search(st, C[0]->s); @@ -306,8 +271,31 @@ static LLVMValueRef llvm_expr(ast *a, syt *st) { 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), ""); + return LLVMBuildLoad2(llvm_builder, llvm_type(C[0]->t->base), llvm_expr(C[0], st, true), ""); } + case AK_ASSIGN: { + return LLVMBuildStore(llvm_builder, llvm_expr(C[1], st, true), llvm_expr(C[0], st, false)); + } break; + case AK_AS_ADD: { + LLVMValueRef vr = LLVMBuildAdd(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); + return LLVMBuildStore(llvm_builder, vr, llvm_expr(C[0], st, false)); + } break; + case AK_AS_SUB: { + LLVMValueRef vr = LLVMBuildSub(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); + return LLVMBuildStore(llvm_builder, vr, llvm_expr(C[0], st, false)); + } break; + case AK_AS_MUL: { + LLVMValueRef vr = LLVMBuildMul(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); + return LLVMBuildStore(llvm_builder, vr, llvm_expr(C[0], st, false)); + } break; + case AK_AS_DIV: { + LLVMValueRef vr = LLVMBuildSDiv(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); + return LLVMBuildStore(llvm_builder, vr, llvm_expr(C[0], st, false)); + } break; + case AK_AS_MOD: { + LLVMValueRef vr = LLVMBuildSRem(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); + return LLVMBuildStore(llvm_builder, vr, llvm_expr(C[0], st, false)); + } break; default: { note(file_name, A.ln, A.cl, -1, "Unhandled AST kind %s (llvm:llvm_expr)", ast_ks[a->k]); } break; } } @@ -326,44 +314,44 @@ static LLVMValueRef llvm_expr_cast(ast *a, syt *st) { if (is_ptr(expr_type)) { if (is_int(a->t)) { - return LLVMBuildPtrToInt(llvm_builder, llvm_expr(C[1], st), llvm_type(a->t), ""); + return LLVMBuildPtrToInt(llvm_builder, llvm_expr(C[1], 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), llvm_type(a->t), is_sign(a->t), ""); + return LLVMBuildIntCast2(llvm_builder, llvm_expr(C[1], 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), llvm_type(a->t), is_sign(a->t), ""); + return LLVMBuildIntCast2(llvm_builder, llvm_expr(C[1], 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), llvm_type(a->t), "stof"); + 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), llvm_type(a->t), "utof"); + return LLVMBuildUIToFP(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), "utof"); } } } else if (is_flt(expr_type)) { if (is_flt(a->t)) { - return LLVMBuildFPCast(llvm_builder, llvm_expr(C[1], st), llvm_type(a->t), "cast"); + return LLVMBuildFPCast(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), "cast"); } else if (is_int(a->t)) { if (is_sign(a->t)) { - return LLVMBuildFPToSI(llvm_builder, llvm_expr(C[1], st), llvm_type(a->t), "ftos"); + 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), llvm_type(a->t), "ftou"); + return LLVMBuildFPToUI(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), "ftou"); } } } 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), llvm_type(a->t), ""); + return LLVMBuildBitCast(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), ""); } } @@ -376,7 +364,7 @@ static LLVMValueRef llvm_arr(ast *a, syt *st) { LLVMValueRef *va = calloc(CL, sizeof (LLVMValueRef)); - for (UINT i = 0; i < CL; i += 1) { va[i] = llvm_expr(C[i], st); } + for (UINT i = 0; i < CL; i += 1) { va[i] = llvm_expr(C[i], st, true); } return LLVMConstArray(llvm_type(C[0]->t), va, CL); } @@ -388,7 +376,7 @@ static LLVMValueRef llvm_hash(ast *a, syt *st) { UINT arg_count = a->c.al; LLVMValueRef *args = calloc(arg_count, sizeof (LLVMValueRef)); for (UINT i = 0; i < arg_count; i += 1) { - args[i] = llvm_expr(a->c.a[i], st); + args[i] = llvm_expr(a->c.a[i], st, true); } LLVMTypeRef unsigned_integer_type = llvm_type(&TYPE(TY_UINT)); diff --git a/src/parse.c b/src/parse.c index 2a9b439..923ac7c 100644 --- a/src/parse.c +++ b/src/parse.c @@ -27,7 +27,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_ID", "AK_CALL", "AK_BOOL", "AK_INT", "AK_FLT", "AK_ARR", "AK_SUBS", "AK_HASH_SYSCALL" }; @@ -107,7 +107,11 @@ type *ast_type(ast *a, syt *st) { if (a->t) { return a->t; } /* Otherwise recurse down the first child */ - if (a->c.al) { return ast_type(a->c.a[0], st); } + if (a->c.al) { + type *rt = ast_type(a->c.a[0], st); + if (a->k == AK_SUBS) { return rt->base; } + else { return rt; } + } /* If no type is found, return NULL */ return NULL; @@ -275,7 +279,7 @@ static ast *parse_expr(lex *l, syt *st, s32 o) { case TK_BW_AND: { left = ast_init(AK_OP_ADO, T.ln, T.cl); } goto prefix; case TK_OP_MUL: { left = ast_init(AK_OP_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, -1, "Unhandled expression of kind %s", tok_ks[T.k]); } break; + default: { note(l->n, T.ln, T.cl, 0, "Unexpected \"%s\", was expecting an expression", tok_ks[T.k]); } break; } /* Parse an infix expression if one is present */ @@ -293,7 +297,11 @@ static ast *parse_expr(lex *l, syt *st, s32 o) { lex_kind(l, TK_RPAREN); } break; case TK_LBRACK: { - /* TODO array access */ + a = ast_init(AK_SUBS, T.ln, T.cl); + lex_next(l); ast_push(a, left); + + ast_push(a, parse_expr(l, st, 0)); + lex_kind(l, TK_RBRACK); } break; case TK_ASSIGN: { a = ast_init(AK_ASSIGN, T.ln, T.cl); } goto infix; case TK_AS_ADD: { a = ast_init(AK_AS_ADD, T.ln, T.cl); } goto infix; @@ -309,8 +317,6 @@ static ast *parse_expr(lex *l, syt *st, s32 o) { infix: { lex_next(l); ast_push(a, left); ast_push(a, parse_expr(l, st, ast_precedence(a->k))); } break; } - if (left == NULL) { note(l->n, T.ln, T.cl, 0, "Expected an expression"); } - return left; } @@ -423,7 +429,7 @@ static ast *parse_flt(lex *l, syt *st) { /* Expression operator precedence: - 8 > expression group (parenthesis), function call + 8 > expression group (parenthesis), procedure call, array subscripting 7 > 6 > positive (prefix +), negative (prefix -), bitwise not (prefix ~), address-of (prefix &), dereference (prefix *) 5 > @@ -436,7 +442,7 @@ static ast *parse_flt(lex *l, syt *st) { /* Get the infix precedence of a token kind. */ static s32 tok_precedence(tok_k tk) { switch (tk) { - case TK_LPAREN: { return 8; } + case TK_LPAREN: case TK_LBRACK: { return 8; } case TK_OP_MUL: case TK_OP_DIV: case TK_OP_MOD: { return 4; } case TK_OP_ADD: case TK_OP_SUB: { return 3; } case TK_ASSIGN: case TK_AS_ADD: case TK_AS_SUB: case TK_AS_MUL: case TK_AS_DIV: case TK_AS_MOD: { return 1; } @@ -447,7 +453,7 @@ static s32 tok_precedence(tok_k tk) { /* Get the precedence of an AST kind. */ static s32 ast_precedence(ast_k ak) { switch (ak) { - case AK_CALL: { return 8; } + case AK_CALL: case AK_SUBS: { return 8; } case AK_OP_POS: case AK_OP_NEG: case AK_BW_NOT: case AK_OP_ADO: case AK_OP_DRF: { return 6; } case AK_OP_MUL: case AK_OP_DIV: case AK_OP_MOD: { return 4; } case AK_OP_ADD: case AK_OP_SUB: { return 3; } diff --git a/src/parse.h b/src/parse.h index d875d72..d0f7da0 100644 --- a/src/parse.h +++ b/src/parse.h @@ -24,7 +24,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_ID, AK_CALL, AK_BOOL, AK_INT, AK_FLT, AK_ARR, AK_SUBS, AK_HASH_SYSCALL } ast_k;