LINUX.ORG.RU

Построение AST и типы Qt

 , ,


0

3

Нужно мне разобрать заголовочный файл и выдернуть из него имена структур, имена полей и типов полей всех структур. Для этого дела мне посоветовали clang. Делал так: передал в clang_parseTranslationUnit нужный мне заголовочный файл и с помощью clang_visitChildren побежал по файлу. Работает все кроме одного,

clang_getTypeSpelling( cursorType )
на все типы отличные от стандартных возвращает int. А как бы мне получить имя типа, если там стоит qint32, QString и т.п.?

Может есть какой более правильный путь для этого?


Ответ на: комментарий от xaizek

Нет конечно не курсор, когда с экрана перепечатывал не туда посмотрел. Конечно сначала делаю

 t = clang_getCursorType( cursor )
а потом уже имя типа вывожу.

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

Похоже, что «int» используется как значение по умолчанию для неизвестных типов (нету заголовка, например).

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

Ну сам разбираемый файл имеет вид вроде такого:

#include <QVariant>

struct MyStruct1
{
    qint32 iField1;
    QByteArray baField2;
};

Сам код разбора имеет вот такой вид: функция visitor:

CXChildVisitResult visitor( CXCursor c, CXCursor parent, CXClientData client_data )
{
    static QString sNameS;
    CXCursorKind cursorKind = clang_getCursorKind( c );

    if ( CXCursor_StructDecl == cursorKind )
    {
        //qDebug() <<
        CXString cxStr = clang_getCursorSpelling(c);
        sNameS = clang_getCString( cxStr );

        clang_disposeString( cxStr );
    }
    else if ( CXCursor_FieldDecl == cursorKind )
    {
        CXType typ = clang_getCursorType(c);
        qDebug() << sNameS << "field:" << clang_getCursorSpelling(c) << clang_getTypeSpelling( typ );


    }

    return CXChildVisit_Recurse;
}

Вызов ее в методе выбора заголовочного файла:

    if ( !sFileName.isEmpty() )
    {
        CXIndex index = clang_createIndex( 0, 0 );
        CXTranslationUnit unit = clang_parseTranslationUnit(
                    index,
                    sFileName.toStdString().c_str(), 
                    nullptr, 0,
                    nullptr, 0,
                    CXTranslationUnit_None);
        if (unit == nullptr)
        {
            qDebug() << "Unable to parse translation unit. Quitting.";
            exit(-1);
        }


        CXCursor cursor = clang_getTranslationUnitCursor(unit);
        clang_visitChildren(
                    cursor,
                    visitor,
                    nullptr);

        clang_disposeTranslationUnit(unit);
        clang_disposeIndex(index);
    }

Что еще нужно указать, чтобы типы правильно определялись?

asaks ()
Ответ на: комментарий от asaks
-#include <QVariant>
+#include <Qt/QVariant>

Как уже сказали, не находит без -I.

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

Указывать include path я так понимаю надо через аргументы командной строки, которые передаются в вызов clang_parseTranslationUnit?

asaks ()
Ответ на: комментарий от xaizek

Добавил пути к header'ам и получил кучу ошибок типа:

 qbasicatomic.h:53:1: error: expected function body after function declarator
qatomic_x86_64.h:52:8: error: unknown type name 'bool' 
И тому подобные ошибки.

И собственно я понял, что это не совсем подходит для моей задачи. Т.к. мне нужно переносимое приложение, чтобы я мог запустить его на любом компе и разобрать любой подсунутый ему заголовочный файл. А так мне получается надо для каждого файла указывать пути к header'ам и они должны быть установлены на машине. А я то хотел получить программу, которую можно запустить на чистой машине без установленных компиляторов/фреймворков/etc и она разберет указанный файл.

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

Если делать с Qt/, то никаких ошибок вроде не возникает (я проверял этим, хотя и сам clang можно заставить показать дамп).

хотел получить программу, которую можно запустить на чистой машине без установленных компиляторов/фреймворков/etc и она разберет указанный файл.

Компиляторы для этого практически не годятся, тут нужна расширенная грамматика, которая проглотит много чего (неизвестные типы, макросы). Есть всякие наколенные парсеры (на питоне от гугла, вроде) для мелких проверок их и можно попробовать использовать. srcML тоже должен подойти, он посерьёзнее будет.

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

Почитал про srcML. Наверное это то, что мне нужно. Полученную xml'ку будет проще распарсить, чем исходный код.

xaizek, а вы сами собирали libsrcml из исходников? Просто возникли некоторые проблемы при сборке.

asaks ()
Ответ на: комментарий от xaizek

Я делал как сказано в BUILD.md и в итоге собрать не удалось.

Во-первых, при конфигурировании получаю warning'и вида:

CMake Warning at /usr/share/cmake-3.7/Modules/FindBoost.cmake:761 (message):
   Imported targets not avalilable for Boost version 106501
Call stack (most recent call first):
   /usr/share/cmake-3.7/Modules/FindBoost.cmake:865 (_Boost_COMPONENT_DEPENDENCIES)
   /usr/share/cmake-3.7/Modules/FindBoost.cmake:1470 (_Boost_MISSING_DEPENDENCIES)
   CMake/config.cmake:99 (find_package)
   CMake/srcml.cmake:20 (include)
   CMakeLists.txt:29 (include)

Boost собирал так:

./bootstrap.sh --without-libraries=atomic,chrono,context,coroutine,exception,graph,graph_parallel,iostreams,locale,log,math,mpi,python,random,serialization,signals,test,timer,wave --prefix=/usr/local

./b2 link=static cxxflags="-fPIC -static -Wl,--whole-archive" threading=multi install

А во-вторых, при сборке получаю ошибку:

/home/asaks/training/srcml-src/src/parser/bitset_bucket_sorter.hpp:53:92: error: template argument 6 is invalid
#define create_token_set(NAME, ...) typedef boost::mpl::vector_c<unsigned long, __VA_ARGS__> NAME
                                                                                           ∧

Использую следующие версии: Linux Mint 18.2 amd64, gcc 6.3.0, boost 1.65.1, cmake 3.7. Все остальные пакеты, указанные в BUILD.md, устанавливал из репозитория.

Спасибо за ссылку, посмотрю как там скрипт сделан, попробую под себя переделать.

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