Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> 編譯器開發系列--Ocelot語言3.類型名稱的消解,編譯器--ocelot

編譯器開發系列--Ocelot語言3.類型名稱的消解,編譯器--ocelot

編輯:關於android開發

編譯器開發系列--Ocelot語言3.類型名稱的消解,編譯器--ocelot


“類型名稱的消解”即類型的消解。類型名稱由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;
    }

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved