wrecc
是一个小巧、精简的x86-64 C99编译器,从零开始编写。这个名字是英文单词_wreck_的变体,意为海底生锈的船只。
该编译器生成x86-64汇编代码,使用AT&T语法,遵循System V ABI,我只在Ubuntu和macOS上进行了测试。它没有任何依赖,你只需要你的汇编器和链接器,编译器会调用它们来创建最终的二进制文件。
目录
安装
预编译二进制文件
如果你的系统上没有安装Rust工具链,你可以直接从发布页面安装最新的二进制文件(适用于MacOS和Linux):
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/PhilippRados/wrecc/releases/download/v0.2.0/wrecc-installer.sh | sh
Cargo
使用cargo binstall
cargo binstall wrecc
或从源代码构建
cargo install wrecc
功能
由于目前并非所有关键字都已实现,wrecc使用自定义标准头文件,这些头文件直接内置在二进制文件中。
预处理器
预处理器实现了所有C99预处理器指令,除了#line
、#error
和#pragma
。目前最显著的缺失是类函数宏,不过这已经在计划中了。
编译器
支持的关键字
除此之外,它还支持:
带有指定初始化器的聚合初始化
struct {
union {
int foo;
long baz;
} nested;
int array[16];
} bar = { .nested.foo = 3, .array[6] = 1};
函数指针
#include <stdio.h>
typedef int (*BinaryOperation)(int, int);
typedef struct {
BinaryOperation add;
BinaryOperation subtract;
} Calculator;
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int main() {
Calculator calc = {add, subtract};
printf("加法结果:%d\n", calc.add(10, 5));
printf("减法结果:%d\n", calc.subtract(10, 5));
}
常量折叠
char **string_offset = (char **)&"hello" + (int)(3 * 1);
int array[(long)3 * 2 - 1];
未实现的功能
除了缺失的关键字外,以下是主要缺失的功能:
- 未指定大小的数组
- 同时编译多个文件
- 原始结构体/联合体作为函数参数/返回类型
- 浮点类型
这里是所有仍然缺失的内容列表:待办事项
错误消息
Wrecc还具有美观的错误消息。错误报告不会在第一个错误后停止。使用--no-color
选项可以关闭错误中的颜色高亮。目前只有错误,没有警告。
C代码 | 错误 |
---|---|
|
AST美化打印器
使用--dump-ast
选项编译时,它会打印解析树
C代码 | AST |
---|---|
|
|
运行wrecc --help
查看所有选项
测试
单元测试
cargo test --workspace
快照测试
bash tests/snapshot_tests.sh
模糊测试
使用afl.rs运行模糊测试
// 在fuzzer目录中
cargo afl build
cargo afl fuzz -i inputs -o outputs target/debug/fuzz_target
故障排除
wrecc
在你的机器上不能正常工作的原因可能是:
- 不支持的架构/操作系统
- 在标准库搜索路径中找不到libc(可以通过使用
-L <path>
选项传递自定义搜索路径来解决) - 如果问题不在未实现的功能部分提到,请提出issue
贡献
如果你想帮助我改进这个编译器,我将非常欢迎。最简单的开始方式可能是实现未实现的功能部分提到的一个缺失的关键字/类型。确保所有测试仍然通过,如果是新功能,请实现你自己的测试。
查看文档以获取编译器管道的高级概述。
项目目标
- 不依赖自定义头文件
- 通过c-testsuite中的所有C99测试
- 编译真实世界的C项目,如Git
资源
以下资源帮助我构建这个编译器:
- Crafting Interpreters
- Engineering a Compiler(书籍)
- acwj
- saltwater
- chibicc