一個功能完整的 Brainfuck 工具集,包含解譯器和 x86 編譯器,能夠執行或編譯標準的 Brainfuck 程式。
- Brainfuck 解譯器 - 直接執行 Brainfuck 程式
- x86-32 編譯器 - 將 Brainfuck 編譯為原生 32 位元機器碼
- x86-64 編譯器 - 將 Brainfuck 編譯為原生 64 位元機器碼
- LLVM 後端 - 產生 LLVM IR,跨平台以 clang 執行
- 高效能 - 編譯版本比解譯版本快 4-10 倍
- 系統調用 - 編譯器使用 Linux 系統調用,不依賴 C 標準庫
- 30,000 記憶體單元 - 符合 Brainfuck 標準規範
Brainfuck 是一種極簡主義的程式語言,只包含 8 個指令:
>- 指標向右移動<- 指標向左移動+- 當前記憶體單元值加 1-- 當前記憶體單元值減 1.- 輸出當前記憶體單元的值(ASCII 字元),- 從輸入讀取一個字元到當前記憶體單元[- 如果當前記憶體單元值為 0,跳轉到對應的]之後]- 如果當前記憶體單元值不為 0,跳轉回對應的[之後
本解譯器提供 30,000 個記憶體單元(8 位元無符號整數),支援完整的 Brainfuck 語法。
# 一般模式
./bf hello.bf
# 除錯模式(預設視窗 8)
./bf -d hello.bf
# 除錯模式 + 自訂視窗寬度
./bf -d -w 12 hello.bf
# 或
./bf --debug --debug-window 12 hello.bfgcc main.c -o bf./bf hello.bf輸出:
Hello World!
優點:簡單、快速啟動 缺點:執行速度較慢
gcc -o compiler_x86 compiler_x86.c./compiler_x86 hello.bf > hello.sgcc -m32 -nostdlib -no-pie -o hello-x86 hello.s./hello-x86輸出:
Hello World!
優點:執行速度快 4-10 倍 缺點:需要額外的編譯步驟
gcc -o compiler_x86_64 compiler_x86_64.c./compiler_x86_64 hello.bf > hello_x64.sgcc -nostdlib -no-pie -o hello_x64 hello_x64.s./hello_x64輸出:
Hello World!
優點:
- 原生 64 位元架構支援
- 使用現代
syscall指令 - 不需要 multilib 支援
- 更好的系統相容性
缺點:需要額外的編譯步驟
請先安裝 LLVM/Clang 工具鏈(含 clang、llc、lli):
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install -y clang llvm llvm-runtime在專案根目錄:
gcc -O2 -o main llvm/llvm.c
# 或(在子資料夾內編譯)
# make./main hello.bf > hello.llclang -O2 hello.ll -o hello
./hello(可選)使用 llc + clang:
llc -O2 -filetype=obj hello.ll -o hello.o
clang hello.o -o hello
./hello(可選)使用 LLVM 直譯器 lli 執行:
lli hello.ll- 產生的 IR 內含
@llvm.memset.p0i8.i64宣告,直接以clang/llc處理即可,無需額外連結。 - 產生器會自動合併連續的
+ - > <指令,並正確處理巢狀[]迴圈。 - 若 Brainfuck 程式括號不匹配,產生器會直接報錯。
在互動模式下,你可以逐鍵輸入 ><+-.,[],每個指令會立即執行,並即時渲染記憶體視窗與輸出。
cd immediate_interpreter
make./bf_immediate- 輸入 Brainfuck 指令:
><+-.,[] - 按
Space鍵:清除所有輸出顯示與狀態(重置) - 逗號
,:會讀取下一個按鍵作為輸入資料 - 按
ESC或Ctrl-C離開 - 畫面會顯示:
- 程式片段與目前 IP
- 輸出緩衝(最後 20 字元)
- 記憶體視窗(固定寬度 50,每 10 個單位交叉顯示),並以
^指示目前指標
compiler_x86.c 將 Brainfuck 程式轉換為 x86-32 組合語言:
| Brainfuck | x86-32 組語 | 說明 |
|---|---|---|
> |
incl %ecx |
指標遞增 |
< |
decl %ecx |
指標遞減 |
+ |
incb (%ecx) |
記憶體值遞增 |
- |
decb (%ecx) |
記憶體值遞減 |
. |
int $0x80 (sys_write) |
輸出字元 |
, |
int $0x80 (sys_read) |
輸入字元 |
[ |
cmpb $0, (%ecx) + je |
條件跳轉(為 0 跳出) |
] |
cmpb $0, (%ecx) + jne |
條件跳轉(非 0 跳回) |
關鍵特性:
- 使用 Linux 系統調用(
int 0x80),無需 C 標準庫 - 入口點為
_start,完全獨立運行 - 靜態分配 30,000 字節記憶體
- 使用
%ecx暫存器作為資料指標 - 暫存器分配優化:
%esi= 常數 1(用於 sys_write, stdout, 長度)%edi= 常數 0(用於 stdin)- 減少系統調用時的立即值載入次數
compiler_x86_64.c 將 Brainfuck 程式轉換為 x86-64 組合語言:
| Brainfuck | x86-64 組語 | 說明 |
|---|---|---|
> |
incq %r12 |
指標遞增(64位元) |
< |
decq %r12 |
指標遞減(64位元) |
+ |
incb (%r12) |
記憶體值遞增 |
- |
decb (%r12) |
記憶體值遞減 |
. |
syscall (sys_write) |
輸出字元(64位元系統調用) |
, |
syscall (sys_read) |
輸入字元(64位元系統調用) |
[ |
cmpb $0, (%r12) + je |
條件跳轉(為 0 跳出) |
] |
cmpb $0, (%r12) + jne |
條件跳轉(非 0 跳回) |
關鍵特性:
- 使用 64 位元 Linux 系統調用(
syscall),無需 C 標準庫 - 入口點為
_start,完全獨立運行 - 靜態分配 30,000 字節記憶體
- 使用
%r12暫存器作為資料指標 - RIP-relative 尋址方式(位置獨立代碼)
- 系統調用參數使用
%rax,%rdi,%rsi,%rdx - 暫存器分配優化:
%r13= 常數 1(用於 sys_write, stdout, 長度)%r14= 常數 0(用於 sys_read, stdin)- 減少系統調用時的立即值載入次數,提升性能
- Brainfuck 解譯器 - 完整實作,支援所有 8 種指令
- x86-32 編譯器 - 使用系統調用,不依賴外部庫
- x86-64 編譯器 - 64 位元原生支援,使用現代 syscall 指令
- LLVM 後端 - 產生 LLVM IR,支援多平台與 LLVM 工具鏈
- 效能優化 - 編譯版本比解譯版本快 4-10 倍
- 指令合併優化 - 自動將連續的
+++/---/>>>/<<<合併為單一指令,減少指令數量 - 迴圈展開優化 - 自動展開簡單迴圈(如
[-]、[+]、[>]、[<]等),優化效能 - 死代碼消除優化 - 自動移除相互抵消的指令(如
+-、-+、><、<>等),提升編譯效率 - 暫存器分配優化 - 預先分配暫存器存儲常用常數,減少重複的立即值載入,提升執行效率
- 範例程式 - 提供 Hello World、Mandelbrot、Hanoi 等範例
- LLVM 後端 - 使用 LLVM IR,支援多平台
- 指令合併 - 將連續的
+++優化為addb $3,和其他-,>,<等相關符號 - 迴圈展開 - 優化簡單迴圈結構(
[-]、[+]、[>]、[<]等) - 死代碼消除 - 移除相互抵消的無效指令(如
+-、-+、><、<>等) - 暫存器分配 - 更有效利用 CPU 暫存器
- 除錯模式 - 顯示執行過程與記憶體狀態
- 即時編譯 - 可即時輸入 brainfuck 符號,並即時顯示記憶體狀態