问题
I have just started using libclang via python bindings. I understand that I can traverse the entire syntax tree (AST) using get_children
, but I have not been able to find a get_next_sibling()
(or whatever it might be called) function so that I can skip subtrees that are not of interest. Does such a function exist?
回答1:
I don't think a get_next_sibling
function exists in the Python API, but I also don't see why you should need it.
In the python API, each node in the AST knows about all its children, so that skipping uninteresting subtrees can easily be done by simply skipping them in the loop over the parent's children. Re-using an example from 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)
回答2:
As francesco pointed out it is possible to skip elements. The mentoined code example though is not working anymore due to changes in latest cindex.py revision.
Below is a minimal example to get specific nodes from AST.
example.cpp file:
int i;
char var[10];
double tmp;
int add (int a, int b)
{
int r;
r=a+b;
return (r);
}
example python code:
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
if you want furthermore the type of each element of the array u get it through:
result[1].type.element_type.kind
#######OUTPUT######
>>> TypeKind.CHAR_S
since the modul cindex.py is well documented it shouldnt be hard to find how to get the information that you need.
回答3:
In terms of clang-c, enum CXChildVisitResult have 3 values, and CXChildVisit_Continue skips visiting children, so visitor comes to next sibling. Something like that should be in python too.
来源:https://stackoverflow.com/questions/16765579/how-to-skip-subtrees-in-ast-traversal-using-python-bindings-for-libclang