English | 简体中文
仓库同时托管在 GitHub 与 Codeberg,两处同步发布与分发。
C++17 编写。把 Brainfuck 编译成 x86-64 汇编(AT&T 语法),再驱动 g++ 汇编链接为只依赖操作系统运行时的独立可执行文件。
g++ -std=c++17 -O2 -static -o bfc.exe bfc.cpp
bfc.exe <input.bf> [-o output.exe]
也可以直接用 Makefile(Linux / macOS / MinGW 均可):
make
make test
正式版的 GitHub Release 附带预编译二进制(Windows x64、Linux x86_64/arm64、 macOS x86_64/arm64),打包与构建分工见 VERSIONING.md 的「正式版 Release 必须附带预编译产物」。
- 中间产物:输入同名 .s(hello.bf -> hello.s)
- 最终产物:默认输入同名可执行文件,可用 -o 覆盖
- 内部执行:g++ -O2 -static -o "output" "input.s"
| 选项 | 作用 |
|---|---|
| -o FILE | 输出文件(默认:可执行文件,或 -c 时的 .o) |
| --target NAME | 目标 ABI:x86_64-windows / x86_64-linux / x86_64-freebsd / x86_64-macos / aarch64-linux / aarch64-macos(默认 auto = 本机) |
| --cc CMD | 指定汇编 / 链接器,例如 --cc x86_64-linux-gnu-g++ |
| --tape-size N | tape 字节数,默认 30000 |
| --bounds-check | 为数据指针生成边界检查,越界以退出码 2 终止(见下) |
| --no-link / -S | 只生成 .s |
| --compile-only / -c | 只生成 .o,不链接 |
| --version / --targets | 打印版本 / 列出目标 |
--bounds-check 只检查数据指针本身;带固定偏移的优化指令([->+<]、[->+>+<<] 等) 因为邻近访问的 guard 区域而保持内存安全(tape 会多分配 2×最大偏移字节)。 不加该选项时不生成任何检查,越界属于未定义行为。
struct Op { char kind; int value; };
class BFCompiler { void parse(); void optimize(); void generate(); };
parse 过滤元字符、配平校验、连续同向合并、相邻反向抵消; optimize 做循环抽象解释;generate 按 Op.kind 输出汇编。
Op.kind:普通 BF 指令,以及 Z 置零 A B C D [->+<]/[->-<]/[-<+>]/[-<->] S 扫描循环 M 通用传输循环(transfers_ 下标)
- 元字符过滤。
- 连续同向合并,相邻反向抵消并重新合并(+++--+ -> addb $2)。
- [-] 与 [+] 折叠为 movb $0。
- 六 token 移动模式 A/B/C/D。
- 扫描循环 [<] / [>](任意步长):进入前判零 + 先移动再判零。
- 通用乘法/复制/传输循环:任意偏移、任意系数、多目标 ([->+++<] 用 imull,[->+>+<<] 复制)。
- 嵌套循环整体折叠:自内向外求摘要,内层摘要代入外层分析。
对每个循环体做抽象解释,每个数据单元记录 (valKnown,val) 与 (deltaKnown,delta):值是否恒为常量、每轮增量是否恒为常量。 遇到嵌套循环先递归求其摘要再施加:控制值已知则精确施加,未知则污染目标, clear 置 0,scan 放弃外层。
接受条件:指针净位移 0;控制单元每轮恰为 -1;其它被动过的单元要么常量累加, 要么被重置为常量。生成时累加用 imull/addb,reset 用 movb,控制单元置 0。
reset 型单元只在“循环体至少执行过一次”时才改变,因此所有 reset(无论来自 第几层嵌套)共用同一个 testb/je (V!=0) 守卫即可,语义完备。无法证明时保守 退回真实循环,不改变语义。
- r12 = tape 基址,r13 = 数据指针;tape 30000 字节在 .bss。
- 入口 rsp = 8 (mod 16),push rbp/r12/r13 后为 0;Windows 再 sub $32 shadow space, 调用点始终 16 字节对齐。
- 平台分支在编译期选择:Windows x64(无前缀,shadow space,-static)、 Linux/*BSD(无前缀,-static)、macOS(下划线前缀,不加 -static)。
| 平台 | 编译 bfc | 编译 BF 产物 | 状态 |
|---|---|---|---|
| Windows 10 / 11 (x64) | 支持 | 支持 | CI 验证 |
| Windows 8 / 8.1 (x64) | 支持 | 支持 | 需安装 UCRT(KB2999226) |
| Windows 7 SP1 (x64) | 部分 | 部分 | 需 UCRT 更新,未 CI 验证 |
| Linux (x86-64, glibc) | 支持 | 支持 | 本机 (WSL) 实测 + CI |
| Linux (x86-64, musl) | 支持 | 支持 | 使用 --cc musl-g++ |
| macOS 10.15+ (x86-64) | 支持 | 支持 | CI 验证(macos-13 运行器) |
| FreeBSD / OpenBSD (x86-64) | 部分 | 部分 | 走 SysV ELF 路径,未 CI 验证 |
| Linux (aarch64, 树莓派 4/5 等) | 支持 | 支持 | 交叉 g++ + qemu 实测 + CI |
| macOS Apple Silicon (aarch64) | 支持 | 支持 | CI 验证(macos-latest 原生 arm64) |
| Windows XP | 不支持 | 不支持 | 没有 UCRT |
| Windows on ARM (aarch64) | 不支持 | 不支持 | 尚未实现 |
| DOS / z/OS / z/VSE / RTOS | 不支持 | 不支持 | 不在支持范围内 |
目标 ABI 在运行时选择,因此可以在一个系统上为另一个系统生成汇编:
bfc --target x86_64-linux --cc x86_64-linux-gnu-g++ hello.bf
bfc --target x86_64-windows --no-link hello.bf # 只生成 .s
bfc --targets # 列出全部目标
- 文件打不开 -> 报错退出,码 1。
- [ / ] 不匹配 -> 报错退出,码 1,不产生可执行文件。
powershell -File tests\run_tests.ps1
26 个功能用例 + 2 个错误用例,全部与独立解释器逐字节比对(当前 28 passed, 0 failed)。 源文件在 tests/bf,生成的汇编分类存放到 tests/asm,详见 tests/README.md。 另以随机差分测试覆盖了通用传输循环与多层 reset 嵌套。g++ -Wall -Wextra 无警告。
本项目采用 GNU Affero General Public License v3.0 或更新版本 (AGPL-3.0-or-later)。SPDX 标识符:AGPL-3.0-or-later。
- 许可证全文:LICENSE
- 编译产物附加许可:LICENSE-EXCEPTION.md
- 贡献指南(DCO 签署、报告 bug):CONTRIBUTING.md
- 安全策略(漏洞私密上报):SECURITY.md
AGPL 本身没有编译器"输出例外"。为避免下游对自己编译出的产物产生许可顾虑, 本项目以 AGPLv3 第 7 条附加许可的形式,明确允许把 bfc 从你自己的 Brainfuck 源码生成的汇编 / 目标文件 / 可执行文件,按你选择的条款使用和分发,详见 LICENSE-EXCEPTION.md。该例外不适用于 bfc 编译器本身。
- libstdc++ / libgcc(-static 静态链入):GPL-3.0-or-later WITH GCC-exception-3.1,明确允许链接与再分发。
- MinGW-w64 运行时与头文件:宽松许可(Public Domain / BSD / ZPL 类)。
- UCRT 的 api-ms-win-crt-* 与 KERNEL32:Windows 系统组件,不是随附库。
- bfc 在运行时调用外部 g++,仅为进程调用,不构成链接。