diff options
author | Carlos Maniero <carlos@maniero.me> | 2023-05-10 00:20:00 -0300 |
---|---|---|
committer | Carlos Maniero <carlos@maniero.me> | 2023-05-10 12:15:01 -0300 |
commit | 5de2e1fd9f426348127a66d2c51c300cb90cc3a4 (patch) | |
tree | 4dfa61999777227ca35a4d9d092f41996af6d26e | |
parent | ad54ee1182b1549880eddc8b1969d3992d9f7f1d (diff) |
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 <carlos@maniero.me>
-rw-r--r-- | examples/if.pipa | 16 | ||||
-rw-r--r-- | src/ast_pretty_printer.c | 15 | ||||
-rw-r--r-- | src/gas_assembly_generator.c | 67 | ||||
-rw-r--r-- | src/gas_assembly_generator.h | 1 | ||||
-rw-r--r-- | test/integration_test.c | 1 |
5 files changed, 91 insertions, 9 deletions
diff --git a/examples/if.pipa b/examples/if.pipa index 2c5578d..b7cadcb 100644 --- a/examples/if.pipa +++ b/examples/if.pipa @@ -1,8 +1,18 @@ fn main(): i32 { - let n: i32 = 42; + let n: i32 = 11; - if n > 42 { - return 42; + if (n == 11) { + if n != 12 { + if n < 12 { + if n <= 11 { + if n > 10 { + if n >= 11 { + return 42; + } + } + } + } + } } return n; diff --git a/src/ast_pretty_printer.c b/src/ast_pretty_printer.c index e2d007a..b14bf34 100644 --- a/src/ast_pretty_printer.c +++ b/src/ast_pretty_printer.c @@ -22,10 +22,12 @@ #include <stdarg.h> #include <stdio.h> -const char operation_kinds[AST_BINOP_N] = { [AST_BINOP_ADITION] = '+', - [AST_BINOP_SUBTRACTION] = '-', - [AST_BINOP_MULTIPLICATION] = '*', - [AST_BINOP_DIVISION] = '/' }; +const char *operation_kinds[AST_BINOP_N] = { + [AST_BINOP_ADITION] = "+", [AST_BINOP_SUBTRACTION] = "-", [AST_BINOP_MULTIPLICATION] = "*", + [AST_BINOP_DIVISION] = "/", [AST_BINOP_EQUAL] = "==", [AST_BINOP_NOT_EQUAL] = "!=", + [AST_BINOP_AND] = "&&", [AST_BINOP_OR] = "||", [AST_BINOP_GT] = ">", + [AST_BINOP_LT] = "<", [AST_BINOP_LT_EQUAL] = "<=", [AST_BINOP_GT_EQUAL] = ">=", +}; void ast_pretty_printer_init(ast_pretty_printer_t *printer, FILE *stream); @@ -76,6 +78,7 @@ ast_pretty_printer_print_ast(ast_pretty_printer_t *printer, ast_node_t *ast) ast_pretty_printer_rm_indentation(printer); } + ast_pretty_printer_set_lst_children(printer); ast_pretty_printer_printf(printer, "body:\n"); ast_pretty_printer_add_indentation(printer); { @@ -90,7 +93,7 @@ ast_pretty_printer_print_ast(ast_pretty_printer_t *printer, ast_node_t *ast) } case AST_BINARY_OPERATION: { ast_binary_operation_t binop = ast->data.binary_operation; - ast_pretty_printer_printf(printer, "BinaryOperation operation='%c'\n", operation_kinds[binop.kind]); + ast_pretty_printer_printf(printer, "BinaryOperation operation='%s'\n", operation_kinds[binop.kind]); ast_pretty_printer_add_indentation(printer); { @@ -130,6 +133,7 @@ ast_pretty_printer_print_ast(ast_pretty_printer_t *printer, ast_node_t *ast) ast_pretty_printer_add_indentation(printer); { + ast_pretty_printer_set_lst_children(printer); ast_pretty_printer_print_ast(printer, ast->data.function.body); ast_pretty_printer_rm_indentation(printer); } @@ -139,7 +143,6 @@ ast_pretty_printer_print_ast(ast_pretty_printer_t *printer, ast_node_t *ast) break; } case AST_BLOCK: { - ast_pretty_printer_set_lst_children(printer); ast_pretty_printer_printf(printer, "Block\n"); ast_pretty_printer_add_indentation(printer); { 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 @@ -45,6 +45,9 @@ 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); static void @@ -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); + } +} diff --git a/src/gas_assembly_generator.h b/src/gas_assembly_generator.h index 92972f9..3d9a43c 100644 --- a/src/gas_assembly_generator.h +++ b/src/gas_assembly_generator.h @@ -46,6 +46,7 @@ typedef struct gas_assembly_generator_t FILE *stream; vector_t *refs; int stack_offset; + uint64_t label_counter; evaluation_result_t latest_evaluation; } gas_assembly_generator_t; diff --git a/test/integration_test.c b/test/integration_test.c index 4178b42..985e574 100644 --- a/test/integration_test.c +++ b/test/integration_test.c @@ -43,6 +43,7 @@ test_examples(const MunitParameter params[], void *user_data_or_fixture) assert_exit_status("../examples/main.pipa", 69); assert_exit_status("../examples/arithmetics.pipa", 13); assert_exit_status("../examples/variables.pipa", 28); + assert_exit_status("../examples/if.pipa", 42); return MUNIT_OK; } |