Clase 2 — El Analizador Léxico — Fundamentos y Componentes
Resumen Ejecutivo
La clase introduce el analizador léxico como primera fase del módulo de análisis de un compilador, explicando su función de leer el código fuente y transformar secuencias de caracteres (lexemas) en componentes léxicos (tokens) que consume el analizador sintáctico. Se establece la relación productor-consumidor entre el léxico y el sintáctico, donde este último actúa como director del proceso. Se repasan los conceptos de lexema, token, patrón, tabla de símbolos y el papel de las expresiones regulares/autómatas finitos en el reconocimiento léxico.
Conceptos Clave
- Analizador léxico: Módulo que lee el código fuente carácter a carácter, agrupa secuencias en lexemas y devuelve tokens al analizador sintáctico. Es el único módulo que lee directamente el código fuente. ⚠️ EXAMEN
- Lexema: Secuencia de caracteres del código fuente cuya estructura se corresponde con el patrón de un componente léxico. No confundir con el significado lingüístico general (raíz de una palabra). ⚠️ EXAMEN
- Token (componente léxico): Cualquier secuencia de caracteres con significado sintáctico propio. Es la unidad que el léxico pasa al sintáctico. ⚠️ EXAMEN
- Patrón: Regla (expresión regular) que describe la forma de los lexemas correspondientes a un token.
- Tabla de símbolos: Estructura compartida (recomendada como tabla hash) donde se almacenan los identificadores y su información asociada (tipo, ámbito, declaración...). ⚠️ EXAMEN
- Algoritmo ambicioso (greedy/maximal munch): El léxico siempre intenta reconocer el lexema más largo posible. ⚠️ EXAMEN
- Acción semántica: Código que se ejecuta cuando el autómata finito alcanza un estado final (p.ej., devolver el token al sintáctico, guardar en tabla de símbolos).
Desarrollo del Temario
1. Arquitectura del módulo de análisis
El compilador tiene tres fases de análisis: léxico → sintáctico → semántico. Aunque el diagrama sugiere un proceso secuencial, en la práctica el analizador sintáctico es el director: actúa como rutina principal y llama al léxico como subrutina cada vez que necesita el siguiente token. ⚠️ EXAMEN
Ejemplo (analogía lingüística): En el análisis sintáctico del español, la gramática dice "sujeto + verbo + predicado". Al sintáctico no le importa si el sujeto es "Ana" o "Pedro", solo que haya un nombre. De la misma forma, al sintáctico de un compilador no le importa si el identificador es
xonum, solo que sea un identificador.
2. Relación léxico-sintáctico (productor-consumidor)
El proceso real funciona así: 1. El sintáctico solicita un componente léxico. 2. El léxico lee del código fuente, compara con un patrón y determina el tipo de token. 3. Devuelve al sintáctico: el token + opcionalmente una referencia a la tabla de símbolos. 4. El sintáctico, al completar una frase, realiza su análisis y vuelve a solicitar tokens.
Ventajas de esta separación: ⚠️ EXAMEN - El sintáctico es independiente del alfabeto del lenguaje; solo trabaja con tipos de palabras. - Mayor eficiencia: el léxico maneja palabras, el sintáctico maneja frases. - Se comunican mediante buffer, llamada a subrutina o retorno.
3. Lexemas, tokens y patrones — La transformación léxica
Dado el código: if x < 10 then x := x + y
Los lexemas reconocidos son: if, x, <, 10, then, x, :=, x, +, y
| Lexema | Token (componente léxico) | Info adicional |
|---|---|---|
if |
Palabra reservada IF | — |
x |
Identificador | Ref. tabla símbolos |
< |
Operador menor | — |
10 |
Literal entero | Valor: 10 |
then |
Palabra reservada THEN | — |
:= |
Operador asignación | — |
+ |
Operador suma | — |
y |
Identificador | Ref. tabla símbolos |
Relación lexema-token: ⚠️ EXAMEN
- Palabras reservadas: relación 1 a 1 (private → token PRIVATE, class → token CLASS).
- Identificadores: relación muchos a 1 (x, y, num, valor... → todos son token IDENTIFICADOR).
- Cada lexema tiene un único componente léxico, pero un componente léxico puede tener muchos lexemas.
4. Tipos de componentes léxicos
En la mayoría de lenguajes se consideran tokens: ⚠️ EXAMEN
- Palabras reservadas (if, then, class, private, new...)
- Operadores: aritméticos (+), comparación (<), asignación (:=), lógicos
- Identificadores (nombres de variables, funciones...)
- Literales/constantes (enteros: 10, reales: 3.14, cadenas: "hola")
- Signos de puntuación (;, (, ), {, })
- Marcas de bloque (si el lenguaje las tiene)
Los blancos, tabuladores y comentarios NO son tokens: solo sirven para delimitar palabras y se descartan. ⚠️ EXAMEN
Ejemplo (cadenas de caracteres): Los blancos dentro de comillas (
"hola mundo") no se eliminan porque forman parte del valor del literal, no son separadores de palabras.
5. Palabras reservadas vs. identificadores
Las palabras reservadas (private, new, class) no pueden usarse como identificadores — están reservadas para posiciones específicas en la gramática.
Decisión de diseño sobre cómo manejar palabras reservadas: ⚠️ EXAMEN - Opción A: Un token específico por cada palabra reservada (TOKEN_IF, TOKEN_THEN...) → más eficiente en ejecución. - Opción B: Un token genérico "PALABRA_RESERVADA" + búsqueda en tabla → gramática más simple pero menos eficiente.
6. Tabla de símbolos
- Se recomienda implementarla como tabla hash (indexación por cadenas, búsqueda e inserción rápidas). ⚠️ EXAMEN
- Almacena los identificadores con información que se va enriqueciendo: tipo, si está declarado, ámbito, etc.
- Los literales como
10no necesitan tanta información asociada (basta con saber tipo y valor), por lo que no siempre se guardan en la tabla. - Es una estructura compartida entre las fases de análisis.
Ejemplo: Cuando el léxico reconoce
x, la guarda en la posición 32 de la tabla de símbolos y devuelve al sintáctico:(IDENTIFICADOR, 32). El sintáctico sabe que hay un identificador y, cuando lo necesite, puede consultar la posición 32 para obtener más información.
7. El algoritmo ambicioso (Maximal Munch)
El léxico siempre intenta leer el lexema más largo posible antes de devolver un token. ⚠️ EXAMEN
Ejemplo: Si existe la palabra reservada
privatey alguien escribe el identificadorprivates, el léxico no se detiene al leerprivate. Sigue leyendo hasta encontrar el delimitador (blanco) y reconoceprivatescomo identificador, no como palabra reservada.
8. Funciones secundarias del analizador léxico
- Eliminar comentarios y espacios en blanco (blancos, tabuladores, saltos de línea).
- Detectar errores léxicos/morfológicos: símbolos no permitidos, identificadores que exceden longitud máxima (típicamente 256 caracteres).
- Mantener la posición actual (línea y carácter) en el archivo fuente → imprescindible para reportar errores con ubicación precisa.
Ejemplo (Python vs Java): En Python, el salto de línea actúa como delimitador de sentencias (no se usa
;), y la indentación delimita bloques. En Java se puede escribir todo en una línea si se respetan los;. Son decisiones de diseño del lenguaje con consecuencias directas en el léxico.
9. Formalización: gramáticas regulares y autómatas finitos
- Los patrones léxicos se formalizan como expresiones regulares. ⚠️ EXAMEN
- Las expresiones regulares definen una gramática regular.
- La gramática regular es reconocida por un autómata finito determinista (AFD).
- Herramientas como JFlex construyen automáticamente el autómata a partir de las expresiones regulares.
| Nivel de análisis | Formalismo | Reconocedor |
|---|---|---|
| Léxico | Expresiones regulares / Gramática regular | Autómata finito (determinista) |
| Sintáctico | Gramática independiente del contexto | Autómata con pila (pushdown) |
Ejemplo de expresión regular para identificador básico (Pascal): \(\text{letra} \cdot (\text{letra} \mid \text{dígito})^*\) En Java se amplía a: \((\text{letra} \mid \$ \mid \_) \cdot (\text{letra} \mid \text{dígito} \mid \$ \mid \_)^*\)
Preguntas de Autoevaluación
-
¿Cuál es la diferencia entre un lexema y un token? Pon un ejemplo donde un mismo token tenga múltiples lexemas asociados.
-
¿Por qué se dice que el analizador sintáctico es el "director" del proceso de análisis? ¿Cómo interactúa con el léxico?
-
¿Qué información pasa el analizador léxico al sintáctico cuando reconoce: (a) una palabra reservada, (b) un identificador, (c) un literal entero, (d) un operador?
-
¿Por qué los blancos y comentarios no se consideran tokens? ¿Existe alguna excepción donde un carácter "blanco" sí tenga relevancia sintáctica?
-
Explica el algoritmo ambicioso (maximal munch). ¿Qué problema resuelve? Pon un ejemplo donde no aplicarlo generaría un error.
-
¿Qué tipo de formalismo se usa para describir los patrones léxicos y qué tipo de autómata los reconoce? ¿En qué se diferencia del formalismo usado para la sintaxis?
-
¿Cuál es la función de la tabla de símbolos en el análisis léxico? ¿Por qué se recomienda implementarla como tabla hash?
-
¿Qué ventaja tiene crear un token específico para cada palabra reservada frente a usar un token genérico "PALABRA_RESERVADA" con tabla de búsqueda?
-
Escribe la expresión regular para un identificador en un lenguaje que permita letras, dígitos, guion bajo y dólar, pero que deba comenzar por letra o guion bajo.
-
¿Qué funciones secundarias realiza el analizador léxico además de reconocer tokens?
Guía generada automáticamente a partir de transcripción con faster-whisper + Claude Opus.