文章目录
编译过程
编译程序即是将高级语言书写的源程序(java,c++等)翻译成与之等价的目标程序(汇编语言:MOV DS,AX或机器语言:只有01)。其工作可分为六个阶段,见下图:
词法分析-(抽词并判别种类)
- 源程序可以看做是多行的字符串,词法分析是编译过程的第一阶段,其任务是对源程序逐字符扫描,从中识别出一个个“单词”,“单词”又叫做符号,它是程序语言的基本语法单位,如关键字(保留字)、标识符、常数、运算符、分隔符等。
- 词法分析程序输出的“单词”以二元组的形式输出,即其种类和值。词法分析过程依据语言的词法规则,即描述“单词”结构的规则。
VAR X,Y,Z:real; X:= Y+Z*60;
如上列代码段: 经词法分析后得到输出如下:
语法分析-(构造语法树)
- 在词法分析结果的基础上,语法分析是根据语言的规则将单词符号序列分解成语法单位,如“表达式”、“语句”、”程序“等。
- 语法规则就是语法单位的构成规则,通过语法分析确定整个输入串能否构成一个语法上正确的程序。如果程序没有错误,语法分析后就能正确的构造出语法树;否则就会指出语法错误,并给出诊断。
根据上面词法分析的结果可以构造出的语法树如下图:
语义分析-(类型匹配,运算匹配,生成校验符号表)
- 语义分析阶段主要分析语法结构的含义,检查源程序是否包含静态语义错误,并收集类型信息供代码生成阶段使用。只有语法和语义都正确的源程序才能翻译成正确的目标程序。
- 语义分析的主要工作就是对类型进行分析和检查,一般类型检查包括两点:类型载体及在其上的运算。如,整除取余运算符只能对整数使用,如果运算对象是浮点数就认为是类型错误。
在确定源程序语法和语义后,就可以对其进行翻译并给出源程序的内部表示。对于声明语句,要记录所遇到的符号信息,此阶段还负责填写校验符号表,对于可执行语句则分析其结构合理性,并补充必要的步骤。
如:
对于上面的变量声明语句VAR X,Y,Z:real;
应生成下面的符号表(real类型占4位)
对于上面变量赋值语句X:= Y+Z*60;
生成的语法树经过语义分析后应如下图,其中增加了一个语义处理点 inttoreal,它的作用是将整型数转换为浮点数:
中间代码生成-(伪代码,四元序列式)
- 该阶段是根据语义分析的结果生成中间代码,“中间”即意味着并非可执行的机器码,它是一种简单含义明确的记号系统,有若干种形式,但所有中间代码的共同特征均为与具体机器无关,类似于算法伪代码的作用。
- 最常用的中间代码是一种与汇编高度类似的三地址码,采用四元式实现,其形式为:(运算符, 运算对象1, 运算对象2, 运算结果)。
如:
对于上述提到的赋值语句X:= Y+Z*60;
可根据语义分析的结果生成以下四元序列式:(inttoreal, 60, -, t1) (*, Z, t1, t2) (+, Y, t2, t3) (:=, t3, -, X)
其中 t1, t2, t3 均为编译程序生成的临时变量,用于存放临时的结果。一元运算符后面的-表示没有第二个运算对象。inttoreal表示将60转换为浮点数
代码优化
由于编译器将源程序翻译成中间代码的工作是按固定模式进行的,因此可以发现中间代码中往往在时间和空间上均有较大浪费。当要生成高效的目标代码则必须进行优化,优化可以在中间代码生成阶段进行,也可以在目标代码生成阶段执行。
由于中间代码与具体机器无关,因此对中间代码的优化主要是对程序的控制流和数据流的分析之上。
如:
对上述赋值语句X:=Y+Z*60;
生成的四元序列式优化,可以发现60是已知的常数,将它转换为浮点数60.0也可以在编译时完成,没有必要生成一个四元式。同时,发现t3的作用只是将结果传递给X,同样也不需要生成一个四元式。因此可优化成如下等价四元序列式:(*, Z, 60.0, t1) (+, Y, t1, X)
当然这只是很简单的优化,实际上的优化要复杂的多,会涉及公共子表达式的提取等更多技术。
目标代码生成
目标代码生成是编译器的最后一个阶段,这一阶段将中间代码转化为目标机器上的绝对指令代码、可重定位指令代码或汇编指令代码,这一阶段与具体机器密切相关。
如:
使用两个寄存器R1和R2将上述的四元序列式生成下面的目标代码:MOVF Z, R2 MULF #60.0, R2 MOVF Y, R1 ADDF R2, R1 MOVF R1, X ```
符号表管理(表格管理)
符号表的主要作用就是记录符号的信息,以辅助语义检查和代码生成。在编译过程中需要对符号表进行快速的查找插入、修改、删除等操作。
符号表的建立一般始于词法分析阶段,但也可以始于词法分析和语义分析阶段。有时候符号表的使用还会伴随到目标代码的运行阶段。
出错处理
源程序不可避免的会出现错误,这些错误大致分为静态错误和动态错误。
- 动态错误又称为动态语义错误,它们发生在程序运行时,例如变量为0时做除数、引用数组元素下标错误等。
- 静态错误是编译阶段发现的程序错误,可分为语法错误和静态语义错误。
- 语法错误如关键字拼写错误、标点符号错误、表达式缺少操作数、括号不匹配等。
- 语义错误主要指语义分析阶段发现的运算符与运算对象类型不合法等错误。
在编译发生错误时,编译过程应想办法能够绕过去,以便在一次编译中发现尽可能多的错误。