南开大学编译原理第6章课件
编译原理教案.ppt
4
第七章:运行时环境
❖ 教学内容及进度:第七章运行时环境7.17.3&7.6-7.8
概述(5分钟) 源语言问题(15分钟) 存储组织(5分钟) 存储分配策略(15分钟) 符号表(20分钟) 支持动态存储分配的语言措施(10分钟) 动态存储分配技术(10分钟)
5
第七章:运行时环境
编译原理教案 第十六课
1
第六章:类型检查 ❖ 教学内容及进度:第六章类型检查6.1-6.2
概述(10分钟) 类型系统(10分钟) 一个简单的类型检查器的说明(20分钟)
2
第六章:类型检查 ❖ 教学目的和要求
掌握类型系统 掌握一个简单的类型检查器的说明
3第六章:类型ຫໍສະໝຸດ 查 ❖ 教学重点掌握类型系统 掌握一个简单的类型检查器的说明
❖ 教学目的和要求
掌握源语言问题 掌握存储组织 掌握存储分配策略 掌握符号表 了解支持动态存储分配的语言措施 了解动态存储分配技术
6
第七章:运行时环境
❖ 教学重点
源语言问题 存储组织 存储分配策略 符号表
❖ 教学主线:存储组织、分配策略和符号表
7
南开大学C++课件_第_6章b_指针、结构体及引用
21
bool compword(char* a, char* b) //比较二字符串大小,按字典序a<b则返1即true(书p155为int型) { while(*a != '\0' && *b != '\0') //a串与b串都没结束时 if(*a != *b) return(*a < *b); //第一个不相等字符, 决定整个a,b串的大小 else {a++; b++;} return(*a=='\0'); //注意,此时至少有一个串已结束(短者优先) }
当要对a赋值123时,下述三个语句是等价的: a=123; *pa=123; ra=123;
4
引用类型变量与其他类型变量不同,它没有 自己的值和地址空间,只是作为另一变量的别 名,在它的生存期期间两个名字绑定在一起, 因此,引用类型的使用是有限制的: 引用类型变量不能被引用; 引用类型不能组成数组; 引用类型不能定义指针。 正是这些限制,保证了它的安全性,反而成 为人们选择它取代方便灵活的指针的原因。
22
6.5.2
构建一个人员档案链表
为了管理人员(职员,学生,居民等)或物资、文献的档案 资料,使用链表形式很方便。链表可长可短,其功能可通过使 用指针以及动态创建和撤消数据对象的运算符new和delete来 完成。
本示例性程序建立并管理人员链表,具体做以下4项工作: 1) 读入若干个人员的档案资料(读入'*'符号时结束输入), 动态生成链表项,并将输入的档案资料存放于链表项之中,而 后总将新链表项加入到原链表的末尾; 2) 遍历链表, 输出整个链表的各项内容; 3 ) 在 链 表 首 加 入 一 项 , 其 name="wang ping", age=20, sex='M' ; 4) 统计出当前链表中共有多少男士,并计算出他们的平均 年龄。
编译原理chapter6 语法分析
可能有几处说明,语言的作用域规则规定:
在语句序列中引用的一个名字是在何处说
明的名字。
3 . 编译时,处理说明把名字及其属性信息填
写进符号表(add(id.entry,id.vul)); 处理引用
名字时,查找这个名字的属性信息
(lookup(id)),符号表管理程序根据语 言的
作用域规则,使 lookup(id)返回id的作用域
中绑定的属性信息。 精品文档
14
6.1.5名字与存储的绑定 名字与存储单元的绑定是指把源程序中的数 据名字映射到目标机存储单元的过程。 引进两个函数,environment和state。 environment把名字映射到一个存储单元上; state把存储单元映射到那里所存放的值上。 可以说,函数environment把一个名字映射为 一个l-value(左-值),而函数state把一个lvalue(左-值)映射为一个r-value(右-值)。 如图6.5所示。
精品文档
11
例6.2 栈和活动树的变化
栈 s Sr S q(1.9) S q(1.9) p(1,9) S q(1.9) q(1,3)
S q(1.9) q(1,3) p(1,3) S q(1.9) q(1,3) q(1,0)
S q(1.9) q(1,3) q(2,3)
s r q(1,9)
p(1,9) q(1,3)
用活动树来讨论正在这个结点上的控 制。
ห้องสมุดไป่ตู้
精品文档
9
s
图6.3 一棵活动树
r q(1,9)
p(1,9) q(1,3)
q(5,9)
p(5,9) q(5,5) q(7,9) p(1,3) q(1,0) q(2,3)
编译原理 6章
布尔矩阵和关系
• 关系可用集合定义,也可用布尔矩阵表示 xRy 当且仅当M[x,y]=1 • • • • 定理6.1 M(RT)=M(R)T 定理6.2 M(R1+R2)=M(R1)+M(R2) 定理6.3 M(R1R2)=M(R1)M(R2) 定理6.4 M(R+)=M(R)+
传递闭包 的Warshall算法 算法
文法G(E): E→E+T | T T→T*F | F F→(E) | i
+ + * i ( ) > > > < > * < > > < > < < i < < ( < < ) > > > = >f+ Nhomakorabeaf*
fi
f(
f)
g+
g*
gi
g(
g)
+
f 4 f+, g+, f(, g) 3 g+,f(,g)
*
6.7.2 Bell 方法
• Bell方法:有向图构造法。 方法: 方法 有向图构造法。 ① 作两排结点:一排为f L ,另一排为g R; L>R, 从L到R连一有向弧; L<R, 从R到L连一有向弧; L=R, 从L到R和从R到L各连一有向弧; ② 计算各结点能到达的结点数(包括自己) 为该函数点的值。 ③ 按定义6.1的条件判断,若不满足则不存在 优先函数。
与文法有关的一些关系: 与文法有关的一些关系:
⑴ 关系和 x, y∈Σ,R1和R2是Σ上的两个关系,R1与 R2的两个关系和记为R1+R2。 x(R1+R2)y 当且仅当 xR1y或xR2y ⑵ 关系积 R1和R2是Σ上的两个关系,R1与R2的两个 关系积记为R1R2。 xR1R2y 当且仅当 存在w∈Σ,使得xR1w与wR2y ⑶ 传递闭包 关系R的传递闭包记为R+,x, y∈Σ, xR+y 当且仅当存在n>0,使得xRny ⑷ 自反传递闭包 关系R的传递闭包记为R*,x, y∈Σ, xR*y 当且仅当 存在n≥0,使得xRny ,其中R0为恒等
编译原理 第6章课件
第6章LR分析法教学要求:1.掌握:活前缀的概念,2.理解:LR (0 ), SLR (1), LR(1)和LALR(1)分析过程,各类分析表的构造3.了解:二义性文法在LR 分析中的应用目录 6.1 LR 分析概述6.2 LR (0) 分析6.3 SLR(1) 分析6.4 LR (1)分析6.5 LALR(1)分析6.6 二义性文法在LR 分析中的应用强调算符之间的优先关系的唯一性,这使得它的适应面比较窄算法在发现最左素短语的尾时,需要回头寻找对应的头LR(k)分析法可分析LR(k)文法产生的语言– L :从左到右扫描输入符号,– R :最右推导对应的最左归约(反序完成最右推导)– k :向前读入k 个符号,以便确定归约用的产生式LR 分析法正是给出一种能根据当前分析栈中的符号串和向右顺序查看输入串的K 个( K ≥0)符号就可唯一地确定分析器的动作是移进还是归约和用哪个产生式归约,因而也就能唯一地确定句柄。
LR 分析法的归约过程是规范推导的逆过程,所以LR 分析过程是一种规范归约过程。
6.1 LR分析概述L:从左到右扫描输入串R : 最右推导的逆过程分析器模型和分析算法• LR分析特征讨论说明:S[i] 为状态栈, X[i]为文法符号栈。
状态转换表用GOTO[S i ,X]= S j 表示,规定当栈顶状态为S i ,遇到当前文法符号为X 时应转向状态S j ,X 为终结符号或非终结符号。
ACTION[S i ,a]规定了栈顶状态为S i ,遇到输入符号为a 应执行的动作。
动作有如下四种: 移进: S j = GOTO[S i ,a]移入状态栈,a 移入到文法符号栈。
归约: 栈顶形成句柄为β时,文法有产生式 A →β,若 β的长度为r ,则从两个栈顶去掉r 个符号,把A 移入符号栈,S j =GOTO[S i ,A] 移入状态栈。
接受acc 报错LR 分析算法 置ip 指向输入串w 的第一个符号 令S 为栈顶状态 a 是ip 指向的符号 重复 begin if ACTION[S,a]=S j then begin PUSH j,a(进栈)ip 前进(指向下一输入符号) end else if ACTION[S,a]=r j (第j 条产生式为A →β)then beginpop |β| 项令当前栈顶状态为S’push GOTO[S’,A]和A(进栈)end else if ACTION[s,a]=accthen return (成功)else errorend.重复LR 文法:对于一个上下文无关文法(Context Free Grammar)-cfg 文法, 如果能 够构造一张 LR 分析表, 使得它的每一个入口均是唯一的(Sj,rj,acc,空白), 则称该 cfg 是LR 文法.LR分析:特征:规范的符号栈中的符号是规范句型的前缀,且不含句柄以后的任何符号(活前缀)分析决策依据:栈顶状态和现行输入符号.• 四种技术 LR(0) SLR(1) LR(1) LALR(1)6.2 LR(0) 分析LR(0)文法--------能力最弱,理论上最重要:存在FA 识别活前缀识别活前缀的DFA 如何构造(LR(0)项目集规范族的构造)LR(0)分析表的构造一、可归约前缀和子前缀最右推导过程(每条产生式尾部加上编号)S ⇒aAcBe[1] ⇒aAcd[4]e[1] ⇒aAb[3]cd[4]e[1]⇒ab[2]b[3]cd[4]e[1]归约时在栈里的句型的前缀 归约前可在栈里的规范句型(不含句柄) 的前缀 ab[2] aaAb[3] a,aAaAcd[4] a,aA,aAcaAcBe[1] a,aA,aAc,aAcB可归约前 子前缀活前缀(viable prefixes )G=(Vn,Vt,P,S),若有S’ ⇒ αA ω ⇒ αβω,γ是αβ的前缀,则称是文法G 的活 前缀. 其中S’是对原文法扩充(S’→S)增加的非终结符.? 为使S’不出现在任何产生式的右部.活前缀是规范句型(右句型)的前缀,但不超过句柄移进归约分析的栈中出现的内容加上余留输入构成规范句型二、识别活前缀的FA启示:可以把非终结符号和终结符号都看成一个FA 的输入符号,每把一个符号 进栈时看成已识别过了该符号,而状态进行转换,当识别到可归约前缀 时,相当于在栈顶形成了句柄,则认为达到了识别句柄的终态。
编译原理第6章_1
STACK REMAINING INPUT
1
(int + int)#
2(
int + int)#
3 (int
+ int)#
4 (T
+ int)#
5 (E
+ int)#
6 (E +
int)#
7 (E + int
)#
8 (E + T
)#
9 (E
)#
10 (E)
#
11 T
#
12 E
#
13 S
#
PARSER ACTION Shift Shift Reduce: T –> int Reduce: E –> T Shift Shift Reduce: T –> int Reduce: E –> E + T Shift Reduce: T –> (E) Reduce: E –> T Reduce: S –> E
的左部而得到的
文法要求
shift-reduce or reduce-reduce 冲突(conflicts)
分析程序不能决定是shift 还是 reduce 或者分析程序归约时有多个产生式可选
例子 (dangling else) : S –> if E then S | if E then S else S
LR分析算法
then begin pop || 项 令当前栈顶状态为S’ push GOTO[S’, A]和A(进栈)
end else if ACTION[s,a]=acc
then return (成功) else error end
编译原理---第6章
——
1
《编译原理》
第6章 语法制导翻译 与属性文法
语法制导翻译概述 属性文法
综合属性与继承属性 S_属性文法 L_属性文法
翻译模式
国家精品课程
——
2
《编译原理》
6.1 语法制导翻译概述
语法制导翻译的概念描述
在进行语法分析的同时,完成相应的语义处理 E→E1 + E2 E.val:=E1.val+E2.val
T → int
T → real
L → L1,id
L → id
1. 纪录标识符的类型 2. 类型信息传递
方法:用T.type记录类
型信息,并传给L.in
国家精品课程
——
15
《编译原理》
例6-2 说明语句的属性文法
D→TL
T → int T → real L → L1,id L → id
digit.lexval=4
例6-4:real id1,id2,id3 的分析树和属性计算
D T .type=real L .in=real D → T { L.in := T.type } L T → int { T.type := integer } T → real { T.type := real }
这种属性叫做继承(Inherited)属性
国家精品课程
——
21
《编译原理》
3. 属性分类——固有属性
语言中的标识符、常数(数值的、符号的) 、常量,它们的属性是用户给定的、固有不 变的
T → int T.type := „integer‟
固有(Inherent)属性(单词属性) 归类于综合属性
编译原理精选版演示课件.ppt
预测分析表
3
表驱动的预测分析程序模型
khk
4
实现步骤:
(1) 判断文法是否为LL(1)文法。 如果文法中含有左递归,必须先消除 左递归
(2)构造预测分析表 : Select(A ) (3)列出预测分析过程
khk
5
第6章:自底向上分析方法
自底向上分析方法,也称移进归约分析法
实现思想(是推导的逆过程):
对输入符号串自左向右进行扫描,并将输入符逐个 移入一个后进先出栈中,边移入边分析,一旦栈顶 符号串形成某个句型的可归约串时,就用该产生式 的左部非终结符代替相应右部的文法符号串,称为 归约。重复这一过程,直到归约到栈中只剩下文法 的开始符号时,则分析成功。
关键问题
khk
6
移进—规约分析(Shift-reduce parsing)
+
A a
可得 b <. a
由A→( B 且B+ ( B… 可得 (<. (
+
B aa…
可得 (<. a
+
B Aa )
可得 (<. A
khk
18
A(B(Aa) …)
(3) 求> .关系:
A(B…B
+
Aa
由S→bAb,且A…) 可得 ) > . b
A+…B 可得 B > . b
khk
88
例1:文法
SaAcBe A b A Ab B d
输入串abbcde#分析
khk
9
归约分析过程(移进归约):
步骤 1 2 3 4 5 6 7 8 9 10 1kh1k
符号栈 # #a #ab #aA #aAb #aA #aAc #aAcd #aAcB #aAcBe #S
ppt编译原理6章6
所以有两条向下的边分别进入结点7 和9。每一个 于L产生式有关的语义规则addtype(id.entry,L.in)都产 生一个虚属性,结点6、8和10都为这些虚属性构造的。
如果一属性文法不存在属性之间的循环依赖关系, 那么该文法为良定义的。为了设计编译程序,我们只 处理良定义的属性文法。
属性的计算次序 一个有向非循环图的拓扑序是图中结点的任何顺序 m1,m2, …mk,使得边必须是从序列中前面的结点指向 后面的结点。也就是说,如果mimj是mi到mj的一条 边,那么在序列中mi必须出现在mj之前。 一个依赖图的任何拓扑排序都给出一个语法树中结 点的语义规则计算的有效顺序。这就是说,在拓扑排 序中,在一个结点上,语义规则b:=f(c1,c2,…ck)中的 属性c1,c2…ck在计算b以前都是可用的。 6.2.2树遍历的属性计算方法 通过树遍历计算属性值得方法很多种。这些方法都 假设语法树已经建立起了,并且树中已带有开始符号 的继承属性和终结符的综合属性。然后以某种次序遍 历语法树,直至计算出所有的属性。最常用的遍历方 法是深度优先,从左到右的遍历方法。
抽象语法树中的每一个结点可以由包含 几个域的记录来实现的. 在一个运算符号对 应的结点中,一个域标识运算符号,其它域包 含指向运算分量的结点的指针。运算符号通 常叫做这个结点的标号。当我们进行翻译时, 抽象语法树中的结点可能会用附加域来存放 结点的属性值(或指向属性的指针)。 6.3 S—属性文法的自下而上计算 这一节我们考虑这样一类属性文法:S— 属性文法,它只含有综合属性。 top 下面我们讨论分析栈中的综合属性。 在自底向上的分析法中。我们使用一个栈来 存放已经分析过的子树的信息。现在我们可 以在分析栈中使用一个附域来存放综合属性 值。图6.9表示的是一个带有一个属性值空间 的分析栈的例子。
编译原理ppt6_2
m r p(1,9)
虚线表示连接的 节点的活动已经 执行完毕
q(1,9) q(1,3)
实线表示连接的节 点的活动没有执行 完毕,需要在控制 栈中保存此活动的 信息
p(1,3) q(1,0) q(2,3)
m r p(1,9) q(1,9) q(1,3)
m a : array
r q(1,9) i:integer i:integer p(1,9) q(1,3)
program sort(input, output); var a: array [0..10] of integer; procedure readarray; var i: integer; begin for i :=1 to 9 do read(a[i]) end; function partition(y,z:integer) :integer; var i,j,x,v:integer; begin ... end; procedure quicksort(m,n:integer); var i: integer; begin if (n>m) then begin i:=partition(m,n); quicksort(m,i-1); quicksort(i+1,n) end end; begin a[0]:=-9999; a[10]:=9999; readarray; quicksort(1,9) end.
m r p(1,9) q(1,9) q(1,3) q(5,9) p(5,9) q(5,5) q(7,9) p(7,9) q(7,7) q(9,9)
p(1,3) q(1,0) q(2,3)
p(2,3) q(2,1) q(3,3)
控制栈
程序的控制流对应于从活动树根节点开始的深 度优先遍历 用控制栈保存活跃的过程活动。基本思想是: 基本思想是: 基本思想是 当活动开始时,把这个活动的节点压入控制栈; 当活动开始时,把这个活动的节点压入控制栈; 当这个活动结束时, 当这个活动结束时,弹出这个节点 控制栈的内容与到活动树的根节点的一条路径 相关。当节点n在控制栈的栈顶时,栈内包含 的是从节点n到根的路径上的节点
编译原理第6章LR分析讲述
活前缀与句柄关系的三种情况
若A-> α1α2
活前缀已含有句柄的全部符号表明产生式a的出现在栈顶活前缀只含句柄的一部分符号表明a推出的符号活前缀不含有句柄的任何符号此时期望a的右部所推出的符号串活前缀句柄已出现在栈顶期待从余留串中得到期望从余留串中得到某一产生式活前缀与句柄关系的三种情况加标志的产生式叫lr0项目
规范归约回顾
在自下而上的分析方法中,每一步都是从当前串中选择 一个子串,将它归约到某个非终结符号,该子串称为 “可归约串” 为此引入:短语、直接短语、句柄等概念 问题的关键:如何找句柄? ----从规范推导出发,探寻句柄的生成过程及时机。
S’
S
ab|bcde aAb|cde aAcd|e aAcBe|S| S’
a A
A
c b
B
e
A为当前句型(A)中 1. 定义: 最右边的非终结符
b * 是文法G的一个规范推导, 设有文法G[S],若S r A r
当前句型()的 文法G中有产 句柄是什么? 生式A;
若符号栈的内容,正好是当前句型的可归前缀,则栈顶肯定已 经形成一个句型的句柄。 2. 可归前缀之间的关系
通过文法已知的可归前缀, 可推出新的可归前缀
可归约前缀的推导:对任一文法,若xUy为可归前缀,且 文法中有产生式Uu,则xu也是文法的可归前缀。
ai ai+1 … am # Sn Xn
编译原理课件PPT 第6章
Chapter 6 Type Checking Section 2 Specification of a Simple Type Checker 3. Type Checking of Statements – S while E do S1 – {S.type= if (E.type==boolean) S1.type else type_error} – S S1;S2 – {S.type= if (S1.type==void) && (S2.type== void) void else type_error}
Chapter 6 Type Checking Section 3 Equivalence of type expressions s for type expression type link=^cell 3.Cycles in representations of types type link=^cell; cell=record info:integer; next :link end;
Chapter 6 Type Checking Section 2 Specification of a Simple Type Checker 1. A simple language 1)Grammar for source language – PD;E – DD;D | id:T – T char | integer | array [num] of T | ^T – E literal | num | id | E mod E | E[E] | E^
Chapter 6 Type Checking Section 2 Specification of a Simple Type Checker 2. Type Checking of Expressions – E E1[E2] – {E.type= if (E2.type==integer) && (E1.type==array(s,t) t else type_error} – E E1^ – {E.type= if (E1.type==pointer(t)) t else type_error}
编译原理课件
int a; Function f(int b) { int c; … } } void main() { a = 0; c = 0; f(3); 错误,超出了c 的作用域 正确,在a的 作用域内
6.1 局部存储分配策略
6.1.2 名字的作用域和绑定 名字的作用域
代 码 静态数据 堆
p的活动记录 main的活动记录
栈
6.1 局部存储分配策略
6.1.3 活动记录 一般的活动记录的布局 返 回 值 实在参数 控 制 链 访 问 链 机器状态 局部数据 临时数据
本过程返回给调用过程的值
调用过程传递给本过程的参数 指向调用过程的指针 用于引用存于其他活动记录的非局部数据 用于保存本过程调用前的机器状态 本过程内部定义的局部变量 临时变量,中间结果
衬垫空白区
c1c2
0 12 4
i
8
f 16
6.1 局部存储分配策略
6.1.5 程序块
语法如{声明 语句} 本身含有局部变量声明的语句,可以嵌 套 最接近的嵌套作用域规则
程序块B’中声明的作用域包括B 如果名字x没有在B中声明,那么B中x的出现 是在外围程序块B’的x声明的作用域中,且满 足
B’有x的声明 B’比其他任何包含x声明的程序块更接近被嵌套 的B { …int a; {….int b; B B1 a = 3; } B2 } {….int a }
6.2 全局存储分配策略
运行栈:把控制栈中的信息拓广到包括过程活 动所需的所有局部信息(即活动记录) s a : array r i: integer s
r
6.2 全局存储分配策略
运行栈:把控制栈中的信息拓广到包括过程活 动所需的所有局部信息(即活动记录) s a : array q (2, 3) k: integer s
《编译原理》第6章 (1)
…a
a >b
24
由定义直接构造:
预备知识:
定义两个集合:
+ + FIRSTVT(B)={b|B b…或B Cb…},
+ + LASTVT(B)={b|B …b或B …bC}
即最后一个终结符 即第一个终结符
25
三种优先关系的计算为: a)≡关系 条件:A…ab... A…aBb… b) <关系 条件:A…aB… bFIRSTVT(B) 结论:a<b c) >关系 条件:A…Bb… aLASTVT(B) 结论:a>b
20
定义:设G是不含产生式的算符文法,若G中任何两个终 结符号之间至多有一种优先关系存在,则G是一个算符 优先文法OPG。 注:不允许有ab、 a≡b、 ab 中的两种同时存在 要完成运算符间优先级的比较,最简单的办法是先定义 各种可能相继出现的运算符的优先级,并将其表示成矩 阵形式,即得到一个算符优先关系表。在分析过程中通 过查询矩阵元素而获得算符间的优先关系。
了解算符优先分析法的优缺点和实际应用中的局限性
2
【学习指南】
算符优先分析法是自下而上语法分析的一种,它的算
法简单、直观、易于理解,故通常作为学习其它自下 而上语法分析的基础。在学习前,应复习有关语法分 析的知识,如:什么是语言、文法、句子、句型、短 语、简单短语、句柄、最右推导、规范归约基本概念
S
A
A→Ab
最右推导 句型
abbcde
句柄 归约用规则 b A→b
S→aAcBe
aAbcde
Ab
d
A→Ab
B→d
A
A→b
B
B→d
aAcde
编译原理ppt6_1
6.1.3 活动记录
过程的一次执行所需要的信息用一块连续的存 储区来管理,这块存储区叫做活动记录或帧 对于Pascal或C语言,在过程被调用时把它的活 Pascal C 动记录压入到运行栈,在控制返回调用者时把 这个活动记录从栈中弹出
名字的绑定
即使每个名字在程序中只声明一次,同一个名 字在运行时也可能代表不同的数据对象。 数据对象指的是保存值的存储单元。 环境表示将名字映射到存储单元的函数 状态表示将存储单元映射到它所保存的值的函 数
环境
状态
名字
存储单元
值
如果环境把存储单元s与名字x联系起来, 则称x绑定到s,这个联系本身称为x的绑 定
影响存储分配策略的一些问题
过程能递归吗? 控制从过程的活动返回时,局部名字的值发生了怎样 的变化? 过程能引用非局部的名字吗? 过程被调用时是怎样传递参数的? 过程是否可以作为参数被传递? 过程能否作为结果被返回? 存储区能否在程序控制下动态地分配? 存储区是否必须显示地释放?
6.1 局部存储分配
返回值 实参 可选的控制链 可选的访问链 保存的机器状态 局部数据 临时数据 活动记录
用于存放被调用过程返回给调 用过程的值 用于存放调用过程提供 给被调用过程的参数 用来指向调用 者的活动记录 引用存于其他活动记录中 的非局部数据 保存过程调用前的机 器状态信息 保存局部于过 程执行的数据 计算表达式时 出现的临时值
6.1.4 局部数据的安排
局部数据域在编译过程中的声明中分配,长度 可变的数据保存在这个域之外 局部变量的相对地址:相对于活动记录的开始 点的相对地址 数据对象的存储布局受目标机器的寻址约束的 影响(对齐)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
类型表达式的图表示不同——叶结点为
基本类型或类型名 递归定义类型会导致回路
6.3.1 类型表达式的结构等价
结构等价(structural equivalence)
1.
2.
相同的基本类型 对子表达式施加的类型构造符相同 两个类型表达式结构等价——dag中对应相 同结点 等价性检查算法稍做修改
第六章 类型检查
内容
类型系统
类型表达式的等价
类型转换
函数和运算符的重载
多态函数 一致化算法
静态检查(static checking)
1. 2.
类型检查(type check)
操作对象必须与操作符匹配:函数名相加×
break必须退出while、for、switch… 对象(变量、标号…)定义必须唯一 相同名字在不同位置
4.
可使用类型表达式变量
图表示类型表达式
(char×char)pointer(integer)
6.1.2 类型系统
type
system:规则的集合 规则——将类型表达式赋予程序的不同 部分 类型检查程序:实现一个类型系统 语法制导方式实现——嵌入语义规则
6.1.2静态/动态检查
5个变量类型是否都相同?——依赖实现 允许类型表达式命名,但不允许回路 名字等价:完全相同 结构等价:名字被替换后完全相同
例6.2
变量 next last p q r 类型表达式 link link pointer(cell) pointer(cell) pointer(cell)
名字等价:next,
例6.1(续)
构造符的编码 pointer array freturns 基本类型编码 boolean char integer real
01 10 11
0000 0001 0010 0011
例6.1(续)
编码方法
最右端四位二进制位表示基本类型 它前面两位表示第一个构造符 再前面两位表示第二个构造符 类型表达式 编码
静态——编译器进行
动态——运行时进行 可靠类型系统,强类型语言——编译器 无type_error运行时无类型错误 int a[10], i; b=a[i];——需动态检查 安全领域也涉及类型检查(缓冲溢出问 题)
6.1.4 错误恢中
…, Tn——T1×…×Tn 更复杂例子:root: (realreal)×realreal
function root(function f(real): real; x: real): real
6.3 类型表达式的等价
两个类型表达式等价的精确定义?
用类型表示方式可快速确定等价性
结构等价和名字等价
错误修正比描述正确程序更困难
根据错误的程序、处理缺失信息,来推测正
确类型在变量使用之前无需定义它 类型变量可用来处理这种问题
6.2 一个简单的类型检查器
6.2.1 一种简单语言
PD;E D D ; D | id : T T char | integer | array [ num ] of T | ^T E literal | num | id | E mod E | E [E] | E^
char freturns(char) pointer(freturns(char)) array(pointer(freturns(char)))
000000 0001 000011 0001 000111 0001 100111 0001
例6.1(续)
加速等价性检查
不同二进制串不可能表示相同类型
可添加其他类型和运算
6.2.3 语句的类型检查
赋值、条件、while 无错误,void;错误,type_error
S id := E
S if E then S1
S while E do S1
S S1 ; S2
{S.type = if (lookup(id.entry)==E.type) then void else type_error } {S.type = if (E.type == boolean) then S1.type else type_error } {S.type = if (E.type == boolean) then S1.type else type_error } {S.type = if (S1.type == void) and (S2.type == void) then void else type_error }
类型表达式(续)
d) 指针:T为类型表达式,则pointer(T)为类型表 达式,表示“指向类型为T的对象的指针”类 型 row *p;——pointer(row) e) 函数:数学上,一个集合“定义域”到另一个 集合“值域”的映射。程序语言,定义域类型 D到值域类型R的映射:DR。 %运算符——(int×int)int int *f(char a, char b);—— (char×char)pointer(integer) 不考虑函数返回数组、函数类型的情况 (integerinteger)(integerinteger)
6.2.4 函数的类型检查
函数定义
T T1„‟ T2
函数调用 E E1(E2) 多参数:T1,
{T.type = T1.typeT2.type }
{E.type = if (E2.type==s) and (E1.type==st) then t else type_error }
6.1.1 类型表达式
type expression——用以表示语言结构 的类型 基本类型或用类型构造符组合基本类型
1.
2.
基本类型:boolean, char, integer, real, type_error, void 类型名
类型表达式(续)
3.
类型构造符
a) 数组:T是类型表达式,I为索引集合(整数范 围),则array(I, T)是一个类型表达式,表示元 素为类型T的数组类型 int A[10];——array({0, …, 9}, integer) b) 笛卡儿积:T1、T2为类型表达式,则T1×T2为 类型表达式
有时要放松条件——数组参数忽略界限
等价性检查算法
bool sequiv(s, t) { if (s和t为相同基本类型) return true; else if (s == array(s1, s2) and t == array(t1, t2)) return sequiv(s1, t1) and sequiv(s2, t2); else if (s == s1×s2 and t = t1×t2) return sequiv(s1, t1) and sequiv(s2, t2); else if (s == pointer(s1) and t == pointer(t1)) return sequiv(s1, t1); else if (s == s1s2 and t == t1t2) return sequiv(s1, t1) and sequiv(s2, t2); else return false; }
控制流检查(flow-of-control check)
3.
4.
唯一性检查(uniqueness check)
名字关联检查(name-related check)
类型检查
检查语法结构的类型与上下文匹配
简单的类型检查 两个类型的匹配
代码生成要利用类型信息
重载,多态
6.1 类型系统
名字等价:next, last类型相同,q, r类型相同, p, next, q类型不同
例6.3(续)
实现方式——构造类型图
对基本类型和类型构造符——创建新结点 对新类型名——创建叶结点,保存与类型表达式的 链接
名字等价——相同结点
6.3.3 回路问题
链表、树:递归定义
实现:记录——数据、指向同一记录类
语法结构、类型、将类型赋予语法结构的规则
+, -, *的两个运算数均为整数,结果为整数 &的结果为指向操作对象的指针,若操作对象类型 为T,结果类型为“指向T的指针”
每个表达式都有一个相关联的类型 类型是有结构的!——指针 基本类型:语言内部支持类型 结构类型:组合基本类型构成新类型
翻译模式
PD;E {} DD;D {} D id : T { addtype(id.entry, T.type) } T char {T.type = char } T integer {T.type = integer } T array [ num ] of T {T.type=array(1..num.val,T.type)} T ^T {T.type = pointer(T.type) }
不同类型可能表示为相同二进制串——数组
界限、函数参数
记录的编码
在类型表达式中记录作为基本类型 用另一个二进制串编码它的域
6.3.2 名字等价
type link = ^cell; var next : link; last : link; p : ^cell; q, r : ^cell;
类型表达式(续)
c) 记录:与笛卡儿积的不同之处仅在于记录的域 有名字。<域名,域类型>元组 typedef struct { int address; char lexeme[15]; } row; row table[101]; 类型表达式为: record((address×integer)× (lexeme×array({0, …, 15}, char)))