本篇文章为你整理了java编译器源码解析(java编译器原理)的详细内容,包含有java编译器源代码 java编译器原理 java编译器ij 编译java源代码 java编译器源码解析,希望能帮助你了解 java编译器源码解析。
填充符号表的核心逻辑在com.sun.tools.javac.comp.Enter类。
在讨论填充符号表的逻辑之前,首先要明确一下,什么是符号?
我们在java代码中,可能会声明一个类,类中有属性和方法,这些对于计算机而言,都是一种符号。
在java编译器的实现中,定义了专门的符号类Symbol及相关的子类
符号有名称,就是我们理解的类名、方法名和属性名。
除此之外,符号还有类型,java专门设计了一套符号类型系统来标识它。
我们举个例子
int a=0;
我们知道,a是一个变量,但编译器认为a是一个VarSymbol,它的类型是JCPrimitiveType.
在执行程序的时候,原生类型和引用类型有不同的处理方式。
原生类型可能存放在常量池中,但引用类型必须存在堆中,所以在编译器在编译期间就需要标识起来。
填充符号表分为两个阶段:
第一:类符号填充Enter
主方法为complete()所有类都进入其作用域,在visit类声明的时候,给相关的JCClassDecl节点的sym类型定义了一个ClassSymbol的值。
类符号填充完成后,进入第二阶段,调用enterMember.complete方法
第二:其他成员符号填充
逻辑在MemberEnter类的complete方法中
MemberEnter.visitMethodDef()给方法声明节点的符号表填充符号。
MemberEnter.visitVarDef()给变量声明节点的符号表填充符号。
第三:其他的符号填充在后续阶段完成
生成符号的同时,符号也被放入相应的Scope中。
Scope又叫作用域,它是符号Symbol的容器,它提供了使用符号名访问符号的方法。
Scope类被实现为具有“开放寻址”和“双重哈希”的哈希表。Scope是可以嵌套的。
二、Symbol及其核心子类
虽然我们这一步的工作是填充符号表,但我发现并不是JCTree所有的节点都有对应的符号,查看源码发现只有这些节点是有对应符号的。
JCCompilationUnit里持有PackageSymbol属性,
JCClassDecl持有ClassSymbol属性,属性名sym
JCMethodDecl持有MethodSymbol属性
JCVariableDecl持有VarSymbol属性
JCNewClass持有Symbol类型的属性,属性名constructor
JCAssignOp持有Symbol类型的属性,属性名operator
JCUnary持有Symbol类型的属性,属性名operator
JCBinary持有Symbol类型的属性,属性名operator
JCFieldAccess持有Symbol属性
JCIdent持有Symbol属性
三、填充符号表
3.1.访问类定义
那么以我们的理解,当我们在AST上visit到一个类定义的时候,一定会生成一个ClassSymbol对象,然后放到符号表中。
我们看下javac中的源码实现,验证一下我们的想法,下面是Enter.visitClassDef()
我们可以看到在visitClassDef中的第三行声明了一个类符号——ClassSymbol c,经常一系列初始化后c被赋值给tree.sym,就在这个节点对应的符号属性
同时我们还看到了作用域有关的信息,第二行就获取了当前作用域enclScope,经过一系列操作后,把当前符号c放入了作用域enclScope中,实际是将符号放入了Scope中的一些Entry数组中。
public void visitClassDef(JCClassDecl tree) {
Symbol owner = env.info.scope.owner;
//获取当前作用域
Scope enclScope = enterScope(env);
//类符号的声明
ClassSymbol c;
if (owner.kind == PCK) {
// 顶级类声明
PackageSymbol packge = (PackageSymbol)owner;
for (Symbol q = packge; q != null q.kind == PCK; q = q.owner)
q.flags_field = EXISTS;
//类符号的定义
c = reader.enterClass(tree.name, packge);
//将当前类放入当前包的作用域中
packge.members().enterIfAbsent(c);
if ((tree.mods.flags PUBLIC) != 0 !classNameMatchesFileName(c, env)) {
log.error(tree.pos(),
"class.public.should.be.in.file", tree.name);
} else {
if (!tree.name.isEmpty()
!chk.checkUniqueClassName(tree.pos(), tree.name, enclScope)) {
result = null;
return;
if (owner.kind == TYP) {
// 内部类声明
c = reader.enterClass(tree.name, (TypeSymbol)owner);
if ((owner.flags_field INTERFACE) != 0) {
tree.mods.flags = PUBLIC STATIC;
} else {
// 局部类声明
c = reader.defineClass(tree.name, owner);
c.flatname = chk.localClassName(c);
if (!c.name.isEmpty())
chk.checkTransparentClass(tree.pos(), c, env.info.scope);
//将符号放入当前AST节点的符号表中
tree.sym = c;
// Enter class into `compiled table and enclosing scope.
if (chk.compiled.get(c.flatname) != null) {
duplicateClass(tree.pos(), c);
result = types.createErrorType(tree.name, (TypeSymbol)owner, Type.noType);
tree.sym = (ClassSymbol)result.tsym;
return;
chk.compiled.put(c.flatname, c);
//将类符号c放入当前作用域
enclScope.enter(c);
}
3.2.访问方法定义
访问定义在MemberEnter.visitMethodDef()中,与访问类定义类似,首先获取了当前作用域,创建方法符号,然后将符号赋值给当前节点的sym属性,并将符号加入当前作用域
public void visitMethodDef(JCMethodDecl tree) {
//获取当前作用域
Scope enclScope = enter.enterScope(env);
//创建方法符号
MethodSymbol m = new MethodSymbol(0, tree.name, null, enclScope.owner);
m.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, m, tree);
//将方法符号赋值给当前节点
tree.sym = m;
//if this is a default method, add the DEFAULT flag to the enclosing interface
if ((tree.mods.flags DEFAULT) != 0) {
m.enclClass().flags_field = DEFAULT;
//创建当前方法的局部变量作用域
Env AttrContext localEnv = methodEnv(tree, env);
annotate.enterStart();
try {
//将所有参数加入局部变量作用域
m.type = signature(m, tree.typarams, tree.params,
tree.restype, tree.recvparam,
tree.thrown,
localEnv);
//删除当前局部作用域的所有entry
localEnv.info.scope.leave();
if (chk.checkUnique(tree.pos(), m, enclScope)) {
//将方法符号加入当前作用域中
enclScope.enter(m);
} finally {
annotate.enterDone();
}
3.3.访问变量定义
MemberEnter.visitVarDef()
public void visitVarDef(JCVariableDecl tree) {
//获取当前变量所在环境
Env AttrContext localEnv = env;
if ((tree.mods.flags STATIC) != 0
(env.info.scope.owner.flags() INTERFACE) != 0) {
localEnv = env.dup(tree, env.info.dup());
localEnv.info.staticLevel++;
//获取当前作用域
Scope enclScope = enter.enterScope(env);
//创建变量符号
VarSymbol v =
new VarSymbol(0, tree.name, tree.vartype.type, enclScope.owner);
v.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, v, tree);
//将符号赋值给当前节点的sym属性
tree.sym = v;
if (chk.checkUnique(tree.pos(), v, enclScope)) {
chk.checkTransparentVar(tree.pos(), v, enclScope);
//将变量符号加入作用域
enclScope.enter(v);
annotateLater(tree.mods.annotations, localEnv, v, tree.pos());
typeAnnotate(tree.vartype, env, v, tree.pos());
v.pos = tree.pos;
} finally {
annotate.enterDone();
}
以上就是java编译器源码解析(java编译器原理)的详细内容,想要了解更多 java编译器源码解析的内容,请持续关注盛行IT软件开发工作室。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。