类型和声明

类型检查(Type checking)

利用一组规则来检查运算分量的类型运算符的预期类型是否匹配。

类型信息的用途:查错、确定名字(对应的数据)所需的内存空间、计算数组元素的地址、类型转换、选择正确的运算符。

类型

基本类型:程序设计语言中的原子类型,如boolean、char、integer、float、void等,通常这些类型的运算都有对应的机器指令

复合类型:由基本类型或其他复合类型复合而成,为语言提供更强的抽象和表达能力,如数组、结构体、函数等。

类型表达式(Type expression):表示类型的表达式,对于基本类型就是类型名字,对于复合类型是通过类型构建算子作用于类型表达式得到。

数组类型

表示同类型数据的聚合,类型构建算子array ,有两个参数:

  • 数组:表示数组的长度

  • 类型:表示数组元素的类型

int[2][3] 对应类型表达式array(2, array(3, integer))

记录类型

表示不同类型数据的聚合(结构体、类)。类型构造算子record ,有多组字段:

  • 字段名:可用于在记录中引用该字段

  • 类型:字段对应数据的类型

记录的基本构造算子是笛卡尔积

  • 如果s,t是类型表达式,那么笛卡尔积s x t也是类型表达式

  • 在记录类型的构造中起到组合作用组合字段名与相应类型组合多组字段

函数类型

类型构造算子->,接受参数类型返回值类型,并构造出函数类型。

类型等价性

判断两个类型是否等价,这是类型检查的基础,不同的语言有不同的类型等价的定义。当语言允许为自定义类型命名时,主要有两种等价性判定方式:

  1. 名等价:类型表达式t与u等价当且仅当它们对应的类型名字相同

  2. 结构等价:对于基本类型,比较它们名字是否相同;对于复合类型,比较类型构造算子,若相同则递归比较构造算子的各参数分量

类型的声明

处理基本类型、数组类型或记录类型的文法:

应用该文法及其对应的语法制导定义,除了得到类型表达式之外,还得进行各种类型的存储布局

局部变量的存储布局

变量的类型可以确定变量需要的内存,即类型的宽度(该类型一个对象所需的存储单元的数量),函数的局部变量总是分配在连续的区间,因此给每个变量分配一个相对于这个区间开始处的相对地址(偏移量)。变量的类型信息保存在符号表中

计算T的类型和宽度的SDT
实际的变量声明

声明序列的SDT

在处理一个过程/函数时,局部变量应该放到该过程/函数对应的符号表中。这些变量的内存布局独立,相对地址从0开始变量的放置和声明的顺序相同

SDT的处理方法:

  • 变量offset记录当前可用的相对地址

  • 每分配一个变量,offset增加相应的值(宽度)

top.put(id.lexeme,T.type,offset) top指向当前函数的符号表,在符号表中创建条目,记录标识符的类型和偏移量

记录和类中的字段

记录变量声明的翻译方案,约定:

  • 一个记录中各个字段的名字必须互不相同

  • 字段名的偏移量(相对地址),是相对于该记录的数据区字段而言的

记录类型使用一个专用的符号表,对其各个字段的类型和相对地址进行单独编码。

记录类型record(t) ,record是类型构造算子,t是符号表对象,保存该记录类型各个字段的信息。

Env环境

当程序中的作用域发生嵌套时,用一个栈Env辅助维护各作用域对应的符号表,栈中存储指向各符号表的指针。

  • 进入一个新作用域时,保存上一作用域(压栈)

  • 从一个作用域退出时,恢复上一作用域(出栈)

Last updated