Construyendo un Tokenizador para un subconjunto de Python

 Introducción

El front-end de un compilador o intérprete es el Tokenizer también llamado Scanner o analizador léxico. La mayoría de los libros de compiladores muestran un procedimiento basado en la teoría de las ciencias computacionales (específicamente la teoría de autómatas finitos) para el diseño y la implementación de un scanner. Aunque de hecho implementar un Scanner a mano no es difícil como ya lo verás más adelante.

Interfaz del Scanner

La entrada de datos de un Scanner en un compilador o intérprete es el código fuente del programa a compilar o interpretar. El Scanner separa todo el código y durante el proceso va formando pequeñas unidades que mantienen una secuencia lógica, estas unidades se conocen como Tokens que más tarde serán pasados como entrada para el analizador sintáctico o Parser.

Un Tokenizer (Scanner) puede implementarse usando 2 enfoques:

  1. Analizar todo el código fuente y proveerle al Parser toda la lista de Tokens encontrados. En otras palabras, el Scanner termina su trabajo antes de que el Parser comience el suyo.
  2. Analizar el código fuente bajo demanda. En este enfoque es el Parser quien tiene el control ya que cada vez que necesite un Token del código fuente, llama a la función correspondiente en el Scanner.
¿Cuál de los dos enfoques es el mejor?

La acción especifica que un parser toma depende por supuesto de la secuencia de tokens que se le haya proporcionado, la mayoría de las veces esta acción es determinada por el token que está siendo analizado. Sin embargo existen otras veces donde el parser necesita conocer el siguiente token (Look Ahead) de la secuencia de tokens para determinar qué regla gramatical ejecutar. 

Este proceso de mirar hacia adelante en la secuencia de tokens es fácil si usamos el enfoque 1 ya que el parser tendría toda la lista de tokens en un tipo de dato y lo único que tendría que hacer es mirar dentro de esa lista. Mirar hacia adelante también es posible usando el enfoque 2 pero es más difícil de implementar ya que tendríamos que devolver los tokens consumidos al scanner.

Como el enfoque 1 es más fácil nos quedaremos con él en este artículo, el tiempo de ejecución para ambos enfoques es el mismo así que ninguno tendría ventaja sobre el otro en términos de rendimiento.

Cuando el Parser detecte un error en la secuencia de tokens que está analizando, debería generar un mensaje de error donde muestre la línea y la columna del token que está violando la sintaxis del lenguaje.














Comentarios