编译过程分为6步:扫描(词法分析)、语法分析、语义分析、源代码优化、代码生成、目标代码优化。
示例代码:array[index] = (index + 4) * (2 + 6)
-
词法分析
源代码被输入到扫描器,运用类似有限状态机的算法将代码的字符序列分割成一系列的记号,Token包括:关键字、标识符、字面量(数字、字符串)和特殊符号(加减)。
扫描器在识别记号的同时,也会将标识符放到符号表,数字字符串常量放到文字表等以备后用。
工具:lex;
- 语法分析
语法分析器将对扫描器产生的记号进行语法分析,生成以表达式为节点的语法树。
相关方法:上下文无关文法、下推自动机;
工具:yacc;
-
语义分析
语义分析器完成语句的语义分析,例如两个指针做乘法在语法上是合法的,但没有意义;- 静态语义:编译阶段可以确定的语义,包括声明和类型的匹配,类型的转换;
- 动态语义:运行阶段才能确定的语义,比如将0作为除数;
经过语义分析阶段后,整个语法树的表达式都被标示了类型,有些会插入隐式转换所需的转换节点。
-
中间代码生成(源代码优化)
源代码优化器会在源代码级别进行优化,例如(2+6)这个表达式可以优化为8;
直接在语法树上进行优化比较困难,源代码优化器会将整个语法树转换为中间代码,它是语法树的顺序表示。
中间代码类似目标代码,但是它跟机器平台无关,不含数据尺寸、变量地址和寄存器的名字。将编译器分为了前端和后段,前端负责产生机器无关的中间代码,后端负责将中间代码转换成目标机器代码。t2 = index + 4 t2 = t2 * 8 array[index] = t2
-
目标代码的生成
代码生成器负责将中间代码转换成机器代码,过程依赖于目标机器,不同的机器不同字长、寄存器、数据类型;
-
目标代码的优化
目标代码优化器对上述的目标代码进行优化,比如选择合适的寻址方式,使用位移来代替乘法运算、删除多余的指令等;
此时index和array的地址还没确定,如果符号的定义和源代码在同一个编译单元,编译器可以为他们分配空间来确定地址,如果定义在其他的模块,需要等到链接时才能确定最终运行时的绝对地址;
网友评论