《编译原理》第6章 类型检查
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
char
类型表达式的表达方法
2.位串(对类型表达式作某些限制) 例如,考虑由POINTER、→和ARRAY 作为构造符 的类型表达式。pointer(t)表示指向类型为t的指针, freturns(t)表示若干变元的函数,其中t为函数返回 对象的类型,而函数变元的类型则存放在其它地方。 ARRAY(t) 表示元素类型为t的数组,而数组元素的 个数保存在其它地方。这样,构造符都成为一元算 符,它们作用于基本类型形成的类型表达式有非常 统一的结构。
类型构造符 编码
pointer 01 array 10 freturns 11
基本 类型 编码
boolean 0000 integer 0010 char real 0001 0011
类型 表达式
编码
char 000000 0001 freturns(char) 000011 0001 pointer(freturns(char)) 000111 0001 array(pointer(freturns(char))) 100111 0001
图6-4 建立变量标识符和类型属性绑定 的翻译模式
6.2.2 类型检查
类型检查可以分为动态和静态两种。 动态检查在运行时刻完成。功效很低。但是如果语言 允许动态确定类型,动态检查是必须的。 静态检查在编译时刻完成。静态检查是高效的。 如果一个语言能够保证经过静态检查之后,程序没有运 行时刻的类型错误,则称为强类型的。 类型检查的内容包括: 表达式 语句 函数
语义分析
类型检查
验证程序中执行的每个操作是否遵守语言的类型系统的过程,编译程序必 须报告不符合类型系统的信息。 控制流语句必须使控制转移到合法的地方。例如,在C语言中break语句使 控制跳离包括该语句的最小while、for或switch语句。如果不存在包括它 的这样的语句,则就报错。 在很多场合要求对象只能被定义一次。例如Pascal语言规定同一标识符在 一个分程序中只能被说明一次,同一case语句的标号不能相同,枚举类型 的元素不能重复出现等等。 有时,同一名字必须出现两次或多次。例如,Ada语言程序中,循环或程 序块可以有一个名字,出现在这些结构的开头和结尾,编译程序必须检查 这两个地方用的名字是相同的。
6.1.2 类型表达式的等价
根据语言的类型体制和类型表达式的表示方法,分结构等 价和名字等价。 结构等价 两个类型表达式结构等价,当且仅当它们完全相同。图 6-6是测试两个类型表达式结构等价的算法,假设类型构造 符仅有数组、笛卡儿积、指针和函数,这个算法递归地比较 两个类型表达式的结构。 FUNCTION eq(s,t):boolean; BEGIN IF s 和 t 是相同的基本类型 THEN return(true)
例
例1 设有下面的函数定义 FUNCTION f(P1:T1;P2:T2;…,Pn:Tn):T; BEGIN ……END; 和f绑定的类型表达式 T1T2 … Tn→T 例2 在函数式语言中可如下定义恒等函数 fun f(x)=x x可以是任何类型的语言结构。因此x可以是任 何类型。f的类型表达式为
为类型变量,其值是任何类型表达式。
类型表达式的表达方法
1.树:内部结点是类型构造符,叶结点是基本类型, 类型名或类型变量。例如, FUNCTION f (a,b:char):integer: ……… charcharpointer(integer)
pointer char integer
用图表示类型表达式
node=record node=record
info integer info integer next pointer next pointer a. 无环 node b. 有环
C语言对除记录(结构)以外的所有类型使用结构等价, 而记录类型用的是名字等价,以避免类型图中的环。
例
设有Pascal 程序片段: TYPE stype=RECORD name:ARRAY [1..8] OF char; score:integer END; VAR table:ARRAY [1..50] OF stype; p: ↑stype; 则stype代表的类型表达式 RECORD((nameARRAY(1..8,char)) (score integer)) 和table绑定的类型表达式 ARRAY(1..50,stype) 和p绑定的类型表达式 POINTER(stype)
6.1 类型表达式
6.1.1 类型表达式定义 语言结构的类型由类型表达式表示,类型表达 式依赖于程序语言的类型体制。类型表达式或者是 简单类型表达式,或者是构造符作用在类型表达式 上得到的类型表达式。类型表达式的定义如下: (1) 类型名和基本类型是类型表达式。integer、 char、real、boolean是基本类型,所以它们是类 型表达式。另外,void表示“无类型”, type_error表示“出错类型”,它们也是类型表达 式。
Token 流
6 类型分析
每个程序设计语言都有自己的类型机制,包括类 型说明和使用。 类型分析是编译器语义分析的重要组成部分 。 编译器首先根据类型说明,确定每一个变量和常量 的类型 ,计算其使用存储空间的大小,从而建立其 到存储空间的映射。进而,编译器要确定每个语言 结构的类型,以完成下面的主要任务: (1) 判定重载算符(函数)在程序中代表的是哪 一个运算;(2) 进行类型转换;(3) 对语言结 构进行类型检查。
类型表示中的环
链表和树结构经常是递归定义的。它们的结点通常 定义成一个记录,记录中含有指向同类型记录的指 针。 设链表中的结点含有一个整型信息和一个指向下 一个结点的指针,实现链表的类型定义: TYPE link=node; node=RECORD info:integer; next: link END;
cell = record
:
:
info integer next pointer cell
6.2 类型分析
6.2.1 变量标识符和类型表达式的绑定 程序说明部分建立计算环境, 其中说明了每个变 量标识符以及与之绑定的类型。语法(6-3)是一个 简单的程序语言语法,该程序由一系列声明D和随 后的一个表达式E组成,假设数组的下标从1开始。 文法G[P],产生式如下: (6-3) P→D;E D→D;D|id:T T→char| integer| ARRAY[num] OF T|↑T E→num |id| E MOD E| E[E]| E↑
ELSE IF (s=ARRAY(s1,s2)) and (t=ARRAY(t1,t2)) THEN return(eq(s1,t1) and eq(s2,t2)) ELSE IF (s=s1s2) and (t=t1t2) THEN return(eq(s1,t1) and (eq(s2,t2)) ELSE IF (s=POINTER(s 1)) and (t=POINTER(t1)) THEN return(eq(s1,t1)) ELSE IF (s=s1→s2) and (t=t1→t2) THEN return(eq(s1,t1) and eq(s2,t2)) ELSE return(false) END
控制流检查
一致性检查
相关名字检查
名字的作用域分析
第六章 类 型 检 查
本章内容
静态检查中最典型的部分 — 类型检查: 类型系统、类型检查、多态函数、重载。 忽略其它的静态检查:控制流检查、唯一性 检查 、相关名字检查。
语法分析器 语法 树 类型检查 器Fra Baidu bibliotek语法 树 中间代码生 成器 中间 表示
6.1 类型表达式
(2)类型构造符作用于类型表达式的结果 仍然是类型表达式。类型构造符包括: (a)数组构造符ARRAY:若T是类型表达 式,则ARRAY(I,T)是类型表达式。 (b)笛卡儿乘积:若T1、T2是类型表达 式,则T1 T2是类型表达式,且是左结合的。 (c)记录类型构造符RECORD:若有标识符N1、 N2……、Nn与类型表达式T1、T2、…、Tn, 则 RECORD((N1 T1) (N2 T2) … (Nn Tn))是一个类型表达式,它表示一个记录类型。
语义分析程序首先处理类型说明,建立类型 表达式,然后处理变量说明,建立变量和类型 表达式的绑定。具体实现是把变量标识符的类 型信息记录在其符号表的表项中,过程 addtype(id.entry,T.type)完成这个任务,其 翻译模式由图6-4给出
P→D;E D→D;D D→id:T {addtype(id.enery,T.TYPE)} T→char {T.type:=char} T→integer {T.type:=integer} T→↑T1 {T.type:=POINTER(T1.type)} T→ARRAY[num] OF T1 {T.type:=ARRAY(num.val,T1.type)}
不同的语言中,通过声明将变量标识符和类型相联 系的规则是不同的,在解释这些规则时,结构等价 和名字等价是两个有用的概念。 例6.3 在一些Pascal的实现中,用隐含的类型名和 每个声明的变量标识符相联系,如果说明中出现没 有名字的类型表达式,就建立一个隐含的类型名。 如(6-2)中的声明是如下处理的: TYPE VAR Link=↑cell; next : link; np=↑cell; last : link; nqr=↑cell; p : np; q : nqr; r : nqr;
类型表达式中的名字
类型可以命名。例如,
TYPE Link=↑cell; VAR next: Link; Last: Link; P: ↑cell; q,r: ↑cell; (6-2)
所谓名字等价,是指两个等价类型有同一个名字,也 就是说,两个不同的类型名表示不同的类型。在结构等 价中,把类型表达式中的所有名字用它们所代表的类型 表达式替换后,两个类型表达式等价即是结构等价。
表达式的类型检查
检查运算对象之间的类型是否满足相容条件,函数 lookup(e)取符号表中保存在条目e中的类型。
E→num {E.type:=integer} E→id {E.type:=lookup(id.entry)} E→E1 MOD E2 {E.type:= IF (E1.type=integer)AND(E2.type=integer) THEN integer ELSE type_error} E→E1[E2] {E.type:= IF(E2.type=integer)AND(E1.type=ARRAY(s,t)) THEN t ELSE type_error } E→E1↑ {E.type:=IF E1.type=POINTER(t) THEN t ELSE type_error} 表达式的类型检查的翻译模式
例6.2 下面给出和声明(6-2)中的5个变量相 联系的类型表达式。 变量 类 型表 达 式
next last p q r Link Link Pointer(cell) Pointer(cell) Pointer(cell)
在名字等价下,变量next和last有同样的类 型; next和p的类型不相同。在结构等价下, 所有五个变量都有同样的类型。
典型的实现是构造一张类型图,每当遇到类 型构造符和基本类型,就建立一个新结点,但 要记住类型名所命名的类型表达式。在这种方 法中,如果两个类型表达式用类型图中同样的 结点表示,那么,它们等价。
next last p q r pointer
link = pointer pointer cell
图6-7
6.1 类型表达式
(d)指针类型构造符POINTER:若T是类型表达式, 则POINTER(T)是类型表达式,它表示一个指针类 型。 (e)函数类型构造符→:若D1、D2、…、Dn和R是 类型表达式,则D1D2 …… Dn→R是类型表达式, 其中优先于→,它表示从定义域类型D1 D2 … Dn到值域类型R的映射。 (3) 类型表达式中可出现类型变量,变量是类 型表达式。