Existe-t-il un préprocesseur C qui élimine les blocs #ifdef basés sur des valeurs définies/non définies?

Question Originale

ce que je voudrais n'est pas un pré-processeur standard C, mais une variation sur elle qui accepterait de quelque part - probablement la ligne de commande via-DNAME1 et-UNAME2 options - une spécification de ce que les macros sont définis, et éliminerait alors le code mort.

il peut être plus facile de comprendre ce que je suis après avec quelques exemples:

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

si la commande était exécutée avec'- DNAME1', le la sortie serait:

#define ALBUQUERQUE "ambidextrous"

si la commande était exécutée avec '- UNAME1', le résultat serait:

#define PHANTASMAGORIA "ghostly"

si la commande était exécutée sans aucune option, la sortie serait la même que l'entrée.

C'est un cas simple - j'espère que le code pourrait traiter des cas plus complexes aussi.

pour illustrer avec un exemple réel mais encore 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 */

j'aimerais lancer la commande avec -DUSE_VOID -UPLATFORM1 et obtenir la sortie:

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

autre exemple:

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

idéalement, je voudrais lancer avec -UOLDUNIX et obtenir la sortie:

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

cela peut pousser ma chance!

Motivation: grande, ancienne base de code avec beaucoup de code conditionnel. Beaucoup de conditions ne s'appliquent plus - la plate-forme OLDUNIX, par exemple, n'est plus faite et n'est plus supportée, il n'est donc pas nécessaire d'y faire référence dans le code. D'autres conditions sont toujours vraies. Par exemple, des fonctionnalités sont ajoutées avec la compilation conditionnelle de sorte qu'une seule version du code peut être utilisée à la fois pour les versions plus anciennes du logiciel où la fonctionnalité n'est pas disponible et pour les versions plus récentes où elle est disponible (plus ou moins). Finalement, les anciennes versions sans la fonctionnalité ne sont plus supportées - Tout utilise la fonctionnalité - la condition selon laquelle la caractéristique est présente ou non devrait être supprimée, et le code "quand la caractéristique est absente" devrait également être supprimé. J'aimerais avoir un outil pour faire le travail automatiquement parce qu'il sera plus rapide et plus fiable que de le faire manuellement (ce qui est plutôt critique lorsque la base de code comprend 21 500 fichiers source).

(une version très intelligente de l'outil pourrait lire #include 'd fichiers pour déterminer si les macros de contrôle-ceux spécifiés par -D ou-U sur la ligne de commande - sont définis dans ces fichiers. Je ne suis pas sûr que ce soit vraiment utile sauf comme diagnostic de secours. Quoi qu'il fasse d'autre, le pseudo-pré-processeur ne doit pas étendre les macros ou inclure des fichiers mot à mot. La sortie doit être source de, mais généralement plus simple que le code d'entrée.)

Rapport de situation (un an plus tard)

après un an d'utilisation, je suis très satisfait de sunifdef " recommandé par la réponse sélectionnée. Il n'a pas encore fait d'erreur, et je ne m'y attends pas. Le seul bémol que j'ai avec c'est stylistique. Compte tenu d'une entrée telle que:

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

et exécuter avec '- UC' (C n'est jamais défini), la sortie est:

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

ceci est techniquement correct parce que '&&' se lie plus étroitement que '||', mais c'est une invitation ouverte à la confusion. Je le préfère à inclure des parenthèses autour de"&&", comme dans le original:

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

cependant, étant donné l'obscurité d'une partie du code que je dois travailler avec, pour que d'être le plus grand nit-pick est un compliment fort; il est outil précieux pour moi.


Le Nouvel Enfant sur le Bloc

ayant vérifié L'URL pour inclusion dans les informations ci-dessus, je vois que (comme prévu) Il ya un nouveau programme appelé Coan qui est le successeur à "sunifdef". Il est disponible sur SourceForge depuis janvier 2010. Je vais le vérifier...d'autres rapports plus tard cette année, ou peut-être l'année prochaine, ou, parfois, ou jamais.

30
demandé sur 李哲源 2009-02-08 09:45:56

5 réponses

Je ne sais absolument rien à propos de C, mais il semble que vous cherchez quelque chose comme unifdef . Notez qu'il n'a pas été mis à jour depuis 2000, mais il y a un successeur appelé "fils d'unifdef" (sunifdef) .

23
répondu Jörg W Mittag 2018-09-10 18:50:21

j'ai utilisé unifdef Il ya des années pour juste le genre de problème que vous décrivez, et il a fonctionné très bien. Même si elle n'a pas été mise à jour depuis 2000, la syntaxe du préprocesseur ifdefs n'a pas changé matériellement depuis, donc je m'attends à ce qu'elle fasse toujours ce que vous voulez. Je suppose qu'il pourrait y avoir quelques problèmes de compilation, bien que les paquets apparaissent récents.

Je n'ai jamais utilisé sunifdef, donc je ne peux pas le commenter directement.

4
répondu Dale Hagglund 2009-02-08 07:37:46

vous pouvez également essayer cet outil http://coan2.sourceforge.net/

quelque chose comme ça va supprimer les blocs ifdef:

coan source-UYOUR_FLAG -- filter c, h --recurse your SourceTree

4
répondu ernesto 2013-06-20 15:58:53

autour de 2004, j'ai écrit un outil qui a fait exactement ce que vous recherchez. Je n'ai jamais eu le temps de distribuer l'outil, mais le code se trouve ici:

http://casey.dnsalias.org/exifdef-0.2.zip (c'est une liaison dsl)

il s'agit d'environ 1,7 lignes k et met en œuvre assez de la grammaire C pour analyser les déclarations préprocesseur, les commentaires et les cordes en utilisant bison et flex.

3
répondu johnny 2009-02-08 07:36:21

si vous avez besoin de quelque chose de similaire à un préprocesseur, la solution flexible est Wave (de boost). C'est une bibliothèque conçue pour construire des outils de préprocesseur en C (incluant des choses comme les préprocesseurs C++03 et C++0x). Comme c'est une bibliothèque, vous pouvez vous connecter à son code d'entrée et de sortie.

2
répondu MSalters 2009-02-10 15:39:14