基於GCC的C語言抽象語法樹重建與可視化研究


作者: 林 渤, 王梟雄, 胡建鵬:上海工程技術大學電子電氣工程學院,上海
關鍵詞: 抽象語法樹;GCC;C語言;可視化;AST; GCC; C Language; Visualization
摘要: 抽象語法樹(abstract syntax tree, AST)作為一種重要的中間表示形式,在代碼靜態分析領域有着重要的研究意義。本文通過研究GCC生成的抽象語法樹文本內容,給出重建抽象語法樹及可視化的方法。GCC編譯器生成的抽象語法樹內容存在大量冗余,不能直接進行解析。針對此問題,本文提出一種改進的去冗余算法,從根節點中先找到main函數后進行遍歷,相比常規的去冗余算法有更高的效率,同時針對可視化操作進行了結構性的優化,能夠將原始的文本轉換為JSON字符串,配合web樹形控件的展示形式實現了可視化界面。
Abstract: The abstract syntax tree (AST), as an important intermediate representation, plays an important role in the field of static analysis of code. This paper gives a method to reconstruct and visualize the AST based on the textual content of the AST generated by the GCC compiler. The contents of the abstract syntax tree generated by the GCC compiler are heavily redundant and cannot be parsed directly. To address this problem, this paper proposes an improved redundancy removal algorithm, which finds the main function from the root node first and then traverses it. It is more efficient than the conventional redundancy removal algorithm and is easy to convert the raw text of AST into JSON strings. Compared with the conventional redundancy removal algorithm, it has higher efficiency and structural optimization for visualization operation, which can convert the raw text of AST into JSON string and realize a visual interface with the presentation of web tree control.

  1. 引言

隨着互聯網和計算機技術的發展,傳統的教學方式已經不能滿足當前的需求,特別是程序設計類課程。C語言作為最基礎高級語言之一,使用人數眾多,實驗教學面臨改革 [1]。傳統實驗課上僅憑課上時間讓教師檢查代碼幾乎不可能,已有的OJ系統僅能通過測試用例去判斷代碼的正確性,因此代碼檢測已經成為一個熱點問題。目前在代碼檢測方面已經有很多研究並且有成熟的產品存在,其中在性能較好的靜態代碼檢查方面主要有機器學習和抽象表示兩個方向。如C/C++代碼檢測中的一個產品cppcheck其中會使用到正則表達式的方法來匹配一類代碼錯誤。同時,在抽象語法樹方面也有大量的研究。抽象語法樹本質上是一棵樹,樹形結構可以直觀的表示出源程序的語法結構,同時作為一種中間表示,它還包含了程序完整的信息,因此適用於靜態分析領域。GCC是由GNU開發的編譯器,它可以處理包括C語言在內的多種語言 [2]。GCC是目前使用的最為廣泛的編譯器系統之一,經過大量的實踐證明,GCC編譯系統生成的代碼具有很高的可靠性和運行效率。可以憑借GCC的命令生成抽象語法樹后對其解析得到需要的結果。GCC生成的抽象語法樹復雜且有依賴性,目前大部分研究只將抽象語法樹解析后用於計算相似度,還沒有人將抽象語法樹進行可視化處理得到適於人閱讀的圖形化界面,因此本文提出了對GCC生成的抽象語法樹進行重建並進行可視化處理的一種方法。

  1. GCC抽象語法樹

抽象語法樹(Abstract Syntax Tree, AST)是一種抽象的表示,它能以樹狀的形式表現出高級語言的語法結構,而不會表示出真實語法中出現的細節。作為一種中間表示形式,主要被用於預處理,因此可以應用在代碼分析領域。代碼經過詞法分析得到字符序列,再由語法分析得到抽象語法樹。抽象語法樹的結構簡單,根節點表示整個程序,內部節點是抽象語法結構或者單詞。圖1為GCC生成的抽象語法樹部分節點內容。

GCC生成的抽象語法樹常用的節點類型大致分為7種,分別為聲明節點(_decl)、標識符節點(identifier_node)、類型節點(_type)、常量節點(_cst)、表達式節點(_expr)、列表節點(_list)、其它節點。每個節點都是以“@”符號開始跟上節點的索引,接着是節點類型和信息,包括變量名、類型、所屬函數、大小等等,這些信息的值有的是直接顯示的,有的是對應節點的索引值。

Figure 1. GCC generates some nodes of the abstract syntax tree

圖1. GCC生成抽象語法樹部分節點

使用GCC編譯器生成的抽象語法樹存在大量的冗余信息。這些信息過於龐大很難直接進行解析,因此需要對其優化從而去除多余和無意義的節點信息。針對這個問題,本文提出了一種去除冗余的方法對抽象語法樹進行重建並進行可視化,使其達到易於閱讀的目的。

目前已經有很多軟件應用基於抽象語法樹實現,如程序自動評分 [3],它是通過對生成的抽象語法樹進行解析和標准化,使用樹的編輯距離計算兩者之間的相似度后對其進行評分。程序修復 [4] 技術在缺陷定位方面也是基於抽象語法樹實現的,通過將錯誤模式和錯誤代碼的抽象語法樹進行匹配得到相應的節點。抄襲檢測 [5] 也是通過對C語言代碼進行規范化處理,對代碼中的變量和函數進行了無類型化處理,經過詞法分析和語法分析后得到抽象語法樹,對其進行分析處理並計算相似度來判斷是否抄襲 [6]。

  1. 抽象語法樹的重建

3.1. 生成抽象語法樹

由於GCC版本的不同,生成抽象語法樹的命令也不同。本文介紹一種生成抽象語法樹的相關命令:

-fdump-translation-unit命令會將整個翻譯單元的樹結構表示形式轉儲到文件中。生成與源文件名相同的tu文件,同時允許調用者以翻譯單元(TU)表的形式提取這些信息。

本文使用-fdump-translation-unit生成抽象語法樹,該命令可以得到完整的抽象語法樹,其中包含了翻譯單元的所有信息。翻譯單元中有關於代碼的各種信息,包括變量聲明、數據結構的定義等。TU文件中的信息適合進行解析,因此選用該命令生成AST。

3.2. 重建抽象語法樹

GCC直接生成的抽象語法樹文本包含了大量的冗余信息,如果直接對原始文本進行解析不僅會降低效率,還可能影響分析的准確率。因此需要對原始的抽象語法樹進行重建。重建的主要方法主要是由預處理、標准化、構建樹三個方面組成 [7]。其中,預處理是實現重建抽象語法樹的基礎。整個重建的步驟如圖2。

3.2.1. 初始化節點

原始的tu文本由多個節點組成,每個節點都是由標號、節點標識、屬性組成。首先要讀取tu文件,以“\n@”為分界符將原始文本分成數個節點,再將其放入一個列表。接着遍歷列表,處理每一個節點,將其轉換為一個節點屬性字典,處理后進行實例化。然后處理實例中“attr”字符串,其中屬性節點可以有多個,它不僅表示屬性,也表示子節點。針對本文所需的可視化需求添加相應實例屬性,構建樹的結

Figure 2. The process of rebuilding the AST

圖2. 重建AST流程

構。最后將處理后的節點重新放入節點列表。

3.2.2. 標記有用節點

有用節點指與數據流和控制流相關的節點,無用節點指與數據流和控制流無關的節點。遍歷節點列表,再對當前節點屬性進行遍歷標記出有用的節點。如果鍵是“srcp”但不是本程序,則將其標記為無用節點,如果鍵是“srcp”且屬性值為本程序,則將其標為有用節點。繼續遍歷節點列表完成關聯節點類型,如果檢測到屬性值為節點,則替換為相應節點序號和對象元組。最后將標記為有用的的節點放入有用節點集合中,同時將原始編號放入有用節點原始編號集合中。

3.2.3. 標准化節點

該操作主要是為了去除冗余節點。遍歷有用節點集合,比對每個有用節點的子節點原始編號是否在有用節點原始編號集合中或該節點的子節點名是否為“scpe”,若是則將該節點的子節點彈出。接着移除空的子節點,根據樹形結構重新給節點編號,最后移除無效的子節點,完成對節點的標准化操作。

3.2.4. 構建抽象語法樹

准備一個空字典。遍歷有用節點集合,如果是第一個有用節點,則將空字典的一個有用節點原始編號位置的值設置為1。查找有用節點的子節點的原始編號作為序號,如果該序號所對應的有用節點的原始編號不在字典中,則將該節點處的“關系”字段設置為當前有用節點對應子節點的名字,並將該對應的有用節點加入子節點中,以便顯示。否則,將對應節點深拷貝一個虛擬節點,加入當前節點的虛擬節點中,最后彈出第一個節點。將處理好的集合轉換為JSON字符串返回。

3.2.5. 葉子節點及虛節點

由於GCC生成的抽象語法樹中包含了大量冗余的信息,尤其是針對子節點沒有一個明確的定義,所以本文中設定將子節點中依然還有子孫的節點提至上層,只顯示代碼中的信息,不顯示類型定義,進行規范化。同時,原始的AST文本實際上是一種圖形結構,存在大量的相互引用,因此文本設置了“虛節點”,即將那些反復出現的、變量聲明的或者函數聲明引用時的節點稱之為虛節點,目的是為了將重建的抽象語法樹化成一棵真正的樹。

  1. 抽象語法樹的可視化

本文針對可視化需求設計了友好的UI界面,可以在瀏覽器中查看樹狀結構圖。展示樹狀結構圖使用的是開源的OrgChart組件,它提供了豐富的功能,包括展開節點、縮放操作、支持移動設備等。同時支持本地或遠程的數據源,只需要提供JSON格式的數據源就能將其渲染為樹形結構。基於它小而精的特點,可以通過二次開發定制各種繁瑣的需求,達到所需目的。在代碼編輯方面,系統使用了了開源的Monaco編輯器,支持快速的代碼補全提示、自動換行、格式化代碼等功能。用戶可以實時查看代碼對應的抽象語法樹的樹形結構圖。同時系統還提供了JSON的數據源和tu文本,可以清楚的看出重建抽象語法樹前后的內容差異。

本文中重建后的抽象語法樹還不能直接作為可視界面的數據源,需要進行處理后才能使用。數據處理主要操作是將原數據節點內容進行區分,通過添加字段來區分該節點是否為虛節點,並控制節點的顯示樣式,圖3中淺色帶虛框的節點即為虛節點。在加載節點時還需要調用相關的初始化函數,控制節點顯示的標題、內容、關系等信息以及為每個節點設置點擊事件來查看該節點的詳細信息,圖中每個節點的上方為關系字段,下方為標號和類型字段。加載完成后可以直接點擊樹狀結構圖中的節點查看該節點的內部信息及其相應的介紹。圖3為生成的可視化樹狀結構圖(隱藏了部分節點)。

Figure 3. Visualization tree structure

圖3. 可視化樹狀結構圖

  1. 應用范例:代碼結構相似性

為了展示重建GCC生成抽象語法樹的效果,本文提供了兩段相似的源代碼,如表1,兩段代碼的功能都是用循環結構打印從1到3的三個數字,而第一段代碼定義的變量名為i,且使用for循環。第二段代碼定義變量名為j,使用的是while循環。兩種循環結構生成的抽象語法樹類似,且不同的的變量名對抽象語法樹的結構不產生影響,結果如圖4、圖5。

代碼1

代碼2

include

int main() {

int i;

for(i = 0; i < 3; i++) {

printf("%d", i);

}

}

include

int main() {

int j = 0;

while(j < 3) {

printf("%d", j);

J++;

}

}

Table 1. Two similar codes

表1. 兩段相似代碼

Figure 4. For loop results

圖4. For循環結果

Figure 5. While loop results

圖5. While循環結果

從兩個生成的抽象語法樹結構對比看來,兩段代碼功能相似,樹形結構相似。觀察樹中的具體節點內容可以看出,兩段代碼中的變量聲明、判斷條件和打印輸出等完全相同的代碼所對應的節點內容相同,只有在循環結構上才出現樹形結構差異情況。可見,本文所介紹的方法在靜態代碼分析領域有者顯著的效果,可以用於軟件缺陷預測技術 [8]。

  1. 結束語

本文提出了一種重建GCC生成的抽象語法樹的方法,實現了抽象語法樹的直觀展示。但是在解析處理抽象語法樹文件過程中僅使用了改進的去冗余算法,效率比常規去冗余算法提高了一些。未來將對去除冗余的算法進行優化,使其達到一個更高效的程度。代碼檢測無論在數據分析還是在數據挖掘等領域中都占據了重要的作用。后續,我們將在算法和應用方面做進一步的研究,使其成為一個成熟的工具,並能將其應用在C語言實驗平台上完成自動靜態評分功能。

參考文獻


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM