(原创)clang的python接口教程(二)

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

参考资料

阅读更多
换一批

没有更多推荐了,返回首页