(原創)clang的python介面教程(二)
阿新 • • 發佈:2019-02-03
clang的python介面(二)
N久之前的一個坑了,今天來為大家填上。(果然需求是第一生產力)
常用類
- Index:
這個類是clang的核心類。具有構建語法樹的主類。
常用方法:
create()
'''
初始化Index類。
'''
parse(self, path, args=None, unsaved_files=None, options = 0)
'''
構建語法樹,同時返回AST的根節點。前兩個引數比較常用,
path:要進行構建的原始檔的路徑
args:編譯選項例如-DUSE_LIBPNG1等
'''
- TranslationUnit:
編譯單元,一般來說指的是進行編譯的檔案。 - CursorKind
語法樹的的索引結點的類別。
常用方法:
get_children()
"""
這個方法用來獲取其子節點列表的迭代器。
"""
get_tokens()
'''
得到了其每個分詞的列表的迭代器。
'''
@property
translation_unit()
"""返回這個節點索引所在的原始檔"""
- TypeKind
這個是每個節點的語義類別。(後文會具體區分和TypeKind的區別) - Config
clang的配置類
AST的構建
抽象語法樹(abstract syntax tree或者縮寫為AST),或者語法樹(syntax tree),是原始碼的抽象語法結構的樹狀表現形式,這裡特指程式語言的原始碼。樹上的每個節點都表示原始碼中的一種結構。之所以說語法是“抽象”的,是因為這裡的語法並不會表示出真實語法中出現的每個細節。比如,巢狀括號被隱含在樹的結構中,並沒有以節點的形式呈現;而類似於if-condition-then這樣的條件跳轉語句,可以使用帶有兩個分支的節點來表示。 —— [ 維基百科 ]
首先說明一下AST的定義,之後通過程式碼具體講解一下clang的工作過程。
from clang.cindex import Config
from clang.cindex import TypeKind
from clang.cindex import CursorKind
from clang.cindex import Index
#首先需要匯入需要的型別包。
#clang的python繫結的具體配置方法看博主的另一篇部落格clang的python介面(-)
libclangPath = '/usr/lib/llvm-4.0/lib/libclang-4.0.so.1'
if Config.loaded==True:
pass
else:
Config.set_library_file(libclangPath)
#libclangPath是libclang.so的具體位置。
index = Index.create()
tu = index.parse(file_path,commands)
構建語法樹的過程十分簡單,接下來根據需要進行遍歷,常用的便利方法一般都是先序遍歷或者層次遍歷。
(關於樹的遍歷可以查詢《演算法導論》之類的有關資料結構的書籍或資料,這裡不進行贅述)
前序遍歷AST
這裡主要講解通過前序遍歷AST來進行提取各個語法單元的過程,
def iterAST(cursor):
'''
前序遍歷嚴格來說是一個二叉樹才有的概念。這裡指的是對於每個節點,先遍歷本節點,再遍歷子節點的過程。
'''
for cur in cursor.get_children():
#do something
iterAST(cur)
語法單元提取
這裡需要通過識別CursorKind以及TypeKind來進行語法單元的識別。
def iterAST(cursor):
'''
在遍歷過程中,遇到了一個節點就進行檢查。
CursorKind指的是這個節點在AST中的位置例如(函式,類,引數定義等)
TypeKind指的是這個節點的語義類別,例如這個引數的類別是const char,int等類別。
'''
for cur in cursor.get_children():
if cur.CursorKind==CursorKind.FUNCTION_DECL:
#do something
for cur_sub in cur.get_children():
if cur_sub .kind == CursorKind.CALL_EXPR:
#do something
#這一段程式碼分析的是函式定義呼叫的其他函式。
elif cur.kind == CursorKind.FIELD_DECL:
#do something
elif cur.type.kind == TypeKind.UCHAR:
#do something
iterAST(cur)
分詞的提取
這裡講解一下如何提取分詞,也就是Token.
def iter_cursor_content(self,cur):
'''
這裡展示的是一個提取每個分詞的方法。
'''
cursor_content=""
for token in cur.get_tokens():
#針對一個節點,呼叫get_tokens的方法。
str_token = token.spelling+" "
cursor_content = cursor_content+str_token
return cursor_content