语义分析包括哪方面的分析(语义分析包括哪方面的分析_语言学)

语义分析,是编译器前端的最后一个阶段。

所有没在语法分析中处理,而又在生成中间代码之前不得不做的事,都是在这个阶段处理的。

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张图:

语义分析包括哪方面的分析(语义分析包括哪方面的分析_语言学)

语义分析包括哪方面的分析(语义分析包括哪方面的分析_语言学)

    

使用无须实名的阿里云国际版,添加 微信:ksuyun  备注:快速云

本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 cloud@ksuyun.com 举报,一经查实,本站将立刻删除。
如若转载,请注明出处:https://www.hanjifoods.com/22961.html