134 lines
3.5 KiB
C
134 lines
3.5 KiB
C
#include "bf_compiler.h"
|
|
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <libtcc.h>
|
|
|
|
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 <inttypes.h>\n");
|
|
str_buffer_append(&c_program, "#include <stdlib.h>\n");
|
|
str_buffer_append(&c_program, "#include <assert.h>\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;
|
|
}
|