89
1 第第第 第第第第第第 7.1 第第第第 7.2 第第第第 7.3 第第第第 7.4 第第第第第 7.6 第第 7.7 第第第第 第第

第七章 中间代码生成 序 7.1 中间语言 7.2 说明语句 7.3 赋值语句 7.4 布尔表达式 7.6 回填 7.7 过程语句

  • Upload
    sakina

  • View
    107

  • Download
    6

Embed Size (px)

DESCRIPTION

第七章 中间代码生成 序 7.1 中间语言 7.2 说明语句 7.3 赋值语句 7.4 布尔表达式 7.6 回填 7.7 过程语句 练习. 序 ◆ “中间代码生成”程 序的 任务 是:把经过语 法分析和语义分析而获得的源程序中间表 示翻译为中间代码表示。 ◆方法:语法制导翻译。 ◆ 采用独立于机器的中间代 码的好处 : 1. 便于编译系统的 建立和编译系统的移植; 2. 便于进行独立于机器的代码优化工作。. 7.1 中间语言 语法树 后缀式 - PowerPoint PPT Presentation

Citation preview

Page 1: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

1

第七章 中间代码生成 序 7.1 中间语言 7.2 说明语句 7.3 赋值语句 7.4 布尔表达式 7.6 回填 7.7 过程语句 练习

Page 2: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

2

◆“ 中间代码生成”程 序的任务是:把经过语

法分析和语义分析而获得的源程序中间表

示翻译为中间代码表示。

◆ 方法:语法制导翻译。

◆ 采用独立于机器的中间代 码的好处: 1. 便于编译系统的 建立和编译系统的移植; 2. 便于进行独立于机器的代码优化工作。

Page 3: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

3

7.1 中间语言 • 语法树 • 后缀式• 三地址代码表示7.1.1 图表示法

语法树,有向非循环图和后缀式表示

源程序的自然层次结构,例如:

a:=b * - c+b * -c

Page 4: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

4

assign

a +

*

b

c

assign

(a) 语法树

*

assign

c

b

Page 5: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

5

assign

a +

*

b

c

assign

(b)dag(Directed Acyclic Graph)

Page 6: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

6

表 7.1 产生赋值语句语法树的语法制导定义

S.nptr:=mknode('assign',mkleaf(id,id.place),E.nptr)

E.nptr:=mknode('+',

E1.nptr,E2.nptr)

E.nptr:=mknode('*',E1.nptr,E2.nptr)

S→id:=E

E→E1+E2

E→E1*E2

产生式 语义规则

Page 7: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

7

E.nptr:=mknode('uminus',E1.nptr)

E.nptr:=E1.nptr

E.nptr:=mkleaf(id,id.place)

E→-E1 E→(E1)

E→id

产生式 语义规则

Page 8: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

8

赋值语句: a:=b*-c+b*-c

后缀式: a b c uminus * b c uminus * + assign

assign

+

*

uminus

id a

id c

id b

*

uminus

id c

id b

id b id c

unimus 1 * 0 2

id b id c

unimus 5 * 4 6 + 3 7

id a assign 9 8

...

Page 9: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

9

7.1.2 三地址代码

◆ 一般形式 x := y op z

图 7.3 相应于图 7.1 的树和 dag 的三地址代码 t1 := -c t1 := -c t2 := b* t1 t2 := b*t1 t3 := -c t5 := t2+t2 t4 := b* t3 a : = t5 t5 := t2+t4 a := t5 ( a )对于语法树的代码 ( b )对于 dag 的代码

Page 10: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

10

7.1.3 三地址语句的种类 ( 1 )赋值语句 x := y op z , op 为二目算术算 符或逻辑算符 ;

( 2 )赋值语句 x := op y , op 为一目算符, 如一目减 uminus 、逻辑非 not 、移位算符 及转换算符 ;

( 3 )复制语句 x := y;

( 4 )无条件转移语句 goto L;

( 5 )条件转移语句 if x relop y goto L ,关系运 算符号 relop ( < , = ,> = 等等) ;

Page 11: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

11

(接上页)

( 6 )过程调用语句 param x 和 call p, n ;

过程返回语句 return y;

( 7 )索引赋值 x:=y[i] 及 x[i] :=y ;

( 8 )地址和指针赋值 x :=& y , x :=* y

和 * x := y 。

◆ 在设计中间代码形式时,选择多少种算 符 需 要 trade off .

Page 12: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

12

7.1.4 语法制导翻译生成三地址代码

S.code:=E.code║gen(id.place':='E.place)E.place:=newtemp; E.code:=E1.code║E2.code ║gen(E.place':='E1.place '+'E2.place)E.place:=newtemp; E.code:=E1.code║E2.code ║gen(E.place':='E1.place '*'E2.place)

S→id:=E

E→E1+E2

E→E1*E2

产生式 语义规则

Page 13: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

13

(续上表)产生式 语义规则

E.place:=newtemp;e.code:=E1.code‖gen(E.place´:=´´uminus´ E1.place)E.place:=E1.place; E.code:=E1.code

E.place:=id.place; E.code:=‘’

E→-E1

E→(E1)

E→id

表 7.2 产生赋值语句三地址代码的语法制导定义

Page 14: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

14

( 1 ) E.place 表示存放 E 值的名字。 ( 2 ) E.code 表示对 E 求值的三地址语句序列。 (3) newtemp 是个函数,对它的调用将产生 一个新的临时变量。 ◆ 三地址语句序列是语法树的线性表示,用 临时变量代替语法树中的结点。◆ 实际实现中,三地址语句序列往往是被存放 到一个输出文件中,而不是将三地址语句序 列置入 code 属性之中

Page 15: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

15

7.1.5 三地址代码的具体实现

1 .四元式 op, arg1, arg2, result

2 .三元式 op, arg1, arg2

3 .间接三元式 间接码表 + 三元式表◆ 四元式需要利用较多的临时单元 , 四元式之 间 的联系通过临时变量实现。◆ 中间代码优化处理时,四元式比三元式方 便的多 , 间接三元式与四元式同样方便,两 种实现方式需要的存储空间大体相同。

Page 16: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

16

对于语句 a:=b*-c+b*-c 的三种表示方法

(0)(1)(2)(3)(4)(5)

uminus*

uminus*+

assign

cbcbt2t5

arg1

t1

t3t4

arg2 result

t1t2t3t4t5a

op表 7.3(a) 三地址语句的四元式表示

Page 17: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

17

(0)(1)(2)(3)(4)(5)

uminus*

uminus*+

assign

cbcb

( 1 )a

arg1

(0)

(2)(3)(4)

arg2op

表 7.3(b) 三地址语句的三元式表示

树:三元式中使用指向三元式语句的指针。

Page 18: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

18

(14)(15)(16)(17)(18)(19)

uminus*

uminus*+

assign

cbcb

( 15 )a

arg1

(14)

(16)(17)(18)

arg2opstatement

(14)(15)(16)(17)(18)(19)

(0)(1)(2)(3)(4)(5)

表 7.3(b) 三地址语句的间接三元式表示

语句的移动仅改变左边的语句表

Page 19: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

19

7.2 说明语句 ◆ 说明语句的翻译:对每个局部名字,在符 号表中建立相应的表项,填写有关的信息 如类型、嵌套深度、相对地址等。◆ 相对地址:相对静态数据区基址或活动记 录中局部数据区基址的一个偏移值。7.2.1 过程中的说明语句 ◆ 一个过程中的所有说明语句作为一个类集 来处理。用一个全程变量 Offset 来记录下 一个数椐在活动记录中的位置。

Page 20: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

20

P→ { offset := 0} D D→D; D D→id : T { enter ( id.name , T.type ,offset ); offset:=offset + T.width } T→integer{ T.type : =integer; T.width : = 4} T→real { T.type := real; T.width := 8} T→array[num]of T1

{ T.type: = array ( num.val, T1.type ); T.width : = num.val *T1.width} T→ ↑T1 { T.type: = pointer ( T1 . type ); T.width : = 4}图 7 . 4 计算说明语句中名字的类型和相对地址

Page 21: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

21

7.2.2 保留作用域信息 1 .问题的提出 一般的语言中,标识符的作用在程序正文中有一个确定的范围。因此,同一个标识符在不同的程序正文中可能标识不同的对象,具有不同的性质,要求分配不同的存储空间。于是提出下面的问题:如何组织符号表,使得同一个标识符在不同的作用域中得到正确的引用而不产生混乱。 编译程序分析说明语句时建立符号表,编译执行语句时查找符号表。 Lookup(id) 返回正

Page 22: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

22

确的 id.entry 。

2. 程序结构

一组嵌套过程,每个过程说明的局部名字建立一个符号表,所有正在翻译过程的符号表组成整个源程序的符号表。翻译语句部分时查找符号表,查找过程的符号表的路线相当于当前被 翻译过程的静态链。

翻译时,实际上,为每一个过程维持一个符号表。

Page 23: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

23

Sort a,x

R i a

E i,j x,a

P y,z,i,j a,v,e(i,j)

Qsort m,n,k,v

k

Page 24: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

24

nil headerax

readarrayexchangequicksort

headerheader headerkv

partition

headerij

sort

readarray exchange quicksort

partition

i

to readarrayto exchange

图 7.5 嵌套过程的符号表

Page 25: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

25

编译过程:用先根次序遍历上一页中的树,用栈来存储编译过程中使用的量,象 table 和offset 。

进入过程 partion , quicksort 过程的编译并未结束,活动记录的设计和符号表的建立尚未完成,因此,要把 quicksort 过程使用的 table 和 offset保存于栈中。

使用两个栈,分别保存刚编译过程的符号表箭头 table 和 offset 的值。

Page 26: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

26

图 7. 6 处理嵌套过程中的说明语句 P→MD {addwidth(top(tblptr),top(offset)); pop(tblptr);pop(offset)} M→ε {t:=mktable ( nil ); push(t,tblptr);push(0,offset) } D→D1 ; D2 D→proc id; N D1 ; S

{t: = top ( tblptr); addwidth(t,top(offset)); pop ( tblptr ); pop ( offset); enterproc(top ( tblptr ), id.name, t)}

Page 27: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

27

D→ id: T {enter(top(tblptr),id.name,T.type, top(offset)); top(offset ): = top(offset) + T.width} N→ε {t := mktable(top ( tblptr)) ; push(t , tblptr ); push ( 0 , offset)} 如下操作:1. mktable( previous )创建一张新符号表2. enter ( table , name , type , offset )插入表项3. addwidth ( table , width )记录总域宽4. enterproc ( table,name, newtable ) 建立过程新表项

Page 28: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

28

7.2.3 记录中的域名

T→ record LD end { T.type:=record ( top ( tblptr)) ; T.width: = top(offset) ;

pop ( tblptr);pop(offset)} L→ε {t:=mktable(nil);

push(t,tblptr);push(0,offset))}

图 7.7 为-个记录中的域名建立一张符号表

该翻译模式强调了作为一个语言结构的记录的设计与活动记录之间的相似处 .

Page 29: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

29

关于符号表的进一步讨论: 1. 符号表的数椐结构 ( a ) 线性表; ( b ) 散列表; ( c ) 树结构。 2. 符号表上的运算: ( a )插入( insert ); ( b )查找( lookup ); ( c )删除 (delete).

Page 30: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

30

3. 符号表必须维持源程序中的作用域信息, 源程序中的作用域规则因语言而异,对 一种语言,根椐符号表采用的数据结构, 维持源程序中的作用域信息方法不同。4 . 符号表中名字的属性信息由两方面组成: ( a )名字在源程序中的属性信息,例如, 名字源程序表示,种类,类型等; ( b )经分析加工得到的有用信息,例如, 对于变量来说,嵌套深度,在活动 记录中的偏移量等。

Page 31: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

31

7.3 赋值语句 • 赋值语句的翻译• 表达式的类型可以是整型、实型、数组 和记 录7.3.1 符号表中的名字 ◆ 名字可以理解为指向符号表中相应该名字 表项的指针

如何根据名字查找符号表的表项?

Page 32: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

32

◆ 过程 lookup(id.name)检查是否在符号表中存在相应此名字的表项。 采用最近嵌套作用域规则查找非局部名字时, lookup 过程先通过 top(tblptr )指针在当前符号表中查找名字为 name 的表项。 若找到,返回有关信息。 若未找到, lookup就利用当前符号表表头 的指针找到该符号表的外围符号表,然后在那里查找名字为 name 的表项,直到所有外围过程的符号表中均无此 name 表项,则 lookup返回 nil, 表明查找失败。

Page 33: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

33

图 7 . 8 产生赋值语句三地址代码的翻译模式

S→id:=E {p:=lookup(id.name); if p<>nil then emit(p':=' E.place) else error }

E→E1+E2{E.place=newtemp; emit(E.place':='E1.place'+'E2.place')

} E→E1*E2{E.place=newtemp;

emit(E.place':='E1.place'*'E2.place')} E →-E { E.place:=newtemp; emit(E.place ´ := ´ ´uminus´E1.place}

Page 34: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

34

E→(E1) {E.place:=E1.place} E→id {p:=lookup(id.name);

if p<>nil then E.place:=p else error}

lookup(id.name)= id.entry nil emit 它将生成的三地址代码送到输出文件上。 语义动作应包括类型分析,文法符号应有类型属性,在类型分析的基础上,进行相容和赋值相容检查,生成类型转换的三地址代码。

Page 35: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

35

7.3.2 数组元素地址分配 数组元素的三地址代码是什么? 如何生成数组元素的三地址代码。 一 . 数组元素地址的计算公式◆ 数组 A 的下标为 i 的元素的开始地址 VAR a:ARRAY [low..high] OF real; 求 a[i] 的地址 .

base +( i- low ) * w ( 7. 3 ) =bace-low*w + i*w 常量部分(可在编译时计算出来) + 变量部分 其中, base 是数组元素 a[low] 的地址。

Page 36: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

36

◆ 对于一个二维数组,可以按行或按列存放 若按行存放,则可用如下公式计算 A[i1,i2] 的相对地址: base +(( i1 一 low1 ) * n2 + i2 一 low2) *w )= base-(( low1 *n2 )+ low2 ) *w + ( i1*n2 )+ i2)* w ( 7. 4 ) 令 c= (( low1 *n2 )+ low2 ) *w 则常量部分 =a[low1,low2]-c. ◆ 计算元素 A[i1,i2,...,ik] 相对地址的推广公式 ((...((i1*n2+i2)*n3+i3...)*nk+ik)*w+base-((...((low1*n2+low2)*n3+low3...)*nk+lowk)*w (7.5)

Page 37: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

37

c=((...((low1*n2+low2)*n3+low3)...)*nk +lowk) * w 变量部分 = ((...((i1*n2+i2)*n3+i3...)*nk+ik)*w a[i1,i2,…in] 的地址 =base-c+ 变量部分 x:=a[i1,i2] 三地址代码结构: t1: = 变量部分 t2:=base-c t3:=t2[t1] x:=t3◆ 计算动态数组元素地址的公式与在固定长度 数组情况下是同样的,只是上、下界在编译 时是未知的。

Page 38: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

38

数组的类型信息:VAR a:ARRAY [1..10,1..20] OF real;

符号表中的信息可组织如下: a 嵌套深度 偏移量 类型 名字表

信息向量C=84

low1=1high1=10

n1=10low2=1

high2=20n2=20基类型

Real标准类型

8

Page 39: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

39

◆ 数组元素引用的文法 L→ id [Elist] | id

Elist→Elist,E|E

变量部分: ((i1*n2+i2)*n3+i3)*n4+……

Elist + i1,i2,…,in

nj:=highj-lowj+1 (7.5)

em=em-1*nm+im (7.6)

为获得有关数组各维长度 nj 的信息,改写为: L→Elist]| id

Elist→Elist,E|id[ E

Page 40: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

40

◆ 有关变量与函数的说明

Elist.ndim :记录 Elist 中的下标表达式的个数, 即维数 ;

函数 limit ( array , j ):返回 nj ,即由 array 所 指示的数组的第 j维长度 ;

Elist.place :临时变量,用来临时存放由 Elist

中的下标表达式计算出来的值 ;

em=em-1*nm

Elist 引进综合属性 array ,指向 a 的符号表地址。

Page 41: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

41

7.3.3 访问数组元素的翻译模式

◆给定文法: ( 1 ) S→L := E ( 2 ) E→E + E ( 3 ) E→ ( E ) ( 4 ) E→L ( 5) L→Elist] ( 6 ) L→id ( 7 ) Elist→Elist , E ( 8 ) Elist→id[ E

Page 42: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

42

◆ 相应语义动作• 若 L 是一个简单的名字,将生成一般的赋值;• 若 L 为数组元素引用,则生成对 L 所指示地址的索引赋值1 . S→L := E { if L. offset = null then emit(L.place' := ' E.place) else emit ( L.place'['L.offset']' : = ' E. Place) } 2 . E→E1 + E2 { E.place := newtemp; emit ( E.place' := ' E1 . place' + 'E2.place )}

Page 43: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

43

(接上页) 3 . E→ ( E1 ) { E.place := E1.place} 使用索引来获得地址 L.place[L.offset] 的内容: 4 . E→L { if L.offset = null then E.place: = L.place / * L is a simple id */ else begin E.place:=newtemp; emit(E.place':='L.place'[L.offset']') end}

Page 44: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

44

(接上页) 5 . L→Elist] { L.place:=newtemp; emit ( L.place':='Elist.array'- ' c) ((…(( low1 nt2 + low2 ) n3 + low3)…) *nk + lowk ) * w )); L.offset:=newtemp; emit ( L.offset':='w'*'Elist.place)} 一个空的 offset 表示一个简单的名字: 6 . L→ld ( L.place:=id.place;L.offset:=null}

Page 45: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

45

(接上页)应用递归公式扫描下一个下标表达式 7 . Elist→Elist1,E {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 }

Page 46: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

46

8 . Elist→id[E { Elist.place:=E.place; Elist.ndim:=1 : Elist.array := id.place}

例 7.1 设 A 为一个 10*20 的数组,即 n1= 10, n2= 20 。并设 w = 4 ,数组第一个元素为 A[1 , 1] 。则有,(( low1*n2 )+ low2 ) *w=(1*20 + 1 ) *4= 84 。对赋值语句 x : = A[y,z] 的带注释的分析树如图 7.10 所示。

Page 47: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

47

L.place = xL.offset = null

L.place = t2L.offset = t3

E.place = t4

Elist.place = t1Elist.ndim = 2Elist.array = A

S

:=

x

]

(未完)

图 7.10 关于 x := A[y, z] 的带注释的分析树

Page 48: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

48

Elist.place = yElist.ndim = 1Elist.array = A

,

L.place = zL.offset = null

E.place = z

A [

z

y

L.place = yL.offset = null

E.place = y

Elist(place=t1,ndim=2,array=A)

Page 49: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

49

该赋值语句在由底向上的分析中被翻译成如下三地址语句序列:

t1 : = y*20 t1 : = t1 + z t2 : = A-84 t3: = 4*t1 t4 : = t2[t3] x : = t4

注意: 20 、 84 、 4都是编译中引入的常量。

Page 50: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

50

7.3.4 访问记录中的域

编译器将记录的域的类型和相对地址保存在相应域名的符号表表项之中,可以把用在符号表中查找名字的程序同样用来查找域名。

例如:表达式: p↑ . info + 1 变量 P 是一个指向某个记录类型的指针, info 为其中一个算术型类型的域名。 编译程序内部把 p 表示为:pointer ( record ( t )) ,域名 info 将可以在 t 所指向的符号表中查找。

Page 51: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

51

TYPE p

link= node;

node=RECORD info

info:integer; next

next:link

END;

VAR p:link;

取 L (level, offsetp)

取 L 0(L)

Page 52: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

52

7.4 布尔表达式

◆ 布尔表达式 : 用布尔运算符号( and , or ,not )作用到布尔变量或关系表达式上而组成

◆ 布尔表达式的作用:

1. 用作计算逻辑值

2. 用作控制流语句如 if-then , if-then-else和 while-do 等之中的条件表达式

◆ 本节考虑由如下文法生成的布尔表达式:

E→E or|E and E| not E|(E ) | id relop id |true|false

Page 53: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

53

7.4.1 翻译布尔表达式的方法

◆ 表示一个布尔表达式的值• 方法一:用数值表示真和假,从而对布尔表达式的求值可以象对算术表达式的求值那样一步一步地来计算• 方法二:通过程序的控制流,即用程序中控制转移到达的位置来表示布尔表达式的值

方法二用于翻译控制流语句中的布尔表达式尤其方便。

Page 54: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

54

7.4.2 数值表示法

用 1 表示真, 0 表示假来实现布尔表达式的翻译

布尔表达式: a or b and not c 翻译成三地址代码序列: 100 : t1:=not c 101 : t2:=b and t1 102 : t3:=a or t1

关系表达式: a<b 等价于 if a<b then 1 else 0 翻译成三地址代码序列:

Page 55: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

55

100 : if a< b goto l03 101 : t : =0 102 : goto l04 。 103 : t:=1 104 :

图 7.11 关于布尔表达式的数值表示法的翻译模式 E→E1 or E2 { E.place:=newtemp; emit(E.place':='E1.place'or E2.place)} E→E1 and E2 { E.place:=newtemp; emit(E.place':='E1.place'and E2.place)}

Page 56: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

56

(接上页)E→not E1 { E.place:=newtemp; emit(E.place':=' 'not' E1.place)} E→id1 relop id2 { E.place:=newtemp; emit('if' id1.place relop.op

id2.place'goto' nextstat+3); emit(E.place':=' '0'); emit('goto'nextstat+2); emit(E.place':=' '1')} E→ture { E.place:=newtemp; emit(E.place':=' '1')} E→false { E.place:=newtemp; emit(E.place':=' '0')}

Page 57: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

57

7.4.3 控制流语句 文法: S→if E then S1 | if E then S1 else S2 | while E do S1

E.code

S1.codeE.true:

...E.false:

(a) if-then

to E.true

to E.false

代码结构:

Page 58: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

58

E.code

S1.codeE.true:

S2.codeE.false:goto S.next

...S.next:

to E.true

to E.false

(b)if-then-else

E.code

S1.codeE.true:

E.false:goto S.begin

...

S.begin:to E.false

to E.true

(c )while-do

Page 59: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

59

语法制导定义:

产生式 语义规则

S→if E then S1

E.true:=newlabel; E.false:=S.next; S1.next:=S.next S.code:=E.code||

gen(E.true’:’)||S1.code

Page 60: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

60

产生式 语义规则

S→if E then S1else S2

E.true:=newlabel; E.false:=newlabel; S1.next:=S.next; S2.next:=S.next; S.code:=E.code||

gen(E.true’:’)||S1.code gen(‘goto’S.next)||

gen(E.false’:’)||S2.code

( 接上页)

Page 61: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

61

产生式 语义规则

S→while E do S1

S.begin:=newlabel; E.true:=newlabel; E.false:= S.next; S1.next:=S.begin; S.code:=gen(S.begin’:’‖ E.code ‖ gen(E.true’:’) ‖ S1.code ‖ gen(‘goto’S.begin)

( 接上页)

Page 62: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

62

7.4.4 控制流语句中的布尔表达式的翻译基本思想 : 假定 E 形如 a< d, 则将生成如下的 E 的代码: if a< b goto E.true

表 7.5 语法制导定义 goto E.false

产生式 语义规则

E→E1 or E2

E1.true:=E.true; E1.false:=newlabel; E2.true:=E.true; E2.false:=E.false E.code:=E1.code|| gen(E1.false’:’)||E2.code

Page 63: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

63

产生式 语义规则

E→E1 and E2

E1.true:= newlabel; E1.false:= E.false; E2.true:=E.true; E2.false:=E.false; E.code:=E1.code‖ gen(E1.true’:’) ‖ E2.code

(接上页)

E→not E1 E1.true:= E.false; E1.false:= E.true; E.code:=E1.code

Page 64: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

64

产生式 语义规则

E→id1 relop id2

E.code:=gen(‘if’ id1.place relop.op id2.place ‘goto’ E.true)|| gen(‘goto’ E.false)

E→true E.code:=gen(‘goto’ E.true)

E→false E.code:=gen(‘goto’ E.false)

E 的 true 和 false 属性都是继承属性

E→(E1) E1.true:= E.true; E1.false:= E.false; E.code:=E1.code

Page 65: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

65

例 7.4 考虑如下语句:

while a< b do if c< d then x : = y + z else x := y-z

根据前面所述,生成代码如右:

L1 : if a< b goto L2 goto Lnext L2 : if c< d goto L3 goto L4 L3 : t1 : = y + z x := t1 goto L1 L4 : t2:=y- z x := t2 goto L1 Lnext :

Page 66: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

66

7.5 CASE 语句 switch 语句的语法: switch expression

begin

case valuE1 : statement1

case valuE2 : statement2

......................... ........

case value n-1 : statement n-1

defalt : statement n

end

Page 67: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

67

switch 语句翻译成的三地址代码控制流程: 1 .对表达式求值; 2 .在列出的 valuE1 , valuE2,… , value n-

1

这些值中寻找与表达式的值相等的值。 如果没有这样的值存在,则让“缺席值” 与表达式匹配; 3 .执行在( 2 )中寻找到的值相联系的语 句(某个 statement )。

Page 68: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

68

switch 语句的目标代码结构: 对 expression 求值并置于 t 的有关代码 goto test L1: 有关 statement1 的代码 goto next L2 : 有关 statement2 的代码 goto next …………………………………… Ln-1 : 有关 statement n-1 的代码 goto next Ln: 有关 statementn 的代码 goto next

Page 69: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

69

(接上页)test : if t = value1 goto L1 if t = value2 goto L2 ……………………. if t = valuen-1goto Ln-1 goto Ln next :expression: 选择器,将被计算出一个值。valueE1,valueE2,… , value n-1: 表达式可能取的 值。default: “缺席值”。用来在 expression 的值不等 于任何 value i 时来匹配 expression 。

Page 70: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

70

7.6 回填 两遍扫描:• 从给定的输入构造出一棵语法树;• 对语法树按深度优先遍历,来进行定义中给出的翻译。

一遍扫描:• 先产生暂时没有填写目标标号的转移指令。 • 对于每一条这样的指令作适当的记录,• 一旦目标标号被确定下来,再将它“回填”到相应的指令中。

Page 71: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

71

7.6.1 使用回填翻译布尔表达式 布尔表达式文法: ( 1 ) E→E1 or M E2 ( 2 ) |E1 and M E2 ( 3 ) |not E1 ( 4 ) |(E1) ( 5 ) |id1 relop id2 ( 6 ) |true ( 7 ) |false ( 8 ) M→ε插入非终结符号 M 是为了引入一个语义动作,以便在适当的时候获得即将产生的下一个四元式的索引,或说四元式的标号

Page 72: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

72

翻译模式用到如下三个函数: 1 . makelist(i) :创建一个仅包含 i 的新表,i 是四元式数组的一个索引(下标),或说 i 是四元式代码序列的一个标号。 2 . merge(p1 , p2) :连接由指针 p1 和 p2指向 的两个表并且返回一个指向连接后的表的 指针。 3 . backpatch ( p , i ):把 i 作为目标标号回 填到 p 所指向的表中的每一个转移指令中 去。此处的“表”都是为“反填”所拉的链

Page 73: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

73

图 7.14 使用一遍扫描的布尔表达式的翻译模式

EE1 OR ME2

{backpatch(E1.falselist,M.quad);

E.truelist:=merge(E1.truelist,E2.truelist);

E.falselist:=E2.falselist }

EE1 AND ME2

{backpatch(E1.truelist,M.quad);

E.truelist:=E2.truelist;

E.falselist:=merge(E1.falselist,E2.falselist);}

Page 74: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

74

Enot E1 { E.truelist:=E1.falselist;

E.falselist:=E1.truelist }

E ( E ) {E.truelist:= E1.truelist;

E.falselist:=E1.falselist}

E id1 relop id2

{E.truelist:= makelist(nextquad);

E.falselist:= makelist(nextquad+1);

emit(´if´id1.place relop.op

id2.place´goto—´);

emit(´goto—´); }

Page 75: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

75

E true {E.truelist:= makelist(nextquad);

emit(´goto—´); }

E false {E.falselist:= makelist(nextquad);

emit(´goto—´); }

M {M.quad:=nextquad }

Page 76: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

76

例 7.15 重新考虑表达式 a< b or c< d and e< f

一棵作了注释的分析树如下图所示E.t={100,104}E.f={103,105}

E.t={100}E.f={101}

E.t={104}E.f={103,105}

OR M.q=102

a < b

E.t={102}E.f={103}

E.t={104}E.f={105}

and M.q=104

c < ed f<

Page 77: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

77

依次分析,得到如下四元式: 100 : if a< b goto-- 101 : goto-- 102 : if c< d goto-- 103 : goto-- 104 : if e< f goto-- 105 : goto--

经过回填得到:

100 : if a< b goto L1 101 : goto l02 102 : if c< d goio l04 103 : goto L2 104 : if e< f goto L1 105 : goto L2

当知道了条件为真时和条件为假时分别应做哪些事时就可以进行回填

Page 78: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

78

7.6.2 使用回填翻译控制流语句

文法: ( 1 ) S→if E then S ( 2 ) | if E then S else S ( 3 ) | while E do S ( 4 ) | begin L end ( 5 ) | A ( 6 ) L→L ; S ( 7 ) |S

S 表示语句 L 表示语句表A 为赋值语句 E 为一个布尔表达式

Page 79: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

79

控制流语句的翻译模式:

1. Sif E then M1 S1 N else M2 S2

E.code

S1.codeE.true:

S2.codeE.false:goto S.next

...S.next:

to E.true

to E.false

M1 处反填 E.truelist

M2 处反填 E.falselist

N 出生成 ´goto S.next ´

Page 80: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

80

{backpatch( E.truelist,M1.quad);

backpatch(E.falselist,M2.quad);

S.nextlist:=merge(S1.nextlist,N.nextlist,

S2.nextlist) }

N {N.nextlist:=makelist(nextquad);

emit(´goto—´) }

Sif E then M S1

{backpatch( E.truelist,M.quad);

S.nextlist:=merge(E.falselist ,S1.nextlist)}

Page 81: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

81

Swhile M1 E do M2 S1

M1 处生成标号 S.begin ,反填 S1.nextlist。 M2 处反填 E.truelist 。 S.nextlist:=E.falselist

{backpatch(S1.nextlist,M1.quad);

backpatch(E.truelist,M2.quad);

S.nextlist:=E.falselist;

emit(´goto´M1.quad) }

S begin L end {S.nextlist:=L.nextlist}

S A {S.nextlist:=makelist( )}

Page 82: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

82

先记录要回填的转移指令地址,在适当的时候进行回填,以便赋值和布尔表达式的求值得到合适的连接,以完成程序的控制流程。

例 7.6 使用自底向上的分析法生成四元式目标 代码,其中 A1 , A2 和 A3 均表示赋值语句。 if a< b or c< d and e< f then A1 else A2; while a< b do A3

LL1;M S {backpatch(L1.nextlist,M.quad);

L.nextlist:=S.nextlist }

LS {L.nextlist:=S.nextlist }

Page 83: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

83

全部四元式代码如下: 100: if a< b goto 106 101 : goto l02 102 : if c< d goto l04 103 : goto ll7 104 : if e< f goto l06 105 : goto 117 106 {此处反填 E.truelist} . . ( 关于 A1 的四元式 ) . 116 : goto 127

Page 84: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

84

117: {此处反填 E.falselist} ( 关于 A2 的四元式 )

127 : if a<b goto 129 {此处反填 S.nextlist} 128: goto 140 129: {此处反填 E.truelist}

( 关于 A3 的四元式 )

139: goto 127 140: {此处反填 E.falselist}

…..

.…

...

Page 85: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

85

7.4.3 标号和转 移语句 ………. goto L; ………. goto L; ………. goto L; ……….L: ………..

goto nil

………...

L

goto

………...

goto

L: ………..拉链 反填

Page 86: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

86

7.7 过程调用

◆ 一个过程调用的翻译包括一个调用序列,即进入和离开每一个过程所采取的动作序列。

◆ 考虑如下的一个简单的过程调用语句的文法: ( 1 ) S→call id ( Elist ) ( 2 ) Elist→Elist , E ( 3 ) Elist→ E

怎样的语法制导定义可以实现该序列?

Page 87: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

87

发生一个过程调用时:• 为被调用过程分配它的活动记录的存储空间;• 把实在参数的信息传递到被调用过程的可取的指定位置;• 建立环境指针以便被调用过程能存取非局部过程的数据;• 保留调用过程的运行状态;• 返回地址应存入指定的单元中;• 应生成一条转移指令转移到被调用过程的代码的开始位置。

Page 88: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

88

从过程返回时:• 如果被调用过程是一个函数,则需将返回的结果值存放在一个指定的位置上;• 调用过程的活动记录需要恢复;• 应生成一条转移指令转移到调用过程的返回地址;

例子:过程调用 “ call i(a+b, c)” 代码如下:

计算 a + b 置于单元 t 中 / * t : = a + b */ param t / * 第一个实参地址 */ param c / * 第二个实参地址 */ call i . Place , 2 / * 调用过程 i */

Page 89: 第七章 中间代码生成            序 7.1   中间语言 7.2   说明语句 7.3   赋值语句 7.4   布尔表达式 7.6   回填 7.7   过程语句

89

语法制导翻译: 1.S→call id ( Elist ) { for each item p on queue do emit ( 'param' p) ; emit ( 'call' id . place ) } S 的代码:首先是 Elist 的代码(即对各参数表达式求值),其次是顺序为每一个参数构造一条 param 语句,最后是一个 call 语句。 2. Elist→Elist , E { 将 E.place加入到 queue 的队尾 }

3 . Elist→E {初始化 queue 仅包含 E.place}