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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

第七章-填充符号表

發(fā)布時間:2023/12/16 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 第七章-填充符号表 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

解析和填充符號表這個過程主要由com.sun.tools.javac.comp.Enter及com.sun.tools.javac.comp.MemberEnter兩個類來實現的。這兩個類會將遇到的所有的定義填充到符號表中,并且把這寫符號和相應的范圍(scope)聯系在一起。實現方法是就是通過前面講解的Visitor(訪問者)類來實現的,由上而下的遍歷AST(抽象語法樹),訪問所有的類,包括類里面的成員類。?

?

1、符號的查找及輸入

對于Javac來說,首先會涉及到依賴符號的查找,例如某個類對依賴類List中的方法調用,就需要通過符號來進行查找。對于包下的類符號及類中成員的符號的加載涉及到一個非常重要的接口:SymbolCompleter,這個接口的定義如下:

/** Symbol completer interface.*/ public interface SymbolCompleter {void complete(Symbol sym) throws SymbolCompletionFailure; }

兩個重要的實現類為ClassReader與MemberEnter,關于MemberEnter的實現及complete()方法的實現邏輯將在后面進行詳細的說明。這里重點說明ClassReader中一些重要的方法。?

/** Completion for classes to be loaded(完成要加載的類). Before a class is loaded* we treeMaker sure its enclosing class (if any) is loaded.*/ public void complete(Symbol sym) throws SymbolCompletionFailure {if (sym.kind == TYP02) {ClassSymbol c = (ClassSymbol)sym;c.members_field = new ErrorScope(c); // treeMaker sure it's always defined// suppressFlush值可以保證下面的annotate在內部類加載完成時只調用一次// 不會由于外部類的加載而重復調用boolean saveSuppressFlush = suppressFlush;suppressFlush = true;try {completeOwners(c.owner);completeEnclosing(c);} finally {suppressFlush = saveSuppressFlush;}fillInClassSymbol(c);} else if (sym.kind == PCK01) {PackageSymbol p = (PackageSymbol)sym;try {fillInPackageSymbol(p);} catch (IOException ex) {throw new SymbolCompletionFailure(sym, ex.getLocalizedMessage()).initCause(ex);}}if (!filling && !suppressFlush) { // 當沒有在讀一個文件并且不需要抑制刷新時annotate.flush(); // finish attaching annotations} }

?可以看到有兩個重要的處理邏輯,一個是對符號類型為TYP02的處理,也就是對類或接口中定義的符號的填充,另外就是對包的處理。

可以這樣想一下,我們在引入依賴類或者繼承了父類時,最可能會用到這些類中定義的成員類、變量及方法,那么就需要將這些符號填充到符號表中便于后面進行語義分析。 

主要是調用fillInClassSymbol(c)來將類內定義的符號填充到members_field屬性中的。在fillInClassSymbol()方法中最主要調用了readClassFile(c)來完成對.class文件的讀取,由于讀取時涉及到了.class文件的內容,這些將在后面的章節(jié)進行詳細的講解。

看一下包符號的填充,這個類似于類符號的填充,主要讀取了這個包下的所有類符號并填充到members_field屬性中。調用的fillInPackageSymbol()方法正是在第二章-文件的讀取與寫入時詳細講解過,這里不做過多介紹。 

?

?

?

2、符號輸入第一階段?

?

/** Bootstrap 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 list// 輸入所有類,創(chuàng)建未完成列表classEnter(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.append(clazz); // defer}}// if there remain any unimported toplevels (these must have// no classes at all), process their import statements as well.for (JCCompilationUnit tree : trees) {if (tree.starImportScope.elems == null) {JavaFileObject prev = log.useSource(tree.sourcefile);Env<AttrContext> topEnv = topLevelEnv(tree);memberEnter.memberEnter(tree, topEnv);log.useSource(prev);}}}} finally {uncompleted = prevUncompleted;annotate.enterDone(); // 處理放到隊列中元素(方法與變量)上的注解} }

  

Enter類繼承了JCTreeVisitor類,這樣就可以通過選擇性的覆寫訪問者方法visitXXX()來實現自己想處理的邏輯了,在Enter中主要覆寫了如下2個訪問者方法:?

(1)visitTopLevel?

填充package屬性,類型為PackageSymbol。如果當前有包名,則調用classReader.enterPackage(fn)賦值,否則值為syms.unnamedPackage。enterPackage()方法的源代碼如下:

/** Make a package, given its fully qualified name.*/ public PackageSymbol enterPackage(Name fullname) {PackageSymbol p = packages.get(fullname);if (p == null) {Assert.check(!fullname.isEmpty(), "rootPackage missing!");Name n = Convert.shortName(fullname);// 如果fullname=java.lang時,temp=javaName temp = Convert.packagePart(fullname);PackageSymbol parentPS = enterPackage(temp);p = new PackageSymbol(n,parentPS);p.completer = this;packages.put(fullname, p);}return p; }

為各個包建立PackageSymbol,并將建立好的符號存儲到packages中。這里將對每個PackageSymbol的completer屬性賦值為ClassReader對象。然后在visitTopLevel()中就可以直接調用package屬性的complete()方法完成包下類符號的填充了,如下代碼:

tree.packge.complete(); // Find all classes in package.

?

接著完成環(huán)境的創(chuàng)建:

?

Env<AttrContext> topEnv = topLevelEnv(tree);

?

  

輸入當前這個編譯單元中定義的類及類成員:

classEnter(tree.defs, topEnv);

  

?

?

(2)visitClassDef

對于visitClassDef()方法的處理邏輯相對多一些,不過主要的邏輯就是創(chuàng)建類的符號并賦值到JCClassDef節(jié)點的sym屬性上。對于頂層類的符號來說,除了要輸入到包的members_filed中,還要輸入到當前包下作用域的的符號表中。

將符號的completer屬性設置為MemberEnter實例,因為這些符號中定義的成員符號還沒有填充到相應的作用域下的符號表中,而這個工作將交由MemberEnter類來完成。

除此之外將類符號壓入隊列中,等待后續(xù)進一步處理其中定義的成員。

?

不過這些符號在通過import關鍵字引入時,在處理具體的引用時就已經被引入到了全局的符號表中了。通過JCCompliationUnit中的兩個重要屬性:

public ImportScope namedImportScope; public StarImportScope starImportScope;

來查找依賴符號。  

?

?

3、符號輸入第二階段?

?

MemberEnter類同樣繼承了JCTreeVisitor類,并對其實的一些visitXXX()方法進行了覆寫,被覆寫的方法主要有:

(1)visitTopLevel
(2)visitImport
(3)visitVarDef
(4)visitMethodDef?

由名字不難看出訪問的各個抽象語法樹的節(jié)點,不過這里沒有visitClassDef,因為每個代表類的樹節(jié)點的符號都會調用complete()方法,間接調用到MemberEnter()方法,如下:

在Enter的complete()方法中在處理完classEnter()后有如下調用邏輯:

while (uncompleted.nonEmpty()) {ClassSymbol clazz = uncompleted.next();if (c == null || c == clazz || prevUncompleted == null) {clazz.complete();} else {prevUncompleted.append(clazz); // defer} }

也就是取出uncompleted隊列中所有示完成的類符號并依次調用complete()方法,由于這些符號在符號輸入第一階段時都被賦值為MemberEnter實例,所以當然會調用MemberEnter的complete()方法。

MemberEnter類中的complete()方法的邏輯有點復雜,不過

?

?

?

  

?

成員包括類成員(靜態(tài)與非靜態(tài)成員)、方法及變量,不過這里并不包括方法形式參數及局部變量的處理,關于方法參數及局部變量的處理主要是在Attr標記階段完成的。

?

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

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

?

?

?

?

?

?

?

?

?

轉載于:https://www.cnblogs.com/extjs4/p/9713927.html

總結

以上是生活随笔為你收集整理的第七章-填充符号表的全部內容,希望文章能夠幫你解決所遇到的問題。

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