一、编译器就是个程序
编译器的作用是将高级语言翻译成低级语言。而编译器本身,就是个程序。
假定现在有一段程序:
while (y < z) {
int x = a + b;
y += x;
}
那么编译器是怎样把这一段程序人类认识的程序转换为CPU认识的二进制机器指令呢?
二、万物皆token
编译器会把源代码中每个空格之间的有效符号视为一个“token”,从源代码中提取出token的过程就被称为词法分析,Lexical Analysis。
经过一遍词法分析,编译器得到了以下token:
T_While while
T_LeftParen (
T_Identifier y
T_Less <
T_Identifier z
T_RightParen )
T_OpenBrace {
T_Int int
T_Identifier x
T_Assign =
T_Identifier a
T_Plus +
T_Identifier b
T_Semicolon ;
T_Identifier y
T_PlusAssign +=
T_Identifier x
T_Semicolon ;
T_CloseBrace }
三、翻译token
编译器在扫描出各个token后根据规则将其用树的形式表示出来,这颗树就被称为语法树。
四、语法树是不是合理的:语义分析
有了语法树后我们还要检查这棵树是不是合法的,比如我们不能把一个整数和一个字符串相加、比较符左右两边的数据类型要相同,等等。
五、根据语法树生成中间代码:代码生成
在语义分析没有问题之后,编译器会遍历语法树,使用中间代码,intermediate representation code,简称IR code来表示。
上述语法树可能就会表示为这样的中间代码:
Loop: x = a + b
y = x + y
_t1 = y < z
if _t1 goto Loop
六、中间代码优化
在生成中间代码后要对其进行优化,我们可以看到,实际上可以把x = a + b这行代码放到循环外,因为每次循环都不会改变x的值,因此优化后就是这样了:
x = a + b
Loop: y = x + y
_t1 = y < z
if _t1 goto Loop
七、代码生成
将上述优化后的中间代码转换为机器指令:
add $1, $2, $3
Loop: add $4, $1, $4
slt $6, $1, $5
beq $6, loop
最终,编译器将程序员认识的代码转换为了CPU认识的机器指令。