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

被刻印的时光 ゝ 提交于 2019-12-07 08:01:14

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!