【问题标题】:How to skip subtrees in AST traversal using python bindings for libclang如何使用 libclang 的 python 绑定跳过 AST 遍历中的子树
【发布时间】:2013-05-21 20:41:01
【问题描述】:

我刚刚开始通过 python 绑定使用libclang。我知道我可以使用 get_children 遍历整个语法树 (AST),但我无法找到 get_next_sibling()(或任何可能被调用的)函数,因此我可以跳过不感兴趣的子树.有这样的功能吗?

【问题讨论】:

    标签: python clang traversal libclang


    【解决方案1】:

    正如 francesco 指出的那样,可以跳过元素。 由于最新 cindex.py 修订版的更改,mentoined 代码示例不再起作用。

    以下是从 AST 获取特定节点的最小示例。

    example.cpp 文件:

    int i; 
    char var[10]; 
    double tmp;
    
    int add (int a, int b)
    {
      int r;
      r=a+b;
      return (r);
    }
    

    示例python代码:

    import sys
    from clang.cindex import *
    
    index = Index.create()
    tu = index.parse('example.cpp')
    
    root_node = tu.cursor
    
    #for further working with children nodes i tend to save them in a seperate list
    #wanted nodes in extra list "result"
    wanted_nodes = ['var', 'tmp']
    result = []
    node_list= []
    
    for i in node.get_children():
        node_list.append(i)
    
    for i in node_list:
        if i.spelling in wanted_nodes:
            result.append(i)
    
    #now result contains the two nodes "var" and "add"
    
    #print the name
    for i in result:
        print i.spelling
    
    #print the type
    for i in result:
        print i.type.kind
    
    ######OUTPUT#######
    >>> var
    >>> add
    >>> TypeKind.CONSTANTARRAY
    >>> TypeKind.DOUBLE
    

    如果你还想知道数组中每个元素的类型,你可以通过:

    result[1].type.element_type.kind
    
    #######OUTPUT######
    >>> TypeKind.CHAR_S
    

    由于模块cindex.py 有据可查,因此应该不难找到如何获取所需信息。

    【讨论】:

      【解决方案2】:

      我认为 Python API 中不存在 get_next_sibling 函数,但我也不明白您为什么需要它。

      在 python API 中,AST 中的每个节点都知道它的所有子节点,因此只需在循环中跳过父节点的子节点即可轻松跳过不感兴趣的子树。重用Eli Bendersky's excellent blog post about the libclang Python API中的一个例子:

      def find_typerefs(node, typename):
          """ Find all references to the type named 'typename'
          """
          if node.kind.is_reference():
              ref_node = clang.cindex.Cursor_ref(node)
              if ref_node.spelling == typename:
                  print 'Found %s [line=%s, col=%s]' % (
                      typename, node.location.line, node.location.column)
      
          # Recurse for children of this node,
          # skipping all nodes not beginning with "a"
          for c in node.get_children():
              if c.spelling.startswith ("a"):
                  find_typerefs(c, typename)
      

      【讨论】:

      • 如何跳过头文件的包含,例如从这个标准库?我可以找出节点,但我缺少跳过功能。如果我在每次 get_children 调用后的分析过程中跳过它,程序将永远耗时。
      【解决方案3】:

      clang-c 中枚举 CXChildVisitResult 有 3 个值,CXChildVisit_Continue 跳过访问孩子,所以访问者来到下一个兄弟。类似的东西也应该在 python 中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-05-04
        • 2023-03-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多