#include "all.h" #include "str.h" static void emit_includes(str *out) { str_append(out, "#include \n"); str_append(out, "#include \n"); str_append(out, "#include \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; }