編輯:關於android開發
“類型名稱的消解”即類型的消解。類型名稱由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; }
RecyclerView和PullToRefreshListView的對比,recyclerview項目中上拉刷新和下拉加載一直都是比較常見的;以前一般都是重寫ListV
Android設計模式之一個例子讓你徹底明白裝飾者模式(Decorator Pattern) 導讀 這篇文章中我不會使用概念性文字來說明裝飾者模式,因為通常概念性的問題都
System.exit(0)和System.exit(1)區別,system.exit區別1.參考文獻 http://hi.baidu.com/accpzhangbo
Android 塗鴉最佳實踐 Android中實現手勢畫圖一般都兩種方式,一是直接在View上繪制,而是使用SurfaceView。 兩者還是有一些差別的。簡介下。