brainfuck/src/bf_compiler_nasm.c
2024-09-14 15:10:05 +03:00

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;
}