语义分析 ======== 类型系统 -------- 类型系统的设计有很多需要取舍和权衡的方面,比如:: 1. 面向对象的拥护者希望所有的类型都是对象,而重视数据计算性能的人认为应该支持非对象化的基础数据类型 2. 你想把字符串作为原生数据类型,还是像 Java 那样只是一个普通的类 3. 是静态类型语言好还是动态类型语言好 根据类型检查是在编译期还是在运行期进行的,我们可以把计算机语言分为两类:: 1. 静态类型语言(全部或者几乎全部的类型检查是在编译期进行的) 因为编译期做了类型检查,所以程序错误较少,运行期不用再检查类型,性能更高。 像 C、Java 和 Go 语言,在编译时就对类型做很多处理,包括: 检查类型是否匹配,以及进行缺省的类型转换 大大降低了程序出错的可能性,还能让程序运行效率更高,因为不需要在运行时再去做类型检查和转换。 2. 动态类型语言(类型的检查是在运行期进行的) 静态语言太严格,还要一遍遍编译,编程效率低,用动态类型语言方便进行快速开发。 JavaScript、Python、PHP 等都是动态类型的。 目前的趋势:: 1. 某些动态类型语言在想办法增加一些机制,在编译期就能做类型检查 比如用 TypeScript 代替 JavaScript 编写程序,做完检查后再输出成 JavaScript 2. 某些静态语言呢,却又发明出一些办法,部分地绕过类型检查,从而提供动态类型语言的灵活性。 跟静态类型和动态类型概念相关联的,还有强类型和弱类型:: 1. 强类型语言中,变量的类型一旦声明就不能改变 2. 弱类型语言中,变量类型在运行期时可以改变 二者的本质区别是: 强类型语言不允许违法操作,因为能够被检查出来 弱类型语言则从机制上就无法禁止违法操作,所以是不安全的 JavaScript是动态类型,也是弱类型;python是动态类型,却是强类型。 .. note:: 静态类型和动态类型说的是什么时候检查的问题,强类型和弱类型说的是就算检查,也检查不出来,或者没法检查的问题 :: 1. 类型检查: Type Checking 2. 类型推导: Type Inference 3. 类型转换: Type Conversion 类型推导:: S 属性(Synthesized Attribute),也就是综合属性 I 属性(Inherited Attribute),也就是继承属性 L 属性 类型检查主要出现在几个场景中:: 1. 赋值语句(检查赋值操作左边和右边的类型是否匹配)。 2. 变量声明语句(因为变量声明语句中也会有初始化部分,所以也需要类型匹配)。 3. 函数传参(调用函数的时候,传入的参数要符合形参的要求)。 4. 函数返回值(从函数中返回一个值的时候,要符合函数返回值的规定)。 类型检查还有一个特点: 以赋值语句为例, 左边的类型,是 I 属性,是从声明中得到的; 右边的类型是 S 属性,是自下而上综合出来的 :: 1. 左值(L-value) 地址 2. 右值(R-value) 值 语义分析过程拆成了好几个任务,对 AST 做了多次遍历:: 1. 类型和作用域解析(TypeAndScopeScanner.java) 2. 类型的消解(TypeResolver.java) 3. 引用的消解和 S 属性的类型的推导(RefResolver.java) 4. 做类型检查(TypeChecker.java) 5. 做一些语义合法性的检查(SematicValidator.java)