#include "bf_compiler.h" #include #include #include #include struct str_buffer { char *data; size_t len; size_t capacity; }; static void str_buffer_init(struct str_buffer *buffer, size_t capacity) { buffer->data = malloc(capacity); assert(buffer->data != NULL); buffer->len = 0; buffer->capacity = capacity; } static void str_buffer_deinit(struct str_buffer *buffer) { free(buffer->data); buffer->data = NULL; buffer->capacity = 0; buffer->len = 0; } static void str_buffer_append_with_len(struct str_buffer *buffer, const char *text, size_t text_len) { if (buffer->len + text_len > buffer->capacity) { while (buffer->len + text_len > buffer->capacity) { buffer->capacity *= 2; } buffer->data = realloc(buffer->data, buffer->capacity); assert(buffer->data != NULL); } memcpy(buffer->data + buffer->len, text, text_len); buffer->len += text_len; } static void str_buffer_append(struct str_buffer *buffer, const char *text) { str_buffer_append_with_len(buffer, text, strlen(text)); } static int bf_compiler_compile_tinycc(struct bf_compiler *compiler, const char *output_filename, const char *program, size_t program_len) { struct str_buffer c_program = { 0 }; str_buffer_init(&c_program, 128); int rc = -1; TCCState *state = tcc_new(); if (!state) { goto err; } const char *cell_type = NULL; if (compiler->cell_size == 8) { cell_type = "uint8_t"; } else if (compiler->cell_size == 16) { cell_type = "uint16_t"; } else if (compiler->cell_size == 32) { cell_type = "uint32_t"; } else { return -1; } char line_buffer[256] = { 0 }; str_buffer_append(&c_program, "#include \n"); str_buffer_append(&c_program, "#include \n"); str_buffer_append(&c_program, "#include \n"); snprintf(line_buffer, sizeof(line_buffer), "typedef %s cell_t;\n", cell_type); str_buffer_append(&c_program, line_buffer); str_buffer_append(&c_program, "int main()\n"); str_buffer_append(&c_program, "{\n"); snprintf(line_buffer, sizeof(line_buffer), "size_t data_len = %d;\n", compiler->data_len); str_buffer_append(&c_program, line_buffer); str_buffer_append(&c_program, "cell_t data_pointer = 0;\n"); str_buffer_append(&c_program, "cell_t *data = calloc(data_len, sizeof(cell_t));\n"); str_buffer_append(&c_program, "assert(data != NULL);\n"); for (int i = 0; i < program_len; i++) { char inst = program[i]; if (inst == '>') { str_buffer_append(&c_program, "data_pointer++;\n"); } else if (inst == '<') { str_buffer_append(&c_program, "data_pointer--;\n"); } else if (inst == '+') { str_buffer_append(&c_program, "data[data_pointer]++;\n"); } else if (inst == '-') { str_buffer_append(&c_program, "data[data_pointer]--;\n"); } else if (inst == '.') { str_buffer_append(&c_program, "putchar(data[data_pointer]); fflush(0);\n"); } else if (inst == ',') { str_buffer_append(&c_program, "data[data_pointer] = getchar();\n"); } else if (inst == '[') { str_buffer_append(&c_program, "while (data[data_pointer] != 0) {\n"); } else if (inst == ']') { str_buffer_append(&c_program, "}\n"); } } str_buffer_append(&c_program, "free(data);\n"); str_buffer_append(&c_program, "return 0;\n"); str_buffer_append(&c_program, "}\n"); str_buffer_append_with_len(&c_program, "\0", 1); tcc_set_output_type(state, TCC_OUTPUT_EXE); tcc_set_options(state, "-w"); if (tcc_compile_string(state, c_program.data) == -1) { goto err; } if (tcc_output_file(state, output_filename)) { goto err; } rc = 0; err: tcc_delete(state); str_buffer_deinit(&c_program); return rc; }