c++ - para - ¿Hay un preprocesador C que elimine los bloques#ifdef en función de los valores definidos/indefinidos?
ifdef c example (5)
Alrededor de 2004 escribí una herramienta que hizo exactamente lo que estás buscando. Nunca llegué a distribuir la herramienta, pero el código se puede encontrar aquí:
http://casey.dnsalias.org/exifdef-0.2.zip (es un enlace dsl)
Se trata de 1.7k líneas e implementa suficiente gramática C para analizar declaraciones de preprocesador, comentarios y cadenas utilizando bison y flex.
Pregunta original
Lo que me gustaría no es un preprocesador C estándar, sino una variación que aceptaría de alguna parte, probablemente la línea de comando a través de las opciones -DNAME1 y -UNAME2 - una especificación de qué macros se definen, y luego eliminaría los muertos código.
Puede ser más fácil entender lo que estoy buscando con algunos ejemplos:
#ifdef NAME1
#define ALBUQUERQUE "ambidextrous"
#else
#define PHANTASMAGORIA "ghostly"
#endif
Si el comando se ejecutara con ''-DNAME1'', la salida sería:
#define ALBUQUERQUE "ambidextrous"
Si el comando se ejecutara con ''-UNAME1'', el resultado sería:
#define PHANTASMAGORIA "ghostly"
Si el comando se ejecutara con ninguna opción, la salida sería la misma que la entrada.
Este es un caso simple: espero que el código también pueda manejar casos más complejos.
Para ilustrar con un ejemplo del mundo real pero aún simple:
#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 */
Me gustaría ejecutar el comando con -DUSE_VOID -UPLATFORM1
y obtener el resultado:
#undef VOID
typedef void VOID;
typedef void * VOIDPTR;
Otro ejemplo:
#ifndef DOUBLEPAD
#if (defined NT) || (defined OLDUNIX)
#define DOUBLEPAD 8
#else
#define DOUBLEPAD 0
#endif /* NT */
#endif /* !DOUBLEPAD */
Idealmente, me gustaría ejecutar con -UOLDUNIX
y obtener el resultado:
#ifndef DOUBLEPAD
#if (defined NT)
#define DOUBLEPAD 8
#else
#define DOUBLEPAD 0
#endif /* NT */
#endif /* !DOUBLEPAD */
¡Esto puede estar empujando mi suerte!
Motivación: base de códigos grande y antigua con muchos códigos condicionales. Muchas de las condiciones ya no se aplican: la plataforma OLDUNIX, por ejemplo, ya no se fabrica y ya no es compatible, por lo que no es necesario tener referencias en el código. Otras condiciones son siempre verdaderas. Por ejemplo, las características se agregan con compilación condicional para que una versión única del código se pueda usar tanto para versiones anteriores del software donde la característica no está disponible como para versiones más nuevas donde está disponible (más o menos). Eventualmente, las versiones antiguas sin la característica ya no son compatibles, todo usa la función, por lo que debe eliminarse la condición de si la característica está presente o no, y también debe eliminarse el código ''cuando la característica está ausente''. Me gustaría tener una herramienta para hacer el trabajo automáticamente porque será más rápido y más confiable que hacerlo manualmente (lo cual es bastante crítico cuando la base de código incluye 21,500 archivos fuente).
(Una versión realmente inteligente de la herramienta podría leer #include
''d files para determinar si las macros de control, las especificadas por -D o -U en la línea de comando, están definidas en esos archivos. No estoy seguro de si eso es verdaderamente útil excepto como un diagnóstico de respaldo. Sin embargo, independientemente de lo que haga, el pseudo preprocesador no debe expandir macros o incluir archivos textualmente. La salida debe ser una fuente similar, pero generalmente más simple, que el código de entrada).
Informe de estado (un año después)
Después de un año de uso, estoy muy contento con '' sunifdef '' recomendado por la respuesta seleccionada. No ha cometido un error todavía, y no espero que lo haga. La única objeción que tengo es estilística. Dada una entrada como:
#if (defined(A) && defined(B)) || defined(C) || (defined(D) && defined(E))
y ejecutar con ''-UC'' (C nunca se define), la salida es:
#if defined(A) && defined(B) || defined(D) && defined(E)
Esto es técnicamente correcto porque ''&&'' se une más fuerte que ''||'', pero es una invitación abierta a la confusión. Preferiría que incluya paréntesis alrededor de los conjuntos de condiciones ''&&'', como en el original:
#if (defined(A) && defined(B)) || (defined(D) && defined(E))
Sin embargo, dada la oscuridad de algunos de los códigos con los que tengo que trabajar, para que eso sea lo más importante es un gran cumplido; es una herramienta valiosa para mí.
El nuevo chico en el bloque
Después de haber revisado la URL para su inclusión en la información anterior, veo que (como se predijo) hay un nuevo programa llamado Coan que es el sucesor de ''sunifdef''. Está disponible en SourceForge y lo ha estado desde enero de 2010. Lo revisaré ... más informes a finales de este año, o tal vez el año que viene, o en algún momento, o nunca.
No sé absolutamente nada sobre C, pero parece que estás buscando algo así como unifdef
. Tenga en cuenta que no se ha actualizado desde 2000, pero hay un sucesor llamado "Hijo de unifdef" (sunifdef) .
Si necesita algo similar a un preprocesador, la solución flexible es Wave (de boost). Es una biblioteca diseñada para construir herramientas similares al preprocesador C (incluyendo cosas como los preprocesadores C ++ 03 y C ++ 0x). Como es una biblioteca, puede conectar su código de entrada y salida.
También puedes probar esta herramienta Coan
algo así eliminará los bloques ifdef:
fuente de Coan -UYOUR_FLAG --filter c, h --recurse YourSourceTree
Usé el uniforme hace años para el tipo de problema que describes, y funcionó bien. Incluso si no se ha actualizado desde 2000, la sintaxis del preprocesador ifdefs no ha cambiado sustancialmente desde entonces, por lo que espero que siga haciendo lo que quiera. Supongo que puede haber algunos problemas de compilación, aunque los paquetes parecen recientes.
Nunca he usado sunifdef, así que no puedo comentarlo directamente.