编译原理第七章
合集下载
编译原理ppt第七章

1 目标
提升生成的目标代码的性能和效率。
2 优化方法
通过代码转换和代码生成技术进行优化,如常量传播、死代码删除等。
3 效果
优化后的代码可以提高程序的执行效率,减少资源消耗。
图片来源
编译系统组成
了解编译系统的组成对于理解整个 编译过程非常重要。
词法分析器
词法分析器将源代码分解成一个个 词法单元,如标识符、关键字、运 算符。
编译原理ppt第七章
通过这一章的学习,你将深入了解编译系统的组成和各个阶段的作用,包括 词法分析器、语法分析器、语义分析器、中间代码生成以及编译器的优化。
课程概述
1 理解编译原理的重要性 2 学习编译原理的实际
应用
编译原理是计算机科学的基
3 掌握编译器的工作原理
通过学习编译器的各个阶段,
础,掌握它有助于开发高效
了解编译系统可以更好地理
你将能够设计和实现自己的
且可靠的软件。
解代码运行的过程,进而改
编译器。
进代码的性能和可维护性。
编译系统概述
定义
编译系统是一种将源代码转换 为目标代码的软件工具。
组成
编译系统由多个阶段组成,每 个阶段负责不同的任务。
功能
编译系统可以进行词法分析、 语法分析、语义分析等操作, 最终生成可执行的目标代码。
编译器的优化
编译器的优化可以提高代码的性能 和效率。
编译系统的阶段
1
词法分析器
将源代码转换为一系列词法单元,如标识符、
语法分析器
2
关键字、运算符等。
根据语法规则分析词法单元的组合,生成抽象语法。3语义分析器
对抽象语法树进行语义检查,如类型匹配、
中间代码生成
提升生成的目标代码的性能和效率。
2 优化方法
通过代码转换和代码生成技术进行优化,如常量传播、死代码删除等。
3 效果
优化后的代码可以提高程序的执行效率,减少资源消耗。
图片来源
编译系统组成
了解编译系统的组成对于理解整个 编译过程非常重要。
词法分析器
词法分析器将源代码分解成一个个 词法单元,如标识符、关键字、运 算符。
编译原理ppt第七章
通过这一章的学习,你将深入了解编译系统的组成和各个阶段的作用,包括 词法分析器、语法分析器、语义分析器、中间代码生成以及编译器的优化。
课程概述
1 理解编译原理的重要性 2 学习编译原理的实际
应用
编译原理是计算机科学的基
3 掌握编译器的工作原理
通过学习编译器的各个阶段,
础,掌握它有助于开发高效
了解编译系统可以更好地理
你将能够设计和实现自己的
且可靠的软件。
解代码运行的过程,进而改
编译器。
进代码的性能和可维护性。
编译系统概述
定义
编译系统是一种将源代码转换 为目标代码的软件工具。
组成
编译系统由多个阶段组成,每 个阶段负责不同的任务。
功能
编译系统可以进行词法分析、 语法分析、语义分析等操作, 最终生成可执行的目标代码。
编译器的优化
编译器的优化可以提高代码的性能 和效率。
编译系统的阶段
1
词法分析器
将源代码转换为一系列词法单元,如标识符、
语法分析器
2
关键字、运算符等。
根据语法规则分析词法单元的组合,生成抽象语法。3语义分析器
对抽象语法树进行语义检查,如类型匹配、
中间代码生成
编译原理_第7章

29
§7.3 赋值语句的翻译
3.例题:写出下列代码段中表达式的翻译制导过 程及其所产生的四元式 begin Integer:B、C、D、X;
X:=-B*(C+D);
end
符号表 <B> B <C> C <D> D <X> X Int Int Int Int (1) (2) (3) (4) 四元式 Op - + * := arg1 <B> <C> T1 T3 arg2 <D> T2 - result T1 T2 T3 X
语义处理分两步:
1.静态语义分析,即验证语法结构合法的程序是否真正有意义。
2.若静态语义正确,语义处理则要执行真正的翻译。 即要么生成程序的一种中间表示形式(中间代码),
要么生成实际的目标代码。
静态语义检查包括:
(1)类型检查; (2)控制流检查; (3)一致性检查; (4)相关名字检查。
2
第七章
8
§7.1 中间语言
例子:如图所示,为a+a*(b-c)+(b-c)*d的DAG
+
+
* a b c
*
d
9
§7.1 中间语言
2.抽象语法树
例子:(1)a:=b*-c+b*-c的图表示法
assign a * b uminus c b + * uminus c DAG
10
assign
a + * b uminus c
数据区中的相对地址offset.
(3)综合属性: T.type-名字的类型; T.width-名字的域宽(即该类型名字所占用 的存储单元个数)
22
§7.2 二、保留作用域信息
编译原理 - 陈火旺版 - 第七章

3
后缀式
后缀式(逆波兰式)
表达式E的后缀形式E’的写法:
• 若E是变量或常量,则E’ = E • 若E=E1 op E2,则E’ =E1’ E2’ op • 若E=(E1),则E’ = E1 表达式变为后缀形式的语义规则
E→E1 op E2 E→(E1) E→i {E.CODE := E1.CODE||E2.CODE||op } {E.CODE := E1.CODE} {E.CODE := i}
推广到表达式外的范围
• 例如 a:=b*c+b*d 后缀形式:abc*bd*+:=
5
图
抽象语法树
内部结点表示运算符,后代表示运算对象
无循环有向图(DAG)
与抽象语法树
• 相同之处:内部结点表示运算符,后代表示运算对象 • 不同之处:考虑到公共子表达式(不只一个父结点),更加紧 凑高效
四元组表示 (1) (-,C, D , T1) (2) (*, B, T1, T2) (3) (+, A, T2 , T3) (4) (↑, F, G , T4) (5) ( /, E, T4, T5) (6) (-, T3, T5 , T6)
13
说明语句的翻译
说明语句
定义局部于该过程的数据对象(以标识符标识) 为数据对象分配空间,在符号表中登记数据对象的名 字,类型,分配的存储地址 有过程嵌套的,表示出嵌套关系
编译方法
中国人民大学信息学院 陈文萍
1
第7章 语义分析和中间代码生成
中间语言 一些语法成分的翻译
说明语句 赋值语句 布尔表达式 控制语句 过程调用
类型检查
2
语义分析概述
编译原理7

编译原理课程组
result T1 T2 T3 T4 T5 a
21
2015年4月13日星期一
三地址语句
三元式
通过计算临时变量值的语句的位置来引用这
个临时变量 三个域: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)
语义规则
S.nptr:=mknode(‘assign’, mkleaf(id,id.place),E.nptr) E.nptr:=mknode(‘+’,E1.nptr,E2.nptr) E.nptr:=mknode(‘*’,E1.nptr,E2.nptr) E.nptr:=mknode(‘uminus’,E1.nptr) E.nptr:=E1.nptr E.nptr:=mkleaf(id,id.place)
2015年4月13日星期一
编译原理课程组
4
逆波兰表示法不用括号。只要知道每个 算符的目数,对于后缀式,不论从哪一 端进行扫描,都能对它进行唯一分解。 后缀式的计算
用一个栈实现。
一般的计算过程是:自左至右扫描后缀式,
每碰到运算量就把它推进栈。每碰到 k 目运 算符就把它作用于栈顶的 k 个项,并用运算 结果代替这k个项。
c 抽象语法树
uminus
c
编译原理课程组
T1:=-c T2:=b*T1 T3:=-c T4:=b*T3 T5:=T2+T4 a:=T5
2015年4月13日星期一
11
抽象语法树对应的代码:
T1:=-c T2:=b*T1 T3:=-c T4:=b*T3 T5:=T2+T4 a:=T5
result T1 T2 T3 T4 T5 a
21
2015年4月13日星期一
三地址语句
三元式
通过计算临时变量值的语句的位置来引用这
个临时变量 三个域: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)
语义规则
S.nptr:=mknode(‘assign’, mkleaf(id,id.place),E.nptr) E.nptr:=mknode(‘+’,E1.nptr,E2.nptr) E.nptr:=mknode(‘*’,E1.nptr,E2.nptr) E.nptr:=mknode(‘uminus’,E1.nptr) E.nptr:=E1.nptr E.nptr:=mkleaf(id,id.place)
2015年4月13日星期一
编译原理课程组
4
逆波兰表示法不用括号。只要知道每个 算符的目数,对于后缀式,不论从哪一 端进行扫描,都能对它进行唯一分解。 后缀式的计算
用一个栈实现。
一般的计算过程是:自左至右扫描后缀式,
每碰到运算量就把它推进栈。每碰到 k 目运 算符就把它作用于栈顶的 k 个项,并用运算 结果代替这k个项。
c 抽象语法树
uminus
c
编译原理课程组
T1:=-c T2:=b*T1 T3:=-c T4:=b*T3 T5:=T2+T4 a:=T5
2015年4月13日星期一
11
抽象语法树对应的代码:
T1:=-c T2:=b*T1 T3:=-c T4:=b*T3 T5:=T2+T4 a:=T5
编译原理第七章

例题
设有文法G(L)
LE,L LE Ea Eb
文法G(L)的LR分析表如下
ACTION表
状态 0 1 2 3 4 5 S3 S4 S5 r3 r4 a S3 b S4 acc r2 r3 r4 2 6 , # E 2
GOTO表
L 1
6
r1
以输入串“a,b,a”为例,给出LR分析 器的分析过程如下表示:
步骤 1 2 3 4 5 0 03 02 025 0254 状态栈 # #a #E #E, #E,b 符号栈 输入符号串 分析动作 a,b,a# S3(移进) ,b,a# r3(规约) ,b,a# S5(移进) b,a# S4(移进) ,a# r4(规约)
6
7 8 9
0252
02525 025253 025252
S4
S6 r2 r2 S8 r3 r3 r3 r2
3
7
r4 r1
r4 r1
r4 r1
以输入串“abbcde”为例,给出LR分析器的分析过程如下表示:
步骤 1 2 3 4 5 6 7 8 9 0 02 024 023 0236 023 0235 02358 02357 状态栈 # #a #ab #aA #aAb #aA #aAc #aAcd #aAcdB 符号栈 输入符号串 分析动作
7.1.2 分析表或分析函数
LR分析表是LR分析器的核心。 分析表由两个子表构成,即动作表(ACTION表)和状 态转换表(GOTO表)。它们都是二维数组形式(数组 名称分别是GOTO和ACTION)。
对于GOTO表。它的一个数组元素GOTO(Sm,Xi)代表一 个状态。表示当状态Sm面临输入符号Xi时转移到的下一个状态 (通常Xi是非终结符)。 对于ACTION表。它的一个数组元素ACTION(Sm, ai)代表一 个动作,表示当状态Sm面临输入符号ai时完成的分析动作(通 常ai是终结符)。动作可以有四种可能,分别是移进、规约、 接受和出错。
编译原理ppt

三地址代码是中间代码的抽象形式,其具体实
现可用记录表示,记录中包含表示运算符和操 作数的域。有以下三种表示方法:
三元式 四元式
间接三元式
四元式
是一个带有四个域的记录结构,格式如下: (算符, 第一运算对象, 第二运算对象, 结果)
如:a=b*c+b*d
(1) (2) (3) (4)
7.3 将下列表达式分别用逆波兰式、DAG图、 三地址语句、及三地址语句的三种具体实现 方法:三元式、间接三元式、四元式表示: A + B * ( C - D ) + E / ( C - D ) ^N 逆波兰 : A B C D - * + E C D – N ^ / + DAG图: +
+ A /
C B A C T4 E T3
D T1 T2 D N T5 T6
T1 ) T2) T3) T4) T5) T6) T7)
A + B * ( C - D ) + E / ( C - D ) ^N
三元式 : (1) ( (2) ( * (3) ( + (4) ( (5) ( ^ (6) ( / (7) ( +
(1)
如:
X:=(A+B)*C ; Y:=D ↑(A+B)
操作码表 (1) (2) (3) (1) (4) (5)
三元式表 (1)( + , A , B ) (2)( * , (1) , C ) (3)( := , X , (2) ) (4)(↑, D , (1) ) (5)(:= , Y , (4) )
例:a+b*(c-d)-e/f**g
(1) ( -, c , d ) (2) ( * , b , (1) ) (3) ( + , a , (2) ) (4) ( ** , f , g ) (5) ( / , e , (4) ) (6) ( -元式表示
编译原理第七章

符号串的前缀是指符号串的任意首部,包括
安徽理工大学
《编译原理》 信息安全系 赵宝
2
空串ε。
定义:对于文法G[S],若有
S
* r
αβ,β∈Vt*
则称α为规范前缀,也称为活前缀。
若α是含句柄的活前缀,并且每个句柄是α 的后缀或本身,则称α是可归规范前缀或可归 前缀(含有句柄的活前缀)。
活前缀不含句柄之右的任何符号。 是规范
由此可见,构造LR分析器的主要工作是构造 分析表
•LR分析表的组成: LR分析表由分析动作(ACTION)表和状态转换 (GOTO)表组成。
1). 分析动作表
安徽理工大学
《编译原理》 信息安全系 赵宝
ቤተ መጻሕፍቲ ባይዱ
10
在分析动作表中,其元素由action(si,aj)来表 示。action(si,aj)表示当前分析栈的状态栈栈顶 元素为si,文法符号栈栈顶元素为aj(当前输入 符号)时,所执行的动作。
特殊符号也可以用“.”,并且要加在产生 式右部的任何地方,表示一个位置。
➢项目集:若干个项目组成的集合称为项目集, 又称为配置集合。
➢后继符号:项目中紧跟在特殊符号“△”后 面的符号称为该项目的后继符号。
安徽理工大学
《编译原理》 信息安全系 赵宝
18
后继符号表示下一时刻读到的符号。有如下两 种情况:
下面我们以输入串 #a,b,a# 为例,具体讲述LR分析过程。
安徽理工大学
《编译原理》 信息安全系 赵宝
15
状态栈 S0 S0S3
S0S2
S0S2S5 S0S2S5S4
S0S2S5S2
S0S2S5S2S5 S0S2S5S2S5S3
S0S2S5S2S5S2
安徽理工大学
《编译原理》 信息安全系 赵宝
2
空串ε。
定义:对于文法G[S],若有
S
* r
αβ,β∈Vt*
则称α为规范前缀,也称为活前缀。
若α是含句柄的活前缀,并且每个句柄是α 的后缀或本身,则称α是可归规范前缀或可归 前缀(含有句柄的活前缀)。
活前缀不含句柄之右的任何符号。 是规范
由此可见,构造LR分析器的主要工作是构造 分析表
•LR分析表的组成: LR分析表由分析动作(ACTION)表和状态转换 (GOTO)表组成。
1). 分析动作表
安徽理工大学
《编译原理》 信息安全系 赵宝
ቤተ መጻሕፍቲ ባይዱ
10
在分析动作表中,其元素由action(si,aj)来表 示。action(si,aj)表示当前分析栈的状态栈栈顶 元素为si,文法符号栈栈顶元素为aj(当前输入 符号)时,所执行的动作。
特殊符号也可以用“.”,并且要加在产生 式右部的任何地方,表示一个位置。
➢项目集:若干个项目组成的集合称为项目集, 又称为配置集合。
➢后继符号:项目中紧跟在特殊符号“△”后 面的符号称为该项目的后继符号。
安徽理工大学
《编译原理》 信息安全系 赵宝
18
后继符号表示下一时刻读到的符号。有如下两 种情况:
下面我们以输入串 #a,b,a# 为例,具体讲述LR分析过程。
安徽理工大学
《编译原理》 信息安全系 赵宝
15
状态栈 S0 S0S3
S0S2
S0S2S5 S0S2S5S4
S0S2S5S2
S0S2S5S2S5 S0S2S5S2S5S3
S0S2S5S2S5S2
编译原理课件第7章

P→MD M→ {offset := 0 }
D→D ; D
D→id : T {enter( , T.type, offset );
offset := offset + T.width}
T→integer {T.type := integer; T.width := 4}
T→real {T.type := real; T.width := 8}
D→id : T {enter( , T.type, offset ); offset := offset + T.width}
P
offset=0
D
D
;
offset=8
D
offset=12
id
:
T
id
:
T
real
enter(x,real,0)
2020/2/3
T.type=real T.width=8
• type row = record
• address: integer;
• lexeme: array[1..15] of char
• end;
• var table : array [1..10] of row;
6.如果T是类型表达式,那么pointer(T)也是类型表 达式,表示“指向类型为T的对象的指针”。
integer T.type=integer
T.width=4
enter(i,integer,8)
20
例 x:real; i:integer 的翻译
P{offset:=0}D {offset:=0}D;D {offset:=0}x:T{enter(x,T.type,offset);
第七章 编译原理

第七章 语义分析和中间代码产生
本章将把上章介绍的属性文法和语法制导翻译的 方法和技术,用于高级语言的语义分析和中间代码产 生中。 紧接词法分析和语法分析之后,编译程序要做的 工作是,静态语义检查和翻译。
●静态语义检查
(1)类型检查
(3) 一致性检查
(2) 控制流检查
(4)相关名字检查
(5)作用域分析
T2:=x+T1
三地址代码可以看成是抽象语法树或DAG图的 一种线性表示。 三地址语句十分类似汇编语言的语句。语句可 以带标号,也可以有各种控制流语句。
本书所使用的三地址语句的种类如下: (1) (2) (3) (4) (5) (6) x :=y op z x := op y x:=y goto L if x relop y goto L param x1
Eid
E.place:=id.place
E.code:=‘’
例如 对 a:=b*-c+b*-c 产生三地址代码
S S
a
:=
E4 *
E9 +
E8
*
.③ E .place = T 2:=b*T1 T 3 1 . E3.code=‘ T13:=-c ’ T :=-c .④ E4.place = T2 4:=b*T3 T
●
例如 写出将表达式翻译成后缀形式的属性文法 SE EE1op E2 E(E1 ) Eid 输入串 (a+b)*c
E.code=ab+ E E.code=a E
{ { { {
print(E.code) } E.code:=E1.code || E2.code || op } E.code:= E1.code } E.code:=id }
本章将把上章介绍的属性文法和语法制导翻译的 方法和技术,用于高级语言的语义分析和中间代码产 生中。 紧接词法分析和语法分析之后,编译程序要做的 工作是,静态语义检查和翻译。
●静态语义检查
(1)类型检查
(3) 一致性检查
(2) 控制流检查
(4)相关名字检查
(5)作用域分析
T2:=x+T1
三地址代码可以看成是抽象语法树或DAG图的 一种线性表示。 三地址语句十分类似汇编语言的语句。语句可 以带标号,也可以有各种控制流语句。
本书所使用的三地址语句的种类如下: (1) (2) (3) (4) (5) (6) x :=y op z x := op y x:=y goto L if x relop y goto L param x1
Eid
E.place:=id.place
E.code:=‘’
例如 对 a:=b*-c+b*-c 产生三地址代码
S S
a
:=
E4 *
E9 +
E8
*
.③ E .place = T 2:=b*T1 T 3 1 . E3.code=‘ T13:=-c ’ T :=-c .④ E4.place = T2 4:=b*T3 T
●
例如 写出将表达式翻译成后缀形式的属性文法 SE EE1op E2 E(E1 ) Eid 输入串 (a+b)*c
E.code=ab+ E E.code=a E
{ { { {
print(E.code) } E.code:=E1.code || E2.code || op } E.code:= E1.code } E.code:=id }
编译原理课后答案——第七章_目标代码生成

第七章 目标代码生成
第七章 目标代码生成
7.1 对下列四元式序列生成目标代码: T=A-B S=C+D
W=E-F
U=W/T V=U*S 其中,V是基本块出口的活跃变量,R0和R1是可用寄存 器。
第七章 目标代码生成 【解答】 简单代码生成算法依次对四元式进行翻译。
我们以四元式T=a+b为例来说明其翻译过程。 汇编语言的加法指令代码形式为 ADD R, X 其中,ADD为加法指令;R为第一操作数,第一操作数必 须为寄存器类型;X为第二操作数,它可以是寄存器类型,也 可以是内存型的变量。ADD R,X指令的含意是:将第一操作数 R与第二操作数相加后,再将累加结果存放到第一操作数所在 的寄存器中。要完整地翻译出四元式T=a+b,则可能需要下面 三条汇编指令:
第七章 目标代码生成 此外,如果必须使用第一条指令,即第一操作数 不在寄存器而是在内存中,且此时所有可用寄存器都 已分配完毕,这时就要根据寄存器中所有变量的待用 信息(也即引用点)来决定淘汰哪一个寄存器留给当前 的四元式使用。寄存器的淘汰策略如下: (1) 如果某寄存器中的变量已无后续引用点且该 变量是非活跃的,则可直接将该寄存器作为空闲寄存 器使用。 (2) 如果所有寄存器中的变量在基本块内仍有引 用点且都是活跃的,则将引用点最远的变量所占用寄 存器中的值存放到内存与该变量对应的单元中,然后 再将此寄存器分配给当前的指令使用。
第七章 目标代码生成 因此,本题所给四元式序列生成的目标代码如下: MOV R0, A SUB R0, C MOV R1, C ADD R1, D /*R1=S*/ /*R0=T*/
MOV S, R1 的值送内存单元S*/
MOV R1, E SUB R1, F SUB R1, R0 MUL R1, S
第七章 目标代码生成
7.1 对下列四元式序列生成目标代码: T=A-B S=C+D
W=E-F
U=W/T V=U*S 其中,V是基本块出口的活跃变量,R0和R1是可用寄存 器。
第七章 目标代码生成 【解答】 简单代码生成算法依次对四元式进行翻译。
我们以四元式T=a+b为例来说明其翻译过程。 汇编语言的加法指令代码形式为 ADD R, X 其中,ADD为加法指令;R为第一操作数,第一操作数必 须为寄存器类型;X为第二操作数,它可以是寄存器类型,也 可以是内存型的变量。ADD R,X指令的含意是:将第一操作数 R与第二操作数相加后,再将累加结果存放到第一操作数所在 的寄存器中。要完整地翻译出四元式T=a+b,则可能需要下面 三条汇编指令:
第七章 目标代码生成 此外,如果必须使用第一条指令,即第一操作数 不在寄存器而是在内存中,且此时所有可用寄存器都 已分配完毕,这时就要根据寄存器中所有变量的待用 信息(也即引用点)来决定淘汰哪一个寄存器留给当前 的四元式使用。寄存器的淘汰策略如下: (1) 如果某寄存器中的变量已无后续引用点且该 变量是非活跃的,则可直接将该寄存器作为空闲寄存 器使用。 (2) 如果所有寄存器中的变量在基本块内仍有引 用点且都是活跃的,则将引用点最远的变量所占用寄 存器中的值存放到内存与该变量对应的单元中,然后 再将此寄存器分配给当前的指令使用。
第七章 目标代码生成 因此,本题所给四元式序列生成的目标代码如下: MOV R0, A SUB R0, C MOV R1, C ADD R1, D /*R1=S*/ /*R0=T*/
MOV S, R1 的值送内存单元S*/
MOV R1, E SUB R1, F SUB R1, R0 MUL R1, S
编译原理第七章_自下而上的LR(K)分析方法

一、根据形式定义求出活前缀的正规表达式,然 后由此正规表达式构造NFA再确定化为DFA(不 实用,略)
二、求出文法的所有项目,按一定规则构造识别 活前缀的NFA再确定化为DFA(了解)
三、使用闭包函数(CLOSURE)和转向函数 (GOTO(I,X))构造文法G’的LR(0)的项目集规范 族,再由转换函数建立状态之间的连接关系得 到识别活前缀的DFA(掌握)
编译原理 Compilers Principles 第7章9
移进-归约中的问题分析
3) #ab 4) #aA 5) #aAb 6) #aA
bcde# bcde# cde# cde#
归约(A→b) 移进
归约(A→Ab) 移进
分析:已分析过的部分在栈中的前缀不同,而且移 进和归约后栈中的状态会发生变化
S aA cBe
Ab d b
0 S 1*
1 * 句子识别态
2a 3b 4
i
5a 6 A 7 b 8
9 a 10 A 11 c 12 d 13
14 a 15 A 16 c 17 B 18 e 10
构造识别活前缀的有限自动机 例子
句柄识别态
X
0S 2a 5a 9a
14 a
*
1
3b 4 6 A7b 10 A 11 c 15 A 16 c
1) # 2) #a 3) #ab
abbcde# bbcde# bcde#
动作
移进 移进 归约(A→b)
状态栈
0 02 024
ACTION
S2 S4 r2
GOTO
3
对输入串abbcde#的LR分析过程
S
1*
b
4
0 a 2 A 3 b 6
二、求出文法的所有项目,按一定规则构造识别 活前缀的NFA再确定化为DFA(了解)
三、使用闭包函数(CLOSURE)和转向函数 (GOTO(I,X))构造文法G’的LR(0)的项目集规范 族,再由转换函数建立状态之间的连接关系得 到识别活前缀的DFA(掌握)
编译原理 Compilers Principles 第7章9
移进-归约中的问题分析
3) #ab 4) #aA 5) #aAb 6) #aA
bcde# bcde# cde# cde#
归约(A→b) 移进
归约(A→Ab) 移进
分析:已分析过的部分在栈中的前缀不同,而且移 进和归约后栈中的状态会发生变化
S aA cBe
Ab d b
0 S 1*
1 * 句子识别态
2a 3b 4
i
5a 6 A 7 b 8
9 a 10 A 11 c 12 d 13
14 a 15 A 16 c 17 B 18 e 10
构造识别活前缀的有限自动机 例子
句柄识别态
X
0S 2a 5a 9a
14 a
*
1
3b 4 6 A7b 10 A 11 c 15 A 16 c
1) # 2) #a 3) #ab
abbcde# bbcde# bcde#
动作
移进 移进 归约(A→b)
状态栈
0 02 024
ACTION
S2 S4 r2
GOTO
3
对输入串abbcde#的LR分析过程
S
1*
b
4
0 a 2 A 3 b 6
编译原理 第七章

第七章
7.1 7.2 7.3 7.4 7.5 7.6
LR分析法
LR分析概述 LR(0)分析 SLR(1)分析 LR(1)分析 LALR(1)分析 二义性文法在LR分析中的应用
复习: 自底向上分析
思想 从输入串出发,反复利用产生式进行归约,如 果最后能得到文法的开始符号,则输入串是句子, 否则输入串有语法错误
由以上分析我们很容易理解,在LR分析过 程中,实际上是把αβ的前缀列出放在符号 栈中,一旦在栈中出现αβ(可归前缀), 即句柄已经形成,则用产生式A→β进行归 约。(参考P125-表7.2)
7.2.2
7.2.3
识别活前缀的有限自动机(略)
活前缀及其可归前缀的一般计算方法(略)
7.2.4
LR(0)项目集规范族的构造
*〉,为终结符串 • 可归前缀:如果有S′=
(或空),含有句柄,且句柄在的后端,称 为可归前缀。 • 活前缀:把形成可归前缀之前包括可归前缀 在内的所有规范句型的前缀都称为活前缀。
R
*〉αAω = 〉αβω是文法G 定义7.1 若S′= R
中的一个规范推导( β 为句柄),如果符 号串γ是αβ的前缀,则称γ 是G的一个活 前缀,γ 的右端不超过句柄的末端。
• 使用CLOSURE和GO(I,X)构造文法G′的 LR(0)项目集规范族:
a)置项目 S′→ S为初态集的核,求CLOSURE ({ S′→ S })得到初态的项目集
b)对初态集或其它的项目集应用转换函数
GO ( I , X ) =CLOSURE ( J )求出新状态 J
的项目集。
c) 重复b) 直到不出现新的项目集为止。
按(2)中方法,列出拓广文法的所有项目, 构造NFA再确定化,这样做确定化的工作量较 大,可以用闭包函数求DFA项目集。
7.1 7.2 7.3 7.4 7.5 7.6
LR分析法
LR分析概述 LR(0)分析 SLR(1)分析 LR(1)分析 LALR(1)分析 二义性文法在LR分析中的应用
复习: 自底向上分析
思想 从输入串出发,反复利用产生式进行归约,如 果最后能得到文法的开始符号,则输入串是句子, 否则输入串有语法错误
由以上分析我们很容易理解,在LR分析过 程中,实际上是把αβ的前缀列出放在符号 栈中,一旦在栈中出现αβ(可归前缀), 即句柄已经形成,则用产生式A→β进行归 约。(参考P125-表7.2)
7.2.2
7.2.3
识别活前缀的有限自动机(略)
活前缀及其可归前缀的一般计算方法(略)
7.2.4
LR(0)项目集规范族的构造
*〉,为终结符串 • 可归前缀:如果有S′=
(或空),含有句柄,且句柄在的后端,称 为可归前缀。 • 活前缀:把形成可归前缀之前包括可归前缀 在内的所有规范句型的前缀都称为活前缀。
R
*〉αAω = 〉αβω是文法G 定义7.1 若S′= R
中的一个规范推导( β 为句柄),如果符 号串γ是αβ的前缀,则称γ 是G的一个活 前缀,γ 的右端不超过句柄的末端。
• 使用CLOSURE和GO(I,X)构造文法G′的 LR(0)项目集规范族:
a)置项目 S′→ S为初态集的核,求CLOSURE ({ S′→ S })得到初态的项目集
b)对初态集或其它的项目集应用转换函数
GO ( I , X ) =CLOSURE ( J )求出新状态 J
的项目集。
c) 重复b) 直到不出现新的项目集为止。
按(2)中方法,列出拓广文法的所有项目, 构造NFA再确定化,这样做确定化的工作量较 大,可以用闭包函数求DFA项目集。
编译原理第七章

7.1.4 控制结构
一个程序设计语言的控制结构是该语言在程序运行期 间用于改变控制流的语言特征集合。
7.2 执行时的内存分配
编译程序需要为源程序中的数据分配执行时的存 储空间,编译程序从操作系统中申请编译程序 计算出的所需的内存,或编译程序生成在运行 时需申请内存的指令。
(1) 确定用来表示某一数据项的内存大小。
目标代码生成
• 输入
– 中间代码
• 三元式 • 四元式
• 输出
– 可执行代码 – 待装配的代码 – 汇编代码
第1章 语言处理程序概述
1.1 语言处理程序的发展过程
• 语言处理程序简介 • 语言处理程序的工作 • 语言处理程序的形式
1.1.1 语言处理程序简介
• 语言处理程序的起源—填补程序设计者的符号 描述与目标机器运行要求之间的差异
一种在程序运行期间均可以对内存实 现分配或解除分配,一旦存储分配解除该 存储空间内的数据便失去意义。叫做动态 存储分配。
7.3 代码优化
目标: 作为一个高级语言的使用者很希望编译 程序所产生的代码能够和直接用机器语言编写 的程序效果一样好。
代码优化是指对原代码进行的变换,从而获得在 时间和空间上效率到:
7.1.1 数据类型
类型的合法性检查是判断数据类型是否与上下文的要求一致 数据类型是对该类型数据(变量或常量)的取值是否合法以 及对该类型数据的运算是否合法的一种说明。
7.1.2 数据结构
一个程序设计语言如允许使用的数组、记录、字符串、 表、栈等形式的数据结构,在编译程序中应为它们提供相 应的翻译。 为了能对数据结构中的元素进行引用,必须完成从逻辑结 构到能够访问这些数据元素的物理结构的映射。应考虑:
1 编译求值 2 合并预算 3 删除死码 4 减少频率 5 强度削弱和变换循环条件 6 减少重写传播
编译原理演示文稿7

例:设有类Pascal程序段 program example(input,output);
type student=record no:integer; name:array[1..10] of char; score:integer end;
weekday=(sun,mon,tue,wed,thu,fri,sat); var st:array[1..50] of student;
name :array[1..20] of char; next:link end; 的无类型结构树或无环 有向图相等即可。检查类型等价也分成静态检查和动态检查。 由编译程序能完成的类型检查叫做静态类型检查;由目标程 序运行时所作的类型检查就称为动态类型检查。一般地,如 果要在生成的目标代码中完成类型检查,则目标代中不但要 保存数据的值,而且还保存该数据的类型,则可完工成相应 的动态类型检查。因算法语言的类型检查多数是静态的类型 检查,在这里仅介绍了静态的类型检查。
7.1.4 控制结构 一种程序设计语言的控制结构是该语言在程序运行期间
用于改变控制流的语言特征集合。它包括有条件控制转移, 条件执行、循环控制、过程序调用、转移和出口。编译程序 在翻译时必须保证源程序不能违法控制结构的语义。如 Pascal中只能从循环体内转向循环体外、C语言中不能从一 个函数转向另一个函数、BASIC中不能在循环体内修改循环 变量的值,而C没有这种限制。 例:错误的控制结构 begin
定义7.1 数据类型是对该类型数据(变量或常量)的取值是 否合法以及对该类型据的运算是否合法的一种说明。
实现和完成数据类型的合法性检查,它包括以下任务:
(1) 检查运算符作用在运算对象上的合法性,这一合法性保 证了该运算能产生正确的运算结果。
编译原理第七章

对例6.1的文法用拓广文法表示成: S′→S[0] S→aAcBe[1] A→b[2] A→Ab[3] B→d[4] 现对句子abbcde的可归前缀列出: S[0] ab[2] aAb[3] aAcd[4] aAcBe[1]
构造识别其活前缀及可归前缀的有限自动机如图7.2。 每一个终态都是句柄识别态,用双圈表示。带"*"号的状态既为句柄识
观察产生式右部的非终结符。 2、应用LR(0)CONTEXT(A→β)=LC(A).β求得包含句柄 的活前缀。 3、由此可构造以文法符号为字母表的识别(包括句柄) 活前缀的不确定有限自动机。 4、应用子集法对上述的不确定有限自动机进行确定化 得到识别可归前缀的确定有限自动机。
结论:对任何一个上下文无关文法只要能构造出识别 可归前缀的有限自动机,就可以构造其相应的分析表。
if ACTION[Si,a]=Sj then begin PUSH j,a (进栈)
ip 前进(指向下一输入符号)
end
else
if ACTION[Si,a]=rj(若第j条产生式 为A→β) then begin
pop |β| 项
对于上面的分析过程我们可以知道:
若当前栈顶状态为Sk push GOTO[Sk,A] 和A(进栈) end
在文法G中每个产生式的右部适当位置添加一个圆点构成项目。
例如,产生式S→aAcBe对应有6个项目:
[0] S→·aAcBe [2] S→aA·cBe [4] S→aAcB·e
7.2.1 可归前缀和子前缀
为了在以后的LR分析中不致引起混淆,现对原文法进行拓广。 若原文法G的开始符号为S,在G中加产生式S′→S后得新的文法G′, 则称G′为原文法G的拓广文法,而S′为拓广后文法G′的开始符号。 对文法进行拓广的目的是为了对某些右部含有开始符号的文法,在 归约过程中能分清是否已归约到文法的最初开始符,还是在文法右 部出现的开始符号,拓广文法的开始符号S′只在左部出现,这样 确保了不会混淆。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
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本身的符号表
相对地址:对静态数据区基址的偏移或对活动 记录中局部数据区基址的偏移。
7.2.1 过程中的声明
一个过程中的所有声明语句可集中处理。用一个全 程变量offset来记录下一个可用的相对地址。
计算声明语句中名字的类型和相对地址 建立符号 P {offset := 0} D S 表条目 DD;D D id : T {enter ( , 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 }
2.
程序结构
一组嵌套过程,为每个过程说明的局 部名字建立一张独立的符号表,所有正在翻 译过程的符号表组成整个源程序的符号表。 翻译语句部分时查找符号表,查找过程的符 号表的路线相当于当前被 翻译过程的静态 链。 翻译时,实际上,为每一个过程维持 一张符号表。过程的符号表之间的关系反映 过程在源程序中的关系。
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
(1) (2) (3) (4) (5)
三元式表
OP + * := ↑ := ARG1 A (1) X D Y ARG2 B C (2) (1) (4)
7.2 声明语句
分析过程或程序块的声明序列时:
为局部名字建立符号表条目 为它分配存储单元
符号表中包含了名字的类型和分配给它的存 储单元的相对地址等信息
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), , t) } Did : T {enter(top(tblptr), , T.type, top(offset)); top(offset) := top(offset) + T.width } N {t := mktable(top(tblptr) ); push(t, tblptr); push(0, offset) }
第七章 中间代码生成
贵州大学 计算机科学与技术学院
本章内容
介绍几种常用的中间表示:后缀表示、图 形表示和三地址代码 用语法制导定义和翻译方案的方法来说明 程序设计语言的结构怎样被翻译成中间形 式
语法分 析器 静态检 查器 中间代码 中间代码 优化器 产生器
本章内容
7.1 7.2 7.3 7.4
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.1.2 图形表示
图表示法
语法树 DAG
图形表示
有向无环图(Directed Acyclic Graph,简称 DAG)
对表达式中的每个子表达式,DAG中都有一个结点 一个内部结点代表一个操作符,它的孩子代表操 作数 在一个DAG中代表公共子表达式的结点具有多个父 结点
a := (b + cd ) + cd的图形表示
中间语言 声明语句 赋值语句 布尔表达式和控制流语句
7.1 中间语言
中间语言(复杂性界于源语言和目标语言之间) 的好处:
便于进行与机器无关的代码优化工作 易于移植 使编译程序的结构在逻辑上更为简单明确
Compiler Front End
源语言 程序
中间语 言程序
Compiler Back End
三地址代码的具体实现
三元式
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)
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
三地址代码的具体实现
四元式
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
目标语 言ห้องสมุดไป่ตู้序
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的后缀式。
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。
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本身的符号表
相对地址:对静态数据区基址的偏移或对活动 记录中局部数据区基址的偏移。
7.2.1 过程中的声明
一个过程中的所有声明语句可集中处理。用一个全 程变量offset来记录下一个可用的相对地址。
计算声明语句中名字的类型和相对地址 建立符号 P {offset := 0} D S 表条目 DD;D D id : T {enter ( , 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 }
2.
程序结构
一组嵌套过程,为每个过程说明的局 部名字建立一张独立的符号表,所有正在翻 译过程的符号表组成整个源程序的符号表。 翻译语句部分时查找符号表,查找过程的符 号表的路线相当于当前被 翻译过程的静态 链。 翻译时,实际上,为每一个过程维持 一张符号表。过程的符号表之间的关系反映 过程在源程序中的关系。
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
(1) (2) (3) (4) (5)
三元式表
OP + * := ↑ := ARG1 A (1) X D Y ARG2 B C (2) (1) (4)
7.2 声明语句
分析过程或程序块的声明序列时:
为局部名字建立符号表条目 为它分配存储单元
符号表中包含了名字的类型和分配给它的存 储单元的相对地址等信息
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), , t) } Did : T {enter(top(tblptr), , T.type, top(offset)); top(offset) := top(offset) + T.width } N {t := mktable(top(tblptr) ); push(t, tblptr); push(0, offset) }
第七章 中间代码生成
贵州大学 计算机科学与技术学院
本章内容
介绍几种常用的中间表示:后缀表示、图 形表示和三地址代码 用语法制导定义和翻译方案的方法来说明 程序设计语言的结构怎样被翻译成中间形 式
语法分 析器 静态检 查器 中间代码 中间代码 优化器 产生器
本章内容
7.1 7.2 7.3 7.4
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.1.2 图形表示
图表示法
语法树 DAG
图形表示
有向无环图(Directed Acyclic Graph,简称 DAG)
对表达式中的每个子表达式,DAG中都有一个结点 一个内部结点代表一个操作符,它的孩子代表操 作数 在一个DAG中代表公共子表达式的结点具有多个父 结点
a := (b + cd ) + cd的图形表示
中间语言 声明语句 赋值语句 布尔表达式和控制流语句
7.1 中间语言
中间语言(复杂性界于源语言和目标语言之间) 的好处:
便于进行与机器无关的代码优化工作 易于移植 使编译程序的结构在逻辑上更为简单明确
Compiler Front End
源语言 程序
中间语 言程序
Compiler Back End
三地址代码的具体实现
三元式
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)
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
三地址代码的具体实现
四元式
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
目标语 言ห้องสมุดไป่ตู้序
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的后缀式。
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。