编译分为4个步骤:预处理(prepressing)、编译(Compilation)、汇编(Assembly)、链接(Linking)。
其中编译有5个步骤:词法分析、语法分析、语义分析、中间语言生成、目标代码生成与优化。
例:array[index] = (index + 4) * (2 + 6)
1、词法分析:将源代码的字符序列分隔成一系列记号。28个非空字符,产生了16个记号。
记号 | 类型 |
array | 标识符 |
[ | 左方括号 |
index | 标识符 |
] | 右方括号 |
= | 赋值 |
( | 左圆括号 |
index | 标识符 |
+ | 加号 |
4 | 数字 |
) | 右圆括号 |
* | 乘号 |
( | 左圆括号 |
2 | 数字 |
+ | 加号 |
6 | 数字 |
) | 右圆括号 |
2、语法分析:由语法分析器生成语法树(以表达式为节点的树)。
3、语义分析:静态语义分析,对语法树上的节点标明类型。动态语义是在运行时才能确定的语义。
4、中间语言生成:产生与机器无关的中间代码,(不包含数据的尺寸、变量地址和寄存器名字等),同时可以做源码级的优化。
中间代码的形式:三地址码。 x = y op z
例子翻译后:t1 = 2 + 6
t2 = index + 4
t3 = t2 * t1
array[index] = t3
优化一下: t2 = index + 4
t2 = t2 * 8
array[index] = t2
5、目标代码的生成及优化:依赖于目标机器,转换成目标机器代码。(不同的字长、寄存器、整数、浮点数数据类型)
movl index, %ecx ;value of index to ecx
addl $4, %ecx ;ecx = ecx + 4
mull $8, %ecx ;ecx = ecx * 8
movl index, %eax ;value of index to eax
movl %ecx, array(,eax,4) ;array[index] = ecx
目标代码优化器进行优化,选择合适的寻址方式、使用位移代替乘法运算、删除多余指令等。
movl index, %edx
leal 32(,%edx,8), %eax
movl %eax, array(,%edx,4)
最后,如果index和array定义在跟例子中的源代码同一个编译单元里,那么编译器可以为index和array分配空间,确定他们的地址。
如果定义在其他模块,就需要在链接时确定地址。