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.