Existe um pré-processador C que elimina blocos #ifdef baseados em valores definidos / indefinidos?

Pergunta original

O que eu gostaria não é um pré-processador C padrão, mas uma variação que aceitaria de algum lugar – provavelmente a linha de comando através das opções -DNAME1 e -UNAME2 – uma especificação de quais macros são definidas e, então, eliminaria código.

Pode ser mais fácil entender o que estou procurando com alguns exemplos:

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

Se o comando foi executado com ‘-DNAME1’, a saída seria:

 #define ALBUQUERQUE "ambidextrous" 

Se o comando foi executado com ‘-UNAME1’, a saída seria:

 #define PHANTASMAGORIA "ghostly" 

Se o comando não fosse executado com nenhuma das opções, a saída seria igual à input.

Este é um caso simples – eu esperaria que o código pudesse lidar com casos mais complexos também.

Para ilustrar com um exemplo real, mas ainda simples:

 #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 */ 

Gostaria de executar o comando com -DUSE_VOID -UPLATFORM1 e obter a saída:

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

Outro exemplo:

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

Idealmente, gostaria de correr com -UOLDUNIX e obter a saída:

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

Isso pode estar empurrando a minha sorte!

Motivação: grande e antiga base de código com muitos códigos condicionais. Muitas das condições não se aplicam mais – a plataforma OLDUNIX, por exemplo, não é mais feita e não é mais suportada, portanto, não há necessidade de ter referências a ela no código. Outras condições são sempre verdadeiras. Por exemplo, os resources são adicionados com a compilation condicional para que uma única versão do código possa ser usada para versões mais antigas do software em que o recurso não está disponível e versões mais recentes onde ele está disponível (mais ou menos). Eventualmente, as versões antigas sem o recurso não são mais suportadas – tudo usa o recurso – então a condição sobre se o recurso está presente ou não deve ser removida, e o código ‘quando o recurso está ausente’ deve ser removido também. Eu gostaria de ter uma ferramenta para fazer o trabalho automaticamente, porque será mais rápido e mais confiável do que fazê-lo manualmente (o que é bastante crítico quando a base de código inclui 21.500 arquivos de origem).

(Uma versão realmente inteligente da ferramenta pode ler arquivos #include ‘d para determinar se as macros de controle – aquelas especificadas por -D ou -U na linha de comando – estão definidas nesses arquivos. Não tenho certeza se isso é realmente útil exceto como um diagnóstico de backup.Para qualquer outra coisa, o pseudo-pré-processador não deve expandir macros ou include arquivos na mesma hora. A saída deve ser semelhante, mas geralmente mais simples, ao código de input.

Relatório de status (um ano depois)

Depois de um ano de uso, estou muito feliz com ‘ sunifdef ‘ recomendado pela resposta selecionada. Não cometeu um erro ainda, e eu não espero que isso aconteça. A única queixa que tenho com isso é estilística. Dado uma input como:

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

e executado com ‘-UC’ (C nunca é definido), a saída é:

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

Isso é tecnicamente correto porque ‘&&’ se liga mais do que ‘||’, mas é um convite aberto à confusão. Eu preferiria que ele incluísse parênteses em torno dos conjuntos de condições ‘&&’, como no original:

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

No entanto, dada a obscuridade de alguns dos códigos com os quais tenho que trabalhar, para que essa seja a maior escolha, é um grande elogio; é uma ferramenta valiosa para mim.


O novo garoto no bloco

Tendo verificado a URL para inclusão nas informações acima, vejo que (como previsto) existe um novo programa chamado Coan que é o sucessor de ‘sunifdef’. Ele está disponível no SourceForge e tem sido desde janeiro de 2010. Eu vou estar verificando … mais relatórios ainda este ano, ou talvez no próximo ano, ou em algum momento, ou nunca.

Eu não sei absolutamente nada sobre C, mas parece que você está procurando algo como unifdef . Note que ele não é atualizado desde 2000, mas existe um sucessor chamado “Son of unifdef” (sunifdef) .

Além disso, você pode tentar esta ferramenta http://coan2.sourceforge.net/

algo como isto irá remover blocos ifdef:

fonte coan -UYOUR_FLAG –filter c, h –recurse YourSourceTree

Eu usei unifdef anos atrás apenas para o tipo de problema que você descreve e funcionou bem. Mesmo que não tenha sido atualizado desde 2000, a syntax do pré-processador ifdefs não mudou materialmente desde então, então espero que ele ainda faça o que você quer. Eu suponho que possa haver alguns problemas de compilation, embora os pacotes pareçam recentes.

Eu nunca usei sunifdef, então não posso comentar diretamente.

Por volta de 2004 eu escrevi uma ferramenta que fez exatamente o que você está procurando. Eu nunca cheguei a distribuir a ferramenta, mas o código pode ser encontrado aqui:

http://casey.dnsalias.org/exifdef-0.2.zip (isso é um link dsl)

É de cerca de 1,7 mil linhas e implementa o suficiente da gramática C para analisar instruções, comentários e sequências de pré-processadores usando bison e flex.

Se você precisa de algo semelhante a um pré-processador, a solução flexível é o Wave (do boost). É uma biblioteca projetada para criar ferramentas semelhantes a pré-processadores C (incluindo coisas como os pré-processadores C ++ 03 e C ++ 0x). Como é uma biblioteca, você pode conectar em seu código de input e saída.