“类型名称的消解”即类型的消解。类型名称由TypeRef 对象表示,类型由Type 对象表示。类型名称的消解就是将TypeRef 对象转换为Type 对象。

TypeResolver 类的处理仅仅是遍历抽象语法树,发现TypeRef 的话就从叶子节点开始将其转换为Type 类型。类型和变量的不同之处在于没有作用域的嵌套(作用域唯一),因此没
有必要使用栈。
【TypeRef 对象和Type 对象的对应关系保存在TypeTable 对象中。】

其中Type为类型的定义。struct point { int x; int y; }; 是类型的定义。

TypeRef为类型的名称。struct point 是类型的名称,之所以特意将Type 类和TypeRef 类分开,是因为在类型定义之前就可以编写用到了该类型的代码。也就是说,可以编写如下所示的代码,C 语言中是不可以编写这样的代码的:

	struct s var;
struct s {
int memb;
};

类型名称的消解入口:

    /*入口
*
*/
// #@@range/resolveProgram{
public void resolve(AST ast) {
/*
* 首先调用defineTypes 方法,根据代码中定义的类型生成Type 对象,并保存到
TypeTable 对象中。通过import 导入的类型定义也在这里处理。
*/
defineTypes(ast.types());
/*类型和抽象语法树的遍历.
* 但defineTypes 方法不处理结构体成员的类型等TypeRef 对象。将抽象语法树中已有
的TypeRef 转换成Type 的处理将在下面的foreach 语句中执行。如果这两部分处理不分开进
行的话,在处理递归的类型定义时程序会陷入死循环。 ast.types()--源文件内外的类型定义
*/
// #@@range/resolveProgram_core{
for (TypeDefinition t : ast.types()) {
t.accept(this);
}
/*
* 第2 个foreach 语句将使用import 从文件外部读入的定义、全局变量以及函数等所有剩余
的TypeRef 转换为Type。 ast.entities()--用import 导入的变量和函数的声明,以及源文件内的变量和函数的定义
*/
for (Entity e : ast.entities()) {
e.accept(this);
}
/*
* 上面两个for循环遍历在源文件内外定义的所有类型、变量、函数,将其中所包含的TypeRef 对象
全部转换为Type 对象。
*/
// #@@}
}

首先对ast.types(),即StructNode(结构体定义)、UnionNode(联合体定义)、TypedefNode(用户类型定义)执行defineTypes:

    /*类型的声明.
* defineTypes 是将类型定义添加到TypeTable 对象的方法
*/
// #@@range/defineTypes{
private void defineTypes(List<TypeDefinition> deftypes) {
/*
* 使用foreach 语句将deftypes 中的TypeDefinition 对象逐个取出, 将def.
typeRef() 和def.definingType() 关联成对, 用typeTable.put 方法添加到
typeTable 中。def.typeRef() 返回的是该TypeDefinition 对象要定义的类型的
TypeRef(类型名称)。def.definingType() 返回的是该TypeDefinition 对象要定义的
Type(类型)。
*/
for (TypeDefinition def : deftypes) {
/*
* 但如果typeTable.isDefined() 为true 的话,说明这个TypeRef 已经存在,这种情
况下取消添加处理并输出错误消息。
*/
if (typeTable.isDefined(def.typeRef())) {
error(def, "duplicated type definition: " + def.typeRef());
}
else {
/*
* TypeDefinition 类是抽象类, 实际生成的实例是TypeDefinition 的子类
StructNode、UnionNode、TypedefNode。StructNode 表示结构体的定义,UnionNode
表示联合体的定义,TypedefNode 表示typedef 语句。
StructNode#definingType:
public Type definingType() {
return new StructType(name(), members(), location());
} 调用TypeTable#put 方法将生成的StrcutType 对
象添加到TypeTable 对象中。TypeTable 对象的内部保存有HashMap 对象, 因此
TypeTable#put 方法只需简单地调用HashMap#put 即可。
*/
typeTable.put(def.typeRef(), def.definingType());
}
}
}

把上面三种类型的名称和类型都保存在typeTable中,注意typeTable初始化的时候已经自动把所有基本类型都put进去了。然后第一个for循环的三个visit方法:

    // #@@range/StructNode{
public Void visit(StructNode struct) {
resolveCompositeType(struct);
return null;
}
// #@@} // #@@range/UnionNode{
public Void visit(UnionNode union) {
resolveCompositeType(union);
return null;
}
// #@@} // #@@range/TypedefNode{
public Void visit(TypedefNode typedef) {
bindType(typedef.typeNode());
bindType(typedef.realTypeNode());
return null;
}
// #@@}

接着:

    public void resolveCompositeType(CompositeTypeDefinition def) {
CompositeType ct = (CompositeType)typeTable.get(def.typeNode().typeRef());
if (ct == null) {
throw new Error("cannot intern struct/union: " + def.name());
}
for (Slot s : ct.members()) {
bindType(s.typeNode());
}
} /*
* 首先,用TypeNode#isResolved 方法检查是否已经完成了转换,如果已经完成,则即
刻使用return 结束处理。如果还未转换,用n.typeRef() 从TypeNode 中取出TypeRef,
再用typeTable.get 转换为Type 对象, 然后将此Type 对象用n.setType 设置到
TypeNode 中。
*/
// #@@range/bindType{
private void bindType(TypeNode n) {
if (n.isResolved()) return;
n.setType(typeTable.get(n.typeRef()));
}

也很简单,resolveCompositeType是针对每种类型的成员的类型检查,关键的类是TypeNode,从它里面获取TypeRef(类型的名称),再通过类型的名称从typeTable获取已有的类型的定义。然后获取到当前类型的所有的成员变量,再将这个成员变量的类型的名称和定义通过bindType方法绑定起来。typeTable实际上是起到一个中转站的作用。

第二个for循环是将除了上面三种类型的所有剩余的TypeRef 转换为Type。比如:

    /*
* 变量定义的类型消解.
*/
// #@@range/DefinedVariable{
public Void visit(DefinedVariable var) {
/*
* TypeRef 对象基本上都存放在TypeNode 对象中。TypeNode 是成对地保存TypeRef 和
Type 的对象,其目的在于简化TypeResolver 类的代码。
*/
bindType(var.typeNode());
if (var.hasInitializer()) {
visitExpr(var.initializer());
}
return null;
}

还有重要的函数类型:

    /*
* 函数定义的类型消解.
*/
// #@@range/DefinedFunction{
public Void visit(DefinedFunction func) {
/*
* 在函数定义中,如下这些地方存在TypeRef。
1. 返回值的类型
2. 形参的类型
3. 函数体的代码中
*/
resolveFunctionHeader(func);
visitStmt(func.body());
return null;
} private void resolveFunctionHeader(Function func) {
/*
* resolveFunctionHeader 方法的第1 行用于处理返回值的类型。func.typeNode()
返回保存有返回值类型的TypeNode 对象,再调用bindType 方法将返回值的类型从
TypeRef 转换为Type。
*/
bindType(func.typeNode());
/*
* resolveFunctionHeader 方法从第2 行开始都是对形参进行的处理。用foreach 语句
* 对func.parameters() 进行遍历,取出表示形参的Parameter 对象。然后用param.
typeNode() 取出Parameter 对象中的TypeNode 对象,将TypeRef 转换为Type。
*/
for (Parameter param : func.parameters()) {
// arrays must be converted to pointers in a function parameter.
/*
* 只有在将形参的TypeRef 转换为Type 时使用了TypeTable 类的getParamType 方法。
它和通常的get 方法的区别在于数组的TypeRef 会被转换为指针的Type。C 语言(C♭)中形
参类型是数组的情况下完全等同于指针类型,因此在此处统一成为指针类型。
*/
Type t = typeTable.getParamType(param.typeNode().typeRef());
param.typeNode().setType(t);
}
}

首先调用resolveFunctionHeader方法,里面第一行是绑定函数的返回类型,然后一个for循环绑定函数的所有形参类型。然后再调用visitStmt(func.body());绑定函数体的所有类型:

    public Void visit(BlockNode node) {
for (DefinedVariable var : node.variables()) {
var.accept(this);
}
visitStmts(node.stmts());
return null;
}

编译器开发系列--Ocelot语言3.类型名称的消解的更多相关文章

  1. 编译器开发系列--Ocelot语言4.类型定义的检查

    这里主要介绍一下检查循环定义的结构体.联合体.是对成员中包含自己本身的结构体.联合体进行检查.所谓"成员中包含自己本身",举例来说,就是指下面这样的定义. struct point ...

  2. 编译器开发系列--Ocelot语言2.变量引用的消解

    "变量引用的消解"是指确定具体指向哪个变量.例如变量"i"可能是全局变量i,也可能是静态变量i,还可能是局部变量i.通过这个过程来消除这样的不确定性,确定所引用 ...

  3. 编译器开发系列--Ocelot语言1.抽象语法树

    从今天开始研究开发自己的编程语言Ocelot,从<自制编译器>出发,然后再自己不断完善功能并优化. 编译器前端简单,就不深入研究了,直接用现成的一款工具叫JavaCC,它可以生成抽象语法树 ...

  4. 编译器开发系列--Ocelot语言6.静态类型检查

    关于"静态类型检查",想必使用C 或Java 的各位应该非常熟悉了.在此过程中将检查表达式的类型,发现类型不正确的操作时就会报错.例如结构体之间无法用+ 进行加法运算,指针和数值之 ...

  5. 编译器开发系列--Ocelot语言7.中间代码

    Ocelot的中间代码是仿照国外编译器相关图书Modern Compiler Implementation 中所使用的名为Tree 的中间代码设计的.顾名思义,Tree 是一种树形结构,其特征是简单, ...

  6. 编译器开发系列--Ocelot语言5.表达式的有效性检查

    本篇将对"1=3""&5"这样无法求值的不正确的表达式进行检查. 将检查如下这些问题.●为无法赋值的表达式赋值(例:1 = 2 + 2)●使用非法的函数 ...

  7. iOS开发系列--C语言之基础知识

    概览 当前移动开发的趋势已经势不可挡,这个系列希望浅谈一下个人对IOS开发的一些见解,这个IOS系列计划从几个角度去说IOS开发: C语言 OC基础 IOS开发(iphone/ipad) Swift ...

  8. iOS开发系列--Swift语言

    概述 Swift是苹果2014年推出的全新的编程语言,它继承了C语言.ObjC的特性,且克服了C语言的兼容性问题.Swift发展过程中不仅保留了ObjC很多语法特性,它也借鉴了多种现代化语言的特点,在 ...

  9. iOS开发系列--C语言之构造类型

    概述 在第一节中我们就提到C语言的构造类型,分为:数组.结构体.枚举.共用体,当然前面数组的内容已经说了很多了,这一节将会重点说一下其他三种类型. 结构体 枚举 共用体 结构体 数组中存储的是一系列相 ...

随机推荐

  1. 为什么做java的web开发我们会使用struts2,springMVC和spring这样的框架?

    今年我一直在思考web开发里的前后端分离的问题,到了现在也颇有点心得了,随着这个问题的深入,再加以现在公司很多web项目的控制层的技术框架由struts2迁移到springMVC,我突然有了一个新的疑 ...

  2. 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)

    一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...

  3. .NET平台开源项目速览(18)C#平台JSON实体类生成器JSON C# Class Generator

    去年,我在一篇文章用原始方法解析复杂字符串,json一定要用JsonMapper么?中介绍了简单的JSON解析的问题,那种方法在当时的环境是非常方便的,因为不需要生成实体类,结构很容易解析.但随着业务 ...

  4. java.lang.NoSuchFieldError: org.apache.http.message.BasicLineFormatter.INSTANCE

    Android发出HTTP请求时出现了这个错误: java.lang.NoSuchFieldError: org.apache.http.message.BasicLineFormatter.INST ...

  5. MySQL:Fabric 安装

    MySQL Fabric安装 MySQL Fabric是Oracle提供的用于辅助进行ha\sharding的工具,它的基本架构: 从上面看出,借助于Fabric, 可以搭建 HA 集群.Sharin ...

  6. 第10章 Shell编程(4)_流程控制

    5. 流程控制 5.1 if语句 (1)格式: 格式1 格式2 多分支if if [ 条件判断式 ];then #程序 else #程序 fi if [ 条件判断式 ] then #程序 else # ...

  7. 关于Hadoop用户体系的设想(胡思乱想)

    关于Hadoop的用户体系设计设想 Hadoop并没有一个完整的用户体系,其权限控制的对象,主要是Linux的其它用户(即非安装Hadoop的用户),控制方式也和Linux的文件权限很像,目前权限控制 ...

  8. Handlebars 模板引擎之前后端用法

    前言 不知不觉间,居然已经这么久没有写博客了,坚持还真是世界上最难的事情啊. 不过我最近也没闲着,辞工换工.恋爱失恋.深圳北京都经历了一番,这有起有落的生活实在是太刺激了,就如拿着两把菜刀剁洋葱一样, ...

  9. 转职成为TypeScript程序员的参考手册

    写在前面 作者并没有任何可以作为背书的履历来证明自己写作这份手册的分量. 其内容大都来自于TypeScript官方资料或者搜索引擎获得,期间掺杂少量作者的私见,并会标明. 大部分内容来自于http:/ ...

  10. windows phone如何才能在中国翻身?

    最近的新闻告诉我们,Android和IOS的系统继续保持市场领先,并且Android的市场份额达到了历史最高点. 做为windows phone的消费者,作为微软粉丝,我感到十分的不爽. 前几天MIU ...