Skip to content

Instantly share code, notes, and snippets.

@Hachem-H
Created August 21, 2023 09:26
Show Gist options
  • Save Hachem-H/d553bd5bcb97181e31b969f139c4eac4 to your computer and use it in GitHub Desktop.
Save Hachem-H/d553bd5bcb97181e31b969f139c4eac4 to your computer and use it in GitHub Desktop.
A Brainf**ck compiler written x64 NASM assembly.
; The BrainCell Brainf**k Compiler
; --------------------------------
;
; BrainCell is a basic brainf**k compiler written in an evening,
; It contains a basic transpiler which translates brainf**k code,
; into the equivalent C code. Then uses `gcc` to compile the
; generated output. Though I do recognize the fact that this
; is not an optimized approach in any way, shape or form,
; but this is a rather fun and simple project, not designed to
; be serious.
;
; The following is the equivalent C code:
; ```c
; #include <stdio.h>
; #include <stdlib.h>
;
; char* ReadFile(const char* filepath)
; {
; FILE* file = fopen(filepath, "r");
; if (!file)
; {
; puts("[ERR]: Could not read file.");
; return NULL;
; }
;
; fseek(file, 0, SEEK_END);
; size_t size = ftell(file);
; rewind(file);
;
; char* buffer = (char*) malloc(size);
; fread(buffer, size, 1, file);
; buffer[size] = 0;
;
; fclose(file);
; return buffer;
; }
;
; void Compile(const char* sourceCode)
; {
; char* header = "#include <stdio.h>\n"
; "static char stack[3000];"
; "static int pointer;"
; "int main(void) {";
;
; FILE* transpiled = fopen("tmp.c", "w");
; if (!transpiled)
; {
; puts("[ERR]: Could not generate output file.");
; return NULL;
; }
;
; fputs(header, transpiled);
;
; for (size_t i = 0; i < strlen(sourceCode); i++)
; {
; char character = sourceCode[i];
; switch (character)
; {
; case '>': fputs("if (pointer+1>2999) pointer=0; else pointer++;", transpiled); break;
; case '<': fputs("if (pointer-1<0) pointer=2999; else pointer--;", transpiled); break;
; case '+': fputs("stack[pointer]++;", transpiled); break;
; case '-': fputs("stack[pointer]--;", transpiled); break;
;
; case '[': fputs("while (stack[pointer]) {", transpiled); break;
; case ']': fputs("}", transpiled);
;
; case '.': fputs("putchar(stack[pointer]);", transpiled); break;
; case ',': fputs("stack[pointer] = getchar();", transpiled); break;
; default: break;
; }
; }
;
; fputs('}', transpiled);
; fclose(transpiled);
;
; system("gcc -o output temp.c -O2");
; system("rm temp.c");
; }
;
; int main(int argc, char* argv[])
; {
; if (argc < 2)
; {
; puts("Usage: BrainCell [source]");
; return 0;
; }
;
; char* sourceCode = ReadFile(argv[1]);
; Compile(sourceCode);
; free(sourceCode);
; }
; ```
; To assemble and link, simply use nasm and gcc like so:
; ```sh
; $ nasm -felf64 BrainCell.asm
; $ gcc -no-pie BrainCell.o -o BrainCell -lc
; ```
global main
extern fopen
extern fputs
extern fseek
extern ftell
extern rewind
extern fread
extern fclose
extern puts
extern system
extern malloc
extern free
section .rodata
readError db "[ERR]: Could not read file.", 0x00
readMode db "r", 0x00
writeError db "[ERR]: Could not generate output file.", 0x00
writeMode db "w", 0x00
header db "#include <stdio.h>", 0x0A
db "static char stack[3000];",
db "static int pointer;",
db "int main(void) {", 0x0A, 0x00
footer db "}", 0x0A, 0x0A, 0x00
SHIFT_RIGHT db "if (pointer+1>2999) pointer = 0; else pointer++;", 0x00
SHIFT_LEFT db "if (pointer-1<0) pointer=2999; else pointer--;", 0x00
INCREMENT db "stack[pointer]++;", 0x00
DECREMENT db "stack[pointer]--;", 0x00
LOOP_START db "while (stack[pointer]) {", 0x00
LOOP_END db "}", 0x00
PRINT db "putchar(stack[pointer]);", 0x00
READ db "stack[pointer]=getchar();", 0x00
compileCommand db "gcc -o output.o tmp.c -O2", 0x00
removeCommand db "rm tmp.c", 0x00
tempPath db "tmp.c", 0x00
usage db "Usage: BrainCell [source]", 0x00
section .bss
originalRSP resq 0x1
originalRSI resq 0x1
sourceFile resq 0x1
outputFile resq 0x1
sourceCodeBuffer resq 0x1
sourceCodeSize resq 0x1
iterator resq 0x1
section .text
ReadFile:
push rbp
mov rbp, rsp
mov rsi, readMode
call fopen
mov QWORD [sourceFile], rax
test rax, rax
jz ReadFileError
mov rdi, QWORD [sourceFile]
xor rsi, 0x00
mov rdx, 0x02
call fseek
mov rdi, QWORD [sourceFile]
call ftell
mov QWORD [sourceCodeSize], rax
mov rdi, [sourceFile]
call rewind
mov rdi, QWORD [sourceCodeSize]
call malloc
mov QWORD [sourceCodeBuffer], rax
mov rdi, QWORD [sourceCodeBuffer]
mov rsi, QWORD [sourceCodeSize]
mov rdx, 0x1
mov rcx, QWORD [sourceFile]
call fread
mov rax, QWORD [sourceCodeSize]
mov rsi, QWORD [sourceCodeBuffer]
add rsi, rax
mov BYTE [rsi], 0x00
jmp ReadFileEnd
ReadFileError:
lea rdi, [rel readError]
call puts
jmp ReadFileEnd
ReadFileEnd:
pop rbp
ret
Compile:
push rbp
mov rbp, rsp
mov rdi, tempPath
mov rsi, writeMode
call fopen
mov QWORD [outputFile], rax
test rax, rax
jz CompileError
mov rdi, header
mov rsi, QWORD [outputFile]
call fputs
mov rsi, [sourceCodeBuffer]
CompileLoopStart:
mov al, BYTE [rsi]
cmp al, 0x00
je CompileLoopEnd
push rsi
cmp al, "+"
je AppendInc
cmp al, "-"
je AppendDec
cmp al, "<"
je AppendShiftR
cmp al, ">"
je AppendShiftL
cmp al, "["
je AppendLoopStart
cmp al, "]"
je AppendLoopEnd
cmp al, "."
je AppendPrint
cmp al, ","
je AppendPrint
jmp EndCase
AppendInc:
mov rdi, INCREMENT
mov rsi, QWORD [outputFile]
call fputs
jmp EndCase
AppendDec:
mov rdi, DECREMENT
mov rsi, QWORD [outputFile]
call fputs
jmp EndCase
AppendShiftR:
mov rdi, SHIFT_RIGHT
mov rsi, QWORD [outputFile]
call fputs
jmp EndCase
AppendShiftL:
mov rdi, SHIFT_LEFT
mov rsi, QWORD [outputFile]
call fputs
jmp EndCase
AppendLoopStart:
mov rdi, LOOP_START
mov rsi, QWORD [outputFile]
call fputs
jmp EndCase
AppendLoopEnd:
mov rdi, LOOP_END
mov rsi, QWORD [outputFile]
call fputs
jmp EndCase
AppendPrint:
mov rdi, PRINT
mov rsi, QWORD [outputFile]
call fputs
jmp EndCase
AppendRead:
mov rdi, READ
mov rsi, QWORD [outputFile]
call fputs
jmp EndCase
EndCase:
pop rsi
inc rsi
jmp CompileLoopStart
CompileLoopEnd:
mov rdi, footer
mov rsi, QWORD [outputFile]
call fputs
mov rdi, QWORD [outputFile]
call fclose
mov QWORD [originalRSP], rsp
mov QWORD [originalRSI], rsi
mov rsi, rsp
sub rsp, 0x8
mov rdi, compileCommand
call system
mov rdi, removeCommand
call system
mov rsp, QWORD [originalRSP]
mov rsi, QWORD [originalRSI]
jmp CompileEnd
CompileError:
lea rdi, [rel writeError]
call puts
jmp CompileEnd
CompileEnd:
pop rbp
ret
main:
cmp rdi, 0x2
jl PrintUsage
mov rdi, [rsi+0x8]
call ReadFile
call Compile
mov rdi, [sourceCodeBuffer]
call free
jmp ProgramEnd
PrintUsage:
mov rdi, usage
call puts
ProgramEnd:
ret
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment