Hoy toca post para informáticos. Como bien sabréis, muchos lenguajes disponen de una forma abreviada de indicar incrementos y decrementos, que son ‘++
‘ y ‘--
‘. Esto, además de facilitar la vida a los programadores evitándoles escribir a=a+1
, es también de utilidad para las optimizaciones que hace el compilador, puesto que en la mayoría de arquitecturas existen instrucciones de incremento y decremento que se ejecutan utilizando menos recursos que una suma convencional.
En algunos lenguajes, como en C y Java, se puede utilizar este operador delante y detrás de las variables, pero tiene un comportamiento distinto. Si el operador está delante, se hace primero la resta y se evalúa el resultado; mientras que si está detrás, primero se devuelve el valor, y después se realiza la resta.
Así, si b=10 y hacemos a=--b
, a y b terminarán con valor 9, pero a=b--
terminará con a=10
y b=9
.
Bien, recordado esto, en mis apuntes de compiladores se menciona como un código algo lioso a primera vista, la siguiente instrucción c=a---b--
. A raíz de ello, he decidido pensar en situaciones similares a ésta, que son:
c = --a---b;
c = --a-b--;
c = a-----b;
c = a---b--;
c = a---b;
Suponiendo que es ilegal --n--
, y obviando la última (hay que acordar cómo se comporta) ¿Alguien se anima a hacer la traza? Es facilita, la hice ayer a mano en lugar de seguir estudiando :P.
Aunque todas salvo la última parezcan correctas y sin ambigüedades, curiosamente hay dos de ellas que ni C ni Java aceptan (con los compiladores GCC 2.8.1, Borlandc 3.0 y JDK 1.6). Son la primera y la tercera, y ocurre lo mismo si en lugar de ‘--
‘ utilizamos ‘++
‘. ¿Por qué? Pues imagino que por el tipo de análisis que hace el compilador.
Tal y como veo que se comporta (he hecho más pruebas aparte de esos 5 casos), cuando el analizador léxico lee el código carácter a carácter, siempre que encuentra dos ‘-‘ seguidos, los considera un único token ‘--
‘ y así es como los envía al siguiente nivel.
Después, en el analizador sintáctico/semántico debe de existir algún tipo de precedencia asignada al operador ‘--
‘ por encima de la resta y el opuesto, de modo que cuando se encuentra con --a
, ó a--
, hace directamente una reducción y pasa a considerar la expresión como una constante, a la que ya no tiene sentido volver a aplicar otro ‘--
‘.
En el caso «especial» c=a---b
, a mi juicio el único que es ambiguo y del que debería quejarse el compilador, se opta por aplicar el operador ‘--
‘ a la variable a; siendo equivalente a ejecutar c=a-b
y después a--
.
También acepta correctamente c=-a--;
// c = -a (y decrementar después a).
Otras asignaciones que dan error de compilación, y comentado a lo que debería corresponder:
c = ---a;
//c = – (decremento de a)
c = --a--b;
//c = (decremento de a) menos (-b)
c = a--b;
// c = a menos (-b)
c = a----b;
// c = a menos (-b) [y después decrementar a]
Por los errores que da el compilador, en el primer caso creo que intentar aplicar el operador ‘--
‘ sobre ‘-
‘, y en el tercer caso, evalua ‘a--
‘, y después encuentra la b sin operadores entre ellos. En el segundo fallan dos cosas: primero aplica correctamente --a
, pero al resultado no se le puede aplicar otra vez ‘--
‘; el segundo fallo es que ha consumido el token ‘--
‘ y se encuentra, de nuevo, con una b solitaria sin operadores entre la a. En el cuarto tenemos otros dos fallos similares al anterior.
¿Ocurrirá así en todos los compiladores de C, o habrán tenido esto en cuenta en algún caso? ¿O es algo definido directamente en el estándar? He echado un vistazo rápido al ANSI C buscando «decrement», pero no he leído nada destacable.