5.1 中间代码生成与优化_简介
在语法分析和语义检查阶段,我们始终在与语句Statement、表达式Expression和外部声明ExternalDeclaration这3个概念打交道。通过声明,我们最终建立起了相应的类型结构,并在符号表中保存了相关标识符的类型信息,到了中间代码生成阶段,我们就不再需要处理外部声明ExternalDeclaration了,只需要为语句和表达式生成相应的中间代码即可。文件ucl\tranexpr.c用于为表达式生成中间代码,文件名tranexpr是Translate Expression的缩写,而ucl\transtmt.c则用于为语句生成中间代码。我们在“第1.4节 UCC编译器预览”时给出过以下图5.1.1中的例子,为阅读方便,我们再次重温一下其中的概念。图5.1.1第1至9行的递归函数用于计算n阶乘,第12至15行的while循环用于打印出1!至10!的值,第19至45是“UCC编译器所生成的中间代码”的字符串形式,UCC编译器内部会用三地址码的结构来表示中间代码。“龙书”把语法树和三地址码都视为中间代码,这里我们在讨论UCC编译器时,如果不作特别声明,中间代码指的是三地址码。三地址码包含两个源操作数、一个目的操作数及一个运算符。例如对于t1 = a+b而言,加号”+”是运算符,a和b是两个源操作数,而t1是目的操作数(即用于存放运算结果),这三个操作数对应三个“地址”,所以称这样的中间代码为三地址码。
图5.1.1 基本块
图5.11第20行的中间代码表示有条件的跳转,第23行的goto表示无条件的跳转,在在汇编语言中,都有与之对应的汇编指令。低级语言中的“有条件或无条件的跳转”会引起控制流的转移,由此我们可以实现高级语言C中的分支语句if和循环语句while等控制结构。当然,函数返回也是一种控制流的变化,在UCC编译器生成的中间代码中,第22行的return 1只是把返回值设为1,真正的返回动作由第30行的ret指令来完成。这样处理的好处在于,即便在C语言中出现了多条return语句(如第5行和第7行的return语句),但在中间代码层次,我们只在第22行设置返回值为1,第29行设置返回值为t2,真正的返回动作只需要在同一个地方处理(即第30行的ret指令),这也意味着我们从函数的入口处开始执行,离开函数时也只有一个出口。执行“函数调用”时,我们要依