语义分析- 其他问题
语义分析中要考虑的其他问题:
- 类型相容性?
- 错误诊断?
- 代码翻译?
1、类型相等
类型检查问题往往归结为判断两个类型是否相等t1 == t2?
在实际的语言中,这往往是个需要谨慎处理的复杂问题。
示例1:名字相等 VS 结构相等
对采用名字相等的语言,可直接比较
对采用结构相等的语言,需要递归比较各个域
struct A
{int i;
} x;struct B
{int i;
} y;x = y;
我们可以看到上述代码中,x与y的存储结构是一样的,都是一个4字节的整形域i(32位机器上),那么把y赋值给x这样的操作合法吗?
这个问题取决于研究的语言的语义,如果这个语言的语义采用的是名字相等的策略,那么这样的赋值就是非法的,因为y的类型名字是B,x的类型名字是A,类型名字是不一样的,所以这样的赋值是不能做的;但如果采用结构相等的语言,两侧同为结构体类型,我们需要看每个域,域的个数是不是一样,每个域是不是可以分别赋值,可能需要递归的来比较各个域。
示例2:面向对象的继承
需要维护类型间的继承关系
class A
{int i;
}class B extends A
{int i;
}A x;
B y;
x = y;
子类对象y赋给父类对象x,如果只看类型的话,y的类型是B,x的类型是A,也是不相等的,所以在面向对象语言中,为了这种类型检查可以通过,需要维护类型间的继承关系,在Java中,继承是一棵树状的关系,任何子类对象都可以赋给父类对象。面向对象中,子类到父类的转换称为向上转型。
2、错误诊断
(1)要给出尽可能准确的错误信息
(2)要给出尽可能多的错误信息
- 从错误中进行恢复
(3)要给出可能准确的出错位置
- 程序代码的位置信息要从前端保留并传递过来
3、代码翻译
现代的编译器中的语义分析模块,除了做语义分析外,还要负责生成中间代码或目标代码
代码生成的过程也同样是对树的某种遍历。
因此,语义分析模块往往是编译器中最庞大也最复杂的模块。