From 5de2e1fd9f426348127a66d2c51c300cb90cc3a4 Mon Sep 17 00:00:00 2001 From: Carlos Maniero Date: Wed, 10 May 2023 00:20:00 -0300 Subject: gas: Generate code for if statement If statements are now working, the only exception is for the comparators || and && that will be addressed in a further commit. Checks tested: fn main(): i32 { let n: i32 = 11; if (n == 11) { if n != 12 { if n < 12 { if n <= 11 { if n > 10 { if n >= 11 { return 42; } } } } } } return n; } To compile the && and || a precedence issue must be addressed: they must have the highest precedence, witch is not working now: 1 == 2 || 3 != 2 The or should be the higher level of the tree in the example above. Signed-off-by: Carlos Maniero --- src/gas_assembly_generator.c | 67 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) (limited to 'src/gas_assembly_generator.c') diff --git a/src/gas_assembly_generator.c b/src/gas_assembly_generator.c index 4b898ed..f63e35b 100644 --- a/src/gas_assembly_generator.c +++ b/src/gas_assembly_generator.c @@ -44,6 +44,9 @@ gas_assembly_generator_compile_variable_assignment(gas_assembly_generator_t *gen static void gas_assembly_generator_compile_block(gas_assembly_generator_t *gen, ast_block_t *block); +static void +gas_assembly_generator_compile_if_stmt(gas_assembly_generator_t *gen, ast_if_stmt_t *if_stmt); + static void gas_assembly_generator_compile_variable(gas_assembly_generator_t *gen, ast_variable_t *variable); @@ -106,6 +109,7 @@ gas_assembly_generator_init(gas_assembly_generator_t *gen, FILE *stream) gen->stream = stream; gen->refs = vector_new(); gen->stack_offset = 0; + gen->label_counter = 0; } void @@ -139,6 +143,8 @@ gas_assembly_generator_compile(gas_assembly_generator_t *gen, ast_node_t *ast) gas_assembly_generator_compile_block(gen, &ast->data.block); break; case AST_IF_STMT: + gas_assembly_generator_compile_if_stmt(gen, &ast->data.if_stmt); + break; case AST_UNKOWN_NODE: assert(false && "unreachable"); } @@ -336,5 +342,66 @@ gas_assembly_generator_binary_operation(gas_assembly_generator_t *gen, ast_binar return; } + if (binary_operation->kind == AST_BINOP_LT || binary_operation->kind == AST_BINOP_GT || + binary_operation->kind == AST_BINOP_EQUAL || binary_operation->kind == AST_BINOP_NOT_EQUAL || + binary_operation->kind == AST_BINOP_AND || binary_operation->kind == AST_BINOP_OR || + binary_operation->kind == AST_BINOP_GT || binary_operation->kind == AST_BINOP_LT || + binary_operation->kind == AST_BINOP_LT_EQUAL || binary_operation->kind == AST_BINOP_GT_EQUAL) { + fprintf(gen->stream, " cmp %%rcx, %%rax\n"); + return; + } + assert(false && "No strategy defined for binary operation"); } + +static void +gas_assembly_generator_compile_binop_if(gas_assembly_generator_t *gen, ast_node_t *binop_node) +{ + assert(binop_node->kind == AST_BINARY_OPERATION); + + char *jump_map[AST_BINOP_N] = { + [AST_BINOP_EQUAL] = "jne", [AST_BINOP_NOT_EQUAL] = "je", [AST_BINOP_LT] = "jge", + [AST_BINOP_LT_EQUAL] = "jg", [AST_BINOP_GT] = "jle", [AST_BINOP_GT_EQUAL] = "jl", + }; + + char *jumper = jump_map[binop_node->data.binary_operation.kind]; + + assert(jumper != NULL); + + gas_assembly_generator_compile(gen, binop_node); + + fprintf(gen->stream, " %s .IF%ld\n", jumper, gen->label_counter); +} + +static void +gas_assembly_generator_compile_if_stmt(gas_assembly_generator_t *gen, ast_if_stmt_t *if_stmt) +{ + switch (if_stmt->condition->kind) { + case AST_LITERAL: { + int if_counter = gen->label_counter++; + + assert(if_stmt->condition->data.literal.kind == AST_LITERAL_BOOL); + + if (!if_stmt->condition->data.literal.value.boolean) { + fprintf(gen->stream, " jmp .IF%d\n", if_counter); + } + + gas_assembly_generator_compile(gen, if_stmt->body); + + fprintf(gen->stream, ".IF%d:\n", if_counter); + break; + } + case AST_BINARY_OPERATION: { + gas_assembly_generator_compile_binop_if(gen, if_stmt->condition); + + int if_counter = gen->label_counter++; + + gas_assembly_generator_compile(gen, if_stmt->body); + + fprintf(gen->stream, ".IF%d:\n", if_counter); + break; + } + default: + assert(false); + } +} -- cgit v1.2.3