summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Maniero <carlos@maniero.me>2023-05-10 00:20:00 -0300
committerCarlos Maniero <carlos@maniero.me>2023-05-10 12:15:01 -0300
commit5de2e1fd9f426348127a66d2c51c300cb90cc3a4 (patch)
tree4dfa61999777227ca35a4d9d092f41996af6d26e
parentad54ee1182b1549880eddc8b1969d3992d9f7f1d (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.pipa16
-rw-r--r--src/ast_pretty_printer.c15
-rw-r--r--src/gas_assembly_generator.c67
-rw-r--r--src/gas_assembly_generator.h1
-rw-r--r--test/integration_test.c1
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;
}