第六章-Javac符号表
需要参考:
(1)Architecture of a Java Compiler
(4)关于类型Type
(5)关于作用域范围Scope
(6)
Java语义分析阶段的一个主要工作是符号表的管理。符号表(symbol table)也称为环境(environment),其作用是将标识符映射到它们的类型和存储位置。在处理类型、变量和方法的定义时,顺便将这些标识符存储到符号表中,同时为这些标识符绑定相关的信息。每当发现标识符的使用(即非定义)时,便在符号表中查找这些标识符的信息。
在进行标识符相关信息的存储时,需要考虑到标识符的类型、作用域,而对于方法来说,至少还需要保存参数数量与类型,以及返回值等。
1、符号
写一段Java程序,不难看出在这段程序中,除了引用已经存在的标识符,剩下的就是定义新的标识符已经引用这些新定义的标识符了,如下:
package com.test20;
class Test{
int a = 0;
public void tm(){
String s = ""+a;
}
}
定义了一个类Test,一个变量a与一个方法tm。在tm()方法中,有对已经声明过的类型的引用,如String,也有对刚声明的变量a进行引用。不难看出,在对已定义好的标识符进行引用时,需要知道它们的一些相关信息,比如如果是变量,则直接使用标识符即可,如果标识符表示的是方法,还需要以方法的形式来调用。那么在获取标识符时,还需要获取到这些标识符的相关信息,如引用一个已经声明的类时,这个类中定义了哪些方法,当前是否可以访问到。在Java编译器中,每声明一个标识符时,就通过Symbol及其子类来表示。

下面来认识一下这些重要的类。
1.1 Symbol(介绍属性及方法)
1.2 TypeSymbol
1.3 VarSymbol
预定义符号的输入
对操作符的处理
1.4 MethodSymbol
2、组织符号表
2.1 Scope属性的介绍
在上一章介绍了在代码编写的过程中可能会定义出各种不同的符号,这一章将详细介绍这些符号是如何符号表来组织的。在Javac中定义了一个Scope类,这个类代表了符号的作用,例如:
class Test{
int x = 1;
{
float x = 2;
}
public void m(){
long x = 2;
}
}
很显示,上面3个变量的定义都不在同一个作用域范围内。所以相同作用域内的符号应该存放到同一个Scope对象中。一个Scope作用域内定义的多个符号用数组来存储,不过并不是直接存储Symbol,而是将Symbol进一步封装为Entry对象。这个数组在Scope中的定义如下:
/** A hash table for the scope's entries. */ Entry[] table;
Entry类的定义及重要的属性如下:
/** A class for scope entries.
* shadowed指针指向桶中的下一个表项,shadowed意为隐蔽之义,sibling指针指向
* 下一个填入哈希表中的表项,和符号的范围scope
*/
public static class Entry {
/** The referenced symbol.
* sym == null iff this == sentinel
*/
public Symbol sym;
/** An entry with the same hash code, or sentinel.
*/
private Entry shadowed;
/** Next entry in same scope.
*/
public Entry sibling;
/** The entry's scope.
* scope == null iff this == sentinel
* for an entry in an import scope, this is the scope
* where the entry came from (i.e. was imported from).
*/
public Scope scope;
// ...
}
sym属性就是这个Entry代表的符号,scope表示这个符号所属的作用域。而shadowed与sibling指针是用来解决冲突的。由于这些定义出来的符号会被被频繁引用,那么符号表的组织就需要一个高效的组织方式,而Java编译器采用了Hash方式,采用Hash来存储符号,必然会产生冲突,通过单链表与二次冲突检测法来解决冲突。一般标识符的名称不同时,通过二次冲突检测法来避免冲突,如果标识符名称相同,则通过单链表来避免冲突,如下:
class Test{
class obj{}
int obj = 0;
public void obj(){
}
}
在同一个作用域内声明了三个不同类型但是名称相同的符号,这些符号最终都会占用hash表中相同的槽位。并且通过shadowed相连,新加入的插入链表的头部,这样查找符号时总是能找到离自己作用域最近的符号的定义,实现了隐藏某些作用域的效果。
定义在同一个作用域内的符号会通过sibling来形成链,通过elems来保存链表的头部,nelems来保存作用域内存储的符号总数。这两个属性的定义如下:
/** A linear list that also contains all entries in * reverse order of appearance (i.e later entries are pushed on top). */ public Entry elems; /** The number of elements in this scope. * This includes deleted elements, whose value is the sentinel. */ int nelems = 0;
由于作用域可以嵌套,所以通过next属性来引用上一个嵌套的作用域,并且每个作用域都有所属的符号owner,属性定义如下:
/** Next enclosing scope (with whom this scope may share a hashtable) */ public Scope next; /** The scope's owner. */ public Symbol owner;
为了节省符号表空间,存储符号的table数组还可能共享,也就是不同的作用域使用同一个table数组,所以通过shared属性来表示,如果当前scope的next所指向的scope的shared属性为1,表示next所指向的Scope作用域与当前作用域共享同一个table数组。这个属性的定义如下:
/** The number of scopes that share this scope's hash table. */ private int shared; // 是个私有变量
2.2 Scope重要方法的介绍
(1)enter()方法
(2)leave()方法
(3)lookup()方法
检查符号定义的唯一性(比如方法或者是变量)
2.3 实例分析
3、类型的表示

4、符号的访问(访问者模式)
第六章-Javac符号表的更多相关文章
- 2017.2.28 activiti实战--第六章--任务表单(二)外置表单
学习资料:<Activiti实战> 第六章 任务表单(二)外置表单 6.3 外置表单 考虑到动态表单的缺点(见上节),外置表单使用的更多. 外置表单的特点: 页面的原样显示 字段值的自动填 ...
- 2017.2.28 activiti实战--第六章--任务表单(一)动态表单
学习资料:<Activiti实战> 第六章 任务表单(一)动态表单 内容概览:本章要完成一个OA(协同办公系统)的请假流程的设计,从实用的角度,讲解如何将activiti与业务紧密相连. ...
- 2017.2.22 activiti实战--第六章--任务表单
学习资料:<Activiti实战> 第六章 任务表单 本章将一步步完成一个协同办公系统(OA)的请假流程的设计,讲解如何将Activiti和实际业务联系起来. 首先讲解动态表单与外置表单的 ...
- 《深入理解java虚拟机》第六章 类文件结构
第六章 类文件结构 6.2 无关性的基石 各种不同平台的虚拟机与所有的平台都统一使用的程序存储格式--字节码(ByteCode)是构成平台无关性的基石.java虚拟机不和包括java在内的任何语言 ...
- JVM学习笔记-第六章-类文件结构
JVM学习笔记-第六章-类文件结构 6.3 Class类文件的结构 本章中,笔者只是通俗地将任意一个有效的类或接口锁应当满足的格式称为"Class文件格式",实际上它完全不需要以磁 ...
- 《Django By Example》第六章 中文 翻译 (个人学习,渣翻)
书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:无他,祝大家年会都中奖!) 第六章 ...
- CSS3秘笈:第六章
第六章 文本格式化 1.font-family 属性设置字体.除了指定想要的字体之外还要使用备用字体.例如: p{ font-family:Arial ,Helvetica ,sans-serif; ...
- 第二章 Javac编译原理
注:本文主要记录自<深入分析java web技术内幕>"第四章 javac编译原理" 1.javac作用 将*.java源代码文件转化为*.class文件 2.编译流程 ...
- 第六章、Linux 的文件权限与目录配置
第六章.Linux 的文件权限与目录配置 1. 使用者与群组 2. Linux文件权限概念 2.1 Linux文件属性 2.2 如何改变文件属性与权限: chgrp, chown, chmod 2.3 ...
随机推荐
- best performance / best appearance
- kepware http接口 Objective-C开发
读取某变量的值(NSURL #import <Foundation/Foundation.h> NSDictionary *headers = @{ @"Connection&q ...
- noip第6课资料
- 转载:Java项目读取配置文件时,FileNotFoundException 系统找不到指定的文件,System.getProperty("user.dir")的理解
唉,读取个文件,也就是在项目里面去获得配置文件的目录,然后,变成文件,有事没事,总是出个 FileNotFoundException 系统找不到指定的文件,气死人啦. 还有就是:System.get ...
- hdu 4923 单调栈
http://acm.hdu.edu.cn/showproblem.php?pid=4923 给定一个序列a,元素由0,1组成,求一个序列b,元素在0~1之间,并且保证递增.输出最小的∑(ai−bi) ...
- 2.mongodb可视化工具
(1)去robomongo官方网址下载,官网地址(https://robomongo.org/)选择相应的版本. (2) tar -xzf robo3t-1.2.1-linux-x86_64-3e50 ...
- lnmp mysql添加用户命令
cd /usr/local/mysql/bin/grant all privileges on *.* to 'root'@'%' identified by '12345678';flush pri ...
- SQL Server 阻塞原因分析
这里通过连接在sysprocesses里字段值的组合来分析阻塞源头,可以把阻塞分为以下5种常见的类型(见表).waittype,open_tran,status,都是sysprocesses里的值,“ ...
- tfs查看最近签入记录及文件
在团队资源管理=>源代码管理资源管理器=>选择某个最近签入的文件夹=>右键=>查看历史记录=>双击某个文件夹 就能看到最近变更集文件
- Linux启动流程与模块管理(15)
系统的启动其实是一项非常复杂的过程,因为内核得要检测硬件并加载适当的驱动程序,接下来则必须要调用程序来准备好系统运行的环境,以让用户能够顺利的操作整台主机系统,如果你能够理解系统启动的原理,那么将有助 ...