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