diff options
author | Carlos Maniero <carlos@maniero.me> | 2023-05-10 01:43:40 -0300 |
---|---|---|
committer | Carlos Maniero <carlos@maniero.me> | 2023-05-10 12:18:17 -0300 |
commit | 88630ebbea03e85119cf9795320a83cb846bdd20 (patch) | |
tree | ecf1f46ce6d9048c5d51ff70413e992936ebf28f /src | |
parent | 3065f54e3a122dd3d8c2deffdec72ec48ea4f165 (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.c | 109 | ||||
-rw-r--r-- | src/gas_assembly_generator.h | 2 |
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; |