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

来源:互联网 发布:美股交易软件 编辑:程序博客网 时间:2024/06/15 11:26

clang的python接口(二)

N久之前的一个坑了,今天来为大家填上。(果然需求是第一生产力)


  • clang的python接口二
    • 常用类
    • AST的构建
    • 前序遍历AST
    • 语法单元提取
    • 分词的提取
    • 参考资料

常用类

  • 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 Configfrom clang.cindex import TypeKindfrom clang.cindex import CursorKindfrom 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

参考资料

原创粉丝点击