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