Есть ли предварительный процессор C, который исключает блоки #ifdef на основе определенных значений/undefined?

Оригинальный вопрос

Я бы хотел, чтобы это был не стандартный предварительный процессор C, а вариация на нем, которая могла бы принять откуда-то - возможно, командная строка через опции -DNAME1 и -UNAME2 - спецификация макросов, которые будут определены, и тогда устранить мертвый код.

Мне может быть легче понять, что мне нужно с некоторыми примерами:

#ifdef NAME1
#define ALBUQUERQUE "ambidextrous"
#else
#define PHANTASMAGORIA "ghostly"
#endif

Если команда была запущена с помощью "-DNAME1", результатом будет:

#define ALBUQUERQUE "ambidextrous"

Если команда была запущена с помощью "-UNAME1", результатом будет:

#define PHANTASMAGORIA "ghostly"

Если команда была запущена ни с одной опцией, выход был бы таким же, как и вход.

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

Чтобы проиллюстрировать реальный, но все же простой пример:

#ifdef USE_VOID
#ifdef PLATFORM1
#define VOID void
#else
#undef VOID
typedef void    VOID;
#endif /* PLATFORM1 */
typedef void *  VOIDPTR;
#else
typedef mint     VOID;
typedef char *  VOIDPTR;
#endif /* USE_VOID */

Я хотел бы запустить команду с -DUSE_VOID -UPLATFORM1 и получить вывод:

#undef VOID
typedef void    VOID;
typedef void *  VOIDPTR;

Другой пример:

#ifndef DOUBLEPAD
#if (defined NT) || (defined OLDUNIX)
#define DOUBLEPAD 8
#else
#define DOUBLEPAD 0
#endif /* NT */
#endif /* !DOUBLEPAD */

В идеале я хотел бы работать с -UOLDUNIX и получить результат:

#ifndef DOUBLEPAD
#if (defined NT)
#define DOUBLEPAD 8
#else
#define DOUBLEPAD 0
#endif /* NT */
#endif /* !DOUBLEPAD */

Это может подтолкнуть мою удачу!

Мотивация: большая, древняя база кода с большим количеством условного кода. Многие из условий больше не применяются - платформа OLDUNIX, например, больше не выполняется и больше не поддерживается, поэтому нет необходимости иметь ссылки на нее в коде. Другие условия всегда верны. Например, функции добавляются с условной компиляцией, так что одна версия кода может использоваться как для старых версий программного обеспечения, где эта функция недоступна, так и для более новых версий, где она доступна (более или менее). В конце концов, старые версии без этой функции больше не поддерживаются - все использует эту функцию, поэтому необходимо исключить условие наличия или отсутствия функции, а также удалить код "когда функция отсутствует". Я хотел бы иметь инструмент для выполнения задания автоматически, потому что он будет быстрее и надежнее, чем делать это вручную (что весьма важно, когда база кода содержит 21 500 исходных файлов).

(На самом деле умная версия инструмента может читать файлы #include 'd, чтобы определить, определены ли в этих файлах макросы управления - те, которые указаны в -D или -U в командной строке. Я не уверен, действительно полезный, кроме как для резервного копирования. Однако, что бы он ни делал, псевдо-предварительный процессор не должен расширять макросы или включать файлы дословно. Результат должен быть источником, похожим на, но обычно более простым, чем код ввода.)

Отчет о состоянии (через год)

После года использования я очень доволен " sunifdef ", рекомендованным выбранным ответом. Он еще не совершил ошибку, и я этого не ожидаю. Единственный куб, который у меня есть, стилистичен. Учитывая такой ввод, как:

#if (defined(A) && defined(B)) || defined(C) || (defined(D) && defined(E))

и запустить с помощью -U C '(C никогда не определяется), выход:

#if defined(A) && defined(B) || defined(D) && defined(E)

Это технически корректно, потому что '&&' связывается более жестко, чем '||', но это открытое приглашение к путанице. Я бы предпочел, чтобы он включал круглые скобки вокруг наборов условий "&&", как в оригинале:

#if (defined(A) && defined(B)) || (defined(D) && defined(E))

Однако, учитывая неясность некоторого кода, с которым мне приходится работать, поскольку это самый большой нит-кик, это сильный комплимент; это ценный инструмент для меня.


Новый малыш на блоке

Проверяя URL-адрес для включения в вышеприведенную информацию, я вижу, что (как и было предсказано) существует новая программа под названием Coan, которая является преемником "sunifdef". Он доступен на SourceForge и с января 2010 года. Я буду проверять его... дальнейшие отчеты в конце этого года или, возможно, в следующем году или когда-нибудь, или никогда.

Ответ 1

Я абсолютно ничего не знаю о C, но похоже, что вы ищете что-то вроде unifdef. Обратите внимание, что он не обновлялся с 2000 года, но есть преемник под названием "Сын unifdef" (sunifdef).

Ответ 2

Я использовал unifdef несколько лет назад только для той проблемы, которую вы описали, и она отлично работала. Даже если он не обновлялся с 2000 года, синтаксис препроцессора ifdefs не изменился с тех пор, поэтому я ожидаю, что он все равно будет делать то, что вы хотите. Я полагаю, что могут возникнуть проблемы с компиляцией, хотя пакеты появляются в последнее время.

Я никогда не использовал sunifdef, поэтому я не могу комментировать его напрямую.

Ответ 3

Также вы можете попробовать этот инструмент http://coan2.sourceforge.net/

что-то вроде этого удалит блоки ifdef:

источник -UYOUR_FLAG -filter c, h -recurse YourSourceTree

Ответ 4

Около 2004 года я написал инструмент, который сделал именно то, что вы ищете. Я никогда не собирался распространять инструмент, но код можно найти здесь:

http://casey.dnsalias.org/exifdef-0.2.zip (ссылка dsl)

Это около 1,7 тыс. строк и реализует достаточное количество грамматики С для анализа выражений препроцессора, комментариев и строк с использованием бизона и гибкости.

Ответ 5

Если вам нужно что-то похожее на препроцессор, гибкое решение Wave (от boost). Это библиотека, предназначенная для создания C-препроцессорных инструментов (в том числе таких, как препроцессоры С++ 03 и С++ 0x). В качестве библиотеки вы можете подключить свой код ввода и вывода.