语句的语义取决于其语法结构和相关符号;前者说明了了要“做什么”,后者说明了操作“什么对象”。所以即使语法结构正确的,如果被操作的对象不合法,语句也是不合法的。语言一般有很多语义规则,有些是运行时的(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&ltj,我们可以进行从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》之 强类型规则的更多相关文章

  1. 《Language Implementation Patterns》之 解释器

    前面讲述了如何验证语句,这章讲述如何构建一个解释器来执行语句,解释器有两种,高级解释器直接执行语句源码或AST这样的中间结构,低级解释器执行执行字节码(更接近机器指令的形式). 高级解释器比较适合DS ...

  2. 《Language Implementation Patterns》之 数据聚合符号表

    本章学习一种新的作用域,叫做数据聚合作用域(data aggregate scope),和其他作用域一样包含符号,并在scope tree里面占据一个位置. 区别在于:作用域之外的代码能够通过一种特殊 ...

  3. 《Language Implementation Patterns》之访问&重写语法树

    每个编程的人都学习过树遍历算法,但是AST的遍历并不是开始想象的那么简单.有几个因素会影响遍历算法:1)是否拥有节点的源码:2)是否子节点的访问方式是统一的:3)ast是homogeneous或het ...

  4. 《Language Implementation Patterns》之 构建语法树

    如果要解释执行或转换一段语言,那么就无法在识别语法规则的同时达到目标,只有那些简单的,比如将wiki markup转换成html的功能,可以通过一遍解析来完成,这种应用叫做 syntax-direct ...

  5. 《Language Implementation Patterns》之 增强解析模式

    上一章节讲述了基本的语言解析模式,LL(k)足以应付大多数的任务,但是对一些复杂的语言仍然显得不足,已付出更多的复杂度.和运行时效率为代价,我们可以得到能力更强的Parser. Pattern 5 : ...

  6. 《Language Implementation Patterns》之 语言翻译器

    语言翻译器可以从一种计算机语言翻译成另外一种语言,比如一种DSL的标量乘法axb翻译成java就变成a*b:如果DSL里面有矩阵运算,就需要翻译成for循环.翻译器需要完全理解输入语言的所有结构,并选 ...

  7. 《Language Implementation Patterns》之 符号表

    前面的章节我们学会了如何解析语言.构建AST,如何访问重写AST,有了这些基础,我们可以开始进行"语义分析"了. 在分析语义的一个基本方面是要追踪"符号",符号 ...

  8. Saga的实现模式——进化(Saga implementation patterns – variations)

    在之前的几个博客中,我主要讲了两个saga的实现模式: 基于command的控制者模式 基于事件的观察者模式 当然,这些都不是实现saga的唯一方式.我们甚至可以将这些结合起来. 发布者——收集者 回 ...

  9. Saga的实现模式——观察者(Saga implementation patterns – Observer)

    https://lostechies.com/jimmybogard/2013/03/11/saga-implementation-patterns-observer/ 侵删. NServiceBus ...

随机推荐

  1. WPF基础篇之控件模板(ControlTemplate)

    WPF中每一个控件都有一个默认的模板,该模板描述了控件的外观以及外观对外界刺激所做出的反应.我们可以自定义一个模板来替换掉控件的默认模板以便打造个性化的控件. 与Style不同,Style只能改变控件 ...

  2. [前端]如何写一个水平导航栏?(浮动、inline-block+消除间距)

    在看W3school时,看到一个很好的例子,如何制作一个水平的导航栏?没有任何要求,只需要达到下面的效果: 我认为这个例子包含了很多css布局需要了解的知识,因此单独写一下. W3school上面的方 ...

  3. RobotFramework下HttpLibrary库其它关键字

    关键字 使用描述 DELETE 向服务器端发送http delete请求,该请求接收一个参数[ url ],请求的方式和post请求非常类似,示例: DELETE /_utils/config.htm ...

  4. (luogu1704)寻找最优美做题曲线 [TPLY]

    寻找最优美做题曲线 题目链接:https://www.luogu.org/problemnew/show/P1704 题目大意: 求包含指定点的最长不降子序列(严格递增) 题解 首先我们发现 一个序列 ...

  5. ThreadLocal用例之周期为一次请求的变量

    public class RecordedLocal { private static ThreadLocal<Recorded> local = new ThreadLocal<R ...

  6. 一年java工作经验的面试题总结(持续更新中)

    本人是17年6月份毕业的,3月份出来实习,算起来也是工作一年了吧,金三银四,博主也考虑换一份工作,于是最近面试了几家,总结一下面试中的问题,大家一起交流学习. 第一次面试  ①说下java类的加载 ② ...

  7. GitHub起步---创建第一个项目

    ---恢复内容开始--- 刚起步学习GitHub,边学边说! {参考教程:http://blog.csdn.net/steven6977/article/details/10567719}这里描述的很 ...

  8. 1. Java Static和Final使用总结

    static:用于属性和方法 static修饰属性:无论一个类生成多少对象,所有这些对象共用唯一一个静态成员变量.一个对象对该静态变量进行修改,其他对象对该静态变量的值也随之发生变化.可以通过类名.成 ...

  9. 使用vlookup嵌套INDIRECT函数实现跨表数据引用

    这是一个使用 vlookup 函数嵌套 INDIRECT 函数来实现跨工作表数据引用的教程. 某小学决定要抽查本校三年级三个班的期末考情况,抽查方法为在每个班中抽查5名学生,将这15名学生的期末考情况 ...

  10. python3.6.4 tkinter安装

    在pyenv虚拟环境中   sudo yum -y install tkinter tcl-devel tk-devel     重新安装python pyenv install -v 3.6.4