编译原理陈火旺版7章7
第七章语义分析和中间代码生成
1、 编译程序的任务是把源语言程序翻译成目标程序, 有些编译程序在编译过程中,不产生中间语言,而 是直接从源语言程序翻译成目标语言程序。
源程序
编译程序
目标代码
以上编译过程省略了中间语言,它不利于编译所产生的目 标代码的优化.为了产生高质量的代码,可以将源语言程序首 先翻译成一种特殊形式的中间语言代码形式,并对其进行优化, 然后再将它翻译成最终的目标代码。
rop为: =,<>,<= <,>=,>
3.转向语句的四元式: 有以下三种跳转四元式:
•(jnz , a , - , p) 表示 if a goto p; •(jrop , x , y , p) 表示 if x rop y goto p; •( j , - , - , p) 表示 goto p;
4.条件语句的四元式: 例1:if a<b then x:=a+b else x:=a-b 对应的四元式为: (1) (j< , a , b , 3 ) 回填 (2) (j , - , - , 6 ) 回填 (3) (+ , a , b , T1 ) (4) (:= , T1 , - , x ) 回填 (5) ( j , - , - , 8 ) (6) ( - , a , b , T2 ) (7) (:= , T2 , - , x ) (8) …… 例2:if a<b and e>d then x:=a+b else x:=a-b 例3:if a<b or e>d then x:=a+b else x:=a-b
#
语法制导翻译的实质
根据文法中每个产生式所蕴含的语义, 为其配备一个(或多个)语句或子程序, 对所要完成的功能进行描述,在语法分 析过程中,当分析器使用该产生式进行 语法分析时(不论是推导还是规约), 除完成语法分析动作之外,还将调用为 其配备的语义子程序,进行相应地语义 处理,完成语义翻译工作。
源程序
语法分析
中间代码
优化
优化后中间代码
目标代码
代码生成
中间代码
中间代码也叫中间语言 (Intermediate code /language)是:源 程序的一种内部表示,不依赖目标机的结构, 复杂性介于源语言和机器语言之间。
中间代码的优点
1、逻辑结构清楚; 2、利于不同目标机上实现同一种语言; 3、利于进行与机器无关的优化;
实例
表达式(中缀式): A+B*(C-D)+E/(C-D) 后缀式: A B CD- * + E CD- /+ 表达式(中缀式):
(a=0∧ b>3)∨ (e ∧x >y) ∧∨ 后缀式: a0=b3 > ∧ e xy >
结论
从以上两个例子我们可得出: 1、在两种表示中,运算对象出现的顺序相同; 2、在后缀表示中,运算符按实际计算顺序 从左到右排列,且每一运算符总是跟在运算 对象之后。 翻译成后缀式的语义描述见P167表7.1。
例
a:=b*-c+b*-c
op arg1 uminus c * b uminus c * b + := T2 T5 arg2 T1 T3 T4 result T1 T2 T3 T4 T5 a
三地址代码-三元式
三元式顾名思义就是带有三个域的记录结 构,他的一般形式为 (i)(op,arg1,arg2) 其中,(i)为三元式的编号,也代表了 该式的运算结果,op,arg1,arg2的含 义与四元式类似,区别在于arg可以是某 三元式的序号,表示用该三元式的结果作 为运算对象。
三地址代码-间接三元式
建立两个与三元式有关的表格,一个称 为三元式表,用于存放各三元式本身;另 一个称为执行表,它按照三元式的执行顺 序,依次列出相应各三元式在三元式表中 的位置,也就是说我们用一个三元式表连 同执行表来表示中间代码。通常我们称这 种表示方法为间接三元式。
例
x:=(a+b)*c b:=a+b y:=c*(a+b)
例1
a+a*(b-c)+(b-c)*d + + a a * b c c * d
b
翻译成抽象语法树的属性文法见P169表7.2
图表示法-DAG图
DAG(Directed Acyclic Graph)有向无循环图
对表达式中的每个子表达式,DAG都有一个 结点,一个内部结点代表一个操作符,他的 孩子代表操作数。在一个DAG中代表公共子 表达式的节点 具有多个父结点(与抽象语 法树中公共子表达式被表示为重复的子树不 同)
后缀式的推广 条件语句的翻译: If e THEN S1 else S2
图表示法-抽象语法树
在语法树中去掉一些对翻译不必要的信 息后,获得的更有效的源程序的中间表示, 这种经过变换后的语法树称为抽象语法树。 在抽象语法树中,操作符和关键字都不 作为叶子节点出现,而是把它们作为内部 节点,即这些叶子节点的父节点。
由此可见:抽象文法符号的具体语义信息,是在语法分析同 步的语义处理过程中获取和加工的。
属性文法
将语义以“属性”的形式附加到各 文法符号上,再根据产生式所蕴含的语 义,给出每个文法符号的属性的求值规 则,从而形成一种带有语义属性的前后 文无关文法,即属性文法。
属性
一个文法符号X的语义信息我们称之为语义 属性或简称为属性(Atrributes)
X.TYPE表示为X的类型 X.VAL表示为X的值
例:
对于文法: E →E+T | T T→ digit
产生式 语义子程序
1、E→ E(1)+T {E.Val=E(1).Val+T.Val 2、E→ T {E.Val=T.Val} 3、T→ digit {T.Val=digit}
例
语法分析栈 语义信息栈 T + E … # T.Val ‘ +’ E(1).Val … E … E.Val …
三地址码的各种形式:P170
1. 2. 3. 4. x:=y op z Goto L Param x x:=y[i] x := op z if x relop y goto L call p,n x[i]:=y x:=*y x:=y if a goto L return y *x:=y
5. x:=&y
三元式
x:=(a+b)*c b:=a+b y:=c*(a+b)
(1)(+,a,b) (5) (+,a,b) (2)(*,(1),c) (6)(*,c,(5)) (3)(:=,x,(2)) (7)(:=,y,(6)) (4)(:=,b,(1))
间接三元式
执行表 (1) (2) (3) (4) (1) (2) (5)
1 2 3 4 5 6 7 8 9 10
…
id
assign …
a
9 … 8 …
三地址代码
三地址代码最基本的用法形式: x:=y op z 其中x、y、z为名字、常数或编译时产生的 临时变量;op代表运算符号。每个语句的右边只 能有一个运算符。 例如:x+y*z可以翻译为: T1:=y*z T2:=x+T1 T1、T2位编译时产生的临时变量
2、对同一表达式而言,所需的三元式或 四元式的个数一般都是相同的。
三元式和四元式的比较
不同点: 1、由于三元式没有result字段,且不需要临时变量, 故三元式比四元式占用的存储空间少; 2、在进行代码优化处理时,常常需要挪动一些运算 的位置,这对于三元式序列来说是很困难的,但对于 四元式来说,由于四元式之间的相互联系是通过临时 变量来实现的,所以,更改其中一些四元式给整个系 列带来的影响就比较小。
中间代码常见的几种形式
1、后缀式 2、图表示法 抽象语法树、DAG图 3、三地址代码 三元式、四元式、间接三元式
后缀式
后缀式是波兰逻辑学家卢卡西维奇 (J.Lukasiewicz)提出的一种对表达式的 表示方法:每一运算符都置于其运算对象之 后,即操作数写在前面,算符写在后面。 它的特点是:表达式中各个运算是按运算符 出现的顺序进行的,故无需用括号来指示运 算顺序,因而又称为无括号式。
赋值语句翻译为三地址码的属性文法 P171 ,表7.3
三地址代码—四元式
四元式实际上是一种“三地址语句”的 等价表示,是一个带有四个域的记录结构。 它 的一般形式为: (op,arg1,arg2,result) 需要指出的是:每个四元式只能有一个 运算符,所以,一个复杂的表达式只能由多 个四元式构成的序列表示。
例
a+a*(b-c)+(b-c)*d
+ + * a * d
b
c
抽象语法树的表示方法
1、每一个结点用一个记录来表示,该记 录包括一个运算符域和若干个指向子结 点的指针域。
例: a:=b*-c+b*-c
assign a * + * a assign + *
b
- b c 抽象语法树
c
b DAG
c
方法1
5.循环语句的四元式 待讨论循环语句的翻译时介绍。
语法制导的翻译方法:
就是对文法中的每个产生式都附加一个 语义动作或语义子程序,且在语法分析过程中, 每当需要使用一个产生式进行推导或归约时,语 法分析程序除执行相应的语法分析动作之外,还 要执行相应地语义动作或语义子程序。每个语义 子程序都指明了相应产生式中各个符号的具体含 义,并规定了使用该产生式进行分析时所应采取 的语义动作。 翻译过程见P171表7。3。 这种模式既把语法分析与语义处理分开,又 令其平行地进行,让其在同一遍扫描中同时完成 语法分析和语义处理两项工作。
语义分析
在词法分析和语法分析之后,编译 程序要完成语义分析和翻译工作。由 于编译器完成的分析是静态定义的,所 以,语义分析也可称作静态语义分析 (static semantic analysis)。