¿Existe un preprocesador de C que elimine los bloques #ifdef en función de valores definidos/indefinidos?

Resuelto Jonathan Leffler asked hace 15 años • 5 respuestas

Pregunta original

Lo que me gustaría no es un preprocesador C estándar, sino una variación del mismo que aceptaría desde algún lugar (probablemente la línea de comando a través de las opciones -DNAME1 y -UNAME2) una especificación de qué macros están definidas y luego eliminaría las muertas. código.

Puede ser más fácil entender lo que busco con algunos ejemplos:

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

Si el comando se ejecutara con '-DNAME1', el resultado sería:

#define ALBUQUERQUE "ambidextrous"

Si el comando se ejecutara con '-UNAME1', el resultado sería:

#define PHANTASMAGORIA "ghostly"

Si el comando se ejecutara sin 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 -DUSE_VOID -UPLATFORM1y 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 -UOLDUNIXy obtener el resultado:

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

¡Esto puede estar poniendo a prueba mi suerte!

Motivación: base de código grande y antigua con mucho código condicional. Muchas de las condiciones ya no se aplican: la plataforma OLDUNIX, por ejemplo, ya no se fabrica ni se admite, por lo que no es necesario tener referencias a ella en el código. Otras condiciones siempre son ciertas. Por ejemplo, las funciones se agregan con la compilación condicional para que se pueda usar una única versión del código tanto para versiones anteriores del software donde la función no está disponible como para versiones más nuevas donde sí está disponible (más o menos). Con el tiempo, las versiones antiguas sin la función ya no son compatibles (todo usa la función), por lo que se debe eliminar la condición sobre si la función está presente o no, y también se debe eliminar el código "cuando la función está ausente". Me gustaría tener una herramienta para hacer el trabajo automáticamente porque será más rápido y confiable que hacerlo manualmente (lo cual es bastante crítico cuando el código base incluye 21,500 archivos fuente).

(Una versión realmente inteligente de la herramienta podría leer #includelos archivos 'd 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 realmente útil, excepto como (un diagnóstico de respaldo. Sin embargo, haga lo que haga, el pseudopreprocesador no debe expandir macros ni incluir archivos palabra por palabra. La salida debe ser similar al código de entrada, pero generalmente más simple).

Informe de situación (un año después)

Después de un año de uso, estoy muy contento con ' sunifdef ' recomendado por la respuesta seleccionada. Todavía no ha cometido ningún error y no espero que lo haga. El único inconveniente que tengo es estilístico. Dada una entrada como:

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

y ejecutar con '-UC' (C nunca está definido), el resultado es:

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

Esto es técnicamente correcto porque '&&' se une más estrechamente que '||', pero es una invitación abierta a la confusión. Preferiría que incluyera 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 parte del código con el que tengo que trabajar, que ese sea el mayor detalle es un gran cumplido; Es una herramienta valiosa para mí.


El chico nuevo de la cuadra

Después de verificar la inclusión de la URL 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é... habrá más informes más adelante este año, o tal vez el próximo año, o en algún momento, o nunca.

Jonathan Leffler avatar Feb 08 '09 13:02 Jonathan Leffler
Aceptado

No sé absolutamente nada sobre C, pero parece que estás buscando algo como unifdef. Tenga en cuenta que no se ha actualizado desde 2000, pero hay un sucesor llamado "Son of unifdef" (sunifdef) .

Jörg W Mittag avatar Feb 08 '2009 07:02 Jörg W Mittag

También puedes probar esta herramienta http://coan2.sourceforge.net/

algo como esto eliminará los bloques ifdef:

fuente coan -UYOUR_FLAG --filter c,h --recurse YourSourceTree

ernesto avatar Jun 20 '2013 15:06 ernesto

Utilicé unifdef hace años para el tipo de problema que usted describe y funcionó bien. Incluso si no se ha actualizado desde 2000, la sintaxis del preprocesador ifdefs no ha cambiado materialmente desde entonces, por lo que espero que siga haciendo lo que usted desea. Supongo que puede haber algunos problemas de compilación, aunque los paquetes parecen recientes.

Nunca he usado sunifdef, por lo que no puedo comentarlo directamente.

Dale Hagglund avatar Feb 08 '2009 07:02 Dale Hagglund

Alrededor de 2004 escribí una herramienta que hacía exactamente lo que buscabas. Nunca logré distribuir la herramienta, pero el código se puede encontrar aquí:

http://casey.dnsalias.org/exifdef-0.2.zip (ese es un enlace dsl)

Tiene aproximadamente 1,7k líneas e implementa suficiente gramática de C para analizar declaraciones, comentarios y cadenas de preprocesador usando bison y flex.

johnny avatar Feb 08 '2009 07:02 johnny