语义分析和中间代码生成
1、概述
1、和语法分析、词法分析的同时进行进行词法检查、语法检查一样,语义分析也伴随语义检查。
- 动态语义检查需要生成相应的目标代码,它是在运行时进行的。
- 静态语义检查是在编译时完成的,主要涉及类型检查(与参与运算的操作数类型相容)、控制流检查(保证控制语句有合法的转向点)、一致性检查(如图标识符在同作用域只说明一次,case语句标号不能同等)(语义是上下文有关的,故形式化困难,目前用属性文法和语法制导翻译)
2、语法制导翻译:为每个产生式配上一个翻译子程序,并在语法分析同时执行这些子程序。
- 自底向上语法制导翻译:(规约时调用翻译子程序,每个产生式语义子程序执行之后,某些结果必须作为产生式左部符号语义值暂时保存下来),原LR分析栈扩充一项为语义值。
- 可以轻易画出语法树,但是语义分析和计算过程不太会
2、属性文法
1、文法符号的属性:(可以根据语法树找,注意复习)
- 继承属性 :从上向下传递,由父节点属性计算得到,由根节点到分支子结点,反映对上下文依赖的特性。(方便地表示程序上下文结构关系)
- 综合属性 :自底向下传递,由子节点属性计算得到,传递方向与综合属性相反。
3、常见的中间语言
1、抽象语法树
- 叶节点表示诸如常量或变量这样的运算对象,其它内部节点表示运算符
-
语法规则中非本质部分去掉,得到抽象语法规则,举例如下。
2、逆波兰表示法
-
表达式的逆波兰表示:书106
-
程序语句的逆波兰表示:
- 赋值语句:x=a+b*c 逆波兰:xabc*+= (左部,表达式,=)
- GOTO语句:GOTO<语句标号> <语句标号>BL
- 条件语句:<顺序号>BR表示无条件转移到BR,BT和BF则是条件e真或假转移到顺序号。<布尔表达式e的逆波兰式><顺序号>BT
- 循环语句:转换为条件语句
练习:
3、 三地址代码:三地址代码是中间代码的一种抽象形式。通常有四元式、三元式和间接三元式三种表示方法。(三地址代码通常包含三个地址,两个存运算对象,一个存运算结果)
- 四元式:(op,arg1,arg2,result),op是运算符,arg和result是指针,可以空缺,单变量只用arg1。
常用:
- 三元式:(op,arg1,arg2)没有结果地址,三元式标号代表结果地址
- 间接三元式:只记录不同的三元式,运算顺序用间接码表表示
举例:
4、表达式及赋值语句的翻译
- 为了实现由表达式到四元式的翻译,需要给文法加上语义子程序,以便在规约的同时执行对应的语义子程序,语义子程序所涉及的语义变量、语义函数说明如下:
- 非终结符E.place表示存放E值的变量名在符号表中的入口地址或临时变量名的整数码。
- 语义函数newtemp(),调用后回送一个代表新临时变量的整数码,临时变量名按顺序可设为T1、T2......
- emit(op,arg1,arg2,result)产生四元式并填入四元式表中。
- 定义lookup(i.name)是审查i.name是否出现在符号表中,是返回i.name在符号表中的入口指针,否则返回NULL
一套语义翻译:
注意语义栈与规约同步,状态栈转换斜对角法
最后再进行手写演算
- 布尔表达式的翻译
- 布尔表达式一般由运算符与运算对象组成,运算符为布尔运算符,(非,与,或)。运算对象也可以为布尔变量,也可为常量或关系表达式。关系表达式的运算对象为算术表达式
- 确定一个表达式的真假出口:
-
例子:
-
自己试试:
-
尝试理解: