У меня есть требование построить автоматизированную систему для анализа файла C++ .h с большим количеством операторов #define
и сделать что-то со значением, которое работает каждый #define
. В файле .h помимо операторов #define
есть много другого мусора.
Цель состоит в том, чтобы создать список ключ-значение, где ключами являются все ключевые слова, определенные операторами #define
, а значениями являются оценки макросов, которые соответствуют определениям. #defines
определяют ключевые слова с помощью ряда вложенных макросов, которые в конечном итоге разрешаются в целочисленные константы времени компиляции. Некоторые из них не разрешаются в целочисленные константы времени компиляции, и их следует пропустить.
Файл .h со временем будет развиваться, поэтому инструмент не может быть длинной жестко закодированной программой, которая создает экземпляр переменной, равной каждому ключевому слову. У меня нет контроля над содержимым файла .h. Единственная гарантия состоит в том, что его можно собрать с помощью стандартного компилятора C++, и что дополнительные #defines
будут добавлены, но никогда не будут удалены. Формулы макросов могут измениться в любое время.
Варианты, которые я вижу для этого, следующие:
- Реализуйте частичный (или подключитесь к существующему) компилятору C++ и перехватите значение макросов на этапе препроцессора.
- Используйте регулярные выражения для динамического создания исходного файла, который будет использовать все макросы, определенные в настоящее время, затем скомпилируйте и выполните исходный файл, чтобы получить оцененную форму всех макросов. Каким-то образом (?) пропустить макросы, которые не оцениваются как целочисленные константы времени компиляции. (Кроме того, не уверен, что регулярное выражение достаточно выразительно, чтобы захватить все возможные определения многострочных макросов)
Оба этих подхода значительно усложнили бы процесс сборки этого проекта, чего я хотел бы избежать. Есть ли лучший способ оценить все макросы #define
в файле C++ .h?
Ниже приведен пример того, что я хочу разобрать:
#ifndef Constants_h
#define Constants_h
namespace Foo
{
#define MAKE_CONSTANT(A, B) (A | (B << 4))
#define MAGIC_NUMBER_BASE 40
#define MAGIC_NUMBER MAGIC_NUMBER_BASE + 0x2
#define MORE_MAGIC_1 345
#define MORE_MAGIC_2 65
// Other stuff...
#define CONSTANT_1 MAKE_CONSTANT (MAGIC_NUMBER + 564, MORE_MAGIC_1 | MORE_MAGIC_2)
#define CONSTANT_2 MAKE_CONSTANT (MAGIC_NUMBER - 84, MORE_MAGIC_1 & MORE_MAGIC_2 ^ 0xA)
// etc...
#define SKIP_CONSTANT "What?"
// More CONSTANT_N mixed with more other stuff and constants which do
// not resolve to compile-time integers and must be skipped
}
#endif Constants_h
Что мне нужно получить из этого, так это имена и оценки всех определений, которые разрешаются в целочисленные константы времени компиляции. В этом случае для показанных определений это будет
MAGIC_NUMBER_BASE 40
MAGIC_NUMBER 42
MORE_MAGIC_1 345
MORE_MAGIC_2 65
CONSTANT_1 1887
CONSTANT_2 -42
На самом деле не имеет значения, в каком формате этот вывод, пока я могу работать с ним как со списком пар ключ-значение дальше по конвейеру.
cpp
с опцией-dU
должен приблизить вас к желаемому результату. - person Matteo Italia   schedule 16.03.2017CONSTANT_1
иCONSTANT_2
в выводе, аMAGIC_NUMBER_BASE
,MAGIC_NUMBER
,MORE_MAGIC_1
,MORE_MAGIC_2
нет? Похоже, они соответствуют вашим критериям (определяют, какие из них разрешают целочисленные константы времени компиляции), по крайней мере, так же, как и два других. - person Ben Voigt   schedule 16.03.2017-dM
, но без предопределенных макросов (-dD
делает это, но также печатает обработанный вывод). - person Matteo Italia   schedule 17.03.2017CONSTANT_1
не является интегральным выражением времени компиляции, пока оно не используется... и возможно, что некоторые из них используются, а некоторые нет. - person Ben Voigt   schedule 17.03.2017