diff options
| author | Elis Eriksson <spelis@spelis.li> | 2026-06-13 17:40:25 +0200 |
|---|---|---|
| committer | Elis Eriksson <spelis@spelis.li> | 2026-06-13 17:40:25 +0200 |
| commit | 7ccae1c362a45b28f4fbf96da4f479730e4b382b (patch) | |
| tree | f59ba4d76221590901784464a03a6a871d774305 /src/codegen.c | |
| download | bfc-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.c | 148 |
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; +} |
