aboutsummaryrefslogtreecommitdiff
path: root/src/codegen.c
diff options
context:
space:
mode:
authorElis Eriksson <spelis@spelis.li>2026-06-13 17:40:25 +0200
committerElis Eriksson <spelis@spelis.li>2026-06-13 17:40:25 +0200
commit7ccae1c362a45b28f4fbf96da4f479730e4b382b (patch)
treef59ba4d76221590901784464a03a6a871d774305 /src/codegen.c
downloadbfc-7ccae1c362a45b28f4fbf96da4f479730e4b382b.tar
bfc-7ccae1c362a45b28f4fbf96da4f479730e4b382b.tar.gz
bfc-7ccae1c362a45b28f4fbf96da4f479730e4b382b.tar.bz2
bfc-7ccae1c362a45b28f4fbf96da4f479730e4b382b.tar.lz
bfc-7ccae1c362a45b28f4fbf96da4f479730e4b382b.tar.xz
bfc-7ccae1c362a45b28f4fbf96da4f479730e4b382b.tar.zst
bfc-7ccae1c362a45b28f4fbf96da4f479730e4b382b.zip
Initial Commit, probably needs heavy code cleanup
Diffstat (limited to 'src/codegen.c')
-rw-r--r--src/codegen.c148
1 files changed, 148 insertions, 0 deletions
diff --git a/src/codegen.c b/src/codegen.c
new file mode 100644
index 0000000..e4972db
--- /dev/null
+++ b/src/codegen.c
@@ -0,0 +1,148 @@
+#include "all.h"
+#include "str.h"
+
+static void emit_includes(str *out) {
+ str_append(out, "#include <stdio.h>\n");
+ str_append(out, "#include <stdlib.h>\n");
+ str_append(out, "#include <string.h>\n\n");
+}
+
+static void emit_runtime(str *out) {
+ str_append(
+ out,
+ "typedef struct {\n"
+ " unsigned char *data;\n"
+ " size_t size;\n"
+ "} tape_t;\n\n"
+
+ "static void tape_init(tape_t *t, size_t initial) {\n"
+ " t->data = calloc(initial, 1);\n"
+ " t->size = initial;\n"
+ "}\n\n"
+
+ "static void tape_grow_right(tape_t *t, size_t needed) {\n"
+ " size_t new_size = t->size;\n"
+ " while (new_size <= needed) new_size *= 2;\n"
+ " unsigned char *new_data = calloc(new_size, 1);\n"
+ " memcpy(new_data, t->data, t->size);\n"
+ " free(t->data);\n"
+ " t->data = new_data;\n"
+ " t->size = new_size;\n"
+ "}\n\n"
+
+ "static void tape_grow_left(tape_t *t, size_t add, size_t *ptr) {\n"
+ " size_t new_size = t->size + add;\n"
+ " unsigned char *new_data = calloc(new_size, 1);\n"
+ " memcpy(new_data + add, t->data, t->size);\n"
+ " free(t->data);\n"
+ " t->data = new_data;\n"
+ " t->size = new_size;\n"
+ " *ptr += add;\n"
+ "}\n\n"
+
+ "static void tape_move_right(tape_t *t, size_t *ptr, size_t amount) {\n"
+ " *ptr += amount;\n"
+ " if (*ptr >= t->size)\n"
+ " tape_grow_right(t, *ptr);\n"
+ "}\n\n"
+
+ "static void tape_move_left(tape_t *t, size_t *ptr, size_t amount) {\n"
+ " if (amount > *ptr) {\n"
+ " size_t need = amount - *ptr;\n"
+ " size_t add = t->size;\n"
+ " while (add <= need)\n"
+ " add *= 2;\n"
+ " tape_grow_left(t, add, ptr);\n"
+ " }\n"
+ " *ptr -= amount;\n"
+ "}\n\n");
+}
+
+static void emit_prelude(str *out) {
+ str_append(out, "int main(void)\n"
+ "{\n"
+ " tape_t tape;\n"
+ " tape_init(&tape, 32);\n"
+ " size_t ptr = tape.size / 2;\n\n");
+}
+
+static void emit_epilogue(str *out) {
+ str_append(out, " free(tape.data);\n"
+ " return 0;\n"
+ "}\n");
+}
+
+static void emit_indent(str *out, int indent) {
+ for (int i = 0; i < indent; i++)
+ str_append(out, " ");
+}
+
+void emit_node(str *out, ast_node_t *node, int indent) {
+ for (; node; node = node->next) {
+ switch (node->type) {
+ case AST_INC:
+ emit_indent(out, indent);
+ str_append(out, "tape.data[ptr] += ");
+ str_appendf(out, "%d;\n", node->val);
+ break;
+
+ case AST_DEC:
+ emit_indent(out, indent);
+ str_append(out, "tape.data[ptr] -= ");
+ str_appendf(out, "%d;\n", node->val);
+ break;
+
+ case AST_PTR_INC:
+ emit_indent(out, indent);
+ str_append(out, "tape_move_right(&tape, &ptr, ");
+ str_appendf(out, "%d", node->val);
+ str_append(out, ");\n");
+ break;
+
+ case AST_PTR_DEC:
+ emit_indent(out, indent);
+ str_append(out, "tape_move_left(&tape, &ptr, ");
+ str_appendf(out, "%d", node->val);
+ str_append(out, ");\n");
+ break;
+
+ case AST_OUT:
+ emit_indent(out, indent);
+ str_append(out, "putchar((int)tape.data[ptr]);\n");
+ break;
+
+ case AST_IN:
+ emit_indent(out, indent);
+ str_append(out,
+ "{ int ch = getchar();\n"
+ " tape.data[ptr] = (ch == EOF) ? 0 : (unsigned char)ch; }\n");
+ break;
+
+ case AST_LOOP:
+ emit_indent(out, indent);
+ str_append(out, "while (tape.data[ptr]) {\n");
+
+ for (int i = 0; i < node->children.len; i++) {
+ emit_node(out, node->children._data[i], indent + 1);
+ }
+
+ emit_indent(out, indent);
+ str_append(out, "}\n");
+ break;
+ }
+ }
+}
+
+str gen_code(ast_node_t *ast) {
+ str out = {0};
+
+ emit_includes(&out);
+ emit_runtime(&out);
+ emit_prelude(&out);
+
+ emit_node(&out, ast, 1);
+
+ emit_epilogue(&out);
+
+ return out;
+}