语义分析

语义,就是程序要表达的意思。

语义规则可以分为两大类。

第一类规则与上下文有关。因为我们说了,语法分析只能处理与上下文无关的工作。而与上下文有关的工作呢,自然就放到了语义分析阶段。

第二类规则与类型有关。在计算机语言中,类型是语义的重要载体。所以,语义分析阶段要处理与类型有关的工作。比如,声明新类型、类型检查、类型推断等。在做类型分析的时候,我们会用到一个工具,就是属性计算。

某些与类型有关的处理工作,还必须到运行期才能去做。比如,在多态的情况,调用一个方法时,到底要采用哪个子类的实现,只有在运行时才会知道。这叫做动态绑定。

在语义分析过程中,会使用两个数据结构。一个还是 AST,但我们会把语义分析时获得的一些信息标注在 AST 上,形成带有标注的 AST。另一个是符号表,用来记录程序中声明的各种标识符,并用于后续各个编译阶段。

 

控制流检查、闭包分析和引用消解,这些分析要结合上下文来进行。

而要正确地使用闭包,就必须在编译期知道哪些变量是自由变量。这里的自由变量是指在本函数外面定义的变量,但被这个函数中的代码所使用。

引用消解(Reference Resolution),有时也被称作名称消解(Name Resolution)或者标签消解(Label Resolution)。对变量名称、常量名称、函数名称、类型名称、包名称等的消解,都属于引用消解。

 

 

作用域的第一个使用场景,指的是变量、函数等标识符可以起作用的范围。

作用域的第二个使用场景,是词法作用域(Lexical Scope),也就是程序中的不同文本区域。比如,一个语句块、参数列表、类定义的主体、函数(方法)的主体、模块主体、整个程序等。

 

标识符和词法的作用域的差异在于:一个本地变量(标识符)的作用域,虽然属于某个词法作用域(如某个函数体),但其作用范围只是在变量声明之后的语句。而类的成员变量(标识符)的作用域,跟词法作用域是一致的,也就是整个类的范围,跟声明的位置无关。如果这个成员变量不是私有的,它的作用域还会覆盖到子类。

那具体到不同的编程语言,它们的作用域规则是不同的

 

在做引用消解的时候,为了更好地查找变量、类型等定义信息,编译器会使用一个辅助的数据结构:符号表

对引用消解,其实就是从符号表里查找被引用的符号的定义。

 

在做类型检查的时候,我们可以从符号表里查找某个符号的类型,从而检查类型是否兼容。

早在词法分析阶段,你就可以为符号表建立条目;在生成 IR、做优化和生成目标代码的时候,都会用到符号表里的信息。

 

 

 

在计算机语言里,类型是数据的一个属性,它的作用是来告诉编译器或解释器,程序可以如何使用这些数据。

一门语言的类型系统是包含了与类型有关的各种规则的一个逻辑系统。类型系统包含了一系列规则,规定了如何把类型用于变量、表达式和函数等程序元素,以及如何创建自定义类型,等等。

类型检查,编译器一般会采用属性计算的方法,来计算出每个 AST 节点的类型属性,然后检查它们是否匹配。

 

同样是计算 AST 节点的类型,等号右边和左边的计算方法是不一样的。

 

属性计算。其中,有些属性是通过子节点计算出来的,这叫做 S 属性(Synthesized Attribute,综合出来的属性),比如等号右边的类型。而另一些属性,则要根据父节点或者兄弟节点计算而来,这种属性叫做 I 属性(Inherited Attribute,继承到的属性),比如等号左边的 b 变量的类型。

 

带有标注信息的 AST,(Annotated Tree),也有人称之为 Decorated Tree,或者 Attributed Tree。

 

 

性计算的方法,就是基于语法规则,来定义一些属性计算的规则,在遍历 AST 的时候执行这些规则,我们就可以计算出属性值。这种基于语法规则定义的计算规则,被叫做属性文法(Attribute Grammar)。

做语法解析(或先解析成 AST,再遍历 AST)的时候,执行方括号中的规则,我们就可以计算出 AST 的值了
add1 → add2 + mul [ add1.value = add2.value + mul.value ]
add → mul [ add.value = mul.value ]
mul1 → mul2 * primary [ mul1.value = mul2.value * primary.value ]
mul → primary [ mul.value = primary.value ]
primary → ( add ) [ primary.value =  add.value ]
primary → integer [ primary.value = strToInt(integer.str) ]

 

这种在语法规则上附加一系列动作,在解析语法的时候执行这些动作的方式,是一种编译方法,在龙书里有一个专门的名字,叫做语法制导的翻译(Syntax Directed Translation,SDT)。使用语法制导的翻译可以做很多事情,包括做属性计算、填充符号表,以及生成 IR。

语义分析相关的代码量往往要比词法分析和语法分析的代码量大。因为一门语言有很多语义规则,所以要做的语义分析和检查工作也很多。

 

并且,因为每门语言之间的差别主要都体现在语义上,所以每门语言在语义处理方面的工作差异也比较大。比如,一门语言支持闭包,另一门语言不支持;有的语言支持泛型,另一门语言不支持;一门语言的面向对象特性是基于继承实现的,而另一门语言则是基于组合实现的,等等。

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值