文档介绍:第七章语义分析和中间代码的产生
本章我们将把上一章所介绍的方法和技术应用于语义分析和中间代码的生成中。
紧接在词法分析和语法分析之后,编译程序要做的工作是进行静态语义检查和翻译。静态语义检查通常包括:1。类型检查。2。控制流检查。3。一致性检查。4。相关名字检查。
翻译为中间语言的好处:
(1)便于进行与机器无关的代码优化;
(2)使编译程序改变目标机更容易;
(3)使编译程序的结构在逻辑上更为简单明确,以中间语言为界面,编译前端和后端的接口更清晰。
第七章语义分析和中间代码产生
7。1中间语言
首先要掌握几种中间语言的基本结构:逆波兰表示,图表示法(DAG 和抽象语法树),三地址代码(四元式、三元式、间接三元式)
7。1。1后缀式
后缀式表示法有称逆波兰表示法。这种方法是,把运算量(操作数)写在前面,把算符写在后面(后缀)。
一个表达式的后缀式可以如下定义:
(1)如果E是一个变量或常量,则E的后缀式是E自身。
(2)如果E是E1 op E2形式的表达式,这里op是任何二元操作符,则E的后缀式为 E1’ E2’op,这里E1’和E2’分别为E1和E2的后缀式。
(3)如果E是(E1)形式的表达式,则E1的后缀式就是E的后缀式。
第七章语义分析和中间代码产生
7。1。2图表示法
我们要介绍的图表示法包括DAG与抽象语法树。
无循环有向图(Directed Acyclic Graph , 简称 DAG ).与抽象语法树一样,对于表达式中的每个子表达式,DAG图中都有一个结点。一个内部结点代表一个操作符,它的孩子代表操作数。两者不同的是,在DAG图中代表公共子表达式的结点具有多个父结点,而在一棵抽象语法树中公共子表达式被表示为重复的子树。
表7。2 和抽象语法树的两种表示法都应掌握。
7。1。3 三地址代码
三地址代码是由下面一般形式的语句构成的序列:
X:=y op z
其中,x、y、z为名字、常数或编译时产生的临时变量;op代表运算符号如定点运算符、浮点运算符、逻辑运算符等。每个语句的右边只能有一个运算符。
第七章语义分析和中间代码产生
表7。3(P171)是为赋值语句生成三地址代码的S—属性文法定义。应在掌握之列
关于四元式,三元式,间接三元式都在必须掌握之列,参看P172—173.
7。2说明语句
当考察一个过程或分程序的一系列说明语句时,便可为局部于该过程的名字分配存储空间。对每个局部名字,我们将在符号表中建立相应的表项,并填入相应的信息如类型、在存储器中的相对地址等。相对地址是指对静态数据区基地址的一个偏移量。
7。2。1 过程中的说明语句
在C、Pascal及FORTRAN等语言的语法中,允许在一个过程中的所有说明语句作为一个组来处理,把他们按排在一所数据区中。从而我们需要一个全程变量如offset来跟踪下一个可用的相对地址的位置。
第七章语义分析和中间代码产生
图7。6关于说明语句的翻译模式是应该掌握的,尤其是用产生式ε的标记非终结符号,改写产生式:
P{offset:=0 } D
以便语义动作均出现整个产生似的右边。改写为:
PMD
M ε{ offset:= 0 }
当遇到一个嵌入的过程说明时,则应当暂停包围此过程的外围过程说明语句的处理。这种方法可以通过加入下的语言把有关语义动作来说明。
P→D
P→D;D|id:T | proc id ;D ;S (7。2)
第七章语义分析和中间代码产生
这里与图7。6中相同,T有两个属性type和width.
为简化起见,我们假定对于式(7。2)的语言的每一个过程都有一张独立的符号表。这种符号表可以用链表实现。当碰到过程说明D→proc id; D1 ;S 时,便创建一张新的符号表。并且把在D1中的所有说明项都填入此符号表内。新表有一个指针指向刚好包围该嵌入过程的外围过程的符号表,由id表示的过程名字作为该外围过程的局部名字。对图7。6 处理变量说明的唯一修改是,要告诉enter在哪个符号表填入一项。
在图7。8种的翻译模式给出了如何在一遍扫描中对数据进行处理,它使用了一个栈tblptr保存各外层过程的符号指针。如对于图7。7 所示的符号表,当处理过程partition中的说明语句时,栈tblptr中将包括指向sort,quicksort及partition的符号表的指针。指向当前符号表的指针在栈顶。另一个栈offset存放各嵌套过程的当前相对地址。Offset 的栈顶元素为当前被处理过程的下一个局部名字的相对地址。
第七章语义分析和中间代码产生
对于 A→BC { action A }
所有关于非终结符号B,C的语义动作均已先于 Action A