Slide08 807007748
Upcoming SlideShare
Loading in...5
×

Like this? Share it with your network

Share
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
177
On Slideshare
177
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
0
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1.
    • 语义分析与中间代码生成
    第八讲
  • 2.
    • 语义分析和中间代码生成在编译程序中的
    • 逻辑位置
    语义分析与中间代码生成 词法分析 语法分析 中间代码生成 中间代码优化 目标代码优化 目标代码生成 静态语义分析 语义处理
  • 3.
    • 语义分析和中间代码生成的重要数据结构
    • 符号表 ( symbol tables )
      • 名字信息建立后加入 / 更改符号表
      • 名字信息如:种类,类型,偏移地址,占用空间等
      • 需要获取名字信息时,查找符号表
      • 符号表的组织可以体现名字作用域规则
    • (符号表的组织已在第七讲专门讨论)
    语义分析与中间代码生成
  • 4.
    • 语义分析
    • 中间代码生成
    语义分析与中间代码生成
  • 5.
    • 与语义分析相关的工作
    语义分析
    • 静态语义检查
      • 编译期间所进行的语义检查
    • 动态语义检查
      • 所生成的代码在运行期间进行的语义检查
    • 收集语义信息
      • 为语义检查收集程序的语义信息
      • 为代码生成等后续阶段收集程序的语义信息
      • 有些内容合并到“中间代码生成”部分讨论
      • (如过程、数组声明的语义处理)
  • 6.
    • 静态语义检查
    • 代码生成前程序合法性检查的最后阶段
      • 静态 类型检查 ( type checks )
      • 检查每个操作是否遵守语言类型系统的定义
      • 名字的作用域 ( scope ) 分析
      • 建立名字的定义和使用之间联系
      • 控制流检查 ( flow-of-control checks )
      • 控制流语句必须使控制转移到合法的地方(如 break
      • 语句必须有合法的语句包围它)
      • 唯一性检查 ( uniqueness checks ) 很多场合要求对
      • 象只能被定义一次(如枚举类型的元素不能重复出现)
      • 名字相关检查 ( name-related checks )
      • (如,一些名字可能被要求配对出现)
      • ……
    语义分析
  • 7.
    • 类型检查程序 ( type checker )负责类型检查
      • 验证语言结构是否匹配上下文所期望的类型
      • 为相关阶段搜集及建立必要的类型信息
      • 实现 某个 类型系统 ( type system )
    • 静态类型检查
      • 编译期间进行的类型检查
    • 动态类型检查
      • 目标程序运行期间进行的类型检查
    • 类型检查
    语义分析
  • 8.
    • 类型表达式 ( type expressions )
      • 由 基本类型 , 类型名字 , 类型变量 ,及 类型构
      • 造子 ( type constructor )归纳定义的表达式
    • 类型系统 ( type systems )
      • 将类型表达式赋给程序各个部分的 规则集合
    • 类型表达式和类型系统
    语义分析
  • 9.
    • 某个类型表达式集合(将用于示范类型检查
    • 程序的设计)归纳定义如下:
      • 基本类型 bool , char , int , real , type_error 和 ok
      • 是类型表达式(其中, type_error 专用于类型检查
      • 时的出错提示; ok 可用于语句的类型检查)
      • 若 T 是类型表达式,则 array(I,T) 是类型表达式,
      • 表示元素类型是 T ,下标集合是 I 的数组类型(这
      • 里, I 是一个整数区间,如 1..10 )
      • 若 T 是类型表达式,则 pointer(T) 是类型表达式,
      • 表示指向类型为 T 的对象的指针类型
    • 类型表达式 举例
    语义分析
  • 10.
    • 以下是定义某个简单语言的上下文无关文法
    • (将用于本讲的设计示例) 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 语义分析
  • 11.
    • 语法制导的方法
      • 将类型表达式作为属性值赋给程序各个部分
      • 设计恰当的翻译模式
      • 可实现相应语言的一个类型系统
    • 类型检查程序的设计
    语义分析
  • 12.
    • 语法制导的方法
      • 处理 声明 的翻译模式(保存标识符的类型)
    • 类型检查程序的设计
    P  D ; E D  D 1 ; D 2 D  id : T T  boolean T  char T  integer T  real T  array [ num ] of T 1 T   T 1 { addtype ( id . entry , T.type )} { T.type := bool } { T.type := char } { T.type := int } { T.type := real } { T.type := array (1.. num .val, T 1 .type ) } { T.type := pointer ( T 1 .type ) } 语义分析
  • 13.
    • 语法制导的方法
      • 表达式 的类型检查
    • 类型检查程序的设计
    E  true E  false E  literal E  num E  num . num E  id E  E 1 op E 2 { E.type := bool } { E.type := bool } { E.type := char } { E.type := int } { E.type := real } { E.type := lookup_type ( id . entry ) } { E.type := if E 1 .type = real and E 2 .type = real then real else if E 1 .type = int and E 2 .type = int then int else type_error } 语义分析
  • 14.
    • 语法制导的方法
      • 表达式 的类型检查(续)
    • 类型检查程序的设计
    E  E 1 rop E 2 E  E 1 [ E 2 ] E  E 1  { E.type := if E 1 .type = real and E 2 .type = real then bool else if E 1 .type = int and E 2 .type = int then bool else type_error } { E.type := if E 2 .type = int and E 1 .type = array(s,t) then t else type_error } { E.type := if E 1 .type = pointer ( t ) then t else type_error } 语义分析
  • 15.
    • 语法制导的方法
      • 语句 的类型检查
    • 类型检查程序的设计
    S  id := E S  if E then S 1 S  while E do S 1 S  S 1 ; S 2 { S.type := if lookup_type ( id . entry ) = E.type then ok else type_error } { S.type := if E.type = bool then S 1 .type else type_error } { S.type := if E.type = bool then S 1 .type else type_error } { S.type := if S 1 .type = ok and S 2 .type = ok then ok else type_error } 语义分析
  • 16.
    • 语法制导的方法
      • 增加数 自动类型转换 ( type casting ) 的支持
    • 类型检查程序的设计
    E  E 1 op E 2 E  E 1 rop E 2 { E.type := if E 1 .type = real and E 2 .type = real then real else if E 1 .type = int and E 2 .type = int then int else if E 1 .type = real and E 2 .type = int then real else if E 1 .type = int and E 2 .type = real then real else type_error } { …… } 语义分析
  • 17.
    • 静态作用域
      • 通过符号表实现
      • (已在第七讲讨论)
    • 动态作用域
      • 通过运行时活动记录实现
      • (参见下一讲)
    • 作用域分析
    语义分析
  • 18. 中间代码生成
    • 源程序的不同表示形式
    • 作用
      • 源语言和目标语言之间的桥梁,避开二者
      • 之间较大的语义跨度,使编译程序的逻辑
      • 结构更加简单明确
      • 利于编译程序的重定向
      • 利于进行与目标机无关的优化
    • 中间代码
  • 19. 中间代码生成
    • 有不同层次不同目的之分
    • 中间代码举例
      • Postfix ( 后缀式 , 逆波兰式 )
      • AST ( Abstract syntax tree , 抽象语法树 )
      • TAC ( Three-address code , 三地址码,四元式 )
      • P-code ( 特别用于 Pasal 语言实现 )
      • Bytecode ( Java 编译器的输出 , Java 虚拟机的输入 )
      • SSA ( Static single assignment form , 静态单赋值形式 )
    • 中间代码的形式
  • 20. 中间代码生成
    • 算术表达式 A + B * ( C - D ) + E / ( C - D ) ^N
    • (中缀形式)
      • Postfix (后缀式 , 逆波兰式 )
      • A B C D - * + E C D – N ^ / +
    • 中间代码举例
  • 21. 中间代码生成
    • 算术表达式 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
    • 中间代码举例
  • 22. 中间代码生成
    • 算术表达式 A + B * ( C - D ) + E / ( C - D ) ^N
    • (中缀形式)
      • AST ( Abstract syntax tree , 抽象语法树 )
    • 中间代码举例
    ^ + + / A * E - B D C - D C N
  • 23. 中间代码生成
    • 算术表达式 A + B * ( C - D ) + E / ( C - D ) ^N
    • (中缀形式)
      • DAG ( Directed Acyclic Graph , 有向无圈图,改进型 AST )
    • 中间代码举例
    ^ + + / A * E B - D C N
  • 24. 中间代码生成
    • 静态单赋值形式
    • 中间代码举例
  • 25. 中间代码生成
    • 语法制导的方法
      • 例: 生成抽象语法树
    • 中间代码生成
    S  id := E S  if E then S 1 S  while E do S 1 S  S 1 ; S 2 E  id E  E 1 + E 2 E  E 1  E 2 E  ( E 1 ) …… { S.ptr := mknode(‘assign’, mkleaf( id .entry), E.ptr) } { S.ptr := mknode(‘if_then’, E.ptr, S 1 .ptr) } { S.ptr := mknode(‘while_do’, E.ptr, S 1 .ptr) } { S.ptr := mknode(‘ ; ’ , S 1 .ptr , S 2 .ptr) } { E.ptr := mkleaf( id .entry) } { E.ptr := mknode(‘ + ’ , E 1 .ptr , E 2 .ptr) } { E.ptr := mknode(‘  ’ , E 1 .ptr , E 2 .ptr) } { E.ptr := E 1 .ptr } …… mknode : 构造内部结点 Mkleaf : 构造叶子结点
  • 26. 中间代码生成
    • 顺序的语句序列 其 语句 一般具有如下 形式
    • x := y op z
    • ( op 为操作符, y 和 z 为操作数, x 为结果 )
    • 三地址码 TAC
  • 27. 中间代码生成
    • 课程后续部分用到的 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 x 1 … param x n call p,n
      • 过程返回语句 return y ( y 可选,存放返回值)
      • 下标赋值语句 x := y [ i ] 和 x [ i ] := y (前者表示将地
      • 址 y 起第 i 个存储单元的值赋给 x , 后者类似)
      • 地址和指针赋值语句 x := &y , x := *y 和 *x := y
    • 参考 A.V.Aho 等的教材(龙书)
  • 28. 中间代码生成
    • 语义属性
      • id . name : id 的词法名字(符号表中的名字)
      • E . place : 用来存放 E 的值的存储位置
      • E . code : E 求值的 TAC 语句序列
    • 语义函数 / 过程
      • lookup ( id . name ) : 从符号表中查找名字为 id . name
      • 的项,返回存放相应值的指针(存储位置),若无该
      • 项,则返回 nil
      • gen : 生成一条 TAC 语句
      • newtempt : 返回一个未使用过的存储位置
    • 赋值语句及算数表达式的语法制导翻译
  • 29. 中间代码生成
    • 翻译模式
    S  id := E E  E 1 + E 2 E  E 1  E 2 E  - E 1 E  ( E 1 ) E  id { p := lookup ( id . name ); if ( p  nil) then S.code := E.code || gen (p ‘:=‘ E.place) else error } { E.place := newtemp; E.code := E 1 .code || E 2 .code || gen ( E.place ‘:=‘ E 1 .place ‘+’ E 2 .place) } { E.place := newtemp; E.code := E 1 .code || E 2 .code || gen ( E.place ‘:=‘ E 1 .place ‘  ’ E 2 .place) } { E.place := newtemp; E.code := E 1 .code || gen ( E.place ‘:=‘ ‘uminus‘ E 1 .palce) } { E.place := E 1 .place ; E.code := E 1 .code } { p := lookup ( id . name ); if ( p  nil) then E.place := p else error ; E.code := ‘’ }
    • 赋值语句及算数表达式的语法制导翻译
  • 30. 中间代码生成
    • 回顾:类型属性的计算
    • 说明语句的语法制导翻译
    P  D ; E D  D 1 ; D 2 D  id : T T  char T  integer T  real T  array [ num ] of T 1 T   T 1 E  … { enter ( id . name , T.type )} { T.type := char } { T.type := integer } { T.type := real } { T.type := array (1.. num .val, T 1 .type ) } { T.type := pointer ( T 1 .type ) } enter ( id . name , T.type ) : 将符号表中 id . name 所对应表项的 type 域置为 T.type
  • 31. 中间代码生成
    • 语义属性
      • 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
    • 过程(函数)中说明语句的语法制导翻译
  • 32. 中间代码生成
    • 过程中说明语句的语法制导翻译
    • 翻译模式
    P  { D.offset := 0 } D ; E D  { D 1 .offset := D.offset } D 1 ; { D 2 .offset := D.offset + D 1 .width } D 2 { D.width := D 1 .width + D 2 .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 T 1 { T.type := array( num .val, T 1 .type ) ; T.width := num .val  T 1 .width } T   T 1 { T.type := pointer ( T 1 .type ) ; T.width := 4 } E  …
  • 33. 中间代码生成
    • 数组说明
    • 参考前页的翻译模式,可了解(一维)数组说明的翻译
    • 思想 . 至于符号表中一般情况下是如何组织数组说明信
    • 息的,随后将会讨论 .
    • 数组说明和数组元素引用的语法制导翻译
    … D  id : T { enter ( id . name , T.type, D.offset ) ; D.width := T.width } … T  array [ num ] of T 1 { T.type := array( num .val, T 1 .width ) ; T.width := num .val  T 1 .width } …
  • 34. 中间代码生成
    • 数组引用
    • 数组说明和数组元素引用的语法制导翻译
    S  id := E S  E 1 [ E 2 ] := E 3 E  E 1 [ E 2 ] E  id … { p := lookup ( id . name ); if ( p  nil) then S.code := E.code || gen (p ‘:=‘ E.place) else error } { S.code := E 2 .code || E 3 .code || gen (E 1 .place ‘[’ E 2 .place ‘]’ ‘:=‘ E 3 .place) } { E.place := newtemp; E.code := E 2 .code || gen ( E.place ‘:=‘ E 1 .place ‘ [ ’ E 2 .place ‘]’ ) } { p := lookup ( id . name ); if ( p  nil) then E.place := p else error ; E.code := ‘’}
  • 35. 中间代码生成
    • 数组的内情向量 ( dove vector )
    • 在处理数组时,通常会将数组的有关信息记录在一些单
    • 元中,称为“内情向量” . 对于静态数组,内情向量可放在
    • 符号表中;对于可变数组,运行时建立相应的内情向量
    • 例: 对于静态数组说明 A [ l 1 : u 1 , l 2 : u 2 ,…, l n : u n ] ,可以在符
    • 号表中建立如下形式的内情向量 :
    • 数组说明和数组元素引用的语法制导翻译
    l 1 u 1 l 2 u 2 l n u n type a n C … … l i : 第 i 维的下界 u i : 第 i 维的上界 type : 数组元素的类型 a : 数组首元素的地址 n : 数组维数 C : 随后解释
  • 36. 中间代码生成
    • 数组元素的地址计算
    • 例: 对于静态数组 A [ l 1 : u 1 , l 2 : u 2 ,…, l n : u n ] ,若数组布局采
    • 用行优先的连续布局,数组首元素的地址为 a ,则数组
    • 元素 A [ i 1 , i 2 ,…, i n ] 的地址 D 可以如下计算 :
          • D = a + ( i 1 - l 1 )( u 2 - l 2 )( u 3 - l 3 ) …( u n - l n )
          • + ( i 2 - l 2 )( u 3 - l 3 )( u 4 - l 4 ) …( u n - l n )
          • +…+ ( i n-1 - l n-1 )( u n - l n ) + ( i n - l n )
    • 数组说明和数组元素引用的语法制导翻译
    • 重新整理后得 : D = a – C + V ,其中
      • C = ( … ( l 1 ( u 2 - l 2 ) +l 2 ) ( u 3 - l 3 ) + l 3 ) ( u 4 - l 4 ) + … + l n-1 ) ( u n - l n ) + l n
      • V = ( … (( i 1 ( u 2 - l 2 ) +i 2 ) ( u 3 - l 3 ) + i 3 ) ( u 4 - l 4 ) + …… + i n-1 ) ( u n - l n ) + i n
    (这里的 C 即为前页内情向量中的 C )
  • 37. 中间代码生成
    • 直接对布尔表达式求值
      • 例如 : 可以用数值“ 1 ” 表示 true; 用数值“ 0 ” 表示 false;
      • 采用与算术表达式类似的方法对布尔表达式进行求值
    • 通过控制流体现布尔表达式的语义
      • 方法 :通过转移到程序中的某个位置来表示布尔表达式的求值结果
      • 优点 :方便实现 控制流语句中 布尔表达式的翻译
      • 常可以得到 短路 ( short-circuit )代码,而避免不必要的
      • 求值,如:在已知 E 1 为真时,不必再对 E 1  E 2 中的 E 2
      • 进行求值;同样,在已知 E 1 为假时,不必再对 E 1  E 2
      • 中的 E 2 进行求值
    • 布尔表达式的语法制导翻译
  • 38. 中间代码生成
    • 直接对布尔表达式求值
    • 布尔表达式的语法制导翻译
    E  E 1 or E 2 E  E 1 and E 2 E  not E 1 E  ( E 1 ) E  id 1 rop id 2 E  true E  false { E.place := newtemp; E.code := E 1 .code || E 2 .code || gen ( E.place ‘:=‘ E 1 .place ‘ or ’ E 2 .place) } { E.place := newtemp; E.code := E 1 .code || E 2 .code || gen ( E.place ‘:=‘ E 1 .place ‘ and ’ E 2 .place) } { E.place := newtemp; E.code := E 1 .code || gen ( E.place ‘:=‘ ‘ not ’ E 1 .palce) } { E.place := E 1 .place ; E.code := E 1 .code } { E.place := newtemp; E.code := gen ( ‘ if ‘ id 1 .place rop.op id 2 .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 语句的下标
  • 39. 中间代码生成
    • 通过控制流体现布尔表达式的语义
    • 例 : 布尔表达式 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
    • 布尔表达式的语法制导翻译
  • 40. 中间代码生成
    • 翻译布尔表达式至短路代码
    • 布尔表达式的语法制导翻译
    E  E 1 or E 2 E  E 1 and E 2 E  not E 1 E  ( E 1 ) E  id 1 rop id 2 E  true E  false { E 1 .true := E .true ; E 1 .false := newlabel; E 2 .true := E .true ; E 2 .false := E .false ; E.code := E 1 .code || gen (E 1 .false ‘ : ‘ ) || E 2 .code } { E 1 .false := E .false ; E 1 .true := newlabel; E 2 .true := E .true ; E 2 .false := E .false ; E.code := E 1 .code || gen (E 1 .true ‘ : ‘ ) || E 2 .code } { E 1 .true := E .false ; E 1 .false := E .true ; E.code := E 1 .code } { E 1 .true := E .true ; E 1 .false := E .false ; E.code := E 1 .code } { E.code := gen ( ‘ if ‘ id 1 .place rop.op id 2 .place ‘goto’ E .true ) || gen ( ‘goto’ E .false ) } { E.code := gen ( ‘goto’ E .true ) } { E.code := gen ( ‘goto’ E .false ) }
  • 41. 中间代码生成
    • if-then 语句
    • S  if E then S 1
      • { E.true := newlable;
      • E.false := S.next;
      • S 1 .next := S.next;
    • S .code := E.code ||
    • gen(E.true ‘:’) ||
    • S 1 .code
    • }
    • 条件语句的语法制导翻译
    E.code S 1 .code E.true: E.false: …… to E.true to E.false newlable 返回一个新的语句标号 S.next 属性表示 S 之后要执行的首条 TAC 语句的标号
  • 42. 中间代码生成
    • if-then-else 语句
    • S  if E then S 1 else S 2
      • { E.true := newlable;
      • E.false := newlable;
      • S 1 .next := S.next;
      • S 2 .next := S.next;
    • S .code := E.code ||
    • gen(E.true ‘:’) ||
    • S 1 .code ||
    • gen(‘goto’ S.next) ||
    • gen(E.false ‘:’) ||
    • S 2 .code
    • }
    • 条件语句的语法制导翻译
    E.code S 1 .code E.true: E.false: goto S .next to E.true to E.fase …… S 2 .code S.next:
  • 43. 中间代码生成
    • 循环语句的语法制导翻译
    • while 语句
    • S  while E do S 1
      • { S.begin := newlable;
      • E.true := newlable;
      • E .false := S.next;
      • S 1 .next := S.begin;
    • S .code := gen(S.begin ‘:’)
    • || E.code
    • || gen(E.true ‘:’)
    • || S 1 .code
    • || gen(‘goto’ S.begin)
    • }
    E.code S 1 .code S.begin: E.false: goto S .begin to E.true to E.false …… E.true:
  • 44. 中间代码生成
    • 复合语句的语法制导翻译
    • 顺序复合语句
    • S  S 1 ; S 2
      • { S 1 .next := newlable;
      • S 2 .next := S.next ;
    • S .code := S 1 .code
    • || gen( S 1 .next ‘:’)
    • || S 2 .code
    • }
    S 1 .code S 2 .code S.next: …… S 1 .next:
  • 45. 中间代码生成
    • 翻译布尔表达式至短路代码(翻译模式)
    • 布尔表达式的语法制导翻译
    E  { E 1 .true := E .true ; E 1 .false := newlabel } E 1 or { E 2 .true := E .true ; E 2 .false := E .false } E 2 { E.code := E 1 .code || gen (E 1 .false ‘ : ‘ ) || E 2 .code } E  { E 1 .false := E .false ; E 1 .true := newlabel } E 1 and { E 2 .true := E .true ; E 2 .false := E .false } E 2 { E.code := E 1 .code || gen (E 1 .true ‘ : ‘ ) || E 2 .code } E  not { E 1 .true := E .false ; E 1 .false := E .true } E 1 { E.code := E 1 .code } E  ( { E 1 .true := E .true ; E 1 .false := E .false } E 1 ) { E.code := E 1 .code } E  id 1 rop id 2   { E.code := gen ( ‘ if ‘ id 1 .place rop.op id 2 .place ‘goto’ E .true ) || gen ( ‘goto’ E .false ) } E  true { E.code := gen ( ‘goto’ E .true ) } E  false { E.code := gen ( ‘goto’ E .false ) }
  • 46. 中间代码生成
    • if-then 语句(翻译模式)
    • S  if { E.true := newlable ; E.false := S.next } E  
    •      then { S 1 .next := S.next }   S 1
    •      { S .code := E.code || gen(E.true ‘:’) || S 1 .code }
    • 条件语句的语法制导翻译
    E.code S 1 .code E.true: E.false: …… to E.true to E.false newlable 返回一个新的语句标号 S.next 属性表示 S 之后要执行的首条 TAC 语句的标号
  • 47. 中间代码生成
    • if-then-else 语句(翻译模式)
    • 条件语句的语法制导翻译
    E.code S 1 .code E.true: E.false: goto S .next to E.true to E.fase …… S 2 .code S.next: S  if { E.true := newlable;      E.false := newlable }    E   then      { S 1 .next := S.next }    S 1   else      { S 2 .next := S.next }    S 2         { S .code := E.code ||       gen(E.true ‘:’) ||       S 1 .code ||       gen(‘goto’ S.next) ||       gen(E.false ‘:’) ||       S 2 .code       }
  • 48. 中间代码生成
    • 循环语句的语法制导翻译
    • while 语句(翻译模式)
    E.code S 1 .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     { S 1 .next := newlable }    S 1        { S.begin :=   S 1 .next;     S .code := gen(S.begin ‘:’)       || E.code       || gen(E.true ‘:’)       || S 1 .code       || gen(‘goto’ S.begin)     }
  • 49. 中间代码生成
    • 复合语句的语法制导翻译
    • 顺序复合语句(翻译模式)
    • S  { S 1 .next := newlable } S 1 ;
    • { S 2 .next := S.next } S 2
    • { S .code := S 1 .code
    •    || gen( S 1 .next ‘:’)
    •    || S 2 .code
    • }
    S 1 .code S 2 .code S.next: …… S 1 .next:
  • 50. 中间代码生成
    • 拉链与代码回填 ( backpatching )
    • 另一种控制流中间代码生成技术
    • 比较:前面的方法采用 L - 属性文法 / 翻译模式
    • 下面的方法采用 S - 属性文法 / 翻译模式
  • 51. 中间代码生成
    • 拉链与代码回填
    • 语义属性
    • E.truelist : “ 真链”,链表中的元素表示 一系列跳转语
    • 句的地址,这些跳转语句的目标标号是体现布
    • 尔表达式 E 为“真”的标号
    • E. falselist : “ 假链”,链表中的元素表示 一系列跳转语
    • 句的地址,这些跳转语句的目标标号是体现布
    • 尔表达式 E 为假的标号
    • S. nextlist : “ next 链”,链表中的元素表示 一系列跳转
    • 语句的地址,这些跳转语句的目标标号是在执
    • 行序列中紧跟在 S 之后的下条 TAC 语句的标号
  • 52. 中间代码生成
    • 拉链与代码回填
    • 语义函数 / 过程
    • makelist(i) : 创建只有一个结点 i 的表,对应存放目标
    • TAC 语句数组的一个下标
    • merge(p 1 ,p 2 ) : 连接两个链表 p 1 和 p 2 ,返回结果链表
    • backpatch(p,i) : 将链表 p 中每个元素所指向的跳转语句
    • 的标号置为 i
    • nextstm : 下一条 TAC 语句的地址
    • emit (…) : 输出一条 TAC 语句,并使 nextstm 加 1
  • 53. 中间代码生成
    • 拉链与代码回填
    • 处理 布尔表达式的翻译模式
    E  E 1 or M E 2 E  E 1 and M E 2 E  not E 1 { backpatch(E 1 .falselist ,M.gotostm) ; E .truelist := merge(E 1 .truelist , E 2 .truelist ) ; E .falselist := E 2 .falselist } { backpatch(E 1 .truelist ,M.gotostm) ; E .falselist := merge(E 1 .falselist , E 2 .falselist ) ; E .truelist := E 2 .truelist } { E .truelist := E 1 .falselist ; E .falselist := E 1 .truelist } 注 : 这里可以规定产生式的优先级依次递增来解决冲突问题 (下同)
  • 54. 中间代码生成
    • 拉链与代码回填
    • 处理 布尔表达式的翻译模式
    E  ( E 1 ) E  id 1 rop id 2 E  true E  false M   { E .truelist := E 1 .truelist ; E .falselist := E 1 .falselist } { E .truelist := makelist ( nextstm ); E .falselist := makelist ( nextstm+1 ); emit ( ‘ if ‘ id 1 .place rop.op id 2 .place ‘goto _’ ) ; emit ( ‘goto _’ ) } { E .truelist := makelist ( nextstm ); emit ( ‘goto _’ ) } { E .falselist := makelist ( nextstm ); emit ( ‘goto _’ ) } { M .gotostm := nextstm }
  • 55. 中间代码生成
    • 拉链与代码回填
    • 布尔表达式 E = a<b or c<d and e<f 的翻译 示意
    ( 0 ) if a<b goto _ or and ( 1 ) goto _ ( 3 ) goto _ ( 2 ) if c<d goto _ ( 4 ) if e<f goto _ ( 5 ) goto _ (4) (2) E .truelist={0,4} E .falselist={3,5}  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
  • 56. 中间代码生成
    • 拉链与代码回填
    • 处理条件 语句的翻译模式
    S  if E then M S 1 { backpatch(E .truelist ,M.gotostm) ; S .nextlist := merge(E .falselist , S 1 .nextlist ) } S  if E then M 1 S 1 N else M 2 S 2 { backpatch(E .truelist , M 1 .gotostm) ; backpatch(E .falselist , M 2 .gotostm) ; S .nextlist := merge(S 1 .nextlist, merge(N .nextlist , S 2 .nextlist ) ) } M   { M .gotostm := nextstm } N   { N .nextlist := makelist( nextstm ); emit(‘goto _’) }
  • 57. 中间代码生成
    • 拉链与代码回填
    • 处理循环、复合及其它 语句的翻译模式
    S  while M 1 E do M 2 S 1 { backpatch(S 1 .nextlist, M 1 .gotostm) ; backpatch(E .truelist, M 2 .gotostm) ; S .nextlist := E .falselist ; emit(‘goto’, M 1 .gotostm) } S  begin L end { S .nextlist := L .nextlist } S  A { S .nextlist := nil } L  L 1 ; M S { backpatch(L 1 .nextlist, M.gotostm) ; L .nextlist := S .nextlist } L  S { L .nextlist := S .nextlist }
  • 58. 中间代码生成
    • 拉链回填技术 示例
    • GOTO 语句的语法制导翻译
    • ……
    • (10) goto L
    • ……
    • (20) goto L
    • ……
    • (30) goto L
    • ……
    • (40) L :
    • ……
    • goto L
    • ……
    …… (100) goto 0 …… (200) goto 100 …… (300) goto 200 …… (400) L :
  • 59. 中间代码生成
    • 拉链回填技术 示例
    • GOTO 语句的语法制导翻译
    • ……
    • (10) goto L
    • ……
    • (20) goto L
    • ……
    • (30) goto L
    • ……
    • (40) L :
    • ……
    • goto L
    • ……
    …… (100) goto 400 …… (200) goto 400 …… (300) goto 400 …… (400) L : …… (500) goto 400 ……
  • 60. 中间代码生成
    • 利用 标号的符号表项维护拉链
      • 若采用类似 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 语句的语法制导翻译
  • 61. 中间代码生成
    • 标号 说明和 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 ) }
  • 62. 中间代码生成
    • 简单 过程调用的翻译
      • 示例: 过程调用 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 // 转子指令
    • 过程调用的语法制导翻译
  • 63. 中间代码生成
    • 简单过程调用的 翻译模式
    • 过程调用的语法制导翻译
    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  L 1 , E { L.n := L 1 .n + 1; L.arglist := append(L 1 .arglist ,makelist(E.place)); L.code := L 1 .code || E.code } L   { L.n := 0; L.arglist := null ; L.code := ‘ ’ } L.n : 参数个数 L.arglist : 实参地址的列表 makelist : 创建实参地址结点 append : 在实参表中添加结点
  • 64. 课后作业 1 熟练掌握本讲出现的每个属性文法 / 翻译模式的 设计目的 , 设计思想和设计技术
    • 参考本讲稿第 39-44 页的 L 属性文法及所用到的语义函数 ,
    • (1) 若在基础文法中增加产生式 E  E  E ,试给出相应
    • 该产生式的语义规则集合。其中 , “  ” 代表 “ 与非 ” 逻辑算
    • 符,可用其它逻辑运算定义为 P  Q  not ( P and Q )
    • (2) 若在基础文法中增加产生式 S  repeat S until E ,
    • 试给出相应该产生式的语义规则集合。
    • 注: repeat < 循环体 > until < 布尔表达式 > 的语义为 :
    • 至少执行 < 循环体 > 一次,直到 < 布尔表达式 > 成真
    • 时结束循环。
  • 65. 课后作业 3 参考本讲稿第 45-49 页的翻译模式及所用到的语义函数 , 重复 2 中 (1), (2) 的工作。
    • 参考本讲稿第 50-56 页的 S 属性文法 / 翻译模式及所用到
    • 的语义函数 , 重复 2 中 (1), (2) 的工作。
  • 66. Thank You That’s all for today.