LINUX.ORG.RU

Рекурсивный обход AST clang

 , ,


0

1

Задача рассчитывать значение некоторого параметра узла на основе значений параметров его потомков. Думал, что используя clang_visitChildren() и возвращая visitor'ом CXChildVisit_Recurse, курсор будет возвращаться от детей к родителю, но получается, что он (курсор) сразу перепрыгивает к следующему брату родителя.

Возможно ли каким-либо образом реализовать рекурсию AST clang как «в книжке»?


Я так понял, ты используешь libclang сишный. Там такого нет, насколько я знаю, но сишное апи сильно отстаёт от крестового в плане актуальности и функциональности. Посмотри крестовое апи для начала.

Если там не разберёшься, задай вопрос в cfe-dev@.

А ещё вариант (если такой возможности нет) добавить параметр и оформить в виде патча, выложить на фабрикатор, вдруг примут ;-) можешь меня там в копию добавить. В копию, а не ревьюером, можешь стукнуться в жаббер ко мне, я подскажу, кого ревьюером назначить, если решишь пойти этим путём.

DELIRIUM ☆☆☆☆☆
()
Последнее исправление: DELIRIUM (всего исправлений: 2)

А можешь показать кусок кода который у тебя не работает? Я просто делаю Continue и оно обходит рекурсивно.

Код примера:

extern crate clang;

use std::error::Error;
use clang::*;

fn main() {
    parse().unwrap();
}

fn parse() -> Result<(), Box<Error>> {
    let clang = Clang::new()?;
    let index = Index::new(&clang, false, false);

    let mut parser = index.parser("main.cpp");
    parser.arguments(&[
        "-std=c++11",
    ]);
    let tu = parser.parse()?;

    fn visitor(e: Entity, level: usize) {
        let name = e.get_display_name().unwrap_or(String::from(""));
        println!("{:>w$}{:?} {}", "", e.get_kind(), name, w = level);

        e.visit_children(|e, _| {
            visitor(e, level + 2);
            EntityVisitResult::Continue
        });
    }

    visitor(tu.get_entity(), 0);
    Ok(())
}

pftBest ★★★★
()
Ответ на: комментарий от pftBest

Ну он как бы обходит и у меня рекурсивно только не возвращается в родительский узел после детей как мне бы хотелось, пытаюсь через clang_getCursorSemanticParent(cursor) получить доступ к родителям, но везде кроме main(int, char**) и cpptest.cpp возвращает пустоту

CXChildVisitResult visitor( CXCursor cursor, CXCursor, CXClientData )
{
    printCursor(cursor);
    clang_visitChildren( cursor, visitor, nullptr );
    std::cout << "parent:";
    printCursor(clang_getCursorSemanticParent(cursor));
    return CXChildVisit_Continue;
}

int main (int argc, char** argv) {
    CXIndex index = clang_createIndex (
        0, // excludeDeclarationFromPCH
        1  // displayDiagnostics
        );
    CXTranslationUnit unit = clang_parseTranslationUnit (
        index, // CIdx
        "cpptest.cpp", // source_filename
        argv, // command_line_args
        argc, // num_command_line_args
        0, // unsave_files
        0, // num_unsaved_files
        CXTranslationUnit_None // options
        );
    if (!unit) {
        std::cout << "Translation unit was not created\n";
    }
    else {
        CXCursor root = clang_getTranslationUnitCursor(unit);
        clang_visitChildren(root, visitor, nullptr);
    }

    clang_disposeTranslationUnit(unit);
    clang_disposeIndex(index);
}
rzhd
() автор топика
Ответ на: комментарий от rzhd

Родитель лежит во втором аргументе визитора, зачем тебе тут был clang_getCursorSemanticParent не понятно.

А по поводу рекурсии, можно все это дело сильно упростить если сохранять детей в вектор, и потом самом решать как ты хочешь по ним ходить.

#include <iostream>
#include <vector>
#include <clang-c/Index.h>

std::string showCursor(CXCursor cursor) {
    CXCursorKind kind = clang_getCursorKind(cursor);
    CXString cxs = clang_getCursorKindSpelling(kind);
    std::string result = clang_getCString(cxs);
    clang_disposeString(cxs);
    return result;
}

CXChildVisitResult visitor(CXCursor cursor, CXCursor parent, CXClientData data) {
    std::vector<CXCursor> *children = static_cast<std::vector<CXCursor> *>(data);
    children->push_back(cursor);
    return CXChildVisit_Continue;
};

void my_visitor(CXCursor cursor, int level) {
    std::vector<CXCursor> children;
    clang_visitChildren(cursor, visitor, &children);

    std::string padding(level, ' ');
    std::cout << padding << showCursor(cursor) << " {" << std::endl;
    for (auto c : children) {
        my_visitor(c, level + 2);
    }
    std::cout << padding << "}" << std::endl;
}

int main (int argc, char** argv) {
    CXIndex index = clang_createIndex (
        0, // excludeDeclarationFromPCH
        1  // displayDiagnostics
        );
    CXTranslationUnit unit = clang_parseTranslationUnit (
        index, // CIdx
        "cpptest.cpp", // source_filename
        argv, // command_line_args
        argc, // num_command_line_args
        0, // unsave_files
        0, // num_unsaved_files
        CXTranslationUnit_None // options
        );
    if (!unit) {
        std::cout << "Translation unit was not created\n";
    }
    else {
        CXCursor root = clang_getTranslationUnitCursor(unit);
        my_visitor(root, 0);
    }

    clang_disposeTranslationUnit(unit);
    clang_disposeIndex(index);
}
pftBest ★★★★
()
Ответ на: комментарий от pftBest

спасибо, про parent visitor'а стыдно сказать не заметил, vector попробую использовать, должно быть полезно

А не подскажите, как можно расширить структура CXCursor еще одним полем? если я наследую от базовой структуры, то не смогу экземпляры производной структуры использовать в функциях родного API, если я правильно понимаю.

Есть ли еще варианты?

typedef struct {
   enum CXCursorKind kind;
   int xdata;
   const void *data[3];
 } CXCursor;

rzhd
() автор топика
Ответ на: комментарий от rzhd

Расширить наверное не получится, курсор везде копируется туда сюда по значению. Но можно просто обернуть его, и хранить уже эту обертку в своих структурах.

struct MyCursor {
    CXCursor raw;
    int my_data;
};
pftBest ★★★★
()
Ответ на: комментарий от pftBest

Пытаюсь по вашему примеру сделать вектор, но уже с производной структурой

typedef struct {
    CXCursor cursor;
    int nsv = 0;
} ExtendedCXCursor;

CXChildVisitResult visitor( CXCursor cursor, CXCursor parent, CXClientData data )
{
    ExtendedCXCursor excursor;
    excursor.cursor = cursor;
    excursor.nsv = 1;

    std::vector<ExtendedCXCursor> *children = static_cast<std::vector<ExtendedCXCursor> *>(data);
    children->push_back(excursor);
    clang_visitChildren(excursor.cursor, visitor, &children);

    return CXChildVisit_Continue;
}


void my_visitor(ExtendedCXCursor excursor) {
    std::vector<ExtendedCXCursor> children;
    clang_visitChildren(excursor.cursor, visitor, &children);

    std::cout << printCursor(excursor.cursor) << " - " << excursor.nsv << std::endl;
    for (auto c : children) {
        my_visitor(c);
    }
}

int main (int argc, char** argv) {
    //String InputFile;
    //std::cin >> InputFile;
    CXIndex index = clang_createIndex (
        0, // excludeDeclarationFromPCH
        1  // displayDiagnostics
        );
    CXTranslationUnit unit = clang_parseTranslationUnit (
        index, // CIdx
        "cpptest.cpp", // source_filename
        argv, // command_line_args
        argc, // num_command_line_args
        0, // unsave_files
        0, // num_unsaved_files
        CXTranslationUnit_None // options
        );
    if (!unit) {
        std::cout << "Translation unit was not created\n";
    }
    else {
        CXCursor root = clang_getTranslationUnitCursor(unit);
        ExtendedCXCursor excursor;
        excursor.cursor = root;
        my_visitor(excursor);
    }

    clang_disposeTranslationUnit(unit);
    clang_disposeIndex(index);
}

Получаю Segmentation fault (core dumped). Ошибка появляется в children->push_back(excursor); С чем может быть связано?

rzhd
() автор топика
Ответ на: комментарий от LjubaSherif

Ну я скачал проект, начал читать код и наткнулся на то что автор упоролся, и в расто коде в хешмапе лежат не байты как в плюсах, а юникод скаляры. На этом мне стало неинтересно и я забил.

pftBest ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.