Lunes 26 de Abril

La sintaxis de Java

Objetivos: Mostrar que la estructura de los programas se rige por reglas sintácticas que se pueden aplicar matemáticamente para determinar si un programa está sintácticamente bien escrito.

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:


La sintaxis

Para un inexperto, la forma en que se combinan las palabras y símbolos para formar programas ejecutables puede parecer confusa y casi antojadiza. Sin embargo, la escritura de programas computacionales se rige por un reducido conjunto de reglas gramaticales. Este conjunto de reglas se denomina la sintaxis del lenguaje de programación. Por esta razón, también se habla de reglas sintácticas como sinónimo de reglas gramaticales.

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:

    a+1 = b;
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.

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.


Categorías sintácticas

Las reglas gramaticales que constituyen la sintaxis de un lenguaje se basan en la existencia de categorías sintácticas. Por ejemplo, en Java, instrucciones, expresiones, asignaciones, etc. son ejemplos de categorías sintácticas de la misma forma que las proposiciones, los verbos, los sustantivos, son categorías sintácticas en un lenguaje hablado como el castellano.

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:


Reglas sintácticas

La sintaxis de un lenguaje permite determinar matemáticamente si un programa es correcto desde el punto de vista sintáctico o no. Esta sintaxis se expresa en base a un conjunto de reglas gramaticales del estilo:

exp -> exp op-bin exp

En donde exp y op-bin son abreviaciones de las categorías sintácticas expresión y operador binario (un símbolo que denota una operación entre dos valores).

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 -> +
-> -
-> *
-> /
-> %


Arbol sintáctico

Una árbol sintáctico permite demostrar que una secuencia de caracteres es una determinada categoría sintáctica. Por ejemplo, el siguiente es un árbol sintáctico que demuestra que 'a+5' es una expresión:

      a     +     5
      |     |     |     
    ident op-bin const
      |     |     |
     exp    |    exp
        \   |   /
         \  |  /
           exp
Para que un árbol sintáctico sea válido se necesita que para cada bifurcación del estilo:

        sub-categorías ...
            \  |  /
           categoría
exista la siguiente regla sintáctica:

categoría -> sub-categorías ...

Por ejemplo la siguiente bifurcación:

         exp op-bin exp
           \   |   /
            \  |  /
              exp
es posible gracias a que existe la regla:

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
En general, basta construir un sólo arbol sintáctico para demostrar que una frase corresponde a la categoría que aparece en la raíz. Si no es posible construir este árbol, entonces la frase no corresponde a esa categoría. Por ejemplo, no es posible construir un árbol sintáctico que muestre que 'a + b c' es una expresión.

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:

Expresiones

exp -> const (1)
-> ident (2)
-> op-unario exp (3)
-> exp op-bin exp (4)
-> ( exp ) (5)

Operadores binarios

aritméticos: op-bin -> +
-> -
-> *
-> /
-> %
relacionales: -> ==
-> !=
-> >=
-> <=
-> >
-> <
booleanos: -> &&
-> ||

Operadores unarios

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:

Del mismo modo, se puede mostrar que 'a+!b' también es una expresión. Para ello basta cambiar el '-' por '!' en el árbol anterior. Sin embargo, aún cuando sintácticamente se trate de una expresión bien escrita, es una expresión incorrecta, puesto que no es posible asignarle un tipo a esta expresión. Esto quedará más claro cuando hablemos sobre el sistema de tipos.

Ejercicios:


Reglas de desambiguación

El árbol sintáctico no sólo muestra que una frase es una expresión, si no que además indica cuál es la parentización que usará el compilador para evaluar la expresión. Por ejemplo, más arriba se vió un árbol sintáctico para la expresión 'a-b*c'. En ese árbol se formaba una sub-expresión a partir de 'b*c'. Al tomar esa decisión se manifiesta que primero se evalúa b*c y luego a + (b*c).

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
En este otro árbol, se calcula 'a-b' y el resultado se multiplica por c, lo que claramente es distinto de lo anterior. Este tipo de expresiones son entonces ambiguas. El lenguaje hablado está típicamente plagado de ambiguedades que a veces causan problemas de interpretación. Sin embargo, un lenguaje computacional no puede ser ambiguo.

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:

Con las reglas de desambiguación toda expresión tiene un único árbol sintáctico válido.


La expresión de asignación

En Java la asignación es una expresión como cualquier otra y por lo tanto se puede colocar válidamente en cualquier lugar en donde deba ir una expresión. La regla sintáctica que describe la asignación es la siguiente:

exp -> ident = exp

Con esta regla, la siguiente expresión está sintácticamente bien escrita:

    a= b= 0       o equivalentemente:   a= (b= 0) 
Su significado semántico también es correcto: la expresión 'b=0' indica que se asigna 0 a la variable b. El resultado de esa expresión es el mismo valor asignado, es decir 0. Ese mismo valor se asigna luego a la variable a.

Este tipo de construcciones puede ser útil para realizar varias inicializaciones en una misma línea:

    a= b= c= d= e= 0
Gracias a que la asignación es una expresión, también es posible escribir:

    ...
    while ( (a= readInt())!=0 ) {
      ...
    }

    en vez de:

    a= readInt();
    while ( a!=0 ) {
      ...
      a= readInt();
    }
Se puede apreciar que el primer trozo de código resulta más breve que el segundo.