编译器简介: 在 Siri 前时代如何与计算机对话
简单说来,一个编译器(compiler)不过是一个可以翻译其他程序的程序。传统的编译器可以把源代码翻译成你的...
简单说来,一个编译器(compiler)不过是一个可以翻译其他程序的程序。传统的编译器可以把源代码翻译成你的计算机能够理解的可执行机器代码。
-- Nicole Orchard
本文导航
◈ Hello, Compiler13%
◈ 前端18%
◈ 优化程序45%
◈ 后端80%
编译自 | https://nicoleorchard.com/blog/compilers
作者 | Nicole Orchard
译者 | ucasFL
简单说来,一个编译器compiler不过是一个可以翻译其他程序的程序。传统的编译器可以把源代码翻译成你的计算机能够理解的可执行机器代码。(一些编译器将源代码翻译成别的程序语言,这样的编译器称为源到源翻译器或转化器transpilers。)LLVM[1] 是一个广泛使用的编译器项目,包含许多模块化的编译工具。
传统的编译器设计包含三个部分:
◈ 优化器Optimizer分析 IR 然后将其转化为更高效的形式。opt[3] 是 LLVM 的优化工具。
◈ 后端Backend通过将 IR 映射到目标硬件指令集从而生成机器代码。llc[4] 是 LLVM 的后端工具。
注:LLVM 的 IR 是一种和汇编类似的低级语言。然而,它抽离了特定硬件信息。
Hello, Compiler
下面是一个打印 “Hello, Compiler!” 到标准输出的简单 C 程序。C 语法是人类可读的,但是计算机却不能理解,不知道该程序要干什么。我将通过三个编译阶段使该程序变成机器可执行的程序。
// compile_me.c
// Wave to the compiler. The world can wait.
#include
int main(){
printf("Hello, Compiler!");
return0;
}
正如我在上面所提到的,
clang是 LLVM 中用于 C 家族语言的前端工具。Clang 包含 C 预处理器C preprocessor、词法分析器lexer、语法解析器parser、语义分析器semantic analyzer和 IR 生成器IR generator。
C 预处理器在将源程序翻译成 IR 前修改源程序。预处理器处理外部包含文件,比如上面的
#include。 它将会把这一行替换为
stdio.hC 标准库文件的完整内容,其中包含
printf函数的声明。
通过运行下面的命令来查看预处理步骤的输出:
clang -E compile_me.c -o preprocessed.i
compile_me.c 的分词过程:语法分析器确定源程序中的单词流是否组成了合法的句子。在分析记号流的语法后,它会输出一个抽象语法树abstract syntax tree(AST)。Clang 的 AST 中的节点表示声明、语句和类型。
compile_me.c 的语法树:语义分析器会遍历抽象语法树,从而确定代码语句是否有正确意义。这个阶段会检查类型错误。如果
compile_me.c的 main 函数返回
"zero"而不是
0, 那么语义分析器将会抛出一个错误,因为
"zero"不是
int类型。
IR 生成器将抽象语法树翻译为 IR。
对 compile_me.c 运行 clang 来生成 LLVM IR:
clang -S -emit-llvm -o llvm_ir.ll compile_me.c
llvm_ir.ll中的 main 函数:
[list=1][*]
; llvm_ir.ll
[/*][*]
@.str =private unnamed_addr constant [18 x i8] c"Hello, Compiler!A0", align 1
[/*][*]
[/*][*]
define i32 @main(){
[/*][*][code] %1= alloca i32, align 4;
关注 Linux中国
微信扫一扫关注公众号