/* * 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_visit_function(ast_visitor_t *visitor, ast_function_declaration_t *func); static void gas_assembly_generator_visit_return_stmt(ast_visitor_t *visitor, ast_return_stmt_t *return_stmt); static void gas_assembly_generator_visit_literal(ast_visitor_t *visitor, ast_literal_t *literal); static void gas_assembly_generator_binary_operation(ast_visitor_t *visitor, ast_binary_operation_t *binary_operation); void gas_assembly_generator_init(gas_assembly_generator_t *gen, FILE *out) { assert(gen && out); gen->super = (ast_visitor_t){ .visit_function = &gas_assembly_generator_visit_function, .visit_literal = &gas_assembly_generator_visit_literal, .visit_return_stmt = &gas_assembly_generator_visit_return_stmt, .visit_binary_operation = &gas_assembly_generator_binary_operation }; gen->out = out; } static void gas_assembly_generator_visit_function(ast_visitor_t *visitor, ast_function_declaration_t *func) { assert(visitor && func); if (!string_view_eq(func->name, string_view_from_str("main"))) { fprintf(stderr, "[ERROR]: no main function has been defined!\n"); exit(EXIT_FAILURE); } gas_assembly_generator_t *gen = (gas_assembly_generator_t *)visitor; fprintf(gen->out, ".global _start\n"); fprintf(gen->out, ".text\n"); fprintf(gen->out, "_start:\n"); for (size_t i = 0; i < func->body->size; i++) { ast_visitor_visit(visitor, vector_at(func->body, i)); } } static void gas_assembly_generator_visit_return_stmt(ast_visitor_t *visitor, ast_return_stmt_t *return_stmt) { assert(visitor && return_stmt); gas_assembly_generator_t *gen = (gas_assembly_generator_t *)visitor; ast_visitor_visit(visitor, return_stmt->argument); fprintf(gen->out, " mov %%rax, %%rbx\n"); fprintf(gen->out, " mov $1, %%al\n"); fprintf(gen->out, " int $0x80\n"); } static void gas_assembly_generator_visit_literal(ast_visitor_t *visitor, ast_literal_t *literal) { gas_assembly_generator_t *gen = (gas_assembly_generator_t *)visitor; switch (literal->kind) { case AST_LITERAL_INTEGER: fprintf(gen->out, " mov $%d, %%rax\n", literal->value.integer); return; default: assert(false && "no code generation strategy."); } } static void gas_assembly_generator_binary_operation(ast_visitor_t *visitor, ast_binary_operation_t *binary_operation) { gas_assembly_generator_t *gen = (gas_assembly_generator_t *)visitor; ast_visitor_visit(visitor, binary_operation->right); fprintf(gen->out, " push %%rax\n"); ast_visitor_visit(visitor, binary_operation->left); fprintf(gen->out, " pop %%rcx\n"); if (string_view_eq(binary_operation->op, string_view_from_str("+"))) { fprintf(gen->out, " add %%rcx, %%rax\n"); return; } if (string_view_eq(binary_operation->op, string_view_from_str("-"))) { fprintf(gen->out, " sub %%rcx, %%rax\n"); return; } if (string_view_eq(binary_operation->op, string_view_from_str("*"))) { fprintf(gen->out, " mul %%rcx\n"); return; } if (string_view_eq(binary_operation->op, string_view_from_str("/"))) { fprintf(gen->out, " xor %%rdx, %%rdx\n"); fprintf(gen->out, " div %%rcx\n"); return; } fprintf(stderr, "no strategy defined for: " SVFMT "\n", SVARG(&binary_operation->op)); assert(false); }