130 lines
3.4 KiB
C
130 lines
3.4 KiB
C
#include "bf_compiler.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
static void fwrite_str(char *str, FILE *f)
|
|
{
|
|
fwrite(str, strlen(str), 1, f);
|
|
}
|
|
|
|
static void fwrite_str_line(char *str, FILE *f)
|
|
{
|
|
fwrite_str(str, f);
|
|
fwrite_str("\n", f);
|
|
}
|
|
|
|
static int bf_compiler_compile_nasm(struct bf_compiler *compiler, const char *output_filename, const char *program, size_t program_len)
|
|
{
|
|
int rc = -1;
|
|
FILE *f = NULL;
|
|
|
|
if (compiler->cell_size != 8) {
|
|
return -1;
|
|
}
|
|
|
|
// TODO: Write to temp directory
|
|
f = fopen("tmp.asm", "w");
|
|
if (!f) {
|
|
goto err;
|
|
}
|
|
|
|
fwrite_str_line("section .bss", f);
|
|
char data_define[128] = { 0 };
|
|
snprintf(data_define, sizeof(data_define), "data resb %d", compiler->data_len);
|
|
fwrite_str_line(data_define, f);
|
|
|
|
fwrite_str_line("section .text", f);
|
|
fwrite_str_line("global _start", f);
|
|
fwrite_str_line("_start:", f);
|
|
|
|
fwrite_str_line("mov bl, 0", f);
|
|
|
|
uint32_t loop_stack[128] = { 0 };
|
|
uint32_t loop_stack_len = 0;
|
|
|
|
uint32_t last_loop_index = 0;
|
|
for (int i = 0; i < program_len; i++) {
|
|
char inst = program[i];
|
|
|
|
if (inst == '>') {
|
|
fwrite_str_line("; >", f);
|
|
fwrite_str_line("inc bl", f);
|
|
} else if (inst == '<') {
|
|
fwrite_str_line("; <", f);
|
|
fwrite_str_line("dec bl", f);
|
|
} else if (inst == '+') {
|
|
fwrite_str_line("; +", f);
|
|
fwrite_str_line("inc byte [data + rbx]", f);
|
|
} else if (inst == '-') {
|
|
fwrite_str_line("; -", f);
|
|
fwrite_str_line("dec byte [data + rbx]", f);
|
|
} else if (inst == '.') {
|
|
fwrite_str_line("; .", f);
|
|
// sys_write
|
|
fwrite_str_line("mov rax, 1", f); // Syscall id
|
|
fwrite_str_line("mov rdi, 1", f); // fd
|
|
fwrite_str_line("lea rsi, byte [data + rbx]", f); // buff
|
|
fwrite_str_line("mov rdx, 1", f); // count
|
|
fwrite_str_line("syscall", f);
|
|
} else if (inst == ',') {
|
|
fwrite_str_line("; ,", f);
|
|
// sys_read
|
|
fwrite_str_line("mov rax, 0", f); // Syscall id
|
|
fwrite_str_line("mov rdi, 0", f); // fd
|
|
fwrite_str_line("lea rsi, byte [data + rbx]", f); // buff
|
|
fwrite_str_line("mov rdx, 1", f); // count
|
|
fwrite_str_line("syscall", f);
|
|
} else if (inst == '[') {
|
|
fwrite_str_line("; [", f);
|
|
|
|
uint32_t loop_index = last_loop_index;
|
|
last_loop_index++;
|
|
|
|
loop_stack[loop_stack_len++] = loop_index;
|
|
|
|
char start_label[128] = { 0 };
|
|
snprintf(start_label, sizeof(start_label), "S%d_start:", loop_index);
|
|
fwrite_str_line(start_label, f);
|
|
|
|
fwrite_str_line("cmp byte [data + rbx], 0", f);
|
|
|
|
char jump_inst[128] = { 0 };
|
|
snprintf(jump_inst, sizeof(jump_inst), "jz S%d_end", loop_index);
|
|
fwrite_str_line(jump_inst, f);
|
|
} else if (inst == ']') {
|
|
fwrite_str_line("; ]", f);
|
|
uint32_t loop_index = loop_stack[--loop_stack_len];
|
|
|
|
char jump_to_start[128] = { 0 };
|
|
snprintf(jump_to_start, sizeof(jump_to_start), "jmp S%d_start", loop_index);
|
|
fwrite_str_line(jump_to_start, f);
|
|
|
|
char end_label[128] = { 0 };
|
|
snprintf(end_label, sizeof(end_label), "S%d_end:", loop_index);
|
|
fwrite_str_line(end_label, f);
|
|
}
|
|
}
|
|
|
|
fwrite_str_line("; exit(0)", f);
|
|
fwrite_str_line("mov rax, 60", f);
|
|
fwrite_str_line("mov rdi, 0", f);
|
|
fwrite_str_line("syscall", f);
|
|
|
|
fclose(f);
|
|
f = NULL;
|
|
|
|
// TODO: Use exec instead of system
|
|
// TODO: Don't hardcode the platform
|
|
system("nasm -felf64 tmp.asm -o tmp.o");
|
|
|
|
char ld_command[256] = { 0 };
|
|
snprintf(ld_command, sizeof(ld_command), "ld tmp.o -o %s", output_filename);
|
|
system(ld_command);
|
|
rc = 0;
|
|
err:
|
|
if (f) fclose(f);
|
|
return rc;
|
|
}
|