Подтвердить что ты не робот

(clang) Как самостоятельно анализировать макросы, получая астра, где это возможно?

Привет, я использую clang для извлечения информации из c файлов. И я пытаюсь извлечь значения макросов.

например. от этого мне нужно значение "13" или ast (+ (* 3 4) 1):

#define SOME_CONSTANT 3*4+1

или от макрофункции, я бы хотел, например, ast. (SOME_MACROFUNC (x y) (+ (add4 x) (* y 9))):

int add4(int q) {return q+4;}
#define SOME_MACROFUNC(x,y) add4(x)+y*9

До сих пор мне удалось выполнить итерацию по всем макросам с помощью функций макропроцессора класса "Препроцессор" macro_begin() и macro_end().

Затем из этого я получил имена макросов, и из класса "MacroInfo" я смог получить, является ли макрос функцией (включая имена параметров) или нет. Я также получил доступ к токенам в макросе, но я могу получить только токен, например: string_literal, идентификатор, запятую, l_paren, r_paren и т.д.

Итак, две вещи:

  • Как получить доступ к фактическому значению токенов, а не только к их типам.

  • Есть ли способ генерировать ast из макросов, учитывая их жетоны? Один из способов, который, как я думал, - разобрать мой исходный код, затем извлечь макросы и использовать их имена, добавить код, включающий эти макросы, в мой источник и повторно обработать его, чтобы получить ast.

например. Что-то вроде:

char *tempSOME_CONSTANT = SOME_CONSTANT;    
void tempSOME_MACROFUNC(char *x, char *y) {SOME_MACROFUNC(x,y);}

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

Спасибо.

изменить:  Чтобы прояснить, я в основном хочу расширенное тело (пока макросы не останутся, только не макро-токены) каждого макроса.

edit2 Решил что-то:

Если кто-либо заинтересован, я намерен вручную развернуть тело макроса.

"preprocessor.getSpelling(токен)", чтобы получить значение токена.

"preprocessor.getIdentifierTable(). get (StringRef (правописание))" для получения идентификационной информации для токена.

И используя "clang\lib\Lex\PPMacroExpansion.cpp" в качестве ссылки.

По-прежнему думать о том, как передать его парсеру без повторного использования всего дерева исходных текстов, но это не должно быть слишком сложно понять.

Благодаря Ире Бакстер для обсуждения, это помогло мне устранить проблему.

4b9b3361

Ответ 1

Я работаю над чем-то очень похожим. Я использую clang front end для сбора контекста (w.r.t. class, function и т.д.), В котором определяется макрос, а затем использовать парсер (псевдо) выражения, чтобы выяснить, является ли макро-тело допустимым выражением или нет. Конечной целью является преобразование макроса в декларацию С++. Недавно мы получили документ, принятый в ICSM -2012, который объясняет, как мы достигаем этого.

Инструменты-demacrofier, используемые для избавления от макросов, размещены здесь

Примеры Иры Бакстер очень проницательны в том, как используются макросы. Тем не менее,% возраста этих макросов очень меньше \ref (Эмпирический анализ использования препроцессора C Ernst et al.). В настоящее время я уделяю больше внимания общим случаям.

Ответ 2

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

#define SOME_MACROFUNC(x,y) add4(x)+y*9

станет

extern int SOME_MACROFUNC(int x, int y);

Затем вы можете запустить это через обычного AST Matcher или посетителя и выполнить необходимую обработку (включая рефакторинг, если это необходимо). Это не очень хорошо масштабируется, но если количество макросов хорошо известно и ограничено, это может быть приемлемым решением.

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