Slide08 807007748

Post on 06-Aug-2015

116 Views

Category:

Education

3 Downloads

Preview:

Click to see full reader

Transcript

《编译原理》

语义分析与中间代码生成

第八讲

《编译原理》

语义分析和中间代码生成在编译程序中的 逻辑位置

语义分析与中间代码生成

词法分析

语法分析

中间代码生成

中间代码优化

目标代码优化

目标代码生成

静态语义分析

语义处理

《编译原理》

语义分析和中间代码生成的重要数据结构

符号表( symbol tables ) • 名字信息建立后加入 / 更改符号表 名字信息如:种类,类型,偏移地址,占用空间等• 需要获取名字信息时,查找符号表

• 符号表的组织可以体现名字作用域规则

(符号表的组织已在第七讲专门讨论)

语义分析与中间代码生成

《编译原理》

语义分析 中间代码生成

语义分析与中间代码生成

《编译原理》

与语义分析相关的工作

语义分析

静态语义检查• 编译期间所进行的语义检查

动态语义检查• 所生成的代码在运行期间进行的语义检查

收集语义信息• 为语义检查收集程序的语义信息

• 为代码生成等后续阶段收集程序的语义信息 有些内容合并到“中间代码生成”部分讨论 (如过程、数组声明的语义处理)

《编译原理》

静态语义检查 代码生成前程序合法性检查的最后阶段

• 静态类型检查( type checks ) 检查每个操作是否遵守语言类型系统的定义• 名字的作用域( scope )分析 建立名字的定义和使用之间联系• 控制流检查( flow-of-control checks ) 控制流语句必须使控制转移到合法的地方(如 break 语句必须有合法的语句包围它)• 唯一性检查( uniqueness checks ) 很多场合要求对 象只能被定义一次(如枚举类型的元素不能重复出现)• 名字相关检查( name-related checks ) (如,一些名字可能被要求配对出现)• ……

语义分析

《编译原理》

类型检查程序( type checker )负责类型检查• 验证语言结构是否匹配上下文所期望的类型• 为相关阶段搜集及建立必要的类型信息• 实现某个类型系统( type system )

静态类型检查• 编译期间进行的类型检查

动态类型检查• 目标程序运行期间进行的类型检查

类型检查

语义分析

《编译原理》

类型表达式( type expressions )• 由基本类型,类型名字,类型变量,及类型构 造子( type constructor )归纳定义的表达式

类型系统( type systems )• 将类型表达式赋给程序各个部分的规则集合

类型表达式和类型系统

语义分析

《编译原理》

某个类型表达式集合(将用于示范类型检查 程序的设计)归纳定义如下:

• 基本类型 bool, char, int, real, type_error 和 ok 是类型表达式(其中, type_error 专用于类型检查 时的出错提示; ok 可用于语句的类型检查)• 若 T 是类型表达式,则 array(I,T) 是类型表达式, 表示元素类型是 T ,下标集合是 I 的数组类型(这 里, I 是一个整数区间,如 1..10 )• 若 T 是类型表达式,则 pointer(T) 是类型表达式, 表示指向类型为 T 的对象的指针类型

类型表达式举例

语义分析

《编译原理》

以下是定义某个简单语言的上下文无关文法 (将用于本讲的设计示例) G[P] :

一个简单语言

P D ; S

D D ; D id : T

T boolean char integer real array [ num ] of T T

E true false literal num num.num id E op E E rop E E [ E ] E

S id := E if E then S while E do S S ; S

语义分析

《编译原理》

语法制导的方法• 将类型表达式作为属性值赋给程序各个部分• 设计恰当的翻译模式• 可实现相应语言的一个类型系统

类型检查程序的设计

语义分析

《编译原理》

语法制导的方法• 处理声明的翻译模式(保存标识符的类型)

类型检查程序的设计

P D ; ED D1 ; D2

D id : TT boolean T charT integerT real T array [ num ] of T1

T T1

{ addtype(id.entry ,T.type)}{ T.type := bool }{ T.type := char }{ T.type := int }{ T.type := real }{ T.type := array(1..num.val, T1.type) }{ T.type := pointer(T1.type) }

语义分析

《编译原理》

语法制导的方法• 表达式的类型检查

类型检查程序的设计

E trueE falseE literalE numE num.num E idE E1 op E2

{ E.type := bool }{ E.type := bool }{ E.type := char }{ E.type := int }{ E.type := real }{ E.type := lookup_type (id.entry) }{ E.type := if E1.type=real and E2.type=real then real else if E1.type=int and E2.type=int then int else type_error }

语义分析

《编译原理》

语法制导的方法• 表达式的类型检查(续)

类型检查程序的设计

E E1 rop E2

E E1 [E2 ]

E E1

{ E.type := if E1.type=real and E2.type=real then bool else if E1.type=int and E2.type=int then bool else type_error }{ E.type := if E2.type=int and E1.type=array(s,t) then t else type_error }{ E.type := if E1.type= pointer(t) then t else type_error }

语义分析

《编译原理》

语法制导的方法• 语句的类型检查

类型检查程序的设计

S id := E

S if E then S1

S while E do S1

S S1 ; S2

{ S.type := if lookup_type (id.entry) = E.type then ok else type_error }{ S.type := if E.type=bool then S1.type else type_error }{ S.type := if E.type=bool then S1.type else type_error }{ S.type := if S1.type=ok and S2.type =ok then ok else type_error }

语义分析

《编译原理》

语法制导的方法• 增加数自动类型转换( type casting )的支持

类型检查程序的设计

E E1 op E2

E E1 rop E2

{ E.type := if E1.type=real and E2.type=real then real else if E1.type=int and E2.type=int then int else if E1.type=real and E2.type=int then real else if E1.type=int and E2.type=real then real else type_error }{ …… }

语义分析

《编译原理》

静态作用域• 通过符号表实现 (已在第七讲讨论)

动态作用域 • 通过运行时活动记录实现 (参见下一讲)

作用域分析

语义分析

《编译原理》中间代码生成

源程序的不同表示形式 作用

• 源语言和目标语言之间的桥梁,避开二者 之间较大的语义跨度,使编译程序的逻辑 结构更加简单明确• 利于编译程序的重定向• 利于进行与目标机无关的优化

中间代码

《编译原理》中间代码生成

有不同层次不同目的之分 中间代码举例

• Postfix (后缀式,逆波兰式)• AST ( Abstract syntax tree ,抽象语法树)• TAC ( Three-address code,三地址码,四元式)

• P-code (特别用于 Pasal 语言实现)• Bytecode ( Java 编译器的输出 , Java 虚拟机的输入)• SSA ( Static single assignment form ,静态单赋值形式)

中间代码的形式

《编译原理》中间代码生成

算术表达式 A + B * ( C - D ) + E / ( C - D ) ^N (中缀形式)

• Postfix (后缀式,逆波兰式) A B C D - * + E C D – N ^ / +

中间代码举例

《编译原理》中间代码生成

算术表达式 A + B * ( C - D ) + E / ( C - D ) ^N (中缀形式)

• TAC ( Three-address code,三地址码,四元式)

(1) ( - C D T1 ) T1 := C - D (2) ( * B T1 T2) T2 := B * T1 (3) ( + A T2 T3) T3 := A + T2 (4) ( - C D T4) 或 T4 := C - D (5) ( ^ T4 N T5) T5 := T4 ^ N (6) ( / E T5 T6) T6 := E / T5 (7) (+ T3 T6 T7) T7 := T3 + T6

中间代码举例

《编译原理》中间代码生成

算术表达式 A + B * ( C - D ) + E / ( C - D ) ^N (中缀形式)

• AST ( Abstract syntax tree ,抽象语法树)

中间代码举例

^

+

+

/

A

*

E-B

DC -

DC

N

《编译原理》中间代码生成

算术表达式 A + B * ( C - D ) + E / ( C - D ) ^N (中缀形式)

• DAG ( Directed Acyclic Graph, 有向无圈图,改进型 AS

T )

中间代码举例

^

+

+

/

A

*

EB

-

DC

N

《编译原理》中间代码生成

静态单赋值形式

中间代码举例

x ¬ 5 x ¬ x - 3 if x < 3 then y ¬ x * 2 w ¬ y else y ¬ x - 3 w ¬ x - y z ¬ x + y

x1 ¬ 5 x2 ¬ x1 - 3 if x2 < 3 then y1 ¬ x2 * 2 w1 ¬ y1 else y2 ¬ x2 - 3y3 ¬ f(y1 , y2) w2 ¬ x2 - y3 z ¬ x2 + y3

《编译原理》中间代码生成

语法制导的方法• 例:生成抽象语法树

中间代码生成

S id := E

S if E then S1

S while E do S1

S S1 ; S2

E idE E1 + E2 E E1 * E2

E ( E1 ) ……

{ S.ptr := mknode(‘assign’, mkleaf(id.entry), E.ptr) }{ S.ptr := mknode(‘if_then’, E.ptr, S1.ptr) } { S.ptr := mknode(‘while_do’, E.ptr, S1.ptr) } { S.ptr := mknode(‘;’ , S1.ptr , S2.ptr) } { E.ptr := mkleaf(id.entry) }{ E.ptr := mknode(‘+’ , E1.ptr , E2.ptr)}{ E.ptr := mknode(‘*’ , E1.ptr , E2.ptr)}{ E.ptr := E1.ptr }……

mknode: 构造内部结点Mkleaf : 构造叶子结点

《编译原理》中间代码生成

顺序的语句序列 其语句一般具有如下形式 x := y op z

(op 为操作符, y 和 z 为操作数, x 为结果 )

三地址码 TAC

《编译原理》中间代码生成 课程后续部分用到的 TAC 语句类型

• 赋值语句 x := y op z ( op 代表二元算术 / 逻辑运算)• 赋值语句 x := op y ( op 代表一元运算)• 复写语句 x := y ( y 的值赋值给 x )• 无条件跳转语句 goto L (无条件跳转至标号 L )• 条件跳转语句 if x rop y goto L ( rop 代表关系运算)• 过程调用语句序列 param x1 … param xn call p,n• 过程返回语句 return y ( y 可选,存放返回值)• 下标赋值语句 x := y[i] 和 x[i] := y (前者表示将地 址 y 起第 i 个存储单元的值赋给 x ,后者类似)• 地址和指针赋值语句 x := &y, x := *y 和 *x := y

参考 A.V.Aho 等的教材(龙书)

《编译原理》中间代码生成

语义属性 id.name : id 的词法名字(符号表中的名字) E.place : 用来存放 E 的值的存储位置 E.code : E 求值的 TAC 语句序列

语义函数 / 过程 lookup ( id.name ) : 从符号表中查找名字为 id.name 的项,返回存放相应值的指针(存储位置),若无该 项,则返回 nil

gen : 生成一条 TAC 语句 newtempt : 返回一个未使用过的存储位置

赋值语句及算数表达式的语法制导翻译

《编译原理》中间代码生成

翻译模式S id := E

E E1 + E2

E E1 * E2

E - E1

E ( E1 ) E id

{ p := lookup (id.name); if ( pnil) then S.code := E.code || gen (p ‘:=‘ E.place) else error }{ 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) }{ E.place := newtemp; E.code := E1.code || gen (E.place ‘:=‘ ‘uminus‘ E1.palce) }{ E.place := E1.place ; E.code := E1.code }{ p := lookup (id.name); if ( pnil) then E.place := p else error ; E.code := ‘’ }

赋值语句及算数表达式的语法制导翻译

《编译原理》中间代码生成

回顾:类型属性的计算 说明语句的语法制导翻译

P D ; ED D1 ; D2

D id : TT charT integerT real T array [ num ] of T1

T T1

E …

{ enter (id.name ,T.type)}{ T.type := char }{ T.type := integer }{ T.type := real }{ T.type := array(1..num.val, T1.type) }{ T.type := pointer(T1.type) }

enter (id.name ,T.type) : 将符号表中 id.name 所对应表项的 type 域置为 T.type

《编译原理》中间代码生成

语义属性 id.name : id 的词法名字(符号表中的名字) T.type : 类型属性 T.width , D.width : 数据宽度(字节数) D.offset : 相对于过程数据区基址的下一个可用的相 对偏移地址(参考下一讲 : 运行时存储组织)

语义函数 / 过程 enter (id.name ,T.type, D.offset) : 将符号表中 id.name 所对应表项的 type 域置为 T.type, offset 域置为 D.offset

过程(函数)中说明语句的语法制导翻译

《编译原理》中间代码生成 过程中说明语句的语法制导翻译

翻译模式P { D.offset := 0 } D ; ED {D1.offset := D.offset } D1 ; {D2.offset := D.offset + D1.width } D2

{D.width := D1.width + D2.width }D id : T { enter (id.name ,T.type, D.offset) ; D.width := T.width } T char { T.type := char ; T.width := 1 } 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 } E …

《编译原理》中间代码生成

数组说明 参考前页的翻译模式,可了解(一维)数组说明的翻译 思想 . 至于符号表中一般情况下是如何组织数组说明信 息的,随后将会讨论 .

数组说明和数组元素引用的语法制导翻译

D id : T { enter (id.name ,T.type, D.offset) ; D.width := T.width } …

T array [ num ] of T1 { T.type := array(num.val, T1.width ) ;

T.width := num.val T1.width } …

《编译原理》中间代码生成

数组引用

数组说明和数组元素引用的语法制导翻译

S id := E

S E1[E2 ] := E3

E E1[E2]

E id

{ p := lookup (id.name); if ( pnil) then S.code := E.code || gen (p ‘:=‘ E.place) else error }{ S.code := E2.code || E3.code || gen (E1.place ‘[’ E2.place ‘]’ ‘:=‘ E3.place) }{ E.place := newtemp; E.code := E2.code || gen (E.place ‘:=‘ E1.place ‘[’ E2.place ‘]’ )}{ p := lookup (id.name); if ( pnil) then E.place := p else error ; E.code := ‘’}

《编译原理》中间代码生成

数组的内情向量( dove vector ) 在处理数组时,通常会将数组的有关信息记录在一些单 元中,称为“内情向量” . 对于静态数组,内情向量可放在 符号表中;对于可变数组,运行时建立相应的内情向量 例: 对于静态数组说明 A[l1:u1,l2:u2,…,ln:un] ,可以在符 号表中建立如下形式的内情向量 :

数组说明和数组元素引用的语法制导翻译

l1 u1

l2 u2

ln un

type a

n C

… …

li : 第 i 维的下界ui : 第 i 维的上界type: 数组元素的类型a: 数组首元素的地址n: 数组维数C: 随后解释

《编译原理》中间代码生成

数组元素的地址计算 例:对于静态数组 A[l1:u1,l2:u2,…,ln:un] ,若数组布局采 用行优先的连续布局,数组首元素的地址为 a ,则数组 元素 A[i1,i2,…,in] 的地址 D 可以如下计算 :

D = a + (i1-l1)(u2-l2)(u3-l3) …(un-ln)

+ (i2-l2)(u3-l3)(u4-l4) …(un-ln)

+…+ (in-1-ln-1)(un-ln) + (in-ln)

数组说明和数组元素引用的语法制导翻译

重新整理后得 : D = a – C + V ,其中 C = (…(l1 (u2-l2) +l2)(u3-l3) + l3)(u4-l4) +…+ l n-1)(un-ln) + ln

V = (…((i1 (u2-l2) +i2)(u3-l3) + i3)(u4-l4) +……+ i n-1)(un-ln) + in

(这里的 C 即为前页内情向量中的 C )

《编译原理》中间代码生成

直接对布尔表达式求值例如 : 可以用数值“ 1” 表示 true; 用数值“ 0” 表示 false;采用与算术表达式类似的方法对布尔表达式进行求值

通过控制流体现布尔表达式的语义方法:通过转移到程序中的某个位置来表示布尔表达式的求值结果 优点:方便实现控制流语句中布尔表达式的翻译常可以得到短路( short-circuit )代码,而避免不必要的求值,如:在已知 E1 为真时,不必再对 E1E2 中的 E2

进行求值;同样,在已知 E1 为假时,不必再对 E1E2

中的 E2 进行求值

布尔表达式的语法制导翻译

《编译原理》中间代码生成

直接对布尔表达式求值

布尔表达式的语法制导翻译

E E1 or E2

E E1 and E2

E not E1

E ( E1 ) E id1 rop id2

E trueE false

{ E.place := newtemp; E.code := E1.code || E2.code || gen (E.place ‘:=‘ E1.place ‘or’ E2.place) }{ E.place := newtemp; E.code := E1.code || E2.code || gen (E.place ‘:=‘ E1.place ‘and’ E2.place) }{ E.place := newtemp; E.code := E1.code || gen (E.place ‘:=‘ ‘not’ E1.palce) }{ E.place := E1.place ; E.code := E1.code }{ E.place := newtemp; E.code := gen ( ‘if‘ id1.place rop.op id2.place ‘goto’ nextstat+3) || gen (E.place ‘:=‘ ‘0’) || gen (‘goto’ nextstat+2) || gen (E.place ‘:=‘ ‘1’) }{ E.place := newtemp; E.code := gen(E.place ‘:=‘ ‘1’) }{ E.place := newtemp; E.code := gen(E.place ‘:=‘ ‘0’) }

nextstat 返回输出代码序列中下一条 TAC 语句的下标

《编译原理》中间代码生成

通过控制流体现布尔表达式的语义 例 : 布尔表达式 E = a<b or c<d and e<f 可能翻译为如 下 TAC 语句序列(采用短路代码, E.true 和 E.false 分别代表 E 为真和假时对应于程序中的位置,可用 标号体现): if a<b goto E.true goto label1 label1: if c<d goto label2 goto E.false label2: if e<f goto E.true goto E.false

布尔表达式的语法制导翻译

《编译原理》中间代码生成

翻译布尔表达式至短路代码

布尔表达式的语法制导翻译

E E1 or E2

E E1 and E2

E not E1

E ( E1 ) E id1 rop id2

E trueE false

{ E1.true := E.true ; E1.false := newlabel; E2.true := E.true ; E2.false := E.false ; E.code := E1.code || gen (E1.false ‘:‘) || E2.code }{ E1.false := E.false ; E1.true := newlabel; E2.true := E.true ; E2.false := E.false ; E.code := E1.code || gen (E1.true ‘:‘) || E2.code }{ E1.true := E.false; E1.false := E.true; E.code := E1.code}{ E1.true := E.true; E1.false := E.false; E.code := E1.code}{ E.code := gen ( ‘if‘ id1.place rop.op id2.place ‘goto’ E.true) || gen (‘goto’ E.false ) }{ E.code := gen (‘goto’ E.true ) }{ E.code := gen (‘goto’ E.false ) }

《编译原理》中间代码生成

if-then 语句 S if E then S1

{ E.true := newlable; E.false := S.next; S1.next := S.next;

S.code := E.code || gen(E.true ‘:’) || S1.code }

条件语句的语法制导翻译

E.code

S1.codeE.true:

E.false: ……

to E.true

to E.false

newlable 返回一个新的语句标号S.next 属性表示 S 之后要执行的首条 TAC 语句的标号

《编译原理》中间代码生成

if-then-else 语句 S if E then S1 else S2

{ E.true := newlable; E.false := newlable; 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 }

条件语句的语法制导翻译

E.code

S1.codeE.true:

E.false:goto S.next

to E.true

to E.fase

……

S2.code

S.next:

《编译原理》中间代码生成 循环语句的语法制导翻译

while 语句 S while E do S1

{ S.begin := newlable; E.true := newlable; E.false := S.next; S1.next := S.begin;

S.code := gen(S.begin ‘:’) || E.code || gen(E.true ‘:’) || S1.code || gen(‘goto’ S.begin) }

E.code

S1.code

S.begin:

E.false:

goto S.begin

to E.true

to E.false

……

E.true:

《编译原理》中间代码生成 复合语句的语法制导翻译

顺序复合语句 S S1 ; S2

{ S1.next := newlable; S2.next := S.next;

S.code := S1.code || gen(S1.next ‘:’) || S2.code }

S1.code

S2.code

S.next: ……

S1.next:

《编译原理》中间代码生成

翻译布尔表达式至短路代码(翻译模式)

布尔表达式的语法制导翻译

E { E1.true := E.true ; E1.false := newlabel } E1 or { E2.true := E.true ; E2.false := E.false } E2

{ E.code := E1.code || gen (E1.false ‘:‘) || E2.code }

E { E1.false := E.false ; E1.true := newlabel } E1 and { E2.true := E.true ; E2.false := E.false } E2

{ E.code := E1.code || gen (E1.true ‘:‘) || E2.code }

E not { E1.true := E.false; E1.false := E.true} E1 {E.code := E1.code}

E ( { E1.true := E.true; E1.false := E.false } E1 ) { E.code := E1.code }

E id1 rop id2   { E.code := gen ( ‘if‘ id1.place rop.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 ) }

《编译原理》中间代码生成

if-then 语句(翻译模式) S if { E.true := newlable ; E.false := S.next } E       then { S1.next := S.next }   S1      { S.code := E.code || gen(E.true ‘:’) || S1.code }

条件语句的语法制导翻译

E.code

S1.codeE.true:

E.false: ……

to E.true

to E.false

newlable 返回一个新的语句标号S.next 属性表示 S 之后要执行的首条 TAC 语句的标号

《编译原理》中间代码生成

if-then-else 语句(翻译模式) 条件语句的语法制导翻译

E.code

S1.codeE.true:

E.false:goto S.next

to E.true

to E.fase

……

S2.code

S.next:

S if { E.true := newlable;     E.false := newlable }    E   then      { S1.next := S.next }    S1   else      { S2.next := S.next }    S2       { S.code := E.code ||       gen(E.true ‘:’) ||       S1.code ||       gen(‘goto’ S.next) ||      gen(E.false ‘:’) ||      S2.code      }

《编译原理》中间代码生成 循环语句的语法制导翻译

while 语句(翻译模式)

E.code

S1.code

S.begin:

E.false:

goto S.begin

to E.true

to E.false

……

E.true:

S while

      { E.true := newlable;     E.false := S.next }    E do     { S1.next := newlable }   S1  

     { S.begin :=   S1.next;    S.code := gen(S.begin ‘:’)      || E.code       || gen(E.true ‘:’)      || S1.code      || gen(‘goto’ S.begin)    }

《编译原理》中间代码生成 复合语句的语法制导翻译

顺序复合语句(翻译模式)

S { S1.next := newlable } S1 ; { S2.next := S.next } S2

{ S.code := S1.code    || gen(S1.next ‘:’)    || S2.code }

S1.code

S2.code

S.next: ……

S1.next:

《编译原理》中间代码生成

拉链与代码回填( backpatching )

另一种控制流中间代码生成技术 比较:前面的方法采用 L- 属性文法 / 翻译模式 下面的方法采用 S- 属性文法 / 翻译模式

《编译原理》中间代码生成 拉链与代码回填 语义属性 E.truelist : “真链”,链表中的元素表示 一系列跳转语 句的地址,这些跳转语句的目标标号是体现布 尔表达式 E 为“真”的标号 E. falselist : “假链”,链表中的元素表示 一系列跳转语 句的地址,这些跳转语句的目标标号是体现布 尔表达式 E 为假的标号 S. nextlist : “next 链”,链表中的元素表示 一系列跳转 语句的地址,这些跳转语句的目标标号是在执 行序列中紧跟在 S 之后的下条 T

AC 语句的标号

《编译原理》中间代码生成 拉链与代码回填 语义函数 / 过程 makelist(i) : 创建只有一个结点 i 的表,对应存放目标 TAC 语句数组的一个下标 merge(p1,p2) : 连接两个链表 p1 和 p2 ,返回结果链表 backpatch(p,i) : 将链表 p 中每个元素所指向的跳转语句 的标号置为 i

nextstm : 下一条 TAC 语句的地址 emit (…) : 输出一条 TAC 语句,并使 nextstm 加 1

《编译原理》中间代码生成

拉链与代码回填 处理布尔表达式的翻译模式

E E1 or M E2

E E1 and M E2

E not E1

{ backpatch(E1.falselist,M.gotostm) ; E.truelist := merge(E1.truelist, E2.truelist) ; E.falselist := E2.falselist }

{ backpatch(E1.truelist,M.gotostm) ; E.falselist := merge(E1.falselist, E2.falselist) ; E.truelist := E2.truelist }

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

注 : 这里可以规定产生式的优先级依次递增来解决冲突问题 (下同)

《编译原理》中间代码生成 拉链与代码回填 处理布尔表达式的翻译模式

E ( E1 )

E id1 rop id2

E true

E false

M

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

{ E.truelist := makelist ( nextstm); E.falselist := makelist ( nextstm+1); emit ( ‘if‘ id1.place rop.op id2.place ‘goto _’ ); emit (‘goto _’) }

{ E.truelist := makelist ( nextstm); emit (‘goto _’) }

{ E.falselist := makelist ( nextstm); emit (‘goto _’) }

{ M.gotostm := nextstm }

《编译原理》中间代码生成 拉链与代码回填 布尔表达式 E = a<b or c<d and e<f 的翻译示意

( 0 ) if a<b goto _

or

E.truelist={0,4}E.falselist={3,5}

and

M.gotostm=2

M.gotostm=4

E.truelist={4}E.falselist={3,5}

E.truelist={0}E.falselist={1}

<a b

E.truelist={2}E.falselist={3}

<c d

E.truelist={4}E.falselist={5}

<e f

( 1 ) goto _

( 3 ) goto _

( 2 ) if c<d goto _

( 4 ) if e<f goto _

( 5 ) goto _

(4)

(2)

《编译原理》中间代码生成 拉链与代码回填 处理条件语句的翻译模式

S if E then M S1 { backpatch(E.truelist,M.gotostm) ; S.nextlist := merge(E.falselist, S1.nextlist) }

S if E then M1 S1 N else M2 S2 { backpatch(E.truelist, M1.gotostm) ; backpatch(E.falselist, M2.gotostm) ; S.nextlist := merge(S1.nextlist, merge(N.nextlist, S2.nextlist) ) }

M { M.gotostm := nextstm }

N { N.nextlist := makelist(nextstm); emit(‘goto _’) }

《编译原理》中间代码生成 拉链与代码回填 处理循环、复合及其它语句的翻译模式

S while M1 E do M2 S1 { backpatch(S1.nextlist, M1.gotostm) ; backpatch(E.truelist, M2.gotostm) ; S.nextlist := E.falselist; emit(‘goto’, M1.gotostm)}

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

S A { S.nextlist := nil }

L L1; M S { backpatch(L1.nextlist, M.gotostm) ; L.nextlist := S.nextlist }

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

《编译原理》中间代码生成

拉链回填技术示例

GOTO 语句的语法制导翻译

……

(10) goto L ……

(20) goto L ……

(30) goto L ……

(40) L: ……

(50) goto L ……

……

(100) goto 0 ……

(200) goto 100 ……

(300) goto 200 ……

(400) L:

《编译原理》中间代码生成

拉链回填技术示例

GOTO 语句的语法制导翻译

……

(10) goto L ……

(20) goto L ……

(30) goto L ……

(40) L: ……

(50) goto L ……

……

(100) goto 400 ……

(200) goto 400 ……

(300) goto 400 ……

(400) L: ……

(500) goto 400 ……

《编译原理》中间代码生成

利用标号的符号表项维护拉链 若采用类似 PL0 的符号表结构,可以设计标号表项包 括如下域: name , kind , level 等,与其它类别的符号一样 defined : 表示该标号的说明是否已处理过 add : 该标号的说明处理之前用于拉链,处理过后表 示该标号的说明翻译后所指向的 TAC 语句位置

语义函数 / 过程 setlbdefined (id.name,x), getlbdefined (id.name) setlbadd (id.name,x), getlbadd (id.name) 分别表示设置和获取标号的 defined 、 add 值 backpatch (nextstm): 沿拉链反向将所有 goto 语句的目标返填为 nextstm

GOTO 语句的语法制导翻译

《编译原理》中间代码生成

标号说明和 GOTO 语句的翻译模式 GOTO 语句的语法制导翻译

S id : S { p := lookup (id.name); if (p=nil) then enter(id.name) ; setlbdefined(id.name,1) ; setlbadd(id.name, nextstm); backpatch(nextstm) }

S goto id { p := lookup (id.name); if (p=nil) then { enter(id.name) ; setlbdefined(id.name,0) ; setlbadd(id.name,0); emit(‘goto’, 0)}; else emit(‘goto’, getlbadd(id.name) )

if getlbdefined (id.name)=0 then setlbadd(id.name, nextstm-1) }

《编译原理》中间代码生成

简单过程调用的翻译• 示例:过程调用 CALL S (A+B,A*B ) 将被翻译为:

计算A+B 置于T中的代码 // T := A+B 计算A * B 置于Z中的代码 // Z := A*B param T // 第一个实参地址 param Z // 第二个实参地址 call S , 2 // 转子指令

过程调用的语法制导翻译

《编译原理》中间代码生成

简单过程调用的翻译模式

过程调用的语法制导翻译

S call id ( L )

{ S.code := L.code ; for L.arglist 中的每一项 p do

S.code := S.code || gen(‘param’ p ) ; S.code := S.code || gen ( ‘call’ id.place , L.n ) }

L L1 , E { L.n := L1.n +1; L.arglist := append(L1.arglist ,makelist(E.place)); L.code := L1.code || E.code }

L { L.n := 0; L.arglist := null ; L.code := ‘ ’ }

L.n : 参数个数 L.arglist : 实参地址的列表makelist :创建实参地址结点append : 在实参表中添加结点

《编译原理》课后作业

1 熟练掌握本讲出现的每个属性文法 / 翻译模式的设计目的 , 设计思想和设计技术

2 参考本讲稿第 39-44页的 L 属性文法及所用到的语义函数 ,

(1) 若在基础文法中增加产生式 E E E ,试给出相应 该产生式的语义规则集合。其中 , “” 代表“与非”逻辑算

符,可用其它逻辑运算定义为 P Q not ( P and Q )

(2) 若在基础文法中增加产生式 S repeat S until E , 试给出相应该产生式的语义规则集合。 注: repeat <循环体 > until <布尔表达式 > 的

语义为 : 至少执行 <循环体 > 一次,直到 <布尔表

达式 > 成真 时结束循环。

《编译原理》课后作业

3 参考本讲稿第 45-49页的翻译模式及所用到的语义函数 ,

重复 2 中 (1), (2) 的工作。

4 参考本讲稿第 50-56页的 S 属性文法 / 翻译模式及所用到

的语义函数 , 重复 2 中 (1), (2) 的工作。

《编译原理》

Thank You

That’s all for today.

top related