/* * Copyright (C) 2023 Johnny Richard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "gas_assembly_generator.h" #include #include #include static void gas_assembly_generator_binary_operation(gas_assembly_generator_t *gen, ast_binary_operation_t *binary_operation); static void gas_assembly_generator_compile_function(gas_assembly_generator_t *gen, ast_function_declaration_t *func); static void gas_assembly_generator_compile_literal(gas_assembly_generator_t *gen, ast_literal_t *literal); static void gas_assembly_generator_compile_return_stmt(gas_assembly_generator_t *gen, ast_return_stmt_t *return_stmt); void gas_assembly_generator_init(gas_assembly_generator_t *gen, FILE *stream) { assert(gen && stream); gen->stream = stream; } void gas_assembly_generator_compile(gas_assembly_generator_t *gen, ast_node_t *ast) { switch (ast->kind) { case AST_BINARY_OPERATION: gas_assembly_generator_binary_operation(gen, &ast->data.binary_operation); break; case AST_FUNCTION_DECLARATION: gas_assembly_generator_compile_function(gen, &ast->data.function); break; case AST_LITERAL: gas_assembly_generator_compile_literal(gen, &ast->data.literal); break; case AST_RETURN_STMT: gas_assembly_generator_compile_return_stmt(gen, &ast->data.return_stmt); break; case AST_IDENTIFIER: assert(false && "TODO: ast identifier not implemented yet"); break; case AST_VARIABLE_DECLARATION: assert(false && "TODO: ast variable declaration not implemented yet"); break; case AST_UNKOWN_NODE: assert(false && "unreachable"); } } static void gas_assembly_generator_compile_function(gas_assembly_generator_t *gen, ast_function_declaration_t *func) { assert(func); if (!string_view_eq(func->identifier.name, string_view_from_str("main"))) { fprintf(stderr, "[ERROR]: no main function has been defined!\n"); exit(EXIT_FAILURE); } fprintf(gen->stream, ".global _start\n"); fprintf(gen->stream, ".text\n"); fprintf(gen->stream, "_start:\n"); for (size_t i = 0; i < func->body->size; i++) { gas_assembly_generator_compile(gen, vector_at(func->body, i)); } } static void gas_assembly_generator_compile_return_stmt(gas_assembly_generator_t *gen, ast_return_stmt_t *return_stmt) { assert(gen && return_stmt); gas_assembly_generator_compile(gen, return_stmt->argument); fprintf(gen->stream, " mov %%rax, %%rbx\n"); fprintf(gen->stream, " mov $1, %%al\n"); fprintf(gen->stream, " int $0x80\n"); } static void gas_assembly_generator_compile_literal(gas_assembly_generator_t *gen, ast_literal_t *literal) { switch (literal->kind) { case AST_LITERAL_INTEGER: fprintf(gen->stream, " mov $%d, %%rax\n", literal->value.integer); return; default: assert(false && "no code generation strategy."); } } static void gas_assembly_generator_binary_operation(gas_assembly_generator_t *gen, ast_binary_operation_t *binary_operation) { gas_assembly_generator_compile(gen, binary_operation->right); fprintf(gen->stream, " push %%rax\n"); gas_assembly_generator_compile(gen, binary_operation->left); fprintf(gen->stream, " pop %%rcx\n"); if (binary_operation->kind == AST_BINOP_ADITION) { fprintf(gen->stream, " add %%rcx, %%rax\n"); return; } if (binary_operation->kind == AST_BINOP_SUBTRACTION) { fprintf(gen->stream, " sub %%rcx, %%rax\n"); return; } if (binary_operation->kind == AST_BINOP_MULTIPLICATION) { fprintf(gen->stream, " mul %%rcx\n"); return; } if (binary_operation->kind == AST_BINOP_DIVISION) { fprintf(gen->stream, " xor %%rdx, %%rdx\n"); fprintf(gen->stream, " div %%rcx\n"); return; } assert(false && "No strategy defined for binary operation"); }