为编译器实现类型检查。 在语法分析的基础上,对抽象语法树进行类型检查,并生成相关报错信息。
完成语法分析的基础上,还需: types.[ch]: 已给出,描述了tiger语言的数据类型 env.[ch]: 实现值环境、类型环境 semant.[ch]:实现类型检查函数SEM_transProg(A_exp exp) semtest.c: 测试平台,main入口 修改makefile
实现方法: 1. 类型检查过程中,遇到声明时,将其按规则检查并构造,放入相应值或类型环境中,遇到类型、变量或函数标示符时在这两个环境中查找。初始tenv中包含int、string两种基本类型,venv包含print,ord等预定义函数。 2. 表达式根据不同类型作相应处理,例如exp1:=exp2要保证exp1和exp2类型相同。特别声明了void类型用于匹配无值表达式,方便处理。 3. 作用域处理。可以通过在环境中插入一个标记实现。作用域开始,插入一个标记,作用域结束,弹出标记以上的所有新增声明或定义。
注意: 1. for、while、if-then等表达式无值返回,需要判断。 2. nil类型只能用于给记录(record)类型赋值或比较,两个nil比较非法。 3. tiger语言中定义的两个数组(array)或记录,即使各个域相同,也不具有等价性。
例如: type a = {x:int, y:int} type b = {x:int, y:int} a和b为两种类型,不能相互赋值。 而 name类型 type a = {x:int, y:int} type b =a a和b视为相同类型。 由此可以容易的实现类型比较,类型构建后都对应唯一的数据结构,只需比较两个非name类型的指针是否相等即可。 - 4. 递归类型和函数声明。 递归类型可以先向环境插入(type_id, Ty_Name(type_id, NULL))项,然后再构造相应结构,替换原来的NULL。递归函数声明类似。 5. 重声明。连续的递归声明中不允许出现重复声明,而其他情况下可以,后来声明会覆盖前面的。 6. break嵌套。用一全局变量loop保存循环嵌套层数,只要在循环中,break就合法。 7. 作用域。除let表达式,函数形参中存在声明,需要作用域规则,for中循环变量也是。 8. for中循环变量不能赋值(未实现,没想到代价比较小的方法)
代码实现: 点我
