日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Javac源码简单分析之解析和填充符号表

發布時間:2023/12/16 java 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Javac源码简单分析之解析和填充符号表 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、說明

符號表是由一組符號地址和符號信息構成的表格。符號表中所登記的信息在編譯的不同階段都要用到,在語義分析(后面的步驟)中,符號表所登記的內容將用于語義檢查和產生中間代碼,在目標代碼生成階段,黨對符號名進行地址分配時,符號表是地址分配的依據。


二、主要的類與方法

解析和填充符號表這個過程主要由com.sun.tools.javac.comp.Entry及com.sun.tools.javac.comp.MemberEnter兩個類來實現的。 ?


? ?

com.sun.tools.javac.comp.Entry 主要的方法如下:

/*** 訪問類聲明*/public void visitClassDef(JCClassDecl tree) {Symbol owner = env.info.scope.owner;Scope enclScope = enterScope(env);ClassSymbol c;if (owner.kind == PCK) {// We are seeing a toplevel class.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.len != 0 &&!chk.checkUniqueClassName(tree.pos(), tree.name, enclScope)) {result = null;return;}if (owner.kind == TYP) {// We are seeing a member class.c = reader.enterClass(tree.name, (TypeSymbol)owner);if ((owner.flags_field & INTERFACE) != 0) {tree.mods.flags |= PUBLIC | STATIC;}} else {// We are seeing a local class.c = reader.defineClass(tree.name, owner);c.flatname = chk.localClassName(c);if (c.name.len != 0)chk.checkTransparentClass(tree.pos(), c, env.info.scope);}}tree.sym = c;// Enter class into `compiled' table and enclosing scope.if (chk.compiled.get(c.flatname) != null) {duplicateClass(tree.pos(), c);result = new ErrorType(tree.name, (TypeSymbol)owner);tree.sym = (ClassSymbol)result.tsym;return;}chk.compiled.put(c.flatname, c);enclScope.enter(c);// Set up an environment for class block and store in `typeEnvs'// table, to be retrieved later in memberEnter and attribution.Env<AttrContext> localEnv = classEnv(tree, env);typeEnvs.put(c, localEnv);// Fill out class fields.c.completer = memberEnter;c.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, c, tree);c.sourcefile = env.toplevel.sourcefile;c.members_field = new Scope(c);ClassType ct = (ClassType)c.type;if (owner.kind != PCK && (c.flags_field & STATIC) == 0) {// We are seeing a local or inner class.// Set outer_field of this class to closest enclosing class// which contains this class in a non-static context// (its "enclosing instance class"), provided such a class exists.Symbol owner1 = owner;while ((owner1.kind & (VAR | MTH)) != 0 &&(owner1.flags_field & STATIC) == 0) {owner1 = owner1.owner;}if (owner1.kind == TYP) {ct.setEnclosingType(owner1.type);}}// Enter type parameters.ct.typarams_field = classEnter(tree.typarams, localEnv);// Add non-local class to uncompleted, to make sure it will be// completed later.if (!c.isLocal() && uncompleted != null) uncompleted.append(c); // System.err.println("entering " + c.fullname + " in " + c.owner);//DEBUG// Recursively enter all member classes.classEnter(tree.defs, localEnv);result = c.type;}/** Main method: enter all classes in a list of toplevel trees.* @param trees The list of trees to be processed.*/public void main(List<JCCompilationUnit> trees) {complete(trees, null);}/*** Main method: enter one class from a list of toplevel trees and* place the rest on uncompleted for later processing.* @param trees The list of trees to be processed.* @param c The class symbol to be processed.*/public void complete(List<JCCompilationUnit> trees, ClassSymbol c) {annotate.enterStart();ListBuffer<ClassSymbol> prevUncompleted = uncompleted;if (memberEnter.completionEnabled) uncompleted = new ListBuffer<ClassSymbol>();try {// enter all classes, and construct uncompleted listclassEnter(trees, null);// complete all uncompleted classes in memberEnterif (memberEnter.completionEnabled) {while (uncompleted.nonEmpty()) {ClassSymbol clazz = uncompleted.next();if (c == null || c == clazz || prevUncompleted == null)clazz.complete();else//將類符號放入prevUncompleted列表(uncompleted列表)prevUncompleted.append(clazz);}// if there remain any unimported toplevels (these must have// no classes at all), process their import statements as well./*** uncompleted列表沒有的符號(除類符號外),根據improt聲明,給頂級抽象樹都添加了一個MemberEnter對象* 這些符號(包括類的參數類型符號也就是泛型、父類符號、接口類型符等)*/for (JCCompilationUnit tree : trees) {if (tree.starImportScope.elems == null) {JavaFileObject prev = log.useSource(tree.sourcefile);Env<AttrContext> env = typeEnvs.get(tree);if (env == null)env = topLevelEnv(tree);memberEnter.memberEnter(tree, env);log.useSource(prev);}}}} finally {//prevUncompleted列表賦值給uncompleted列表uncompleted = prevUncompleted;annotate.enterDone();}}

com.sun.tools.javac.comp.MemberEnter 主要的方法如下:

/** Complete entering a class.* 將未處理列表中的所有符號都解析到各自的類符號表中* @param sym The symbol of the class to be completed.*/public void complete(Symbol sym) throws CompletionFailure {// Suppress some (recursive) MemberEnter invocationsif (!completionEnabled) {// Re-install same completer for next time around and return.assert (sym.flags() & Flags.COMPOUND) == 0;sym.completer = this;return;}ClassSymbol c = (ClassSymbol)sym;ClassType ct = (ClassType)c.type;Env<AttrContext> env = enter.typeEnvs.get(c);JCClassDecl tree = (JCClassDecl)env.tree;boolean wasFirst = isFirst;isFirst = false;JavaFileObject prev = log.useSource(env.toplevel.sourcefile);try {// Save class environment for later member enter (2) processing.halfcompleted.append(env);// If this is a toplevel-class, make sure any preceding import// clauses have been seen.if (c.owner.kind == PCK) {memberEnter(env.toplevel, env.enclosing(JCTree.TOPLEVEL));todo.append(env);}// Mark class as not yet attributed.c.flags_field |= UNATTRIBUTED;if (c.owner.kind == TYP)c.owner.complete();// create an environment for evaluating the base clausesEnv<AttrContext> baseEnv = baseEnv(tree, env);// Determine supertype.Type supertype =(tree.extending != null)? attr.attribBase(tree.extending, baseEnv, true, false, true): ((tree.mods.flags & Flags.ENUM) != 0 && !target.compilerBootstrap(c))? attr.attribBase(enumBase(tree.pos, c), baseEnv,true, false, false): (c.fullname == names.java_lang_Object)? Type.noType: syms.objectType;ct.supertype_field = supertype;// Determine interfaces.ListBuffer<Type> interfaces = new ListBuffer<Type>();Set<Type> interfaceSet = new HashSet<Type>();List<JCExpression> interfaceTrees = tree.implementing;if ((tree.mods.flags & Flags.ENUM) != 0 && target.compilerBootstrap(c)) {// add interface Comparable<T>interfaceTrees =interfaceTrees.prepend(make.Type(new ClassType(syms.comparableType.getEnclosingType(),List.of(c.type),syms.comparableType.tsym)));// add interface SerializableinterfaceTrees =interfaceTrees.prepend(make.Type(syms.serializableType));}for (JCExpression iface : interfaceTrees) {Type i = attr.attribBase(iface, baseEnv, false, true, true);if (i.tag == CLASS) {interfaces.append(i);chk.checkNotRepeated(iface.pos(), types.erasure(i), interfaceSet);}}if ((c.flags_field & ANNOTATION) != 0)ct.interfaces_field = List.of(syms.annotationType);elsect.interfaces_field = interfaces.toList();if (c.fullname == names.java_lang_Object) {if (tree.extending != null) {chk.checkNonCyclic(tree.extending.pos(),supertype);ct.supertype_field = Type.noType;}else if (tree.implementing.nonEmpty()) {chk.checkNonCyclic(tree.implementing.head.pos(),ct.interfaces_field.head);ct.interfaces_field = List.nil();}}// Annotations.// In general, we cannot fully process annotations yet, but we// can attribute the annotation types and then check to see if the// @Deprecated annotation is present.attr.attribAnnotationTypes(tree.mods.annotations, baseEnv);if (hasDeprecatedAnnotation(tree.mods.annotations))c.flags_field |= DEPRECATED;annotateLater(tree.mods.annotations, baseEnv, c);attr.attribTypeVariables(tree.typarams, baseEnv);chk.checkNonCyclic(tree.pos(), c.type);/*** 增加一個默認的構造方法(當類沒有構造方法時)*/if ((c.flags() & INTERFACE) == 0 &&!TreeInfo.hasConstructors(tree.defs)) {List<Type> argtypes = List.nil();List<Type> typarams = List.nil();List<Type> thrown = List.nil();long ctorFlags = 0;boolean based = false;if (c.name.len == 0) {JCNewClass nc = (JCNewClass)env.next.tree;if (nc.constructor != null) {Type superConstrType = types.memberType(c.type,nc.constructor);argtypes = superConstrType.getParameterTypes();typarams = superConstrType.getTypeArguments();ctorFlags = nc.constructor.flags() & VARARGS;if (nc.encl != null) {argtypes = argtypes.prepend(nc.encl.type);based = true;}thrown = superConstrType.getThrownTypes();}}JCTree constrDef = DefaultConstructor(make.at(tree.pos), c,typarams, argtypes, thrown,ctorFlags, based);tree.defs = tree.defs.prepend(constrDef);}// If this is a class, enter symbols for this and super into// current scope.if ((c.flags_field & INTERFACE) == 0) {VarSymbol thisSym =new VarSymbol(FINAL | HASINIT, names._this, c.type, c);thisSym.pos = Position.FIRSTPOS;env.info.scope.enter(thisSym);if (ct.supertype_field.tag == CLASS) {VarSymbol superSym =new VarSymbol(FINAL | HASINIT, names._super,ct.supertype_field, c);superSym.pos = Position.FIRSTPOS;env.info.scope.enter(superSym);}}// check that no package exists with same fully qualified name,// but admit classes in the unnamed package which have the same// name as a top-level package.if (checkClash &&c.owner.kind == PCK && c.owner != syms.unnamedPackage &&reader.packageExists(c.fullname)){log.error(tree.pos, "clash.with.pkg.of.same.name", c);}} catch (CompletionFailure ex) {chk.completionError(tree.pos(), ex);} finally {log.useSource(prev);}// Enter all member fields and methods of a set of half completed// classes in a second phase.if (wasFirst) {try {while (halfcompleted.nonEmpty()) {finish(halfcompleted.next());}} finally {isFirst = true;}// commit pending annotationsannotate.flush();}}

三、過程及簡單源碼解析

Enter過程中,編譯器會找到當前范圍(enclosing scope)中發現的所有的定義(definitions),并且把這些定義注冊成符號(symbols)。
Enter又分為以下兩個階段:


第一個階段:



編譯器會注冊所有類的符號,并且把這寫符號和相應的范圍(scope)聯系在一起。實現方法是使用一個Visitor(訪問者)類,由上而下的遍歷AST(抽象語法樹),訪問所有的類,包括類里面的內部類。Enter給每一個類的符號都添加了一個MemberEnter對象,這個對象是由第二個階段來調用的。
?

整個操作的方法調用過程如下:




上面這個過程是訪問者模式的一種實現。
Enter是一個JCTree.Visitor.Enter.classEnter(l.head, env)調用JCTree.accept(Visitor v),而accept方法又是調用的Visitor類里面的visitXXX()方法,而這些方法的實現又是在Enter類中。也就是Enter.visitClassDef(JCClassDecl tree)方法,在這個方法中,會將類符號放入uncompleted列表;?


visitClassDef(JCClassDecl tree)方法主要做三件事:

1、將類符號(當前類)填入類自身的符號表,添加了一個MemberEnter對象
? ? ? ?

// Enter class into `compiled' table and enclosing scope.if (chk.compiled.get(c.flatname) != null) {duplicateClass(tree.pos(), c);result = new ErrorType(tree.name, (TypeSymbol)owner);tree.sym = (ClassSymbol)result.tsym;return;}chk.compiled.put(c.flatname, c);enclScope.enter(c);// Set up an environment for class block and store in `typeEnvs'// table, to be retrieved later in memberEnter and attribution.Env<AttrContext> localEnv = classEnv(tree, env);typeEnvs.put(c, localEnv);// Fill out class fields.c.completer = memberEnter;c.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, c, tree);c.sourcefile = env.toplevel.sourcefile;c.members_field = new Scope(c);


2、解析填寫其它的類符號,包括當前類中使用到的內部類、枚舉、變量等抽象樹的類符號。
// Enter type parameters.ct.typarams_field = classEnter(tree.typarams, localEnv);



3、將類符號放入uncompleted列表
? ? ? ?? if (!c.isLocal() && uncompleted != null) uncompleted.append(c);




Enter給每一個類的符號都添加了一個MemberEnter對象,這個對象是由第二個階段來調用的。
memberEnter.memberEnter(tree, env);

第二個階段:



這些類被MemberEnter對象所完成(completed,即完成類的成員變量的Enter)。首先,MemberEnter決定一個類的參數,父類和接口。然后這些符號被添加進了類的范圍中。不像前一個步驟,這個步驟是懶惰執行的。類的成員只有在被訪問時,才加入類的定義中的。這里的實現,是通過安裝一個完成對象(member object)到類的符號中。這些對象可以在需要時調用memberEnter。



整個操作的方法調用過程如下:



Enter是一個JCTree.Visitor.Enter.classEnter(l.head, env)調用JCTree.accept(Visitor v),而accept方法又是調用的Visitor類里面的visitXXX()方法,而這些方法的實現又是在Enter類中。也就是Enter.visitClassDef(JCClassDecl tree)方法,在這個方法中,會將類符號解析和填入類自身的符號表。




最后,enter把所有的頂層類(top-level classes)放到一個todo-queue中。


總結

以上是生活随笔為你收集整理的Javac源码简单分析之解析和填充符号表的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。