* [PATCH olang v1 0/3] compiler: enable full compilation for vars
@ 2024-09-21 0:20 Johnny Richard
2024-09-21 0:20 ` [PATCH olang v1 1/3] scope: create scope data structure Johnny Richard
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Johnny Richard @ 2024-09-21 0:20 UTC (permalink / raw)
To: ~johnnyrichard/olang-devel; +Cc: Johnny Richard
The variables are consts and need more work to get fully functional.
This first patchset is a beginning of the work.
Johnny Richard (3):
scope: create scope data structure
checker: create checker and populate scope on ast nodes
codegen: add support scopes and symbols lookups for var
src/ast.h | 4 +
src/checker.c | 125 +++++++
src/checker.h | 34 ++
src/codegen_linux_x86_64.c | 347 ++++++++++--------
src/codegen_linux_x86_64.h | 16 +-
src/main.c | 12 +-
src/scope.c | 101 +++++
src/scope.h | 54 +++
.../integration/tests/0024_var_definition.ol | 4 +
9 files changed, 551 insertions(+), 146 deletions(-)
create mode 100644 src/checker.c
create mode 100644 src/checker.h
create mode 100644 src/scope.c
create mode 100644 src/scope.h
base-commit: 29cc9fc4a69e74987a1b6c216ff701a9eaf379b3
--
2.46.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH olang v1 1/3] scope: create scope data structure
2024-09-21 0:20 [PATCH olang v1 0/3] compiler: enable full compilation for vars Johnny Richard
@ 2024-09-21 0:20 ` Johnny Richard
2024-09-21 0:20 ` [PATCH olang v1 2/3] checker: create checker and populate scope on ast nodes Johnny Richard
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Johnny Richard @ 2024-09-21 0:20 UTC (permalink / raw)
To: ~johnnyrichard/olang-devel; +Cc: Johnny Richard
Signed-off-by: Johnny Richard <johnny@johnnyrichard.com>
---
src/scope.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/scope.h | 54 ++++++++++++++++++++++++++++
2 files changed, 155 insertions(+)
create mode 100644 src/scope.c
create mode 100644 src/scope.h
diff --git a/src/scope.c b/src/scope.c
new file mode 100644
index 0000000..3271856
--- /dev/null
+++ b/src/scope.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2024 olang maintainers
+ *
+ * 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "scope.h"
+
+scope_t *
+scope_new(arena_t *arena)
+{
+ assert(arena);
+ scope_t *scope = (scope_t *)arena_alloc(arena, sizeof(scope_t));
+ if (scope == NULL) {
+ fprintf(stderr, "[FATAL] Out of memory: scope_new: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ scope->arena = arena;
+ scope->symbols = map_new(arena);
+ return scope;
+}
+
+symbol_t *
+symbol_new(arena_t *arena, string_view_t id)
+{
+ assert(arena);
+ symbol_t *symbol = (symbol_t *)arena_alloc(arena, sizeof(symbol_t));
+ if (symbol == NULL) {
+ fprintf(stderr, "[FATAL] Out of memory: symbol_new: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ symbol->id = id;
+ return symbol;
+}
+
+symbol_t *
+scope_lookup(scope_t *scope, string_view_t id)
+{
+ assert(scope);
+ while (scope != NULL) {
+
+ char cstr_id[id.size + 1];
+ cstr_id[id.size] = 0;
+ memcpy(cstr_id, id.chars, id.size);
+
+ symbol_t *symbol = (symbol_t *)map_get(scope->symbols, cstr_id);
+ if (symbol != NULL) {
+ return symbol;
+ }
+ scope = scope->parent;
+ }
+ return NULL;
+}
+
+void
+scope_insert(scope_t *scope, symbol_t *symbol)
+{
+ assert(scope);
+ assert(symbol);
+
+ char id[symbol->id.size + 1];
+ id[symbol->id.size] = 0;
+ memcpy(id, symbol->id.chars, symbol->id.size);
+
+ map_put(scope->symbols, id, symbol);
+}
+
+scope_t *
+scope_push(scope_t *scope)
+{
+ assert(scope);
+
+ scope_t *child = scope_new(scope->arena);
+ child->parent = scope;
+
+ return child;
+}
+
+scope_t *
+scope_pop(scope_t *scope)
+{
+ assert(scope);
+ assert(scope->parent);
+ return scope->parent;
+}
diff --git a/src/scope.h b/src/scope.h
new file mode 100644
index 0000000..ddb0cd0
--- /dev/null
+++ b/src/scope.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 olang maintainers
+ *
+ * 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 SCOPE_H
+#define SCOPE_H
+
+#include "arena.h"
+#include "map.h"
+#include "string_view.h"
+
+typedef struct symbol
+{
+ string_view_t id;
+} symbol_t;
+
+typedef struct scope
+{
+ struct scope *parent;
+ arena_t *arena;
+ map_t *symbols;
+} scope_t;
+
+scope_t *
+scope_new(arena_t *arena);
+
+symbol_t *
+symbol_new(arena_t *arena, string_view_t id);
+
+symbol_t *
+scope_lookup(scope_t *scope, string_view_t id);
+
+void
+scope_insert(scope_t *scope, symbol_t *symbol);
+
+scope_t *
+scope_push(scope_t *scope);
+
+scope_t *
+scope_pop(scope_t *scope);
+
+#endif /* SCOPE_H */
--
2.46.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH olang v1 2/3] checker: create checker and populate scope on ast nodes
2024-09-21 0:20 [PATCH olang v1 0/3] compiler: enable full compilation for vars Johnny Richard
2024-09-21 0:20 ` [PATCH olang v1 1/3] scope: create scope data structure Johnny Richard
@ 2024-09-21 0:20 ` Johnny Richard
2024-09-21 0:20 ` [PATCH olang v1 3/3] codegen: add support scopes and symbols lookups for var Johnny Richard
2024-09-21 0:59 ` [PATCH olang v1 0/3] compiler: enable full compilation for vars Carlos Maniero
3 siblings, 0 replies; 6+ messages in thread
From: Johnny Richard @ 2024-09-21 0:20 UTC (permalink / raw)
To: ~johnnyrichard/olang-devel; +Cc: Johnny Richard
The checker will check semantic analysis in the future, now we want to
focus on create the scope (symbol table) and attach to a couple of ast
nodes.
We want the scope to be accessible from the ast nodes to easily resolve
scope on the next compiler pipeline steps.
Signed-off-by: Johnny Richard <johnny@johnnyrichard.com>
---
src/ast.h | 4 ++
src/checker.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/checker.h | 34 ++++++++++++++
src/main.c | 4 ++
4 files changed, 167 insertions(+)
create mode 100644 src/checker.c
create mode 100644 src/checker.h
diff --git a/src/ast.h b/src/ast.h
index 94ee6b4..7d065c6 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -21,6 +21,7 @@
#include "arena.h"
#include "list.h"
+#include "scope.h"
#include "string_view.h"
typedef struct ast_node ast_node_t;
@@ -66,6 +67,7 @@ typedef struct ast_var_definition
string_view_t identifier;
type_t type;
ast_node_t *value;
+ scope_t *scope;
} ast_var_definition_t;
typedef enum
@@ -85,6 +87,7 @@ typedef struct ast_literal
typedef struct ast_ref
{
string_view_t identifier;
+ scope_t *scope;
} ast_ref_t;
typedef enum ast_binary_op_kind
@@ -118,6 +121,7 @@ typedef struct ast_binary_op
typedef struct ast_return_stmt
{
+ // FIXME: rename to a meaningful name like expr
ast_node_t *data;
} ast_return_stmt_t;
diff --git a/src/checker.c b/src/checker.c
new file mode 100644
index 0000000..5925158
--- /dev/null
+++ b/src/checker.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2024 olang maintainers
+ *
+ * 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 "checker.h"
+#include "scope.h"
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+
+static void
+populate_scope(checker_t *checker, scope_t *scope, ast_node_t *ast);
+
+checker_t *
+checker_new(arena_t *arena)
+{
+ assert(arena);
+
+ checker_t *checker = (checker_t *)arena_alloc(arena, sizeof(checker_t));
+ if (checker == NULL) {
+ fprintf(stderr, "[FATAL] Out of memory: checker_new: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ checker->arena = arena;
+ return checker;
+}
+
+void
+checker_check(checker_t *checker, ast_node_t *ast)
+{
+ assert(checker);
+ assert(ast);
+
+ scope_t *scope = scope_new(checker->arena);
+ populate_scope(checker, scope, ast);
+
+ // TODO: traverse the ast tree to verify semantics
+}
+
+static void
+populate_scope(checker_t *checker, scope_t *scope, ast_node_t *ast)
+{
+ switch (ast->kind) {
+ case AST_NODE_PROGRAM: {
+ populate_scope(checker, scope, ast->as_program.fn);
+ return;
+ }
+
+ case AST_NODE_FN_DEF: {
+ // FIXME: insert function symbol to scope
+ populate_scope(checker, scope, ast->as_fn_def.block);
+ return;
+ }
+
+ case AST_NODE_IF_STMT: {
+ populate_scope(checker, scope, ast->as_if_stmt.cond);
+ populate_scope(checker, scope, ast->as_if_stmt.then);
+
+ if (ast->as_if_stmt._else) {
+ populate_scope(checker, scope, ast->as_if_stmt._else);
+ }
+
+ return;
+ }
+
+ case AST_NODE_BINARY_OP: {
+ ast_binary_op_t bin_op = ast->as_bin_op;
+
+ populate_scope(checker, scope, bin_op.lhs);
+ populate_scope(checker, scope, bin_op.rhs);
+ return;
+ }
+
+ case AST_NODE_RETURN_STMT: {
+ ast_return_stmt_t return_stmt = ast->as_return_stmt;
+
+ populate_scope(checker, scope, return_stmt.data);
+ return;
+ }
+
+ case AST_NODE_BLOCK: {
+ ast_block_t block = ast->as_block;
+ scope = scope_push(scope);
+
+ list_item_t *item = list_head(block.nodes);
+
+ while (item != NULL) {
+ populate_scope(checker, scope, (ast_node_t *)item->value);
+ item = list_next(item);
+ }
+
+ return;
+ }
+
+ case AST_NODE_VAR_DEF: {
+ string_view_t id = ast->as_var_def.identifier;
+ symbol_t *symbol = symbol_new(checker->arena, id);
+
+ scope_insert(scope, symbol);
+ ast->as_var_def.scope = scope;
+ return;
+ }
+
+ case AST_NODE_REF: {
+ ast->as_ref.scope = scope;
+ return;
+ }
+
+ case AST_NODE_LITERAL:
+ case AST_NODE_UNKNOWN:
+ return;
+ }
+}
diff --git a/src/checker.h b/src/checker.h
new file mode 100644
index 0000000..681f405
--- /dev/null
+++ b/src/checker.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2024 olang maintainers
+ *
+ * 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 CHECKER_H
+#define CHECKER_H
+
+#include "arena.h"
+#include "ast.h"
+
+typedef struct checker
+{
+ arena_t *arena;
+} checker_t;
+
+checker_t *
+checker_new(arena_t *arena);
+
+void
+checker_check(checker_t *checker, ast_node_t *ast);
+
+#endif /* CHECKER_H */
diff --git a/src/main.c b/src/main.c
index 030f34c..810bf2d 100644
--- a/src/main.c
+++ b/src/main.c
@@ -22,6 +22,7 @@
#include <string.h>
#include "arena.h"
+#include "checker.h"
#include "cli.h"
#include "codegen_linux_aarch64.h"
#include "codegen_linux_x86_64.h"
@@ -136,6 +137,9 @@ handle_codegen_linux(cli_opts_t *opts)
ast_node_t *ast = parser_parse_program(&parser);
+ checker_t *checker = checker_new(&arena);
+ checker_check(checker, ast);
+
char asm_file[opts->output_bin.size + 3];
sprintf(asm_file, "" SV_FMT ".s", SV_ARG(opts->output_bin));
--
2.46.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH olang v1 3/3] codegen: add support scopes and symbols lookups for var
2024-09-21 0:20 [PATCH olang v1 0/3] compiler: enable full compilation for vars Johnny Richard
2024-09-21 0:20 ` [PATCH olang v1 1/3] scope: create scope data structure Johnny Richard
2024-09-21 0:20 ` [PATCH olang v1 2/3] checker: create checker and populate scope on ast nodes Johnny Richard
@ 2024-09-21 0:20 ` Johnny Richard
2024-09-21 0:23 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-09-21 0:59 ` [PATCH olang v1 0/3] compiler: enable full compilation for vars Carlos Maniero
3 siblings, 1 reply; 6+ messages in thread
From: Johnny Richard @ 2024-09-21 0:20 UTC (permalink / raw)
To: ~johnnyrichard/olang-devel; +Cc: Johnny Richard
It introduces a new struct designed to maintain the stack offset for
local variables. This data structure facilitates the sharing of state
between function calls, including essential information such as the FILE
*out pointer.
Signed-off-by: Johnny Richard <johnny@johnnyrichard.com>
---
src/codegen_linux_x86_64.c | 347 ++++++++++--------
src/codegen_linux_x86_64.h | 16 +-
src/main.c | 8 +-
.../integration/tests/0024_var_definition.ol | 4 +
4 files changed, 229 insertions(+), 146 deletions(-)
diff --git a/src/codegen_linux_x86_64.c b/src/codegen_linux_x86_64.c
index 8ed127c..4e0ea52 100644
--- a/src/codegen_linux_x86_64.c
+++ b/src/codegen_linux_x86_64.c
@@ -20,22 +20,38 @@
#include "codegen_linux_x86_64.h"
#include "list.h"
+#include "map.h"
+#include "scope.h"
#define SYS_exit (60)
+#define PTR_HEX_CSTR_SIZE (18 + 1)
+// FIXME: move label_index to codegen_linux_x86_64_t structure
size_t label_index;
static void
-codegen_linux_x86_64_emit_start_entrypoint(FILE *out);
+codegen_linux_x86_64_emit_start_entrypoint(codegen_x86_64_t *codegen);
static void
-codegen_linux_x86_64_emit_function(FILE *out, ast_fn_definition_t *fn);
+codegen_linux_x86_64_emit_function(codegen_x86_64_t *codegen, ast_fn_definition_t *fn);
void
-codegen_linux_x86_64_emit_program(FILE *out, ast_node_t *node)
+codegen_linux_x86_64_init(codegen_x86_64_t *codegen, arena_t *arena, FILE *out)
+{
+ assert(codegen);
+ assert(arena);
+ assert(codegen);
+ codegen->base_offset = 0;
+ codegen->symbols_stack_offset = map_new(arena);
+ codegen->out = out;
+ codegen->arena = arena;
+}
+
+void
+codegen_linux_x86_64_emit_program(codegen_x86_64_t *codegen, ast_node_t *node)
{
label_index = 0;
- codegen_linux_x86_64_emit_start_entrypoint(out);
+ codegen_linux_x86_64_emit_start_entrypoint(codegen);
assert(node->kind == AST_NODE_PROGRAM);
ast_program_t program = node->as_program;
@@ -43,20 +59,20 @@ codegen_linux_x86_64_emit_program(FILE *out, ast_node_t *node)
ast_fn_definition_t fn = program.fn->as_fn_def;
assert(string_view_eq_to_cstr(fn.identifier, "main"));
- codegen_linux_x86_64_emit_function(out, &fn);
+ codegen_linux_x86_64_emit_function(codegen, &fn);
}
static void
-codegen_linux_x86_64_emit_start_entrypoint(FILE *out)
+codegen_linux_x86_64_emit_start_entrypoint(codegen_x86_64_t *codegen)
{
- fprintf(out, ".text\n");
- fprintf(out, ".globl _start\n\n");
-
- fprintf(out, "_start:\n");
- fprintf(out, " call main\n");
- fprintf(out, " mov %%eax, %%edi\n");
- fprintf(out, " mov $%d, %%eax\n", SYS_exit);
- fprintf(out, " syscall\n");
+ fprintf(codegen->out, ".text\n");
+ fprintf(codegen->out, ".globl _start\n\n");
+
+ fprintf(codegen->out, "_start:\n");
+ fprintf(codegen->out, " call main\n");
+ fprintf(codegen->out, " mov %%eax, %%edi\n");
+ fprintf(codegen->out, " mov $%d, %%eax\n", SYS_exit);
+ fprintf(codegen->out, " syscall\n");
}
static size_t
@@ -66,7 +82,7 @@ codegen_linux_x86_64_get_next_label(void)
}
static void
-codegen_linux_x86_64_emit_expression(FILE *out, ast_node_t *expr_node)
+codegen_linux_x86_64_emit_expression(codegen_x86_64_t *codegen, ast_node_t *expr_node)
{
switch (expr_node->kind) {
case AST_NODE_LITERAL: {
@@ -74,200 +90,215 @@ codegen_linux_x86_64_emit_expression(FILE *out, ast_node_t *expr_node)
assert(literal_u32.kind == AST_LITERAL_U32);
uint32_t n = literal_u32.as_u32;
- fprintf(out, " mov $%d, %%rax\n", n);
+ fprintf(codegen->out, " mov $%d, %%rax\n", n);
+ return;
+ }
+ case AST_NODE_REF: {
+ ast_ref_t ref = expr_node->as_ref;
+
+ symbol_t *symbol = scope_lookup(ref.scope, ref.identifier);
+ assert(symbol);
+
+ char symbol_ptr[PTR_HEX_CSTR_SIZE];
+ sprintf(symbol_ptr, "%p", (void *)symbol);
+
+ size_t *offset = (size_t *)map_get(codegen->symbols_stack_offset, symbol_ptr);
+ assert(offset);
+
+ fprintf(codegen->out, " mov -%ld(%%rbp), %%rax\n", *offset);
return;
}
case AST_NODE_BINARY_OP: {
ast_binary_op_t bin_op = expr_node->as_bin_op;
switch (bin_op.kind) {
case AST_BINOP_ADDITION: {
- codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
- fprintf(out, " push %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.rhs);
+ fprintf(codegen->out, " push %%rax\n");
- codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
- fprintf(out, " pop %%rcx\n");
- fprintf(out, " add %%rcx, %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.lhs);
+ fprintf(codegen->out, " pop %%rcx\n");
+ fprintf(codegen->out, " add %%rcx, %%rax\n");
return;
}
case AST_BINOP_MULTIPLICATION: {
- codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
- fprintf(out, " push %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.rhs);
+ fprintf(codegen->out, " push %%rax\n");
- codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
- fprintf(out, " pop %%rcx\n");
- fprintf(out, " mul %%rcx\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.lhs);
+ fprintf(codegen->out, " pop %%rcx\n");
+ fprintf(codegen->out, " mul %%rcx\n");
return;
}
case AST_BINOP_DIVISION: {
- codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
- fprintf(out, " push %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.rhs);
+ fprintf(codegen->out, " push %%rax\n");
- codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
- fprintf(out, " pop %%rcx\n");
- fprintf(out, " xor %%rdx, %%rdx\n");
- fprintf(out, " div %%rcx\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.lhs);
+ fprintf(codegen->out, " pop %%rcx\n");
+ fprintf(codegen->out, " xor %%rdx, %%rdx\n");
+ fprintf(codegen->out, " div %%rcx\n");
return;
}
case AST_BINOP_REMINDER: {
- codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
- fprintf(out, " push %%rax\n");
- fprintf(out, " xor %%edx, %%edx\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.rhs);
+ fprintf(codegen->out, " push %%rax\n");
+ fprintf(codegen->out, " xor %%edx, %%edx\n");
- codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
- fprintf(out, " pop %%rcx\n");
- fprintf(out, " xor %%rdx, %%rdx\n");
- fprintf(out, " div %%rcx\n");
- fprintf(out, " mov %%edx, %%eax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.lhs);
+ fprintf(codegen->out, " pop %%rcx\n");
+ fprintf(codegen->out, " xor %%rdx, %%rdx\n");
+ fprintf(codegen->out, " div %%rcx\n");
+ fprintf(codegen->out, " mov %%edx, %%eax\n");
return;
}
case AST_BINOP_SUBTRACTION: {
- codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
- fprintf(out, " push %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.rhs);
+ fprintf(codegen->out, " push %%rax\n");
- codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
- fprintf(out, " pop %%rcx\n");
- fprintf(out, " sub %%rcx, %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.lhs);
+ fprintf(codegen->out, " pop %%rcx\n");
+ fprintf(codegen->out, " sub %%rcx, %%rax\n");
return;
}
case AST_BINOP_CMP_EQ: {
- codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
- fprintf(out, " push %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.rhs);
+ fprintf(codegen->out, " push %%rax\n");
- codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
- fprintf(out, " pop %%rcx\n");
- fprintf(out, " cmp %%rcx, %%rax\n");
- fprintf(out, " sete %%al\n");
- fprintf(out, " movzb %%al, %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.lhs);
+ fprintf(codegen->out, " pop %%rcx\n");
+ fprintf(codegen->out, " cmp %%rcx, %%rax\n");
+ fprintf(codegen->out, " sete %%al\n");
+ fprintf(codegen->out, " movzb %%al, %%rax\n");
return;
}
case AST_BINOP_CMP_LT: {
- codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
- fprintf(out, " push %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.rhs);
+ fprintf(codegen->out, " push %%rax\n");
- codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
- fprintf(out, " pop %%rcx\n");
- fprintf(out, " cmp %%rcx, %%rax\n");
- fprintf(out, " setl %%al\n");
- fprintf(out, " movzb %%al, %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.lhs);
+ fprintf(codegen->out, " pop %%rcx\n");
+ fprintf(codegen->out, " cmp %%rcx, %%rax\n");
+ fprintf(codegen->out, " setl %%al\n");
+ fprintf(codegen->out, " movzb %%al, %%rax\n");
return;
}
case AST_BINOP_CMP_GT: {
- codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
- fprintf(out, " push %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.rhs);
+ fprintf(codegen->out, " push %%rax\n");
- codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
- fprintf(out, " pop %%rcx\n");
- fprintf(out, " cmp %%rcx, %%rax\n");
- fprintf(out, " setg %%al\n");
- fprintf(out, " movzb %%al, %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.lhs);
+ fprintf(codegen->out, " pop %%rcx\n");
+ fprintf(codegen->out, " cmp %%rcx, %%rax\n");
+ fprintf(codegen->out, " setg %%al\n");
+ fprintf(codegen->out, " movzb %%al, %%rax\n");
return;
}
case AST_BINOP_CMP_NEQ: {
- codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
- fprintf(out, " push %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.rhs);
+ fprintf(codegen->out, " push %%rax\n");
- codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
- fprintf(out, " pop %%rcx\n");
- fprintf(out, " cmp %%rcx, %%rax\n");
- fprintf(out, " setne %%al\n");
- fprintf(out, " movzb %%al, %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.lhs);
+ fprintf(codegen->out, " pop %%rcx\n");
+ fprintf(codegen->out, " cmp %%rcx, %%rax\n");
+ fprintf(codegen->out, " setne %%al\n");
+ fprintf(codegen->out, " movzb %%al, %%rax\n");
return;
}
case AST_BINOP_CMP_LEQ: {
- codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
- fprintf(out, " push %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.rhs);
+ fprintf(codegen->out, " push %%rax\n");
- codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
- fprintf(out, " pop %%rcx\n");
- fprintf(out, " cmp %%rcx, %%rax\n");
- fprintf(out, " setle %%al\n");
- fprintf(out, " movzb %%al, %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.lhs);
+ fprintf(codegen->out, " pop %%rcx\n");
+ fprintf(codegen->out, " cmp %%rcx, %%rax\n");
+ fprintf(codegen->out, " setle %%al\n");
+ fprintf(codegen->out, " movzb %%al, %%rax\n");
return;
}
case AST_BINOP_CMP_GEQ: {
- codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
- fprintf(out, " push %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.rhs);
+ fprintf(codegen->out, " push %%rax\n");
- codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
- fprintf(out, " pop %%rcx\n");
- fprintf(out, " cmp %%rcx, %%rax\n");
- fprintf(out, " setge %%al\n");
- fprintf(out, " movzb %%al, %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.lhs);
+ fprintf(codegen->out, " pop %%rcx\n");
+ fprintf(codegen->out, " cmp %%rcx, %%rax\n");
+ fprintf(codegen->out, " setge %%al\n");
+ fprintf(codegen->out, " movzb %%al, %%rax\n");
return;
}
case AST_BINOP_BITWISE_LSHIFT: {
- codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
- fprintf(out, " push %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.rhs);
+ fprintf(codegen->out, " push %%rax\n");
- codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
- fprintf(out, " pop %%rcx\n");
- fprintf(out, " shl %%cl, %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.lhs);
+ fprintf(codegen->out, " pop %%rcx\n");
+ fprintf(codegen->out, " shl %%cl, %%rax\n");
return;
}
case AST_BINOP_BITWISE_RSHIFT: {
- codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
- fprintf(out, " push %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.rhs);
+ fprintf(codegen->out, " push %%rax\n");
- codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
- fprintf(out, " pop %%rcx\n");
- fprintf(out, " shr %%cl, %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.lhs);
+ fprintf(codegen->out, " pop %%rcx\n");
+ fprintf(codegen->out, " shr %%cl, %%rax\n");
return;
}
case AST_BINOP_BITWISE_XOR: {
- codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
- fprintf(out, " push %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.rhs);
+ fprintf(codegen->out, " push %%rax\n");
- codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
- fprintf(out, " pop %%rcx\n");
- fprintf(out, " xor %%ecx, %%eax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.lhs);
+ fprintf(codegen->out, " pop %%rcx\n");
+ fprintf(codegen->out, " xor %%ecx, %%eax\n");
return;
}
case AST_BINOP_BITWISE_AND: {
- codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
- fprintf(out, " push %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.rhs);
+ fprintf(codegen->out, " push %%rax\n");
- codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
- fprintf(out, " pop %%rcx\n");
- fprintf(out, " and %%ecx, %%eax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.lhs);
+ fprintf(codegen->out, " pop %%rcx\n");
+ fprintf(codegen->out, " and %%ecx, %%eax\n");
return;
}
case AST_BINOP_BITWISE_OR: {
- codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
- fprintf(out, " push %%rax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.rhs);
+ fprintf(codegen->out, " push %%rax\n");
- codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
- fprintf(out, " pop %%rcx\n");
- fprintf(out, " or %%ecx, %%eax\n");
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.lhs);
+ fprintf(codegen->out, " pop %%rcx\n");
+ fprintf(codegen->out, " or %%ecx, %%eax\n");
return;
}
case AST_BINOP_LOGICAL_AND: {
size_t label_exit = codegen_linux_x86_64_get_next_label();
- codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
- fprintf(out, " cmp $0, %%rax\n");
- fprintf(out, " je .L%ld\n", label_exit);
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.lhs);
+ fprintf(codegen->out, " cmp $0, %%rax\n");
+ fprintf(codegen->out, " je .L%ld\n", label_exit);
- codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
- fprintf(out, " cmp $0, %%rax\n");
- fprintf(out, " je .L%ld\n", label_exit);
- fprintf(out, " mov $1, %%rax\n");
- fprintf(out, ".L%ld:\n", label_exit);
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.rhs);
+ fprintf(codegen->out, " cmp $0, %%rax\n");
+ fprintf(codegen->out, " je .L%ld\n", label_exit);
+ fprintf(codegen->out, " mov $1, %%rax\n");
+ fprintf(codegen->out, ".L%ld:\n", label_exit);
return;
}
@@ -275,17 +306,17 @@ codegen_linux_x86_64_emit_expression(FILE *out, ast_node_t *expr_node)
size_t label_t = codegen_linux_x86_64_get_next_label();
size_t label_f = codegen_linux_x86_64_get_next_label();
- codegen_linux_x86_64_emit_expression(out, bin_op.lhs);
- fprintf(out, " cmp $0, %%rax\n");
- fprintf(out, " jne .L%ld\n", label_t);
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.lhs);
+ fprintf(codegen->out, " cmp $0, %%rax\n");
+ fprintf(codegen->out, " jne .L%ld\n", label_t);
- codegen_linux_x86_64_emit_expression(out, bin_op.rhs);
- fprintf(out, " cmp $0, %%rax\n");
- fprintf(out, " je .L%ld\n", label_f);
+ codegen_linux_x86_64_emit_expression(codegen, bin_op.rhs);
+ fprintf(codegen->out, " cmp $0, %%rax\n");
+ fprintf(codegen->out, " je .L%ld\n", label_f);
- fprintf(out, ".L%ld:\n", label_t);
- fprintf(out, " mov $1, %%rax\n");
- fprintf(out, ".L%ld:\n", label_f);
+ fprintf(codegen->out, ".L%ld:\n", label_t);
+ fprintf(codegen->out, " mov $1, %%rax\n");
+ fprintf(codegen->out, ".L%ld:\n", label_f);
return;
}
@@ -300,7 +331,7 @@ codegen_linux_x86_64_emit_expression(FILE *out, ast_node_t *expr_node)
}
}
static void
-codegen_linux_x86_64_emit_block(FILE *out, ast_block_t *block)
+codegen_linux_x86_64_emit_block(codegen_x86_64_t *codegen, ast_block_t *block)
{
size_t nodes_len = list_size(block->nodes);
@@ -313,12 +344,37 @@ codegen_linux_x86_64_emit_block(FILE *out, ast_block_t *block)
ast_node_t *expr = return_stmt.data;
- codegen_linux_x86_64_emit_expression(out, expr);
+ codegen_linux_x86_64_emit_expression(codegen, expr);
+
+ fprintf(codegen->out, " ret\n");
- fprintf(out, " ret\n");
+ break;
+ }
+
+ case AST_NODE_VAR_DEF: {
+ ast_var_definition_t var_def = node->as_var_def;
+ scope_t *scope = var_def.scope;
+
+ symbol_t *symbol = scope_lookup(scope, var_def.identifier);
+ assert(symbol);
+
+ char symbol_ptr[PTR_HEX_CSTR_SIZE];
+ sprintf(symbol_ptr, "%p", (void *)symbol);
+
+ if (var_def.value) {
+ codegen_linux_x86_64_emit_expression(codegen, var_def.value);
+ }
+
+ codegen->base_offset += 8;
+ size_t *offset = arena_alloc(codegen->arena, sizeof(size_t));
+ *offset = codegen->base_offset;
+
+ map_put(codegen->symbols_stack_offset, symbol_ptr, offset);
+ fprintf(codegen->out, " mov %%rax, -%ld(%%rbp)\n", codegen->base_offset);
break;
}
+
case AST_NODE_IF_STMT: {
ast_if_stmt_t if_stmt = node->as_if_stmt;
@@ -329,28 +385,30 @@ codegen_linux_x86_64_emit_block(FILE *out, ast_block_t *block)
size_t end_if_label = codegen_linux_x86_64_get_next_label();
size_t end_else_label = codegen_linux_x86_64_get_next_label();
- codegen_linux_x86_64_emit_expression(out, cond);
- fprintf(out, " cmp $1, %%rax\n");
- fprintf(out, " jnz .L%ld\n", end_if_label);
+ codegen_linux_x86_64_emit_expression(codegen, cond);
+ fprintf(codegen->out, " cmp $1, %%rax\n");
+ fprintf(codegen->out, " jnz .L%ld\n", end_if_label);
assert(then->kind == AST_NODE_BLOCK && "invalid if-then block");
ast_block_t then_block = then->as_block;
- codegen_linux_x86_64_emit_block(out, &then_block);
- fprintf(out, " jmp .L%ld\n", end_else_label);
+ codegen_linux_x86_64_emit_block(codegen, &then_block);
+ fprintf(codegen->out, " jmp .L%ld\n", end_else_label);
- fprintf(out, ".L%ld:\n", end_if_label);
+ fprintf(codegen->out, ".L%ld:\n", end_if_label);
if (_else != NULL) {
ast_block_t else_block = _else->as_block;
- codegen_linux_x86_64_emit_block(out, &else_block);
+ codegen_linux_x86_64_emit_block(codegen, &else_block);
}
- fprintf(out, ".L%ld:\n", end_else_label);
+ fprintf(codegen->out, ".L%ld:\n", end_else_label);
break;
}
default: {
+ // FIXME: improve error: replace the node->kind to a string representation
+ fprintf(stderr, "node kind %d not supported\n", node->kind);
assert(0 && "unsupported block statement");
break;
}
@@ -359,13 +417,16 @@ codegen_linux_x86_64_emit_block(FILE *out, ast_block_t *block)
}
static void
-codegen_linux_x86_64_emit_function(FILE *out, ast_fn_definition_t *fn)
+codegen_linux_x86_64_emit_function(codegen_x86_64_t *codegen, ast_fn_definition_t *fn)
{
+ codegen->base_offset = 0;
ast_node_t *block_node = fn->block;
- fprintf(out, "" SV_FMT ":\n", SV_ARG(fn->identifier));
+ fprintf(codegen->out, "" SV_FMT ":\n", SV_ARG(fn->identifier));
+
+ fprintf(codegen->out, " mov %%rsp, %%rbp\n");
assert(block_node->kind == AST_NODE_BLOCK);
ast_block_t block = block_node->as_block;
- codegen_linux_x86_64_emit_block(out, &block);
+ codegen_linux_x86_64_emit_block(codegen, &block);
}
diff --git a/src/codegen_linux_x86_64.h b/src/codegen_linux_x86_64.h
index 2050c91..cad530a 100644
--- a/src/codegen_linux_x86_64.h
+++ b/src/codegen_linux_x86_64.h
@@ -17,9 +17,23 @@
#ifndef CODEGEN_X86_64_H
#define CODEGEN_X86_64_H
+#include "arena.h"
#include "ast.h"
+#include "map.h"
+#include <stdio.h>
+
+typedef struct codegen_x86_64
+{
+ arena_t *arena;
+ size_t base_offset;
+ map_t *symbols_stack_offset;
+ FILE *out;
+} codegen_x86_64_t;
+
+void
+codegen_linux_x86_64_init(codegen_x86_64_t *codegen, arena_t *arena, FILE *out);
void
-codegen_linux_x86_64_emit_program(FILE *out, ast_node_t *prog);
+codegen_linux_x86_64_emit_program(codegen_x86_64_t *codegen, ast_node_t *prog);
#endif /* CODEGEN_X86_64_H */
diff --git a/src/main.c b/src/main.c
index 810bf2d..312b0c1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -147,10 +147,14 @@ handle_codegen_linux(cli_opts_t *opts)
assert(out);
if (!(opts->options & CLI_OPT_ARCH)) {
- codegen_linux_x86_64_emit_program(out, ast);
+ codegen_x86_64_t codegen = { 0 };
+ codegen_linux_x86_64_init(&codegen, &arena, out);
+ codegen_linux_x86_64_emit_program(&codegen, ast);
} else {
if (strcmp(opts->arch, "x86_64") == 0) {
- codegen_linux_x86_64_emit_program(out, ast);
+ codegen_x86_64_t codegen = { 0 };
+ codegen_linux_x86_64_init(&codegen, &arena, out);
+ codegen_linux_x86_64_emit_program(&codegen, ast);
} else if (strcmp(opts->arch, "aarch64") == 0) {
codegen_linux_aarch64_emit_program(out, ast);
} else {
diff --git a/tests/integration/tests/0024_var_definition.ol b/tests/integration/tests/0024_var_definition.ol
index 241fc1a..5c23449 100644
--- a/tests/integration/tests/0024_var_definition.ol
+++ b/tests/integration/tests/0024_var_definition.ol
@@ -18,6 +18,10 @@ fn main(): u32 {
return code
}
+# TEST test_compile(exit_code=0)
+
+# TEST test_run_binary(exit_code=0)
+
# TEST test_contains_tokens WITH
# ./tests/0024_var_definition.ol:17:3: <var>
# END
--
2.46.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [olang/patches/.build.yml] build success
2024-09-21 0:20 ` [PATCH olang v1 3/3] codegen: add support scopes and symbols lookups for var Johnny Richard
@ 2024-09-21 0:23 ` builds.sr.ht
0 siblings, 0 replies; 6+ messages in thread
From: builds.sr.ht @ 2024-09-21 0:23 UTC (permalink / raw)
To: Johnny Richard; +Cc: ~johnnyrichard/olang-devel
olang/patches/.build.yml: SUCCESS in 21s
[compiler: enable full compilation for vars][0] from [Johnny Richard][1]
[0]: https://lists.sr.ht/~johnnyrichard/olang-devel/patches/55131
[1]: mailto:johnny@johnnyrichard.com
✓ #1333519 SUCCESS olang/patches/.build.yml https://builds.sr.ht/~johnnyrichard/job/1333519
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH olang v1 0/3] compiler: enable full compilation for vars
2024-09-21 0:20 [PATCH olang v1 0/3] compiler: enable full compilation for vars Johnny Richard
` (2 preceding siblings ...)
2024-09-21 0:20 ` [PATCH olang v1 3/3] codegen: add support scopes and symbols lookups for var Johnny Richard
@ 2024-09-21 0:59 ` Carlos Maniero
3 siblings, 0 replies; 6+ messages in thread
From: Carlos Maniero @ 2024-09-21 0:59 UTC (permalink / raw)
To: Johnny Richard, ~johnnyrichard/olang-devel
We did it! Applied!
To git.sr.ht:~johnnyrichard/olang
29cc9fc..cb4b63f main -> main
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2024-09-21 0:59 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-09-21 0:20 [PATCH olang v1 0/3] compiler: enable full compilation for vars Johnny Richard
2024-09-21 0:20 ` [PATCH olang v1 1/3] scope: create scope data structure Johnny Richard
2024-09-21 0:20 ` [PATCH olang v1 2/3] checker: create checker and populate scope on ast nodes Johnny Richard
2024-09-21 0:20 ` [PATCH olang v1 3/3] codegen: add support scopes and symbols lookups for var Johnny Richard
2024-09-21 0:23 ` [olang/patches/.build.yml] build success builds.sr.ht
2024-09-21 0:59 ` [PATCH olang v1 0/3] compiler: enable full compilation for vars Carlos Maniero
Code repositories for project(s) associated with this public inbox
https://git.johnnyrichard.com/olang.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox