C编译器剖析_4.4 语义检查_外部声明_临门一脚

4.4.5  对外部声明进行语义检查的临门一脚

         在前面几小节的基础上,我们基本上已经把球从后场带到对方球门前了,就差临门一脚了。在这一节中,我们来分析一下对全局变量进行语义检查的函数CheckGlobalDeclaration,和对函数定义进行语义检查的函数CheckFunction。对全局变量进行检查的主要代码如图4.4.23所示,我们省略了一些细节。图4.4.23第7行的CheckDeclarationSpecifiers、第22行的CheckDeclarator和第24行的DeriveType正是我们构建类型结构的三部曲,第31行调用LookupID函数查询符号表,如果是第一次遇到此全局变量,我们就会在第32行调用AddVariable将其加入到符号表中。如果是带初值的全局变量,则在第36行调用CheckInitializer函数来对初值进行检查;由于全局变量的初值必须是常量,我们还需要在第37行调用CheckInitConstant函数来处理。第39至44行的代码用于处理我们在上一节介绍的“内部连接”和“外部连接”,sclass为0表示外部声明中没有static也没有extern,sclass为TK_EXTERN表示带有extern,sclass为TK_STATIC则表示带有static关键字。由于可能存在多个重名的外部声明,我们会在第46行调用IsCompatibleType来检查一下同名的类型是否相容,在相容的情况下,会在第50行调用CompositeType函数进行类型合成。第52至59行用于检查是否全局变量的重复定义,第56行在全局变量对应的符号中保存“由若干个struct  initData对象构成的链表”,其中包含了用于初始化全局变量的各个初值。图4.4.23中所涉及到的各个函数,我们都已在前文分析过。这是我们在本节中的第一脚射门,在中场和后场组织好的前锋下,前锋这临门一脚就轻松多了。


图4.4.23 CheckGlobalDeclaration()

         另一脚射门是关于函数定义的,如图4.4.24所示。第10行、第14行和第16行的函数调用仍然是构建类型结构的三部曲,第22行查符号表,如果是第一次遇到此函数,则在第25行调用AddFunction函数来把函数相关信息加入到符号表;如果之前把此标识符声明为其他类型,则在第27行报错。如果之前已经对此函数名作过声明,则我们在第35行调用IsCompatibleType来检查一下两次声明的类型是否相容,如果相容,则在第39行调用CompositeType函数进行类型合成。第46行创建的向量loops存放循环语句,第47行的向量breakable用于存放循环语句和switch语句,而第48行的向量swtches用于存放switch语句,我们在对语句进行语义检查时使用过这些向量。由于函数的形参和局部变量要处在同一个作用域中,第51行调用的RestoreParameterListTable函数用于恢复“我们在第14行调用CheckDeclarator函数对形参的类型进行分析时,通过SaveParameterListTable函数所保存的符号表”,第53行至57行将各个形参加入到此符号表中。而第61行调用的CheckCompoundStatement函数则用于对函数体进行语义检查,C语言的函数体实际上就是一个复合语句。第62行则调用ExitScope退出当前作用域。


图4.4.24 CheckFunction()

         而用于对局部变量声明进行语义检查的函数CheckLocalDeclaration,与图4.4.23中的CheckGlobalDeclaration()有很多相似的地方,较大的不同在于局部变量的初值不一定非得是常量,因此我们在调用CheckInitializer函数检查完初值后,不再需要调用CheckInitConstant。只有对函数体内出现的static变量,我们才需要调用CheckInitConstant来检查其初值是否为常量。另一个较大的区别是,函数体中出现的局部变量是“No  Linkage”,同一作用域中不可以出现同名的局部变量,因此也就不需要调用CompositeType函数进行相容类型的类型合成。

         至此,我们完成了语义检查,UCC编译器可把语义检查后得到的语法树打印出来,这个工作由ucl\dumpast.c中的DumpTranslationUnit函数来完成,相关代码并不太复杂,我们就从略。在下一章中,我们准备开始讨论中间代码生成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值