实验内容
本阶段的内容是对pa1中生成的ast进行语义分析。
语义分析的目的是理解输入程序的含义,即弄清楚输入中所出现的每个标识符所指的内容以及明确输入中所出现的各种语句的含义,从而检查那些符合语法的程序可能出现的语义错误,以及提供信息以辅助中间代码生成。
对于标识符所指的内容,我们往往借助符号表来进行处理:随着语义分析过程的进行,当遇到符号定义的时候,我们需要往符号表中加入适当的记录信息;当遇到对符号的引用的时候,我们在符号表中查找这个符号的名字,并确定这个引用所指的是什么符号。对于语句的含义,我们需要根据语言规范中的规定对每一个语句或者表达式进行类型检查,看其是否符合语言的类型系统的要求,例如检查一个函数调用表达式的各个参数的类型是否符合函定义,并且推断出结果的类型用于上层的表达式的类型检查。
在具体实现中,我们把语义分析分为ast的两趟扫描进行:第一趟扫描的时候建立符号表的信息,并且检测符号声明冲突以及跟声明有关的符号引用问题;第二趟扫描的时候检查所有的语句以及表达式的参数的数据类型。目前的实现下,在第一趟扫描和第二趟扫描间插入了一次检查,如果已经发现错误的话就不进行第二趟扫描。除次之外,第一趟扫描内部也有一个检查点,即在类的继承关系检查完成后。这样做的考虑是,继承上出现的问题往往是比较严重的问题(因为继承一个类可能给作用于引入很多符号),所以一旦出现继承上的问题,也不再继续检查。
本阶段我们将借助ast结点的附加属性信息f进行语义分析。为了规避rust对于可变引用的许多限制,框架中ast节点的附加属性一般都用Cell
或者RefCell
包裹起来。这的确不是一种很优雅的方式,另一种可行的做法是保持ast节点的不可变性,在原始的ast节点定义中不包含这些附加属性,需要添加属性的时候就创建新ast节点。这有一点函数式编程的思想,不过在rust中这样实现会不可避免地需要更大的代码量和更大的运行时开销,为了简单起见我们还是使用前一种看起来比较丑陋,但是实现起来相对容易的方法。
实验框架中已经实现了decaf语言的基本语法的语义分析,大家的任务是实现新语法的语义分析,同时也有可能需要修改既有的实现。新语法的具体语义可以参考专门的文档。如果有什么特别需要注意的地方,之后会在这里补充。
从这开始之后的实验中,由于大家已经对框架有了一定的了解,而且文件本身的含义相比前面也更清晰一些,所以不会再提供文件结构和对应的文件用途了,大家需要自己观察需要修改的文件。
Last updated