《Language Implementation Patterns》之 强类型规则
语句的语义取决于其语法结构和相关符号;前者说明了了要“做什么”,后者说明了操作“什么对象”。所以即使语法结构正确的,如果被操作的对象不合法,语句也是不合法的。语言一般有很多语义规则,有些是运行时的(dynamic semantics),比如“不能除以零”、“不能越界访问数组”;有些是编译时的(static semantics)。运行时&编译时的界限取决于具体的语言,python是动态类型的语言,所有的值编译时都不会指定类型,解释器在运行时检查类型和执行语义规则;C++则是另一个极端,所有的值必须有静态的类型,运行时不做检查;java既有静态类型检查,又在运行时检查类型。无论动态的或静态的类型检查,只要能阻止不相容的类型操作,语言就是“类型安全”的。
本章讲述了如何实施静态类型规则,将会讨论一下几种模式:
- Pattern 20 Computing Static Expression Types,保证类型安全的第一步是计算表达式的类型;
- Pattern 21 Automatic Type Promotion, 将操作数的类型提升至相同或相容的类型;
- Pattern 22 Enforcing Static Type Safety,检查类型相容性,保证类型安全;
- Pattern 23 Enforcing Polymorphic Type Safety, 面向对象类型语言里面的对象类型相容,多态的引用类型;
下面分别讲述这些模式,以类c语言的规则为样例。
Pattern 20 Computing Static Expression Types
展示了在显示声明类型的语言,比如C,如何计算表达式的类型
下面的表格说明了类型计算规则。
Subexpression | Result Type |
true,false | boolean |
!«expr » | boolean |
f(«args») | 函数f的返回类型 |
«expr» bop «expr» | bop代表二元运算符,因为两侧的操作数的类型是一致的,所以可以选取左侧操作数的类型为表达式类型 |
«expr» relop «expr» | boolean,relop是代表关系操作符 |
实现
假设我们已经构建了AST,和scope tree,进行类型计算就是另一轮AST遍历,可以通过Tree Pattern Matcher技术来寻找表达式节点并计算类型。
具体的实现代码请参考原书。
Pattern 21 Automatic Type Promotion
描述了如何自动、安全地提升数学运算操作数的类型
类型提升将单个运算符的所有操作数提升至相同类型或相容类型,这本质上是CPU对操作数的要求。编程语言能够自动地转换类型,只要“转换“不丢失信息;比如4可以安全地转换成4.0,而4.5不能转换成4;这种安全的类型转换被称之为”类型提升”,因为它拓宽了类型。
这里有一个简单的方式描述类型提升规则;首先将类型按最“窄”到最“宽”进行排序,然后如果i<j,我们可以进行从TYPEi到TYPEj的提升。
为了实现类型提升,需要两个函数,第一个是根据运算符和运算数类型返回结果类型;第二个从运算符和目标类型判断是否需要对操作数执行类型提升。
resultType(type1, op, type2)
resultType(char, "<", int) == boolean
resultType(char, "+", int) == int
resultType(boolean, "<", boolean) == void
promoteFromTo(type, op, destination-type)
promoteFromTo(char, "+", int) == int
promoteFromTo(int, "+", int) == null
结果void意味着该表达式不合法,null意味着不需要类型转换。按这个规则,表达式’a’+3+4.2的类型提升可以表示为(float)((int)’a’+3)+4.2,AST如图:
每个节点都知道自己的求值类型,提升类型。
具体的java实现代码,请参考原书。
Pattern 22 Enforcing Static Type Safety
通过静态检查,发现表达式或语句里面类型不相容的类型
概括起来,类型相容包含两个方面:
- 对操作数类型,操作符是有定义的,即resultType(operandtype1, op, operandtype2) != void;
- 如果我们需要一个类型T的值,那么提供的值必须是T或可以被提升为T。
在Pattern 21的基础上增加类型检查不是困难,只要出现void都意味着类型不相容;对于点操作符,函数调用,return语句等需要特殊处理。
具体的实现代码,请参考原书。
Pattern 23 Enforcing Polymorphic Type Safety
检查对象引用赋值的类型相容性
对象类型引用赋值的相容性判断如下:
public class PointerType extends Symbol implements Type {
public boolean canAssignTo(Type destType) {
// if not a pointer, return false
if ( !(destType instanceof PointerType) ) return false;
// What type is the target pointing at?
Type destTargetType = ((PointerType)destType).targetType;
Type srcTargetType = this.targetType;
// if this and target are object pointers, check polymorphism
if ( destTargetType instanceof ClassSymbol &&
this.targetType instanceof ClassSymbol )
{
ClassSymbol thisClass = (ClassSymbol)srcTargetType;
ClassSymbol targetClass = (ClassSymbol)destTargetType;
// Finally! Here it is: the polymorphic type check :)
return thisClass.isInstanceof(targetClass);
}
// not comparing object pointers; types we point at must be the same
// For example: int *p; int *q; p = q;
return srcTargetType == destTargetType;
}
}
/** Return true if 'ancestor' is this class or above in hierarchy */
public boolean isInstanceof(ClassSymbol ancestor) {
ClassSymbol t = this;
while ( t!=null ) {
if ( t == ancestor ) return true;
t = t.superClass;
}
return false;
}
《Language Implementation Patterns》之 强类型规则的更多相关文章
- 《Language Implementation Patterns》之 解释器
前面讲述了如何验证语句,这章讲述如何构建一个解释器来执行语句,解释器有两种,高级解释器直接执行语句源码或AST这样的中间结构,低级解释器执行执行字节码(更接近机器指令的形式). 高级解释器比较适合DS ...
- 《Language Implementation Patterns》之 数据聚合符号表
本章学习一种新的作用域,叫做数据聚合作用域(data aggregate scope),和其他作用域一样包含符号,并在scope tree里面占据一个位置. 区别在于:作用域之外的代码能够通过一种特殊 ...
- 《Language Implementation Patterns》之访问&重写语法树
每个编程的人都学习过树遍历算法,但是AST的遍历并不是开始想象的那么简单.有几个因素会影响遍历算法:1)是否拥有节点的源码:2)是否子节点的访问方式是统一的:3)ast是homogeneous或het ...
- 《Language Implementation Patterns》之 构建语法树
如果要解释执行或转换一段语言,那么就无法在识别语法规则的同时达到目标,只有那些简单的,比如将wiki markup转换成html的功能,可以通过一遍解析来完成,这种应用叫做 syntax-direct ...
- 《Language Implementation Patterns》之 增强解析模式
上一章节讲述了基本的语言解析模式,LL(k)足以应付大多数的任务,但是对一些复杂的语言仍然显得不足,已付出更多的复杂度.和运行时效率为代价,我们可以得到能力更强的Parser. Pattern 5 : ...
- 《Language Implementation Patterns》之 语言翻译器
语言翻译器可以从一种计算机语言翻译成另外一种语言,比如一种DSL的标量乘法axb翻译成java就变成a*b:如果DSL里面有矩阵运算,就需要翻译成for循环.翻译器需要完全理解输入语言的所有结构,并选 ...
- 《Language Implementation Patterns》之 符号表
前面的章节我们学会了如何解析语言.构建AST,如何访问重写AST,有了这些基础,我们可以开始进行"语义分析"了. 在分析语义的一个基本方面是要追踪"符号",符号 ...
- Saga的实现模式——进化(Saga implementation patterns – variations)
在之前的几个博客中,我主要讲了两个saga的实现模式: 基于command的控制者模式 基于事件的观察者模式 当然,这些都不是实现saga的唯一方式.我们甚至可以将这些结合起来. 发布者——收集者 回 ...
- Saga的实现模式——观察者(Saga implementation patterns – Observer)
https://lostechies.com/jimmybogard/2013/03/11/saga-implementation-patterns-observer/ 侵删. NServiceBus ...
随机推荐
- CSS3动画以及animation事件
1.CSS3动画以及animation事件的定义 animation :name duration timing-function delay iteration-count direction an ...
- 关于CI框架访问数据库类提示Call to undefined function mysqli_init()
大家好,我曾经是ASP.NET MVC的践行者,现在是PHP,同时也是CodeIgniter框架的初学者和践行者,当时由于项目原因,我被迫给自己打满鸡血,满怀激情的选用Yii2,Lavarel5,Co ...
- 伯克利推出世界最快的KVS数据库Anna:秒杀Redis和Cassandra
天下武功,唯快不破. 伯克利 RISE 实验室推出了最新的键值存储数据库 Anna,提供了惊人的存取速度.超强的伸缩性和史无前例的一致性保证.Jeff Dean 说,当一个系统增长到十倍规模时,就需要 ...
- Windows Live Writer 2014版绿色版制作及主题获取
前年才建好博客的时候就尝试用Windows Live Writer(WLW)写博客,用的是直接在网上找到的一个WLW 2009绿色美化版.但因为当时WLW获取的博客主题是主页的,预览的时候特别不爽,就 ...
- 简单的同步Socket程序服务端
首先,Socket是.Net提供的 System.Net.Sockets命名空间的Scoket类为网络通信提供了一套丰富的方法和属性 服务器按照Socket的基本流程 先创建Socket 在用Bind ...
- Spring MVC注解式开发
MVC注解式开发即处理器基于注解的类开发, 对于每一个定义的处理器, 无需在xml中注册. 只需在代码中通过对类与方法的注解, 即可完成注册. 定义处理器 @Controller: 当前类为处理器 @ ...
- python web开发-flask读取txt文件内容
某些情况下,需要读取flask网站要目录下的txt文件.但是直接在flask网站的目录下创建一个文件是无法访问的.从网站找了一些资料,最终发现通过写一个方法返回txt内容比较简单方便,不过此方法适用于 ...
- ajax利用FormData异步文件提交
通常情况下,我们上传文件都会使用form表单来提交文件.但有时候,我们会有异步提交文件的需求,在这种情况下,我们就需要新建一个Formdata来提交文件,后台如果使用的是PHP的话可以使用$_FILE ...
- poj-1005-l tanink i need a houseboat
Description Fred Mapper is considering purchasing some land in Louisiana to build his house on. In t ...
- VMware 下快速克隆出多个 Linux 环境
念念不忘,必有回响 好好工作,好好吃饭,困了倒头就睡:吃你认为好吃的,吃到饱:买贵的,你想买的:去玩去野: 就这样. 为什么要克隆多个 Linux 系统? 因为要玩阿. 其实也不是了,就是为了折腾嘛, ...