关于 clang:如何使用 libclang 的 python 绑定在 AST 遍历中跳过子树

How to skip subtrees in AST traversal using python bindings for libclang

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


正如弗朗西斯科指出的那样,可以跳过元素。
由于最新的 cindex.py 修订版的变化,所提到的代码示例不再工作了。

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

example.cpp 文件:

1
2
3
4
5
6
7
8
9
10
int i;
char var[10];
double tmp;

int add (int a, int b)
{
  int r;
  r=a+b;
  return (r);
}

示例python代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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

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

1
2
3
4
result[1].type.element_type.kind

#######OUTPUT######
>>> TypeKind.CHAR_S

因为模块 cindex.py 有很好的文档记录,所以不难找到如何获取您需要的信息。


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

在 Python API 中,AST 中的每个节点都知道其所有子节点,因此只需在父节点的循环中跳过它们,就可以轻松跳过无趣的子树。重用 Eli Bendersky 关于 libclang Python API 的优秀博客文章中的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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)


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