編譯器開發系列--Ocelot語言4.類型定義的檢查

這裏主要介紹一下檢查循環定義的結構體、聯合體。是對成員中包含本身自己的結構體、聯合體進行檢查。所謂「成員中包含本身自己」,舉例來講,就是指下面這樣的定義。java

struct point {
struct point p;
};

這裏所說的「成員中包含本身自己」是指直接包含本身自己,經過指針來應用本身自己是沒有問題的。例如剛纔的例子,若是是下面這樣的話就沒有問題了。算法

struct point {
struct point *ptr;
};

剛纔的例子中存在直接的循環定義,所以一眼就能看出來。還有以下所示的間接循環定義的狀況,也須要注意。數組

struct point_x {
    struct point_y y;
};

typedef struct point_x my_point_x;

struct point_y {
    my_point_x x;
};

上述例子中還夾雜着使用typedef 定義的類型,所以調查起來更爲繁瑣。ui

檢查「循環定義的類型」的方法。進行這樣的類型檢查須要將類型定義的總體看成圖(graph)來思考。spa

將類型的定義抽象爲圖時,能夠將類型做爲節點,將該類型對其餘類型的引用做爲邊。例如結構體的定義,將該結構體的類型做爲節點,向成員的類型的節點鏈接一條邊。使用typedef 的狀況下,將新定義的類型做爲節點,向原來的類型節點引一條邊。指針

再來看一個例子。如今假設有以下所示的定義。對象

struct st {
    struct point pnt;
    long len;
};

typedef unsigned int uint;

struct point {
    uint x;
    uint y;
};

將上述定義轉化爲圖,如圖10.2 所示。blog

若是發生循環定義,那麼在生成類型定義的圖時,圖中某處一定存在閉環。循環定義狀況下的圖如圖10.3 所示。get

可見圖中存在閉環。檢查是否存在循環定義,只需檢查類型定義的圖中是否存在閉環便可it

檢測有向圖中的閉環的算法

由於邊存在方向性,因此類型定義的圖屬於有向圖。要檢測有向圖中是否存在閉環,可使用以下算法。

1. 選擇任意一個節點(類型)並標註爲「查找中」
2. 沿着邊依次訪問全部與該節點相鄰的節點
3. 若是訪問到的節點沒有標註任何狀態,則將該節點標註爲「查找中」;若是標註了「查找結束」,則不作任何處理,返回以前的節點;若是已經標註爲「查找中」,則說明存在閉環
4. 從當前的節點重複步驟2 和3,若是已經沒有可訪問的相鄰節點,則將該節點標註爲「查找結束」,並沿原路返回
5. 按照上述流程對全部節點進行處理,若是查找過程當中沒有遇到「查找中」狀態的節點,就說明不存在閉環

上述算法中使用了「有向圖的深度優先檢索」來檢測閉環。簡單地說,該算法的概要就是「只要節點有未訪問的相鄰節點就試着訪問,調查是否會回到原來的節點」。從算法執行過程當中的某一時刻來看,就是在爲從起始節點到某一節點的路徑上的全部節點標註上「查找中」的狀態。

具體算法以下:

    protected void checkRecursiveDefinition(Type t, ErrorHandler h) {
        _checkRecursiveDefinition(t, new HashMap<Type, Object>(), h);
    }

    static final protected Object checking = new Object();
    static final protected Object checked = new Object();

    /*結構體、聯合體的循環定義檢查
     * 結構體、聯合體、數組、typedef 所定義的類型之外的類型只有整數類型和指針,所以除
		了上述4 個類型之外,其餘狀況下都不可能出現邊。包含某類型的指針的狀況下,由於不會產
		生循環依賴,因此不會有問題。
		算法說明中的「標註狀態」的實現方式是「將Type 對象和它的狀態做爲一組保存在
		Map 對象marks 中」,這是上述算法的重點。
     */
    protected void _checkRecursiveDefinition(Type t,
                                             Map<Type, Object> marks,
                                             ErrorHandler h) {
    	/*
    	 * 若是t 的狀態爲「查找中」,輸出錯誤並return
    	 */
        if (marks.get(t) == checking) {
            h.error(((NamedType)t).location(),
                    "recursive type definition: " + t);
            return;
        }
        /*
         * t 的狀態爲「查找結束」
         */
        else if (marks.get(t) == checked) {
            return;
        }
        /*
         * 訪問的節點尚未被標註狀態。
         * 將t 標註爲「查找中」,
         * 訪問全部和t 相鄰的節點(調用_checkRecursiveDefinition),
         * 將t 標註爲「查找結束」。
         */
        else {
            marks.put(t, checking);
            if (t instanceof CompositeType) {
                CompositeType ct = (CompositeType)t;
                for (Slot s : ct.members()) {
                    _checkRecursiveDefinition(s.type(), marks, h);
                }
            }
            else if (t instanceof ArrayType) {
                ArrayType at = (ArrayType)t;
                _checkRecursiveDefinition(at.baseType(), marks, h);
            }
            else if (t instanceof UserType) {
                UserType ut = (UserType)t;
                _checkRecursiveDefinition(ut.realType(), marks, h);
            }
            marks.put(t, checked);
        }
    }
相關文章
相關標籤/搜索