summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarlos Maniero <carlos@maniero.me>2023-05-10 01:43:40 -0300
committerCarlos Maniero <carlos@maniero.me>2023-05-10 12:18:17 -0300
commit88630ebbea03e85119cf9795320a83cb846bdd20 (patch)
treeecf1f46ce6d9048c5d51ff70413e992936ebf28f /src
parent3065f54e3a122dd3d8c2deffdec72ec48ea4f165 (diff)
gas: Implement && and || for if statements
Now if statements are complete! The function %gas_assembly_generator_compile_condition% is generic and will be used for any other flow-control statment. The only requirement to it work is having two labels: One to jump when the condition is true, and another one when the condition is false. Signed-off-by: Carlos Maniero <carlos@maniero.me>
Diffstat (limited to 'src')
-rw-r--r--src/gas_assembly_generator.c109
-rw-r--r--src/gas_assembly_generator.h2
2 files changed, 81 insertions, 30 deletions
diff --git a/src/gas_assembly_generator.c b/src/gas_assembly_generator.c
index f63e35b..c85d7a7 100644
--- a/src/gas_assembly_generator.c
+++ b/src/gas_assembly_generator.c
@@ -109,7 +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;
+ gen->cur_label_index = 0;
}
void
@@ -344,7 +344,6 @@ gas_assembly_generator_binary_operation(gas_assembly_generator_t *gen, ast_binar
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");
@@ -354,51 +353,103 @@ gas_assembly_generator_binary_operation(gas_assembly_generator_t *gen, ast_binar
assert(false && "No strategy defined for binary operation");
}
+static char *jump_map[AST_BINOP_N] = {
+ [AST_BINOP_EQUAL] = "je", [AST_BINOP_NOT_EQUAL] = "jne", [AST_BINOP_LT] = "jl",
+ [AST_BINOP_LT_EQUAL] = "jle", [AST_BINOP_GT] = "jg", [AST_BINOP_GT_EQUAL] = "jge",
+};
+
+static char *inverse_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",
+};
+
static void
-gas_assembly_generator_compile_binop_if(gas_assembly_generator_t *gen, ast_node_t *binop_node)
+gas_assembly_generator_compile_condition(gas_assembly_generator_t *gen,
+ ast_node_t *condition,
+ uint64_t true_label_index,
+ bool jump_when_true,
+ uint64_t false_label_index,
+ bool jump_when_false)
{
- assert(binop_node->kind == AST_BINARY_OPERATION);
+ assert(condition->kind == AST_BINARY_OPERATION || condition->kind == AST_LITERAL);
+
+ if (condition->kind == AST_LITERAL) {
+ assert(condition->data.literal.kind == AST_LITERAL_BOOL);
+
+ if (jump_when_false && !condition->data.literal.value.boolean) {
+ fprintf(gen->stream, " jmp .L_%ld\n", false_label_index);
+ return;
+ }
+
+ if (jump_when_true && condition->data.literal.value.boolean) {
+ fprintf(gen->stream, " jmp .L_%ld\n", true_label_index);
+ }
+
+ return;
+ }
+
+ if (condition->data.binary_operation.kind == AST_BINOP_OR) {
+ uint64_t or_false_branch_label_index = gen->cur_label_index++;
+
+ gas_assembly_generator_compile_condition(
+ gen, condition->data.binary_operation.left, true_label_index, true, or_false_branch_label_index, false);
+
+ fprintf(gen->stream, ".L_%ld:\n", or_false_branch_label_index);
+
+ gas_assembly_generator_compile_condition(
+ gen, condition->data.binary_operation.right, true_label_index, false, false_label_index, true);
+ return;
+ }
+
+ if (condition->data.binary_operation.kind == AST_BINOP_AND) {
+ uint64_t and_true_branch_label_index = gen->cur_label_index++;
- 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",
- };
+ gas_assembly_generator_compile_condition(
+ gen, condition->data.binary_operation.left, and_true_branch_label_index, false, false_label_index, true);
- char *jumper = jump_map[binop_node->data.binary_operation.kind];
+ fprintf(gen->stream, ".L_%ld:\n", and_true_branch_label_index);
- assert(jumper != NULL);
+ gas_assembly_generator_compile_condition(
+ gen, condition->data.binary_operation.right, true_label_index, false, false_label_index, true);
+ return;
+ }
+
+ gas_assembly_generator_compile(gen, condition);
+
+ if (jump_when_false) {
+ char *jumper = inverse_jump_map[condition->data.binary_operation.kind];
+
+ assert(jumper != NULL);
+
+ fprintf(gen->stream, " %s .L_%ld\n", jumper, false_label_index);
+ return;
+ }
+
+ if (jump_when_true) {
+ char *jumper = jump_map[condition->data.binary_operation.kind];
- gas_assembly_generator_compile(gen, binop_node);
+ assert(jumper != NULL);
- fprintf(gen->stream, " %s .IF%ld\n", jumper, gen->label_counter);
+ fprintf(gen->stream, " %s .L_%ld\n", jumper, true_label_index);
+ }
}
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_BINARY_OPERATION:
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);
+ uint64_t true_label_index = gen->cur_label_index++;
+ uint64_t false_label_index = gen->cur_label_index++;
- int if_counter = gen->label_counter++;
+ gas_assembly_generator_compile_condition(
+ gen, if_stmt->condition, true_label_index, false, false_label_index, true);
+ fprintf(gen->stream, ".L_%ld:\n", true_label_index);
gas_assembly_generator_compile(gen, if_stmt->body);
- fprintf(gen->stream, ".IF%d:\n", if_counter);
+ fprintf(gen->stream, ".L_%ld:\n", false_label_index);
break;
}
default:
diff --git a/src/gas_assembly_generator.h b/src/gas_assembly_generator.h
index 3d9a43c..2e195fb 100644
--- a/src/gas_assembly_generator.h
+++ b/src/gas_assembly_generator.h
@@ -46,7 +46,7 @@ typedef struct gas_assembly_generator_t
FILE *stream;
vector_t *refs;
int stack_offset;
- uint64_t label_counter;
+ uint64_t cur_label_index;
evaluation_result_t latest_evaluation;
} gas_assembly_generator_t;