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

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

То, что я хотел бы, это не стандартный препроцессор 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))

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

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

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

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

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


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

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

5 ответов

Решение

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

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

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

источник коана -UYOUR_FLAG --фильтр c,h -recurse YourSourceTree

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

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

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

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

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

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

Другие вопросы по тегам