1. 程式人生 > >CPP巨集定義解析處理【python】

CPP巨集定義解析處理【python】

問題描述

c++巨集定義檔案中關鍵字有#define, #undef #ifndef, #ifdef, #else,#endif, 處理註釋,//,/*,*/, 解析檔案,輸出其中的巨集定義

分析思路

文字分析基礎是字串處理,巨集定義檔案的處理需要對遇到的關鍵字執行特殊的處理。

檔案定義的中間資料結構用巢狀列表,巨集定義主要是順序結構和分支結構,順序結構好理解,一個巨集定義作為一個字典,字典作為列表的元素;對於分支結構,用子列表表示它,這個子列表的結構如下

[

{{'id': 1},{'parent': 0}, {'pos':0}},    # id給當前子列表編號,parent是子列表的父列表編號,pos是當前處理分支的左右分支,true是左,標記為1;false是右,標記為2.

{'macro_key': ''}, #macro_key是當前分支結構的條件

[], #表示左子列表

[],#表示右子列表

]

這樣表示後,再定義當前分支子列表branch(這裡利用了python的引用特徵),當前列表編號node_id,父列表編號parent_id,左右分支位置pos,輔助對巢狀列表的遍歷。

儲存巨集定義的格式是巨集定義字典,鍵是巨集名,值是巨集定義值。還有一個輔助資料結構,預定義巨集名列表,用於記錄預定義的巨集名。

下面對遇到的不同關鍵字作不同的分析:

1. 對註釋的處理

註釋有三種,//,/*,*/,其中/*和*/成對出現,用棧來表示順序關係。採用逐個字元掃描的方法,對於每個字元,如果是//,後面的內容省略;對於/*,如果棧為空或/*,就入棧;對於*/,如果棧頂是/*, 就彈棧,遊標向後一步;否則,如果棧頂不是/*,說明是有效字元,否則忽略。

2. 對關鍵字的統一處理

巨集的定義一般是2個詞,或3個詞,中間空格分隔,常見的思路是split,這裡有個小坑,如果定義的是字串,字串中間有空格,這樣split會把第三個詞割裂了。這裡給split加個引數,maxsplit=2,意思是隻分隔前兩次遇到的空格,後面的作為整體。

2.1 遇到#ifndef: 

插入子列表

[{'id': node_id, 'parent': parent_id, 'pos': node_pos}, {key_name: ''}, [], []]

node_pos為2,表示右分支,branch分支指向字列表的第3個元素(空的子列表),其他欄位定義見上面的說明。

2.2 遇到#ifdef:

插入子列表

[{'id': node_id, 'parent': parent_id, 'pos': node_pos}, {key_name: ''}, [], []]

node_pos為1,表示左分支,branch分支指向字列表的第2個元素(也是一個空的子列表),其他欄位定義見上面的說明。

2.3 遇到#else:

需要切換分支,只需要修改pos值,1變成2,2變化成1;而且,當前branch是列表中的一個元素,需要找到它的父列表,我們就需要在整個巢狀列表上搜索父列表的id,找到這個列表,再根據pos調整到它的另外一個分支。如何搜尋指定id的列表?這個單獨設立一個函式,後面再詳述。

2.4 遇到#define:

這是巨集的一個定義,只需要在當前branch上append一個字典即可,如果只有巨集名,值域留空。

2.5 遇到#endif:

這是一個分支退出的標記,需要變換當前的branch到父列表上,左右分支要求能恢復到父列表對應的左右分支才行。同樣的,這裡用到對整個樹的搜尋,和#else不同的地方,#endif不指定左右分支位置。

2.6 遇到#undef:

undef表示取消設定巨集,

{'MC2': '', 'reverse': 1}

巨集字典後面再加一個欄位,reverse表示是取消巨集的設定。

至此,所有的關鍵字處理完畢。

對於巢狀列表的搜尋,用遞迴,演算法思路如下:

輸入引數3個,搜尋的分支branch,待搜尋的子列表號node_id,左右子列表型別(-1表示以搜尋到pos為準,1表示左字列表,2表示右子列表)

輸出結果2個,搜尋結果0失敗,1成功;[當前列表編號, 當前父列表編號, 當前左右分支位置, 當前分支branch]

如果當前分支為空,輸出0,[0, 0, 0, []]

獲取當前branch的字典型別元素的序列,找到包含id關鍵字的字典,比較id的值是不是node_id,如果是那就成功找到了,當要求的節點型別是1,2,分支取branch的子列表[1取左,2取右],輸出當前結果;當要求的節點型別是-1,取id關鍵字字典的pos,分支取branch的子列表[pos對應的子列表]

如果左子樹不空(子樹長度>=1),搜尋左子樹,如果搜尋結果欄位不為0,左子樹的輸出結果就是最終的結果

如果右子數不空(子樹長度==2),搜尋右子樹,如果搜尋結果欄位不為0,右子樹的輸出結果就是最終的結果

以上輸出條件都不滿足,輸出0,[0,0,0[]]

其他

整個過程還是非常有挑戰的,最後效果還好,複雜情況的處理還是火候不夠,很多情況的處理可以更好。加油吧。