2010-03-11 19 views
5

que estaba buscando una herramienta que puede convertir expresiones de código C para la forma:C: ¿Convert A? B: C en si (A) B cosa C

a = (A) ? B : C; 

en la sintaxis 'por defecto' con if/else declaraciones:

if (A) 
    a = B 
else 
    a = C 

¿Alguien conoce una herramienta que sea capaz de hacer tal transformación?

Trabajo con GCC 4.4.2 y creo un archivo preprocesado con -E pero no quiero tales estructuras en él.

Editar: siguiente código debe ser transformado, también:

a = ((A) ? B : C)->b; 
+0

¡Esto grita "macro impresionante, incompleto!" a mi. –

+1

¿Es solo un archivo? Si es así, quizás puedas hacerlo con una expresión regular sofisticada y la función de búsqueda y reemplazo de un editor que puede hacer esto. –

+23

¿Por qué? Debería considerar que hay situaciones en las que no hay equivalente semántico. No hay nada malo con el operador ternario. – GManNickG

Respuesta

12

Coccinelle puede hacer esto con bastante facilidad.

Coccinelle es una coincidencia de programa y motor de transformación que proporciona el idioma SMPL (Semántica Patch Language) para especificar deseados partidos y transformaciones en código C. Coccinelle se apuntó inicialmente a para realizar las actualizaciones colaterales en Linux. Tales evoluciones comprenden los cambios que son necesarios en código de cliente en respuesta a evoluciones en APIs de la biblioteca, y puede incluir modificaciones tales como el cambio de nombre una función, añadiendo un argumento de la función cuyo valor es de alguna manera dependiente del contexto, y la reorganización una estructura de datos . Más allá de las garantías colaterales evoluciones, Coccinelle se ha utilizado con éxito (por nosotros y otros) para encontrar y solucionar errores en el código del sistema.

EDIT: Un ejemplo de parche semántica:

@@ expression E; constant C; @@ 
(
    !E & !C 
| 
- !E & C 
+ !(E & C) 
) 

De la documentación:

El patrón x & y. Una expresión de esta forma casi siempre carece de sentido, ya que combina un operador booleano con un operador de bit. En particular, si el bit más a la derecha de y es 0, el resultado siempre será 0. Este parche semántico se enfoca en el caso en donde y es una constante.

Tiene un buen conjunto de ejemplos here.

La lista de correo es muy activa y útil.

0

No tengo conocimiento de que el operador ternario esté incorporado en las especificaciones de idioma como un atajo para la lógica if ... la única forma en que puedo pensar en hacer esto es buscar manualmente esas líneas y reescríbalo en la forma en que se usa if ...como un consenso general, el operador ternario funciona de la siguiente

 
expr_is_true ? exec_if_expr_is_TRUE : exec_if_expr_is_FALSE; 

Si la expresión se evalúa para ser verdad, ejecutar la parte entre ? y :, de lo contrario ejecutar la última parte entre : y ;. Sería la inversa, si la expresión se evalúa como falsa

 
expr_is_false ? exec_if_expr_is_FALSE : exec_if_expr_is_TRUE; 
0

Si los estados son muy regulares como éste por qué no ejecutar sus archivos a través de un pequeño script Perl? La lógica central para hacer la búsqueda y la transformación es simple para su línea de ejemplo. Aquí hay un enfoque bastante básico:

use strict; 
while(<>) { 
    my $line = $_; 
    chomp($line); 
    if ($line =~ m/(\S+)\s*=\s*\((\s*\S+\s*)\)\s*\?\s*(\S+)\s*:\s*(\S+)\s*;/) { 
     print "if(" . $2 . ")\n\t" . $1 . " = " . $3 . "\nelse\n\t" . $1 . " = " . $4 . "\n"; 
    } else { 
     print $line . "\n"; 
    } 
} 
exit(0); 

que había corrido que de este modo:

perl transformer.pl <foo.c> foo.c.new 

Por supuesto, se hace más difícil y más difícil si el patrón de texto no es tan regular como la que usted envió. Pero gratis, rápido y fácil de probar.

+0

Esto no funciona para: a = ((A)? B: C) -> b; – tur1ng

+0

Le advertí que era solo por el ejemplo que proporcionó. :) En lugar de intentar escribir alguna expresión regular súper, podrías hacer que un segundo caso elsif sea bastante fácil: m/(\ S +) \ s * = \ s * \ (\ s * \ ((\ s * \ S + \ s *) \) \ s * \? \ s * (\ S +) \ s *: \ s * (\ S +) \ s * \) \ s * -> \ s * (\ S +) \ s *;/- - la llamada de desreferencia es el grupo de juego $ 4 ahora. –

+1

@ tur1ng: Creo que el ejemplo con el-> probablemente no puede leerse sin una variable temporal. –

3

El siguiente parche semántico para Coccinelle hará la transformación.

@@ 
expression E1, E2, E3, E4; 
@@ 

- E1 = E2 ? E3 : E4; 
+ if (E2) 
+ E1 = E3; 
+ else 
+ E1 = E4; 

@@ 
type T; 
identifier E5; 
T *E3; 
T *E4; 
expression E1, E2; 
@@ 

- E1 = ((E2) ? (E3) : (E4))->E5; 
+ if (E2) 
+ E1 = E3->E5; 
+ else 
+ E1 = E4->E5; 


@@ 
type T; 
identifier E5; 
T E3; 
T E4; 
expression E1, E2; 
@@ 

- E1 = ((E2) ? (E3) : (E4)).E5; 
+ if (E2) 
+ E1 = (E3).E5; 
+ else 
+ E1 = (E4).E5; 
1

El DMS Software Reengineering Toolkit puede hacerlo, mediante la aplicación de transformaciones de programa.

una transformación específica DMS para que coincida con su ejemplo específico:

domain C. 

rule ifthenelseize_conditional_expression(a:lvalue,A:condition,B:term,C:term): 
stmt -> stmt 
= " \a = \A ? \B : \C; " 
-> " if (\A) \a = \B; else \a=\C ; ". 

Se necesitaría otra regla para manejar su otro caso, pero es igualmente fácil de expresar.

Las transformaciones operan en estructuras de código fuente en lugar de texto, por lo que la distribución y los comentarios no afectarán el reconocimiento o la aplicación. Las comillas en la regla no son comillas de cadena tradicionales, sino que son citas metalingüísticas que separan el lenguaje de sintaxis de la regla de la languidez del patrón utilizada para especificar la sintaxis concreta que se va a cambiar.

Existen algunos problemas con las directivas de preprocesamiento si tiene la intención de conservarlos. Como aparentemente está dispuesto a trabajar con código expandido por preprocesador, puede solicitar a DMS que realice el preprocesamiento como parte del paso de transformación; tiene preprocesadores compatibles con GCC4 y GCC4 integrados.

Como han observado otros, este es un caso bastante fácil porque lo especificó funciona en el nivel de una declaración completa. Si desea eliminar el código de cualquier tarea que se parece a esta declaración, con tales asignaciones incrustadas en varios contextos (inicializadores, etc.) puede necesitar un conjunto más grande de transformaciones para manejar el conjunto de casos especiales, y puede necesidad de fabricar otras estructuras de código (por ejemplo, variables temp del tipo apropiado). Lo bueno de una herramienta como DMS es que puede calcular explícitamente un tipo simbólico para una expresión arbitraria (por lo tanto, la declaración de tipo de cualquier temperatura necesaria) y que puede escribir un conjunto más grande de forma bastante sencilla y aplicarlos todos.

Dicho todo esto, no estoy seguro del valor real de realizar su operación de eliminación de expresiones condicionales ternarias. Una vez que el compilador obtiene el resultado, puede obtener un código de objeto similar como si no hubiera realizado las transformaciones. Después de todo, el compilador también puede aplicar transformaciones que preservan la equivalencia.

Obviamente, es valioso hacer cambios regulares en general.

(DMS puede aplicar transformaciones de programa fuente a fuente a muchos lenguajes, incluidos C, C++, Java, C# y PHP).

Cuestiones relacionadas