编译原理第七章
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
(1) (2) (3) (4) (5)
三元式表
OP + * := ↑ := ARG1 A (1) X D Y ARG2 B C (2) (1) (4)
7.2 声明语句
分析过程或程序块的声明序列时:
为局部名字建立符号表条目 为它分配存储单元
符号表中包含了名字的类型和分配给它的存 储单元的相对地址等信息
相对地址:对静态数据区基址的偏移或对活动 记录中局部数据区基址的偏移。
7.2.1 过程中的声明
一个过程中的所有声明语句可集中处理。用一个全 程变量offset来记录下一个可用的相对地址。
计算声明语句中名字的类型和相对地址 建立符号 P {offset := 0} D S 表条目 DD;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 }
三地址代码的具体实现
三元式Fra Baidu bibliotek
a:=b*(-c)+b*(-c) T1:=-c T2:=b*T1 T5:=T2+T2 a:=T5
三个域:op、arg1和arg2 通过计算临时变量值的语句的位置来引用 这个临时变量 op arg1 arg2 (0) uminus c (1) * b (0) (2) uminus c (3) * b (2) (4) + (1) (3) (5) assign a (4)
top
处理嵌套过程中的声明语句
P M D S {addwidth (top (tblptr), top (offset) ); pop(tblptr); pop (offset) } M {t := mktable (nil); push(t, tblprt); 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) } Did : 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) }
op z z 翻译成的三地址语句序列是 z t1
三地址代码是语法树或DAG的一种线性表示:生成三地 址代码时,临时变量的名字对应抽象语法树的内部结 点 a := (b + cd ) + cd 语法树的代码 t1 := b t2 := c d t3 := t1 + t2 uminus t4 := c d t5 := t3 + t4 a := t5
7.1.2 图形表示
图表示法
语法树 DAG
图形表示
有向无环图(Directed Acyclic Graph,简称 DAG)
对表达式中的每个子表达式,DAG中都有一个结点 一个内部结点代表一个操作符,它的孩子代表操 作数 在一个DAG中代表公共子表达式的结点具有多个父 结点
a := (b + cd ) + cd的图形表示
空
sort 表 头 指向readarray 指向exchange
a x readarray exchange quicksort
readarray 表 头
i
exchange 表 头
quicksort 表 头 k v partition
partition
嵌套过程的符号表
7.2.3 记录的域名
下述产生式中的非终结符T产生记录类型 T record L D end 例: c= record a:integer; b:real; end 编译程序为记录中的域名建立单独的符号表
assign a + + a assign +
c d
uminus b
c
d
+ uminus c b
d
(a) 语法树
(b) DAG
构造赋值语句语法树的语法制导定义
产生式
S id :=E E E1 +E2
语
义
规
则
S.nptr := mknode(‘assign’, mkleaf (id, id.entry), E.nptr) E.nptr := mknode( ‘+’, E1.nptr, E2.nptr) E.nptr := mknode( ‘’, E1.nptr, E2.nptr)
4.翻译方案中用到的全程量和函数 全程量:有序对栈(tblptr, offset) 其中,tblptr 保存指向符号表节点的指针, tblptr offset offset 保存各嵌套过程的当前相对地址。 函数: mktable(previous)—创建新的符号表,并返回指向新 表的指针。 previous指向直接外围过程的符号表(放 在符号表首部) enter(table, name, type, offset) addwidth(table, width)—在指针table指示的符号 表表头记录下该表中所有名字占用的总域宽 enterproc(table, name, newtable)—为过程名name 建立新条目,newtable指向过程name本身的符号表
后缀式表示法不用括号,只要知道每个算符的 目数。 (8 4) + 2 的后缀表示是8 4 2 + 8 (4 + 2)的后缀表示是8 4 2 + 对于后缀式,不论从哪一端进行扫描,都能对 它进行唯一分解。 后缀式的计算
用一个栈实现。 一般的计算过程是:自左至右扫描后缀式,每碰到 运算对象就把它推进栈。每碰到k目运算符就把它 作用于栈顶的k个项,并用运算结果代替这k个项。
program main var A, B : real; … procedure P1 var B:boolean; … begin … end procedure P2 var A:integer; … begin … end begin … end
A(real) A(integr) B(real) B(bool)
第七章 中间代码生成
贵州大学 计算机科学与技术学院
本章内容
介绍几种常用的中间表示:后缀表示、图 形表示和三地址代码 用语法制导定义和翻译方案的方法来说明 程序设计语言的结构怎样被翻译成中间形 式
语法分 析器 静态检 查器 中间代码 中间代码 优化器 产生器
本章内容
7.1 7.2 7.3 7.4
2.
程序结构
一组嵌套过程,为每个过程说明的局 部名字建立一张独立的符号表,所有正在翻 译过程的符号表组成整个源程序的符号表。 翻译语句部分时查找符号表,查找过程的符 号表的路线相当于当前被 翻译过程的静态 链。 翻译时,实际上,为每一个过程维持 一张符号表。过程的符号表之间的关系反映 过程在源程序中的关系。
E E1 E2 E E1
E (E1) E id
E.nptr := mkunode( ‘uminus’, E1.nptr) E.nptr := E1.nptr
E.nptr := mkleaf (id, id.entry)
7.1.3 三地址代码
一般形式: x := y 表达式x + y t1 := y t2 := x +
7.2.2 作用域信息的保存
1 .问题的提出 一般的语言中,标识符的作用在程序正文中有一 个确定的范围。因此,同一个标识符在不同的程序 正文中可能标识不同的对象,具有不同的性质,要 求分配不同的存储空间。于是提出下面的问题:如 何组织符号表,使得同一个标识符在不同的作用域 中得到正确的引用而不产生混乱。 编译程序分析声明语句时建立符号表,编译执 行语句时查找符号表。Lookup(id)返回正确的 id.entry。
中间语言 声明语句 赋值语句 布尔表达式和控制流语句
7.1 中间语言
中间语言(复杂性界于源语言和目标语言之间) 的好处:
便于进行与机器无关的代码优化工作 易于移植 使编译程序的结构在逻辑上更为简单明确
Compiler Front End
源语言 程序
中间语 言程序
Compiler Back End
3.所讨论语言的文法(允许过程嵌套) P D S (1) 问题:如何在处理产生 式(1)和(4)的语言结构 D D ; D (2) 时正确地填写符号表信 | id : T (3) 息? | proc id ; D ; S (4) 修改文法,使得在定义D之前生成符号表 P → M D S (1) D → D ; D (2) | id : T (3) | proc id ; N D; S (4) M →ε (5) N →ε (6)
7.2.3 记录的域名
T record L D end {T.type := record (top(tblptr) ); T.width := top(offset); pop(tblptr); pop(offset) } L {t := mktable (nil); push(t, tblprt); push(0, offset) }
三地址代码的具体实现
间接三元式
为了便于优化,用 三元式表+间接码表 表 示中间代码 间接码表:一张指示器表,按运算的先后次 序列出有关三元式在三元式表中的位置。 优点: 方便优化,节省空间
例如,语句
X:=(A+B)*C; Y:=D↑(A+B)
的间接三元式表示如下表所示。
间接代码
(1) (2) (3) (1) (4) (5)
三地址代码的具体实现
四元式
a:=b*(-c)+b*(-c) T1:=-c T2:=b*T1 T5:=T2+T2 a:=T5
一个带有四个域的记录结构,这四个域分别 称为op, arg1, arg2及result op arg1 arg2 result (0) uminus c T1 (1) * b T1 T2 (2) uminus c T3 (3) * b T3 T4 (4) + T2 T4 T5 (5) := T5 a
a := (b + cd ) + cd
DAG的代码 assign t1 := b a + t2 := c d + t3 := t1 + t2 uminus c d t4 := t3 + t2 b a := t4
常用的三地址语句
赋值语句x := y op z, x := op y, x := y 无条件转移goto L 条件转移if x relop y goto L 过程调用param x 和call p , n 过程返回 return y 索引赋值x := y[ i ]和 x[ i ] := y 地址和指针赋值x := &y,x := y 和x := y
目标语 言程序
7.1 中间语言
常用的中间语言:
后缀式,逆波兰表示 图表示: DAG、语法树 三地址代码
三元式 四元式 间接三元式
7.1.1
后缀式
后缀式表示法:Lukasiewicz发明的一种表示 表达式的方法,又称逆波兰表示法。 一个表达式E的后缀形式可以如下定义:
1. 如果E是一个变量或常量,则E的后缀式是E自身。 2. 如果E是E1 op E2形式的表达式,其中op是任何 二元操作符,则E的后缀式为E1 E2 op,其中E1 和E2 分别为E1 和E2的后缀式。 3. 如果E是(E1)形式的表达式,则E1 的后缀式就 是E的后缀式。
三元式表
OP + * := ↑ := ARG1 A (1) X D Y ARG2 B C (2) (1) (4)
7.2 声明语句
分析过程或程序块的声明序列时:
为局部名字建立符号表条目 为它分配存储单元
符号表中包含了名字的类型和分配给它的存 储单元的相对地址等信息
相对地址:对静态数据区基址的偏移或对活动 记录中局部数据区基址的偏移。
7.2.1 过程中的声明
一个过程中的所有声明语句可集中处理。用一个全 程变量offset来记录下一个可用的相对地址。
计算声明语句中名字的类型和相对地址 建立符号 P {offset := 0} D S 表条目 DD;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 }
三地址代码的具体实现
三元式Fra Baidu bibliotek
a:=b*(-c)+b*(-c) T1:=-c T2:=b*T1 T5:=T2+T2 a:=T5
三个域:op、arg1和arg2 通过计算临时变量值的语句的位置来引用 这个临时变量 op arg1 arg2 (0) uminus c (1) * b (0) (2) uminus c (3) * b (2) (4) + (1) (3) (5) assign a (4)
top
处理嵌套过程中的声明语句
P M D S {addwidth (top (tblptr), top (offset) ); pop(tblptr); pop (offset) } M {t := mktable (nil); push(t, tblprt); 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) } Did : 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) }
op z z 翻译成的三地址语句序列是 z t1
三地址代码是语法树或DAG的一种线性表示:生成三地 址代码时,临时变量的名字对应抽象语法树的内部结 点 a := (b + cd ) + cd 语法树的代码 t1 := b t2 := c d t3 := t1 + t2 uminus t4 := c d t5 := t3 + t4 a := t5
7.1.2 图形表示
图表示法
语法树 DAG
图形表示
有向无环图(Directed Acyclic Graph,简称 DAG)
对表达式中的每个子表达式,DAG中都有一个结点 一个内部结点代表一个操作符,它的孩子代表操 作数 在一个DAG中代表公共子表达式的结点具有多个父 结点
a := (b + cd ) + cd的图形表示
空
sort 表 头 指向readarray 指向exchange
a x readarray exchange quicksort
readarray 表 头
i
exchange 表 头
quicksort 表 头 k v partition
partition
嵌套过程的符号表
7.2.3 记录的域名
下述产生式中的非终结符T产生记录类型 T record L D end 例: c= record a:integer; b:real; end 编译程序为记录中的域名建立单独的符号表
assign a + + a assign +
c d
uminus b
c
d
+ uminus c b
d
(a) 语法树
(b) DAG
构造赋值语句语法树的语法制导定义
产生式
S id :=E E E1 +E2
语
义
规
则
S.nptr := mknode(‘assign’, mkleaf (id, id.entry), E.nptr) E.nptr := mknode( ‘+’, E1.nptr, E2.nptr) E.nptr := mknode( ‘’, E1.nptr, E2.nptr)
4.翻译方案中用到的全程量和函数 全程量:有序对栈(tblptr, offset) 其中,tblptr 保存指向符号表节点的指针, tblptr offset offset 保存各嵌套过程的当前相对地址。 函数: mktable(previous)—创建新的符号表,并返回指向新 表的指针。 previous指向直接外围过程的符号表(放 在符号表首部) enter(table, name, type, offset) addwidth(table, width)—在指针table指示的符号 表表头记录下该表中所有名字占用的总域宽 enterproc(table, name, newtable)—为过程名name 建立新条目,newtable指向过程name本身的符号表
后缀式表示法不用括号,只要知道每个算符的 目数。 (8 4) + 2 的后缀表示是8 4 2 + 8 (4 + 2)的后缀表示是8 4 2 + 对于后缀式,不论从哪一端进行扫描,都能对 它进行唯一分解。 后缀式的计算
用一个栈实现。 一般的计算过程是:自左至右扫描后缀式,每碰到 运算对象就把它推进栈。每碰到k目运算符就把它 作用于栈顶的k个项,并用运算结果代替这k个项。
program main var A, B : real; … procedure P1 var B:boolean; … begin … end procedure P2 var A:integer; … begin … end begin … end
A(real) A(integr) B(real) B(bool)
第七章 中间代码生成
贵州大学 计算机科学与技术学院
本章内容
介绍几种常用的中间表示:后缀表示、图 形表示和三地址代码 用语法制导定义和翻译方案的方法来说明 程序设计语言的结构怎样被翻译成中间形 式
语法分 析器 静态检 查器 中间代码 中间代码 优化器 产生器
本章内容
7.1 7.2 7.3 7.4
2.
程序结构
一组嵌套过程,为每个过程说明的局 部名字建立一张独立的符号表,所有正在翻 译过程的符号表组成整个源程序的符号表。 翻译语句部分时查找符号表,查找过程的符 号表的路线相当于当前被 翻译过程的静态 链。 翻译时,实际上,为每一个过程维持 一张符号表。过程的符号表之间的关系反映 过程在源程序中的关系。
E E1 E2 E E1
E (E1) E id
E.nptr := mkunode( ‘uminus’, E1.nptr) E.nptr := E1.nptr
E.nptr := mkleaf (id, id.entry)
7.1.3 三地址代码
一般形式: x := y 表达式x + y t1 := y t2 := x +
7.2.2 作用域信息的保存
1 .问题的提出 一般的语言中,标识符的作用在程序正文中有一 个确定的范围。因此,同一个标识符在不同的程序 正文中可能标识不同的对象,具有不同的性质,要 求分配不同的存储空间。于是提出下面的问题:如 何组织符号表,使得同一个标识符在不同的作用域 中得到正确的引用而不产生混乱。 编译程序分析声明语句时建立符号表,编译执 行语句时查找符号表。Lookup(id)返回正确的 id.entry。
中间语言 声明语句 赋值语句 布尔表达式和控制流语句
7.1 中间语言
中间语言(复杂性界于源语言和目标语言之间) 的好处:
便于进行与机器无关的代码优化工作 易于移植 使编译程序的结构在逻辑上更为简单明确
Compiler Front End
源语言 程序
中间语 言程序
Compiler Back End
3.所讨论语言的文法(允许过程嵌套) P D S (1) 问题:如何在处理产生 式(1)和(4)的语言结构 D D ; D (2) 时正确地填写符号表信 | id : T (3) 息? | proc id ; D ; S (4) 修改文法,使得在定义D之前生成符号表 P → M D S (1) D → D ; D (2) | id : T (3) | proc id ; N D; S (4) M →ε (5) N →ε (6)
7.2.3 记录的域名
T record L D end {T.type := record (top(tblptr) ); T.width := top(offset); pop(tblptr); pop(offset) } L {t := mktable (nil); push(t, tblprt); push(0, offset) }
三地址代码的具体实现
间接三元式
为了便于优化,用 三元式表+间接码表 表 示中间代码 间接码表:一张指示器表,按运算的先后次 序列出有关三元式在三元式表中的位置。 优点: 方便优化,节省空间
例如,语句
X:=(A+B)*C; Y:=D↑(A+B)
的间接三元式表示如下表所示。
间接代码
(1) (2) (3) (1) (4) (5)
三地址代码的具体实现
四元式
a:=b*(-c)+b*(-c) T1:=-c T2:=b*T1 T5:=T2+T2 a:=T5
一个带有四个域的记录结构,这四个域分别 称为op, arg1, arg2及result op arg1 arg2 result (0) uminus c T1 (1) * b T1 T2 (2) uminus c T3 (3) * b T3 T4 (4) + T2 T4 T5 (5) := T5 a
a := (b + cd ) + cd
DAG的代码 assign t1 := b a + t2 := c d + t3 := t1 + t2 uminus c d t4 := t3 + t2 b a := t4
常用的三地址语句
赋值语句x := y op z, x := op y, x := y 无条件转移goto L 条件转移if x relop y goto L 过程调用param x 和call p , n 过程返回 return y 索引赋值x := y[ i ]和 x[ i ] := y 地址和指针赋值x := &y,x := y 和x := y
目标语 言程序
7.1 中间语言
常用的中间语言:
后缀式,逆波兰表示 图表示: DAG、语法树 三地址代码
三元式 四元式 间接三元式
7.1.1
后缀式
后缀式表示法:Lukasiewicz发明的一种表示 表达式的方法,又称逆波兰表示法。 一个表达式E的后缀形式可以如下定义:
1. 如果E是一个变量或常量,则E的后缀式是E自身。 2. 如果E是E1 op E2形式的表达式,其中op是任何 二元操作符,则E的后缀式为E1 E2 op,其中E1 和E2 分别为E1 和E2的后缀式。 3. 如果E是(E1)形式的表达式,则E1 的后缀式就 是E的后缀式。