类型和声明
类型检查(Type checking)
利用一组规则来检查运算分量的类型和运算符的预期类型是否匹配。
类型信息的用途:查错、确定名字(对应的数据)所需的内存空间、计算数组元素的地址、类型转换、选择正确的运算符。
类型
基本类型:程序设计语言中的原子类型,如boolean、char、integer、float、void等,通常这些类型的运算都有对应的机器指令。
复合类型:由基本类型或其他复合类型复合而成,为语言提供更强的抽象和表达能力,如数组、结构体、函数等。
类型表达式(Type expression):表示类型的表达式,对于基本类型就是类型名字,对于复合类型是通过类型构建算子作用于类型表达式得到。
数组类型
表示同类型数据的聚合,类型构建算子array
,有两个参数:
数组:表示数组的长度
类型:表示数组元素的类型
如int[2][3]
对应类型表达式array(2, array(3, integer))
记录类型
表示不同类型数据的聚合(结构体、类)。类型构造算子record
,有多组字段:
字段名:可用于在记录中引用该字段
类型:字段对应数据的类型
记录的基本构造算子是笛卡尔积:
如果s,t是类型表达式,那么笛卡尔积s x t也是类型表达式
在记录类型的构造中起到组合作用,组合字段名与相应类型,组合多组字段
函数类型
类型构造算子->,接受参数类型与返回值类型,并构造出函数类型。
类型等价性
判断两个类型是否等价,这是类型检查的基础,不同的语言有不同的类型等价的定义。当语言允许为自定义类型命名时,主要有两种等价性判定方式:
名等价:类型表达式t与u等价当且仅当它们对应的类型名字相同
结构等价:对于基本类型,比较它们名字是否相同;对于复合类型,比较类型构造算子,若相同则递归比较构造算子的各参数分量。
类型的声明
处理基本类型、数组类型或记录类型的文法:
应用该文法及其对应的语法制导定义,除了得到类型表达式之外,还得进行各种类型的存储布局。
局部变量的存储布局
变量的类型可以确定变量需要的内存,即类型的宽度(该类型一个对象所需的存储单元的数量),函数的局部变量总是分配在连续的区间,因此给每个变量分配一个相对于这个区间开始处的相对地址(偏移量)。变量的类型信息保存在符号表中。
声明序列的SDT
在处理一个过程/函数时,局部变量应该放到该过程/函数对应的符号表中。这些变量的内存布局独立,相对地址从0开始,变量的放置和声明的顺序相同。
SDT的处理方法:
变量offset记录当前可用的相对地址
每分配一个变量,offset增加相应的值(宽度)
top.put(id.lexeme,T.type,offset)
top指向当前函数的符号表,在符号表中创建条目,记录标识符的类型和偏移量。
记录和类中的字段
记录变量声明的翻译方案,约定:
一个记录中各个字段的名字必须互不相同
字段名的偏移量(相对地址),是相对于该记录的数据区字段而言的
记录类型使用一个专用的符号表,对其各个字段的类型和相对地址进行单独编码。
记录类型record(t)
,record是类型构造算子,t是符号表对象,保存该记录类型各个字段的信息。
Env环境
当程序中的作用域发生嵌套时,用一个栈Env辅助维护各作用域对应的符号表,栈中存储指向各符号表的指针。
进入一个新作用域时,保存上一作用域(压栈)
从一个作用域退出时,恢复上一作用域(出栈)
Last updated