Implementación de un Léxico

Una vez que se tiene descrito mediante una especificación léxica qué lexemas son válidos y a qué tokens pertenecen, ya se podría implementar el analizador léxico.

Se ha visto anteriormente en entrega de los tokens que un analizador era básicamente una clase con un método nextToken que, cada vez que se le llamaba, devolvía el siguiente token (hasta devolver el token END).




 


class Lexico {
    ...

    Token nextToken() {} // Sólo devuelve un Token cada vez
}

Este método es el que ahora hay que implementar. Y, para ello, hay que establecer previamente qué tareas tiene que hacer.

Tareas de un Léxico

En cada llamada al método nextToken, un analizador léxico tiene que realizar las siguientes tareas (aunque con excepciones en algunos lenguajes de programación):

  1. Ignorar los comentarios. Es decir, el léxico no debe devolver un token COMENTARIO. La siguiente fase, el analizador sintáctico, no está interesado en dicho token e interferiría en el orden de los tokens que realmente espera.

  2. Ignorar los espacios en blanco y saltos de línea. Aunque hay lenguajes que sí utilizan el salto de línea como terminador de sentencias (y, por tanto, sí necesitarían dicho token), lo más común es que a los lenguajes no les afecte si el programa se ha hecho en una sola línea o separado en varias. De hecho, lo habitual es que el léxico filtre la entrada dando la ilusión a las demás fases de que todo el programa se ha escrito en una única línea y sin tabuladores entre los lexemas.

  3. Comprobar los patrones de la especificación. El léxico debe coge los caracteres de la entrada y mirar si cumplen algún patrón. Si se cumple alguno, devuelve el objeto Token correspondiente a la entrada.

  4. Notificar errores. Al igual que ocurría con el token COMENTARIO, devolver al sintáctico un token ERROR_LÉXICO no le aportaría nada al sintáctico. Si el léxico encuentra un error, es este el que debe dar toda la información sobre lo ocurrido en vez de traspasar el problema a otra fase. Es recomendable que cada fase se encargue de tratar sus errores.

Formas de Implementación

Una vez establecidas qué tareas tiene que realizar el método nextToken, queda ahora decidir el cómo se implementa. Para ello, hay dos alternativas.

Cada una de las dos alternativas tiene ventajas e inconvenientes:

  • La implementación manual es más tediosa, pero ofrece mayor control y eficiencia. Aunque hay varias maneras de implementar un analizador léxico de forma manual, las más comunes son la Tabla de estados y la implementación Estructurada.
  • La implementación mediante Herramienta permite una implementación mucho más rápida y cómoda y es suficientemente eficiente para la mayoría de las situaciones. Por contra, hay que aprender su notación adecuadamente. Las herramientas más comunes son flex, JFlexx y ANTLR.

Independientemente de cómo se implemente el analizador léxico (a mano o con herramienta), su comportamiento externo debe ser exactamente el mismo. El analizador sintáctico no debería necesitar saber de cuál de las formas se ha implementado el analizador léxico para poder usarlo.

En los siguientes capítulos se verán, con más o menos detalle en cada caso, algunas de las formas de implementación comentadas.