编译原理 笔记 4
静态语义分析与中间代码生成
静态语义分析
本章可以对应实验中的:namer
与typer
静态语义检查指在编译期间所进行的语义检查,包括但不限于:
- 静态类型检查
- 符号的作用域分析
- 控制流检查
- 唯一性检查
- 符号的上下文相关性检查
类型检查
验证语言结构是否匹配上下文所期望的类型,实现某个类型系统,分为静态和动态两大类,
类型系统的严格定义较为复杂,在此不做赘述,可以简单理解为C语言等强类型语言中类型定义的部分
我们可以借助翻译模式来设计类型检查程序,将类型表达式作为属性值赋给程序的各个部分(如实验中的Expression
基类所拥有的type
成员),利用类型系统的给出的形式化定义来设计相应的翻译模式

当然,如果语法上有一些修改,那么相应的翻译模式也需要进行修改,例如如果规定break
和continue
只能出现在循环体内,则需要添加一个继承属性用来记录当前语句是在在循环内
作用域分析
- 静态作用域:通过符号表来实现
- 动态作用域:通过运行时活动记录实现,下一讲会详细介绍
中间代码生成
本章可以对应实验中的:tacgen
及其相关部分
中间代码的作用是:
- 对源语言和目标语言进行语义上的过渡
- 有利于重定向和机器无关优化
在实验中,一共有AST和TAC两种中间代码,AST由yacc库生成,TAC由tacgen
包生成
详细的利用翻译模式重写python的结果参考pdf
- 对于数组类型,在处理的过程中通常会将其有关的信息记录在一些单元中,称之为数组的内情向量,例如数组的维度、每一维的大小等等
- 对于布尔表达式,我们可以直接使用bool值进行计算,也可以通过转移到程序中的位置来表示表达式的求值结果
,也即E = (a < b) or ((c < d) and (e < f))
类似:
1 | if (a < b) goto E.true |

同理,我们可以将tacgen
中生成条件语句的代码也写成类似的形式,详细写法参考ppt
拉链与代码回填
显然,上面的翻译模式是L-翻译模式,那如果我们希望使用S-翻译模式甚至S-属性文法是否可以做到呢
我们定义真链与假链,分别代表当布尔表达式为真/假时,需要跳转到的标号,这样我们在处理布尔表达式的时候只需要维护着两条链

通过这两条链,我们可以将条件语句、循环语句等写成S-翻译模式,如:

但是在上述的布尔表达式中,我们可以看出其实生成的goto语句是不完整的,这是因为我们在利用综合属性处理布尔表达式的时候,我们没有办法得知当这个式子为真/假的时候究竟要跳到哪里,也即我们不知道E.true
和E.false
所代表的具体标号,而这个过程需要通过backpatch(p, i)
函数完成,这个函数会将链p
中每一条跳转语句的目的标号置为i
我认为,这个通常用于处理布尔表达式用于跳转的情况,例如if(a) {} else {}
,但是这个正好是布尔表达式最常用的情况