Esta materia no será preguntada en ningún control, sin embargo, el profesor de este curso estima conveniente conocerla, puesto que su comprensión ayudará a los alumnos a explicarse muchos de los errores que arrojan los compiladores.
Temas:
Las reglas gramaticales son similares a sus contrapartes de los lenguajes hablados. La diferencia radica en que en un lenguaje hablado una frase gramaticalmente mal formada, una persona es capaz de comprender. Al contrario, en un lenguaje de programación, cualquier descuido en el cumplimiento de su gramática o sintaxis se traduce en un mensaje de error, y por lo tanto, un programa que no funciona.
Por ejemplo, la siguiente instrucción:
podría ser interpretada como calcular a+1 y asignársela a b.
Pero el compilador es incapaz de captar esta interpretación y termina con
un mensaje de error.
a+1 = b;
Por esta razón, es sumamente importante dominar la gramática del lenguaje que se usa para programar. Su conocimiento, permite comprender más rápidamente los errores que se cometerán inevitablemente al escribir un programa. Tales errores serán típicamente comunicados por el compilador en un lenguaje rudo y críptico.
A lo largo del curso, hemos descrito estas reglas gramaticales. Sin embargo, éste es un buen momento para repasar tales reglas y verlas como un todo. También aprovecharemos el momento para presentar nuevas reglas no vistas hasta el momento.
Cada lenguaje de programación posee su propia sintaxis. Las reglas que rigen para Java, no son las mismas que para Pascal o Visual Basic. Por razones de tiempo, en este curso solo veremos en profundidad las reglas del lenguaje Java. La buena noticia es que una vez que se entiende la sintaxis de un lenguaje específico, es muy fácil aprender la sintaxis de otros lenguajes de programación.
Cuando una regla gramatical especifica que en tal contexto debe ir tal categoría sintáctica, significa que ahí puede y debe ir cualquier construcción del lenguaje que sea considerada de esa categoría.
Para el caso específico del lenguaje Java, las categorías sintácticas más importantes son las siguientes:
Lo que aparece a la izquierda del símbolo -> es el nombre de la categoría sintáctica que se pretende describir. A la derecha se indica una de las formas de construir frases del lenguaje que pertenecen a esa categoría. La regla sintáctica anterior se lee como: una expresión puede ser construida a partir de otra expresión seguida de un operador binario y luego una tercera expresión.
Una sola regla gramatical no basta para describir lo que es una expresión. No todas las expresiones se construyen en base a operaciones sobre otras expresiones. La siguientes reglas indican que una constante o un identificador también son expresiones.
exp | -> const |
-> ident |
En donde const es la abreviación para una constante e ident es un identificador.
(Obs.: en la última regla sintáctica se ha omitido la categoría sintáctica exp con el objeto de aligerar la notación.)
También se necesita describir qué es un operador binario. Esto se hace mediante las siguientes reglas gramaticales:
op-bin | -> | + |
-> | - | |
-> | * | |
-> | / | |
-> | % |
a + 5
| | |
ident op-bin const
| | |
exp | exp
\ | /
\ | /
exp
sub-categorías ...
\ | /
categoría
categoría | -> sub-categorías ... |
Por ejemplo la siguiente bifurcación:
exp op-bin exp
\ | /
\ | /
exp
exp | -> exp op-bin exp |
El principio básico de la sintaxis consiste en que una frase corresponde a una categoría sintáctica determinada, sí y solo sí (i) es posible construir un árbol sintáctico en donde en la raíz aparezca la categoría sintáctica pretendida y (ii) la lectura secuencial de las hojas corresponde a la frase original.
La secuencia 'a+b*c' también es una expresión, puesto que su árbol sintáctico es:
a + b * c
| | | | |
ident | ident | ident
| | | | |
| | exp op-bin exp
| | \ | /
exp op-bin exp
\ \ /
\ \ /
exp
Sin embargo, con las reglas que hemos enunciado para una expresión hasta el momento, no podemos mostrar que '-a + b' es una expresión. El siguiente grupo de reglas sintácticas permite enriquecer el conjunto de frases que corresponden a expresiones:
exp | -> const | (1) |
-> ident | (2) | |
-> op-unario exp | (3) | |
-> exp op-bin exp | (4) | |
-> ( exp ) | (5) |
aritméticos: | op-bin | -> | + |
-> | - | ||
-> | * | ||
-> | / | ||
-> | % | ||
relacionales: | -> | == | |
-> | != | ||
-> | >= | ||
-> | <= | ||
-> | > | ||
-> | < | ||
booleanos: | -> | && | |
-> | || |
aritméticos: | op-unario | -> | - |
-> | + | ||
booleanos: | -> | ! |
Hemos enumerado las reglas que describen lo que es una expresión para indicar cuando se aplican en los árboles sintácticos que mostrares a continuación:
- a + 5
| | | |
op-unario ident op-bin const
\ | | |
\ exp(2)/ exp(1)
\ / / /
exp(3) / /
\ / /
--+-------
|
exp(4)
a - ( b - 5 )
| | | | | | |
ident op-bin | ident op-bin const |
| | | | | | |
exp(2) | | exp(2) | exp(1)|
\ \ \ \ | / /
\ \ \ ---+---- /
\ \ \ exp(4) /
\ \ \ | /
\ \ -----+-------
\ \ exp(5)
\ \ /
-----\----
exp(4)
a + - b
| | | |
ident | op-unario ident
| | \ /
| | \ exp(2)
| | \ /
exp(2) op-bin exp(3)
\ | /
----|--------
exp(4)
Ejercicios:
Para cada expresión que aparezca en el árbol, indique el número
de la regla que justifica esa bifurcación.
-(a+-5*b)
a + 5 c
| | | |
ident | const ident
| | | |
| | exp exp
| | \ /
exp | exp
\ | /
---|------
exp
El problema es que esta expresión posee un segundo árbol sintáctico:
a - b * c
| | | | |
ident op-bin ident op-bin ident
\ | / / /
exp | exp / exp
\ | / / /
exp / /
\ / /
--+-----
exp
Por esta razón, los lenguajes de programación incluyen además de las reglas sintácticas, reglas de desambiguación que le dan un sentido único a las expresiones como la anterior. Estas reglas son las siguientes:
Indica qué operadores tienen precedencia al momento de construir el árbol sintáctico. En Java, las prioridades son las siguientes:
- + | (operadores unarios) |
* / % | |
+ - | (operadores binarios) |
== != >= <= > < | |
! | |
&& || |
Estas reglas eliminan el segundo árbol sintáctico como posible interpretación. Java interpreta inequívocamente la expresion 'a-b*c' por medio del primer árbol sintáctico.
Indica como parentizar en caso de operadores de la misma precedencia. En Java casi todos los operadores se parentizan de izquierda a derecha. Esto significa que:
a+b+c es equivalente a (a+b)+c
exp | -> ident = exp |
Con esta regla, la siguiente expresión está sintácticamente bien escrita:
a= b= 0 o equivalentemente: a= (b= 0)
Este tipo de construcciones puede ser útil para realizar varias inicializaciones en una misma línea:
a= b= c= d= e= 0
Se puede apreciar que el primer trozo de código resulta más breve que
el segundo.
...
while ( (a= readInt())!=0 ) {
...
}
en vez de:
a= readInt();
while ( a!=0 ) {
...
a= readInt();
}