(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" в качестве ссылки.

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

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

Ответ 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 находит его первым при запуске анализа, поэтому вам не нужно изменять исходную исходную базу.