当前位置:文档之家› 编译原理 第七章——语义分析和中间代码生成

编译原理 第七章——语义分析和中间代码生成


中间语言
常见的中间语言的形式: 后缀式(逆波兰式) 三地址代码 - 三元式 - 四元式 - 间接三元式 DAG图
后缀式
又称逆波兰表示法,把运算量(操作数)写在前面,把算 符写在后面(后缀)。 如:a+b 写成 ab+ a+b*c 写成 abc*+ 定义: 1.如果表达式E是一个变量或常量,则E的后缀式是E自身; 2.如果E是E1 op E2形式的表达式 (op为二元操作符) ,则E的 后缀式为E1’E2’op。E1’ 、E2’分别为E1、E2的后缀式; 3.如果E式(E1)形式的表达式,则E1的后缀式就是E的后缀式。 •这种表达式不需要括号 这种表达式不需要括号
(0) (=[ ],x,i) (1) (:=,(0),y)
([ ]=,y,-,x[i]) //变址存数四元式
(0) ( [ ]=,y,i) (1) (:=,x,(0))
(=[ ],y[i] ,-,x) //变址取数四元式
如a:=b*-c+b*-c
四元式
op (0) (1) (2) (3) (4) (5) arg1 arg2 resul t T1 uminus C
如a*(b+c) 写成 abc+* (a+b)*(c+d) 写成 ab+cd+*
* a b + c a + b c *

d
将表达式翻译为后缀式的语义规则
产生式
E→E1 op E2 E→(E) E→id
语义规则
E.code:=E1.code||E2.code|| op E.code:=E1.code E.code:=id
a:=b*-c+b*-c的三地址代码为:
T1 := -c T2 :=b*T1 T3 := -c T4 :=b*T3 T5 :=T2 +T4 a := T5
对于抽象语法树的代码 c c b * uminus b * uminus a assign

a:=b*-c+b*-c的三地址代码为:
T1 := -c T2 :=b*T1 T5 :=T2 +T2 a := T5
按行存放
A[1,1] A[1,2] A[2,1] A[2,2]
多维数组的地址计算
二维数组若按行存放:A[i1,i2]的相对地址为: ((i1×n2)+i2)×w+(base-(low1×n2)+low2)×w
在编译时可确定
将数组元素加入赋值语句后的翻译模式 在算术表达式中,当有两种不同类型的量进行运 算时,如整型量和实型量,规定首先必须把整型 转换成实型。
数组元素的引用
数组在存储器中的存放方式决定了数组元素的地址 计算法。 ①若数组存放在一片连续单元。假设A每个元素宽度为 w,则A[i]的起始地址为: base+(i-low)×w=i×w+(base-low×w)
记为C,可在数组说明时计算出来
②多维数组:按列存放
A[1,1] A[2,1] A[1,2] A[2,2]
assign • id a + • * • • • • 或
0 1 2 3
* • •
id id uminu s * id id uminu s * + id ……
b c 1 0 b c 5 4 3 a 8 6 7 2
4 5 6 7 8 9 10 11
id b uminus • id c
id b uminus • id c
(1) (4) (5)
(3) (4) (5)
:= * :=
X D Y
(2) (1) (4)
•当要调整运算顺序时,只需要重新安排间接码表。
说明语句
说明语句的翻译模式 P→D D→D;D D→id:T T→integer T→real T→array[num] of T1 T→↑T1 {offset:=0} {enter(,T.type,offset); offset:=offset+T.width} {T.type:=integer T.width:=4} {T.type:=real T.width:=8} {T.type:=array(num.val,T1.type); T.width:=num.val×T1.width} {T.type:=pointer(T1.type); T.width:=4}
赋值语句的翻译 1.简单算术表达式和赋值语句
S →id := E E→E1+E2 E→E1*E2 → E→ - E1 E→( E1) E→id { P:=lookup () ; if P≠nil then emit( P“:=”E.place) else error } {E.place:= newtemp; emit(E.place“:=” E1.place“+”E2.place)} {E.place:= newtemp; emit(E.place“:=” E1.place“*”E2.place)} { E.place:=newtemp; emit(E.place“:=”“uminus” E1.place)} { E.place:= E1.place} {E.place:=newtemp; P:=lookup(); if P≠nil then E.place:=P else error}
布尔表达式的翻译
三地址语句的种类
X :=Y op Z X := op Y X :=Y goto L if x relop y goto L 或if a goto L 用于过程调用的param x 和call p,n及 return y x :=y[i] 及 x[i] :=y x :=&y, x :=*y, *x :=y
T1:=y*20 T1:=T1+z T2:=A-84 T3:=4*T1 T2[T3]:= X
布尔表达式的翻译
布尔表达式的两个基本作用: -用于计算逻辑值 -用于控制流语句中的条件表达式 布尔表达式是用布尔运算符号(and,or,not)作用到 布尔变量或关系表达式上组成的。 关系表达式:E1 relop E2 relop为关系运算符 规定优先级not,and,or依次降低。
assign 9
三地址代码
三地址代码是由下面一般形式的语句构成的序列: X :=Y op Z。其中,X,Y,Z为名字,常数或编译时 产生的临时变量,op代表运算符号。 每个语句右边只能有一个运算符。
如:x+y*z 可翻译为: x+y z
T1 :=y*z T2 :=x+T1
T1,T2为编译时产生的临时变量。
E.code表示E的后缀式,op为二元操作符,“||”表示 后缀形式的连接。
图表示法
DAG 抽象语法树
DAG: 无循环有向图。对表达式的每个子表达式, DAG中都有一个结点。一个内部结点代表一个操作符, 它的孩子代表操作数。 在一个DAG图中,代表公共子表达式的结点具有多个 + 父结点。 如表达式a+a*(b-c)+(b-c)*d的DAG图为: +
对于DGA的代码 b a assign

* uminus c
a:=b*-c+b*-c的三地址代码为:
T1 := -c T2 :=b*T1 T3 := -c T4 :=b*T3 T5 :=T2 +T4 a := T5
对于抽象语法树的代码 对于DGA的代码
T1 := -c T2 :=b*T1 T5 :=T2 +T2 a := T5
S →L:= E
E→E1+st →Elist1,E
Elist →id[E
{ if L.offset=null then emit( L.place“:=”E.place) else emit( L.place ‘[’ L.offset ‘]’ ‘:=’E.place)} { E.place := newtemp; emit(E.place ‘:=’ E1.place ‘+’ E2.place)} { E.place:= E1.place} { if L.offset=null then E.place:=L.place; else begin E.place := newtemp; emit(E.place ‘:=’ L.place ‘[’ L.offset ‘]’ ) end} { L.place := newtemp; emit(L.place ‘:=’ Elist.array-C L.offset := newtemp; emit(L.offset ‘:=’ w ‘*’Elist.place)} { L.place:= id.place; L.offset := null } {t := newtemp; m := Elist1.ndim+1; emit(t ’:=’ Elist1.place ‘*’ limit(Elist1.array,m)); emit(t ‘:=’ t ’+’ E.place); Elist.array := Elist1.array; Elist.place := t; Elist.ndim := m} {Elist.place := E.place; Elist.ndim := 1; Elist.array := id.place }
x:=A[y,z]
设A为10×20的数组,w=4,则 x:=A[y,z]的三地址语句序列为:
T1:=y*20 T1:=T1+z T2:=A-84 T3:=4*T1 T4:=T2[T3] X:=T4
84=C=(1×20+1)×4
设A为10×20的数组,w=4,则 A[y,z] := x 的三地址语句序列为:
* a b - c * d
又如 a:=b*-c+b*-c
DAG图 assign a

抽象语法树 assign a * uminus c b uminus c b
相关主题