所有没在语法分析中处理,而又在生成中间代码之前不得不做的事,都是在这个阶段处理的。
1,类型检查,
例如,if (1 = a) a++;
它的抽象语法树如下:
if语句的抽象语法树有2-3个子节点,第1个是条件表达式,第2个是条件TRUE时的主体部分,第3个是条件为FALSE时的else部分(可以省略)。
上图只有前2个部分。
在语义分析时,把if的这些子节点挨个遍历一遍就行。
遍历时要使用递归去处理子节点的子节点,如果有的话。
当处理到赋值运算符=时,就可以发现它的左值1是个常量(不能被赋值),就可以发现这个语法错误。
所以编程书上都是建议把数字写在==的前面[呲牙]就是因为编译器在语义分析时很容易发现这类错误。
如果把变量写在==前面,而又手一抖把==写成了=,那就变成了if (a = 1)了,这个条件相当于if (1)恒为TRUE。
费劲查了2个小时的BUG,结果发现我居然能把代码写成这样,真是尴尬的不要不要的[捂脸]
2,自动类型转换(auto type cast),也是在语义分析阶段处理的。
例如:
int a = 1;
double d = a + 0.5;
a = 1和d = a + 0.5是同一个顺序块里的2行代码。
d = a + 0.5,其中a的类型是int整数,0.5的类型是double常量,它们两个的类型并不一致,需要转换为同一个类型。
编程语言规定:当int和double进行运算的时候,需要把int转换为double,因为后者可以表达的数字范围比前者大,无论是从精度上还是大小上。
这里是一个自动类型转换,程序员几乎感觉不到,但编译器是要给抽象语法树添加上这个运算符的。
如上图,变量a与加号+之间多的那个cast::double,就是编译器自动添加的。
写在源代码里就是d = (double)a + 0.5;
在对上图的表达式进行语义分析的时候,编译器总是比较运算符两端的变量类型是否一致,并进行自动类型转换。
如果没法自动类型转换的话,就给程序员一个语法错误或警告的提示。
例如:T* p = malloc(sizeof(T));
在C++中因为类型检查太过严格,void*指针转换到T*时不能自动进行,就总是给提示error。
类型转换可以极大地减少运算时的操作数对的种类。
如果有N种变量类型,那么双目运算符面临的操作数对的种类就是N^2种,但类型转换之后就只剩下了N种。
这就是C语言之父设计出type cast的意义。
3,常量表达式的提前计算,
如果表达式里含有多个常量,就可以提前把它计算出来,以降低运行时的时间消耗。这个处理也是在语义分析阶段进行的。
4,运算符的重载,是在语义分析时处理的。
语义分析时,就可以确定运算符要处理的变量类型。如果至少其中一个是类对象的话,就可以把运算符改成对应的重载函数的调用。
这个处理步骤大概如下:
A,首先分析运算符的2个操作数的变量类型,
B,然后查找它们对应的类类型里是否有合适的重载函数,
C,然后修改抽象语法树,把乘法运算转换成函数调用,
D,如果有必要,对这两个实参进行类型转换。
5,函数调用链的处理,
在语义分析时,已经可以确定各个函数之间的调用关系了。
当函数调用链形成一个回路(环)时,说明存在递归调用。
函数调用链,在指针别名分析和自动内存管理时都是必须的。
6,全局变量、全局常量,
全局常量需要记录下来,最终写入.o文件的.rodata数据段。
全局变量需要计算出初始值来,最终写入.o文件的.data数据段。
在语义分析阶段,这两类数据已经都可以确定下来了。
struct dfa_module_t module_expr = {
.name = "expr",
.init_module = init_module_expr,
.init_syntax = init_syntax_expr,
};
这里的module_expr就是全局变量,它的名字字符串"expr"就是全局常量。
它的两个函数指针对应的函数init_module_expr()和init_syntax_expr(),也是“全局常量”。
当编译完成的时候,这两个函数的地址都是一个确定的无符号整数。
在语义分析阶段,并不能给出这3个全局常量的具体数值,但可以给出一个重定位符号,等待连接器处理。
抽象语法树(AST)是个多叉树,而且每个节点的叉数是不同的,每个节点的处理函数也是不同的,这就是语义。
语义分析的具体代码还是比较多的,scf编译器框架的语义分析包含2个主要文件:
scf_operator_handler_semantic.c,
scf_operator_handler_const.c,
大概4000行代码,它的主体是由各种语句类型的语义分析函数组成的数组。
具体的代码细节,就不再说了,有兴趣的可以去看看。
最后给个if语句的语义分析代码(它比较简单),如下2张图:
如若转载,请注明出处:https://www.hanjifoods.com/22961.html