#编译器 #x86-64 #代码生成 #C

app wrecc

从头开始编写的x86_64 C99编译器

2个不稳定版本

0.2.0 2024年4月19日
0.1.0 2024年4月4日

#170 in 开发工具

Download history 7/week @ 2024-04-08 128/week @ 2024-04-15 16/week @ 2024-04-22

每月 75 次下载

MIT 许可协议

555KB
13K SLoC

Test

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。目前最显著的是还缺少函数宏,但已列入议程。

编译器

支持的键词

keywords

除此之外,它还支持

使用指定初始化器的聚合初始化
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("Result of addition: %d\n", calc.add(10, 5));
  printf("Result of subtraction: %d\n", calc.subtract(10, 5));
}

常量折叠
char **string_offset = (char **)&"hello" + (int)(3 * 1);
int array[(long)3 * 2 - 1];

未实现的功能

除了缺少关键词外,这些是主要缺少的功能

  • [x] 未指定大小的数组
  • 一次性编译多个文件
  • [ ] 将原始结构体/联合体作为函数参数/返回类型
  • [ ] 浮点类型

以下是一个仍然缺失的所有内容的列表:待办事项

错误信息

Wrecc也有很好的外观信息。错误报告不会在第一个错误后停止。使用--no-color选项,您可以关闭错误中的颜色高亮。目前只有错误,没有警告。

C代码 错误
int foo(void);
int main() {
  int a = foo(1);
  long *p = a;

  return p * 2;
}
error

AST pretty-printer

当使用--dump-ast选项编译时,它会打印解析树

C代码 AST
#define SIZE 16
void foo(char);
int main() {
  int arr[SIZE] = {1, 2};
  char p = (char)(*arr + 3);

  switch (p) {
  case 'c':
    foo(p);
  }
}
Declaration:
-Decl: 'foo'
FuncDef: 'main'
-Declaration:
--Init: 'arr'
---Aggregate:
----Scalar:
-----Literal: 1
----Scalar:
-----Literal: 2
-Declaration:
--Init: 'p'
---Scalar:
----Cast: 'char'
-----Grouping:
------Binary: '+'
-------Unary: '*'
--------Ident: 'arr'
-------Literal: 3
-Switch:
--Ident: 'p'
--Block:
---Case:
----Literal: 99
----Expr:
-----FuncCall:
------Ident: 'foo'
------Ident: 'p'

通过运行wrecc --help来检查所有选项

测试

单元测试

cargo test --workspace

快照测试

这将运行所有固定文件并将它们与预期的快照进行比较

bash tests/snapshot_tests.sh

模糊测试

使用afl.rs运行fuzzer

// in fuzzer directory
cargo afl build
cargo afl fuzz -i inputs -o outputs target/debug/fuzz_target

故障排除

导致wrecc在您的机器上无法正常工作的原因

  • 不支持的架构/操作系统
  • 在标准库搜索路径中找不到libc(可以通过使用-L 选项传递自定义搜索路径来修复)
  • 如果它未在未实现功能部分中提及,请提出问题

贡献

如果您想帮助我完成这个编译器,我会非常欢迎。最简单的开始方法可能是实现未实现功能部分中提到的缺失关键字/类型之一。确保所有测试仍然通过,并在需要时实现新的测试。
查看文档以获取编译器管道的高级概述。

项目目标

  • 不依赖于自定义头文件
  • 通过c-testsuite中的所有C99测试
  • 编译真实世界的C项目,如Git

资源

以下资源帮助我构建了这个编译器

依赖项