Обход Clang AST с использованием Python

#python-3.x #clang #abstract-syntax-tree

#python-3.x #clang #абстрактное синтаксическое дерево

Вопрос:

Я работаю над использованием clang bingings python для преобразования кода c / c в AST, как я могу получить структуру AST на основе дерева? Несколько советов о том, с чего начать, учебные пособия или что-либо еще в этом отношении окажут большую помощь!!!

Я нашел очень полезную работу (если вы хотите это проверить, вот ссылка:https://www.chess.com/blog/lockijazz/using-python-to-traverse-and-modify-clang-s-ast-tree ) и попробовал его код, к сожалению, я не получил полезного результата.

 function_calls = []           
function_declarations = []     
def traverse(node):

    for child in node.get_children():
        traverse(child)

    if node.type == clang.cindex.CursorKind.CALL_EXPR:
        function_calls.append(node)

    if node.type == clang.cindex.CursorKind.FUNCTION_DECL:
        function_declarations.append(node)


    print 'Found %s [line=%s, col=%s]' % (node.displayname, node.location.line, node.location.column)

clang.cindex.Config.set_library_path("/Users/tomgong/Desktop/build/lib")
index = clang.cindex.Index.create()

tu = index.parse(sys.argv[1])

root = tu.cursor        
traverse(root)
  

Ответ №1:

На всякий случай, если у кого-то все еще возникли проблемы, я обнаружил, что если вы должны использовать kind вместо type

вы можете запустить clang.cindex.CursorKind.get_all_kinds() для извлечения всех видов и увидеть, что при использовании node.type ни в одном из них не отображается.

 function_calls = []           
function_declarations = []     
def traverse(node):

    for child in node.get_children():
        traverse(child)

    if node.kind == clang.cindex.CursorKind.CALL_EXPR:
        function_calls.append(node)

    if node.kind == clang.cindex.CursorKind.FUNCTION_DECL:
        function_declarations.append(node)


    print 'Found %s [line=%s, col=%s]' % (node.displayname, node.location.line, node.location.column)

clang.cindex.Config.set_library_path("/Users/tomgong/Desktop/build/lib")
index = clang.cindex.Index.create()

tu = index.parse(sys.argv[1])

root = tu.cursor        
traverse(root)
  

Ответ №2:

как я могу получить структуру AST на основе дерева?

Курсор объекта translation unit ( tu.cursor ) на самом деле является начальным узлом AST. Возможно, вы захотите использовать clang инструмент для визуального анализа дерева. Возможно, это прольет свет и даст вам представление о том, как работать с деревом.

clang -cc1 -ast-dump test.cpp

Но в основном, это сводится к получению дочерних узлов основного узла ( tu.cursor ) и рекурсивному обходу их и получению узлов, которые представляют для вас интерес.

Возможно, вы также захотите ознакомиться со статьей Эли Бендерски о том, как начать работать с привязкой python: https://eli.thegreenplace.net/2011/07/03/parsing-c-in-python-with-clang#id9

к сожалению, я не получил полезного результата.

Вы можете столкнуться с неполным или неправильным синтаксическим анализом, когда вы не предоставляете пути к включениям в анализируемом файле модулю libclang. Например, если исходный файл, который вы хотите проанализировать, использует некоторые из включений QT, тогда вам нужно указать соответствующие пути включения в parse() вызове, как в приведенном здесь примере:

 index = clang.cindex.Index.create()
tu = index.parse(src_file, args = [
     '-I/usr/include/x86_64-linux-gnu/qt5/',
     '-I/usr/include/x86_64-linux-gnu/qt5/QtCore'])
  

Также поищите некоторые комментарии в модуле python libclang.cindex, они могут вам помочь. Например, я нашел решение выше, прочитав эти комментарии.

Ответ №3:

Я использовал pycparser для того, чтобы получить AST исходного кода C / C и изучить то же самое с помощью python.

Вы можете найти API для изучения AST в этом примере из репозитория.