diff options
-rw-r--r-- | src/ast.c | 63 | ||||
-rw-r--r-- | src/ast.h | 57 | ||||
-rw-r--r-- | src/gas_assembly_generator.c | 66 | ||||
-rw-r--r-- | src/gas_assembly_generator.h | 33 | ||||
-rw-r--r-- | src/parser.c | 15 | ||||
-rw-r--r-- | src/parser.h | 15 | ||||
-rw-r--r-- | src/pipac.c | 14 |
7 files changed, 231 insertions, 32 deletions
diff --git a/src/ast.c b/src/ast.c new file mode 100644 index 0000000..f8c2713 --- /dev/null +++ b/src/ast.c @@ -0,0 +1,63 @@ +/* +* 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 <https://www.gnu.org/licenses/>. +*/ +#include <assert.h> +#include "ast.h" + +void +ast_node_accept_visitor(ast_node_t *node, ast_visitor_t *visitor) +{ + assert(node); + assert(node->accept_visitor); + node->accept_visitor(node, visitor); +} + +static void +ast_function_accept_visitor(ast_node_t *node, ast_visitor_t *visitor) +{ + visitor->visit_function(visitor, (ast_function_t *) node); +} + +static void +ast_return_stmt_accept_visitor(ast_node_t *node, ast_visitor_t *visitor) +{ + visitor->visit_return_stmt(visitor, (ast_return_stmt_t *) node); +} + +ast_return_stmt_t +ast_return_stmt_create(uint32_t number) +{ + return (ast_return_stmt_t) { + .super = (ast_node_t) { + .accept_visitor = &ast_return_stmt_accept_visitor + }, + .number = number + }; +} + +ast_function_t +ast_function_create(string_view_t name, type_t return_type, ast_return_stmt_t body) +{ + return (ast_function_t) { + .super = (ast_node_t) { + .accept_visitor = &ast_function_accept_visitor + }, + .name = name, + .return_type = return_type, + .body = body + }; +} + diff --git a/src/ast.h b/src/ast.h new file mode 100644 index 0000000..7f5a198 --- /dev/null +++ b/src/ast.h @@ -0,0 +1,57 @@ +/* +* 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 <https://www.gnu.org/licenses/>. +*/ +#ifndef AST_H +#define AST_H +#include <stdint.h> +#include "string_view.h" + +#define ast_visitor_visit(visitor, node) ast_node_accept_visitor((ast_node_t *) node, (ast_visitor_t *) visitor); + +typedef enum { + TYPE_I32 +} type_t; + +typedef struct ast_visitor_t ast_visitor_t; + +typedef struct ast_node_t { + void (*accept_visitor)(struct ast_node_t *, ast_visitor_t *); +} ast_node_t; + +typedef struct ast_return_stmt_t { + struct ast_node_t super; + uint32_t number; +} ast_return_stmt_t; + +typedef struct ast_function_t { + struct ast_node_t super; + string_view_t name; + type_t return_type; + ast_return_stmt_t body; +} ast_function_t; + +typedef struct ast_visitor_t { + void (*visit_function)(struct ast_visitor_t *, ast_function_t *); + void (*visit_return_stmt)(struct ast_visitor_t *, ast_return_stmt_t *); +} ast_visitor_t; + +void ast_node_accept_visitor(ast_node_t *node, ast_visitor_t *visitor); + +ast_function_t ast_function_create(string_view_t name, type_t return_type, ast_return_stmt_t body); +ast_return_stmt_t ast_return_stmt_create(uint32_t number); + +#endif /* AST_H */ + diff --git a/src/gas_assembly_generator.c b/src/gas_assembly_generator.c new file mode 100644 index 0000000..d164b7d --- /dev/null +++ b/src/gas_assembly_generator.c @@ -0,0 +1,66 @@ +/* +* 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 <https://www.gnu.org/licenses/>. +*/ +#include "gas_assembly_generator.h" + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + +static void gas_assembly_generator_visit_function(ast_visitor_t *visitor, ast_function_t *func); +static void gas_assembly_generator_visit_return_stmt(ast_visitor_t *visitor, ast_return_stmt_t *return_stmt); + +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_return_stmt = &gas_assembly_generator_visit_return_stmt + }; + gen->out = out; +} + +static void +gas_assembly_generator_visit_function(ast_visitor_t *visitor, ast_function_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"); + + ast_visitor_visit(visitor, &func->body); +} + +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; + + fprintf(gen->out, " mov $1, %%al\n"); + fprintf(gen->out, " mov $%d, %%ebx\n", return_stmt->number); + fprintf(gen->out, " int $0x80\n"); +} + diff --git a/src/gas_assembly_generator.h b/src/gas_assembly_generator.h new file mode 100644 index 0000000..64f861e --- /dev/null +++ b/src/gas_assembly_generator.h @@ -0,0 +1,33 @@ +/* +* 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 <https://www.gnu.org/licenses/>. +*/ +#ifndef GAS_ASSEMBLY_GENERATOR_H +#define GAS_ASSEMBLY_GENERATOR_H + +#include "ast.h" +#include <stdio.h> + +typedef struct gas_assembly_generator_t { + ast_visitor_t super; + FILE *out; +} gas_assembly_generator_t; + +void gas_assembly_generator_init(gas_assembly_generator_t *, FILE *); + +void gas_assembly_generator_visit(gas_assembly_generator_t * gen, ast_node_t* ast); + +#endif /* GAS_ASSEMBLY_GENERATOR_H */ + diff --git a/src/parser.c b/src/parser.c index 593f75a..b956c4e 100644 --- a/src/parser.c +++ b/src/parser.c @@ -20,6 +20,7 @@ #include <stdlib.h> #include <string.h> +#include "ast.h" #include "lexer.h" #include "parser.h" @@ -92,9 +93,7 @@ parser_parse_return_stmt(parser_t *parser) char number_as_str[number_token.value.size]; string_view_to_str(&number_token.value, number_as_str); - return (ast_return_stmt_t) { - .number = atoi(number_as_str) - }; + return ast_return_stmt_create(atoi(number_as_str)); } ast_function_t @@ -106,9 +105,9 @@ parser_parse_function(parser_t *parser) expected_token(parser, TOKEN_COLON); type_t return_type = parser_parse_type(parser); - return (ast_function_t) { - .name = func_name_token.value, - .return_type = return_type, - .body = parser_parse_return_stmt(parser) - }; + return ast_function_create( + func_name_token.value, + return_type, + parser_parse_return_stmt(parser) + ); } diff --git a/src/parser.h b/src/parser.h index d44a4df..b846ae1 100644 --- a/src/parser.h +++ b/src/parser.h @@ -17,6 +17,7 @@ #ifndef PARSER_H #define PARSER_H +#include "ast.h" #include "lexer.h" #include "string_view.h" @@ -24,20 +25,6 @@ typedef struct parser_t { lexer_t *lexer; } parser_t; -typedef enum { - TYPE_I32 -} type_t; - -typedef struct ast_return_stmt_t { - uint32_t number; -} ast_return_stmt_t; - -typedef struct ast_function_t { - string_view_t name; - type_t return_type; - ast_return_stmt_t body; -} ast_function_t; - void parser_init(parser_t *parser, lexer_t *lexer); ast_function_t parser_parse_function(parser_t *parser); diff --git a/src/pipac.c b/src/pipac.c index 6e6df9e..e56d8a1 100644 --- a/src/pipac.c +++ b/src/pipac.c @@ -21,21 +21,15 @@ #include "lexer.h" #include "parser.h" #include "string_view.h" +#include "gas_assembly_generator.h" void generate_gas_x86_64_linux(ast_function_t *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_init(&gen, stdout); - printf(".global _start\n"); - printf(".text\n"); - printf("_start:\n"); - printf(" mov $1, %%al\n"); - printf(" mov $%d, %%ebx\n", func->body.number); - printf(" int $0x80\n"); + ast_visitor_visit(&gen, func); } void |