-
-
Save ldzm/53b6d386ebbbed799b32e238fa052548 to your computer and use it in GitHub Desktop.
Show the AST of a translation unit with libclang and python
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# inspired by http://eli.thegreenplace.net/2011/07/03/parsing-c-in-python-with-clang/ | |
import sys | |
import clang.cindex | |
def verbose(*args, **kwargs): | |
'''filter predicate for show_ast: show all''' | |
return True | |
def no_system_includes(cursor, level): | |
'''filter predicate for show_ast: filter out verbose stuff from system include files''' | |
return (level!= 1) or (cursor.location.file is not None and not cursor.location.file.name.startswith('/usr/include')) | |
# A function show(level, *args) would have been simpler but less fun | |
# and you'd need a separate parameter for the AST walkers if you want it to be exchangeable. | |
class Level(int): | |
'''represent currently visited level of a tree''' | |
def show(self, *args): | |
'''pretty print an indented line''' | |
print '\t'*self + ' '.join(map(str, args)) | |
def __add__(self, inc): | |
'''increase level''' | |
return Level(super(Level, self).__add__(inc)) | |
def is_valid_type(t): | |
'''used to check if a cursor has a type''' | |
return t.kind != clang.cindex.TypeKind.INVALID | |
def qualifiers(t): | |
'''set of qualifiers of a type''' | |
q = set() | |
if t.is_const_qualified(): q.add('const') | |
if t.is_volatile_qualified(): q.add('volatile') | |
if t.is_restrict_qualified(): q.add('restrict') | |
return q | |
def show_type(t, level, title): | |
'''pretty print type AST''' | |
level.show(title, str(t.kind), ' '.join(qualifiers(t))) | |
if is_valid_type(t.get_pointee()): | |
show_type(t.get_pointee(), level+1, 'points to:') | |
def show_ast(cursor, filter_pred=verbose, level=Level()): | |
'''pretty print cursor AST''' | |
if filter_pred(cursor, level): | |
level.show(cursor.kind, cursor.spelling, cursor.displayname, cursor.location) | |
if is_valid_type(cursor.type): | |
show_type(cursor.type, level+1, 'type:') | |
show_type(cursor.type.get_canonical(), level+1, 'canonical type:') | |
for c in cursor.get_children(): | |
show_ast(c, filter_pred, level+1) | |
if __name__ == '__main__': | |
index = clang.cindex.Index.create() | |
tu = index.parse(sys.argv[1]) | |
print 'Translation unit:', tu.spelling | |
for f in tu.get_includes(): | |
print '\t'*f.depth, f.include.name | |
show_ast(tu.cursor, no_system_includes) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment