编译过程概述
这次我们使用的编译目标是 C0,一种简化了 C 语言语义和编译过程、同时魔改了语法的玩具编程语言。
编译过程
整个 C0 工具链分为两个部分,分别是你接下来需要写的 编译器 和我们提供的 虚拟机。整个编译流程如下:
- 编译器(你要写的)
- 读入 c0 源代码
- 输出 o0 二进制代码
- 虚拟机
- 读入 o0 二进制代码
- 解释执行代码
- 输出运行结果
你的编译器至少能通过某种命令行接口读入一个 c0 文件,并将编译出的 o0 文件输出到另一个文件中。接口的实际特征我们不做规定,需要你自己定义并写在评测配置中,具体见 评测要求。
o0 二进制代码的定义见 这里。
我们不限制你编写编译器使用的语言,且允许复用 miniplc0 实验中的代码。
如果你决定编译到其他目标(自己设计的指令集、LLVM IR、Java Bitcode、物理 CPU 指令集等),请联系助教进行单独手动评测。由于需要单独评测,你不太可能因此获得额外的加分。
编译目标
我们编译的目标是本课程自行设计的 navm
虚拟机使用的 o0
代码。有关 navm
虚拟机的设计、结构参见 对 navm 虚拟机的介绍。
比如如果你编译这个文件:
fn foo(i: int) -> int {
return -i;
}
fn main() -> void {
putint(foo(-123456));
}
你得到的结果应该类似于这个(o0
格式没有规定相应的文字形式,以下是官方参考实现 natrium
和 navm
使用的输出格式):
static: 66 6F 6F (`foo`)
static: 70 75 74 69 6E 74 (`putint`)
static: 6D 61 69 6E (`main`)
static: 5F 73 74 61 72 74 (`_start`)
fn [3] 0 0 -> 0 {
0: StackAlloc(0)
1: Call(2)
}
fn [0] 0 1 -> 1 {
0: ArgA(0)
1: ArgA(1)
2: Load64
3: NegI
4: Store64
5: Ret
}
fn [2] 0 0 -> 0 {
0: StackAlloc(0)
1: StackAlloc(1)
2: Push(123456)
3: NegI
4: Call(1)
5: CallName(1)
6: Ret
}