Está en la página 1de 27

ANALIZADOR LÉXICO

UNIDAD IV
Función del Analizador Léxico
Leer los caracteres de entrada y elaborar como salida una secuencia de componentes léxicos que utiliza el
analizador sintáctico para hacer el análisis.
El analizador léxico es la primera fase de un compilador.
Su principal función consiste en leer los caracteres de entrada y elaborar como salida una secuencia de
componentes léxicos que utiliza el analizador sintáctico para hacer el análisis. Esta interacción, suele aplicarse
convirtiendo al analizador léxico en una subrutina o corrutina del analizador sintáctico. Recibida la orden
"obtén el siguiente componente léxico" del analizador sintáctico, el analizador léxico lee los caracteres de
entrada hasta que pueda identificar el siguiente componente léxico.
Funciones secundarias.
Como el analizador léxico es .la parte del compilador que lee el texto fuente. También puede realizar ciertas
funciones secundarias en la interfaz del usuario, como eliminar del programa fuente comentarios y espacios en
blanco en forma de caracteres de espacio en blanco, caracteres TAB y de línea nueva. Otra función es
relacionar os mensajes de error del compilador con el programa fuente. Por ejemplo, el analizador léxico
puede tener localizado el número de caracteres de nueva línea detectados, de modo que se pueda asociar un
número de línea con un mensaje de error.
En algunos compiladores, el analizador léxico se encarga de hacer una copia del programa fuente en el que
están marcados los mensajes de error. Si el lenguaje fuente es la base de algunas funciones de pre
procesamiento de macros, entonces esas funciones del preprocesador también se pueden aplicar al hacer el
análisis léxico.
Componentes Léxicos, Patrones y Lexemas

• Un token es un par que consiste en un nombre de token y un valor de atributo opcional. El nombre del
token es un símbolo abstracto que representa un tipo de unidad léxica; por ejemplo, una palabra clave
específica o una secuencia de caracteres de entrada que denotan un identificador. Los nombres de los
tokens son los símbolos de entrada que procesa el analizador sin táctico. A partir de este momento, en
general escribiremos el nombre de un token en negrita. Con frecuencia nos referiremos a un token por
su nombre.

• Un patrón es una descripción de la forma que pueden tomar los lexemas de un token. En el caso de una
palabra clave como token, e l patrón es sólo la secuencia de caracteres que forman la palabra clave.
Para los identificadores y algunos otros tokens, el patrón es una estructura más compleja que se
relaciona mediante muchas cadenas.
• Un lexema es una secuencia de caracteres en el programa fuente, que coinciden con el patrón para un
token y que el analizador léxico identifica como una instancia de ese token.
Atributos de los Componentes Léxicos
El analizador léxico recoge información sobre los componentes léxicos en sus atributos asociados. Los
componentes léxicos influyen en las decisiones del análisis sintáctico y los atributos en la traducción de los
componentes léxicos:
En la práctica, los componentes léxicos suelen tener un solo atributo -un apuntador a la entrada de la tabla de
símbolos donde se guarda la información sobre el componente léxico; el apuntador se convierte en el atributo
del componente léxico. A efectos de diagnóstico, puede considerarse tanto el lexema para un identificador como
el número de línea en el que éste se encontró por primera vez. Estos dos elementos de información se pueden
almacenar en la entrada de la tabla de símbolos para el identificador.
Ejemplo 3.1. Los componentes léxicos y los valores de atributos asociados para la proposición de FORTRAN.
E = M * e ** 2
Se escriben a continuación como una secuencia de parejas:
< id, apuntador a la entrada de la tabla de símbolos para E>
< op_asign. >
< id, apuntador a la entrada de la tabla de símbolos para M>
< op-mult,>
< id. apuntador a la entrada de la tabla de si m bolos para e>
< op_exp, >
< núm. valor entero 2 >
Obsérvese que en ciertas parejas no se necesita un valor de atributo: el primer componente es suficiente para
identificar el lexema. En este pequeño ejemplo, se ha dado al componente léxico núm un atributo de valor entero.
El compilador puede almacenar la cadena de caracteres que forma un número en una tabla de símbolos y dejar
que el atributo del componente léxico núm sea un apuntador a la entrada de la tabla.
Especificación de los Componentes Léxicos
Las expresiones regulares son una notación importante para especificar patrones. Cada patrón concuerda con
una serie de cadenas, de modo que las expresiones regulares servirán como nombres para conjuntos de
cadenas.
Cadenas y lenguajes
El término alfabeto o clase de carácter denota cualquier conjunto finito de símbolos. Ejemplos típicos de
símbolos son las letras y los caracteres. El conjunto {0 , 1} es el alfabeto binario. Los códigos ASSCII y EBCDIC
son dos ejemplos de alfabetos de computador.
Una cadena sobre algún alfabeto es una secuencia finita de símbolos tomados de ese alfabeto. En teoría del
lenguaje, los términos frase y palabra a menudo se utilizan como sinónimos del término "cadena". La longitud
de una cadena s, que suele escribirse lsl, es el número de apariciones de símbolos en s. Por ejemplo, camino es
una cadena de longitud seis. La cadena vacía, representada por Є, es una cadena especial de longitud cero.
El término lenguaje se refiere a cualquier conjunto de cadenas de un alfabeto fijo. Esta definición es muy
amplia, y abarca lenguajes abstractos como Ǿ, el conjunto vacío, o {Є} y el conjunto que sólo contiene la
cadena vacía, así como al conjunto de todos los programas de Pascal sintácticamente bien formados y el
conjunto de todas las oraciones en inglés gramaticalmente correctas, aunque los dos últimos conjuntos son mucho
más difíciles de especificar.

Hay varias operaciones importantes que se pueden aplicar a los lenguajes. Para el análisis léxico, interesan
principalmente la unión, la concatenación y la cerradura.
Expresiones Regulares
En Pascal, un identificador es una letra seguida de cero o más letras o dígitos; es decir, un identificador es
un miembro del conjunto de todas las cadenas de letras y dígitos que comienzan con una letra.
Con esta notación, se pueden definir los identificadores de Pascal como
letra ( letra | dígito ) *
La barra vertical aquí significa "o", los paréntesis se usan para agrupar sub-expresiones, el asterisco
significa "cero o más casos de" la expresión entre paréntesis, y la yuxtaposición de letra con el resto de la
expresión significa concatenación.
Una expresión regular se construye a partir de expresiones regulares más simples utilizando un conjunto de
reglas definitorias. Cada expresión regular r representa un lenguaje L(r). Las reglas de definición
especifican cómo se forma L(r) combinando de varias maneras los lenguajes representados por las
subexpresiones de r.
Las siguientes son las reglas que definen las expresiones regulares del alfabeto ∑. Asociada a cada regla
hay una especificación del lenguaje representado por la expresión regular que se está definiendo.
Є es una expresión regular designada por {Є}; es decir, el conjunto que contiene la cadena vacía.
Si a es un símbolo de ∑, entonces a es una expresión regular designada por {a}; por ejemplo, el conjunto
que contiene la cadena a. Aunque se usa la misma notación para las tres, técnicamente, la expresión
regular a es distinta de la cadena a o del símbolo a. El contexto aclarará si se habla de a como expresión
regular, cadena o símbolo.
Suponiendo que r y s sean expresiones regulares representadas por los lenguajes L(r) y L(s), entonces,
(r) 1 (s) es una expresión regular representada por L(r) U L(s).
(r)(s) es una expresión regular representada por L(r)L(s).
(r)* es una expresión regular representada por (L(r))*.
(r) es una expresión regular representada por L(r)2.
Se dice que un lenguaje designado por una expresión regular es un conjunto regular. La especificación de
una expresión regular es un ejemplo de definición recursiva. Las reglas 1 y 2 son la base de la definición;
se usa el término símbolo básico para referirse a Є o a un símbolo de ∑ que aparezcan en una expresión
regular. La regla 3 proporciona el paso inductivo.
Se pueden evitar los paréntesis innecesarios en las expresiones regulares si se adoptan las convenciones:
El operador unario * tiene la mayor precedencia y es asociativo por la izquierda,
La concatenación tiene la segunda mayor precedencia y es asociativa por la izquierda,
| tiene la menor precedencia y es asociativo por la izquierda.
Según estas convenciones, (a)| ((b)*(c)) es equivalente a a|b*c. Estas dos expresiones designan el conjunto
de cadenas que tienen una sola a, o cero o más b seguidas de una c.
Definiciones Regulares
Por conveniencia de notación, puede ser deseable dar nombres a las expresiones regulares y definir
expresiones regulares utilizando dichos nombres como si fueran símbolos. Si ∑ es un alfabeto de
símbolos básicos, entonces una definición regular es una secuencia de definiciones de la forma
d1->r1
d2->r2

dn->rn
donde cada d1 es un nombre distinto, y cada r1 es una expresión regular sobre los símbolos de∑ U {d1,
d2, … , d1_1}, por ejemplo, los símbolos básicos y los nombres previamente definidos. Al limitar cada r1
a los símbolos de ∑ y a los nombres previamente definidos, se puede construir una expresión regular en
∑ para cualquier r1, reemplazando una y otra vez los nombres de las expresiones regulares por las
expresiones que designan. Si r1 utilizara d¡ para alguna j≥ i, entonces ri se podría definir recursivamente
y este proceso de sustitución no tendría fin.
Para distinguir los nombres de los símbolos, se imprimen en negritas los nombres de las definiciones
regulares.
Reconocimiento de los Componentes Léxicos
En esta sección, se estudia el reconocimiento de los componentes léxicos y se utiliza como ejemplo el lenguaje
generado por la siguiente gramática.
prop -> if expr then prop
| if expr then prop else prop

expr -> término oprel término
| término
término -> id
| núm
donde los terminales if, then, else, oprel, id y núm generan conjuntos de cadenas dados por las siguientes
definiciones regulares:
if -> if
then -> then
else -> else
oprel -> < | <= | = | <> | > | >=
id -> letra ( letra | digito )*
núm-> digito+( . dígito+)? (E( + | - )? dígito+ .. )?
donde letra y dígito se han definido anteriormente.
Para este fragmento de lenguaje, el analizador léxico reconocerá las palabras clave if, then, else, al igual
que los lexemas representados por oprel, id y núm. Para simplificar las cosas, se supone que las palabras
clave son reservadas; es decir, no se pueden usar como identificadores, núm representa los números enteros y
reales sin signo de Pascal.
Además, se supone que los lexemas están separados por espacio en blanco, formados por secuencias no
nulas de espacios en blanco, caracteres TAB y caracteres de nueva línea. El analizador léxico eliminará los
espacios en blanco. Esto lo hará comparando una cadena con la definición de la expresión regular eb
siguiente.
delim -> blanco | tab | lineanueva
eb -> delim+
Si se encuentra una concordancia para eb, el analizador léxico no devuelve un componente léxico al
analizador sintáctico, sino que se dispone a encontrar un componente léxico a continuación del espacio en
blanco y lo devuelve al analizador sintáctico.
El objetivo es construir un analizador léxico que aislé el lexema para el siguiente componente Léxico del
buffer de entrada y que produzca como salida un par formado por el componente léxico apropiado y el
valor de atributo, utilizando la tabla de traducción mostrada a continuación. Los valores de atributo para
los operadores relacionales están dados por las constantes simbólicas MEN, MEI, IGU, MAY, MAI.
Diagrama de Transiciones
Como paso intermedio en la construcción de un analizador léxico, primero se produce un diagrama de flujo
estilizado, llamado diagrama de transiciones. Los diagramas de transiciones representan las acciones que
tienen lugar cuando el analizador léxico es llamado por el analizador sintáctico para obtener el siguiente
componente léxico.
Se utiliza un diagrama de transición para localizar la información sobre los caracteres que se detectan a
medida que el apuntador delantero examina la entrada. Esto se hace cambiando de posición en el diagrama
según se leen los caracteres.
Las posiciones en un diagrama de transición se representan con un círculo y se llaman estados. Los estados se
conectan mediante flechas, llamadas aristas. Las aristas que salen del estado s tienen etiquetas que indican los
caracteres de entrada que pueden aparecer después de haber llegado el diagrama de transición al estado s.
La etiqueta otro se refiere a todo carácter que no haya sido indicado por ninguna de las otras aristas que
salen de s. Un estado se etiqueta como el estado de inicio; es en el estado inicial del diagrama de transición
donde reside el control cuando se empieza a reconocer un componente léxico. Ciertos estados pueden tener
acciones que se ejecutan cuando el flujo del control alcanza dicho estado. Al entrar en un estado se lee el
siguiente carácter de entrada. Si hay una arista del estado en curso de ejecución cuya etiqueta concuerde con
ese carácter de entrada, entonces se va al estado apuntado por la arista. De otro modo, se indica un fallo.
En la figura se muestra un diagrama de transiciones para los patrones >= y >. El diagrama de transiciones
funciona de la siguiente forma. Su estado de inicio es el estado 0. En el estado 0 se lee el siguiente
carácter de entrada. La arista etiquetada con >del estado O se debe seguir hasta el estado 6 si este
carácter de entrada es >. De otro modo, significa que no se habrá reconocido ni > ni >=.

Al llegar al estado 6 se lee el siguiente carácter de entrada. La arista etiquetada con = que sale del
estado 6 deberá seguirse hasta el estado 7 si este carácter de entrada es un =. De otro modo, la arista
etiquetada con otro indica que se deberá ir al estado 8. El circulo doble del estado 7 indica que éste es
un estado de aceptación, un estado en el cual se ha encontrado el componente léxico >=.
Obsérvese que el carácter > y otro carácter adicional se leen a medida que se sigue La secuencia de
aristas desde el estado inicial al estado de aceptación 8. Como el carácter adicional no es parte del
operador relacional >, se debe retroceder un carácter el apuntador delantero. Se usa un * para indicar
los estados en que se debe llevar a cabo este retroceso en la entrada.
En general, puede haber varios diagramas de transiciones, cada uno de los cuales especifique un grupo
de componentes léxicos. Si surge un fallo mientras se está siguiendo un diagrama de transiciones, se
debe retroceder el apuntador delantero hasta donde estaba en el estado inicial de dicho diagrama, y
activar el siguiente diagrama de transiciones. Dado que los apuntadores de inicio de lexema y los
delanteros marcaban la misma posición en el estado inicial del diagrama, se retrocede el apuntador
delantero hasta la posición que marca el apuntador al inicio de lexema. Si el fallo surge en todos los
diagramas de transiciones, es que se ha detectado un error léxico y se invoca una rutina de
recuperación de errores.
Autómatas Finitos
Un reconocedor de un lenguaje es un programa que toma como entrada una cadena x y responde "sí" si
x es una frase del programa, y "no", si no lo es. Se compila una expresión regular en un reconocedor
construyendo un diagrama de transiciones generalizado llamado autómata finito. Un autómata finito
puede ser determinista o no determinista, donde "no determinista" significa que en un estado se puede
dar el caso de tener más de una transición para el mismo símbolo de entrada.
Tanto los autómatas finitos deterministas como los no deterministas pueden reconocer con precisión a los
conjuntos regulares. Por tanto, ambos pueden reconocer con precisión lo que denotan las expresiones
regulares. Sin embargo, hay un conflicto entre espacio y tiempo; mientras que un autómata finito
determinista puede dar reconocedores más rápidos que uno no determinista, un autómata finito
determinista puede ser mucho mayor que un autómata no determinista equivalente. En la siguiente
sección, se introducen métodos para convertir expresiones regulares en ambas clases de autómatas
finitos. La conversión en un autómata no determinista es más directa, por lo que primero se estudia este
caso.
Autómatas Finitos Deterministas
Un autómata finito determinista (abreviado AFD) es un caso especial de un autómata finito no
determinista en el cual.
Ningún estado tiene una transición Є es decir, una transición con la entrada Є,
Para cada estado s y cada símbolo de entrada a, hay a lo sumo un arista etiquetada a que sale de s.
Un autómata finito tiene a lo sumo una transición desde cada estado con cualquier entrada. Si se esta
usando una tabla de transiciones para representar la función de transición de un AFD, entonces cada
entrada en la tabla de transiciones es solo un solo estado. Como consecuencia, es muy fácil determinar si un
autómata finito determinista acepta o no una cadena de entrada, puesto que hay a lo sumo un camino
desde el estado de inicio etiquetado con esa cadena. El siguiente algoritmo muestra como simular el
comportamiento de un AFD con una cadena de entrada.
ENTRADA: Una cadena de entrada x, que se termina con un carácter de fin de archivo eof. Un AFDD con el
estado inicial S0, que acepta estados F, y la función de transición mover.
SALIDA: Responde “sí” en caso de que D acepte a x “no” en caso contrario.
MÉTODO: Aplíquese el algoritmo siguiente a la cadena de entrada x. La función mueve: (s, c) da el estado
al cual hay una transición desde el estado S en un carácter de entrada c. La función sigtecar devuelve el
siguiente carácter de la cadena de entrada x.
S: =S0;
C: =sigtecar;
While c ≠ eof do
S: = mueve (s,c);
C: =sigtecar;
End:
If s esta en F then
Return “si”
Else return “no”;

Ejemplo. En la siguiente figura se ve al grafo de transiciones de un autómata finito determinista aceptar el


mismo lenguaje (a | b)*abb aceptado por el AFN de la figura
Con este AFD y la cadena de entrada ababb. el algoritmo sigue la secuencia de estados 0, 1, 2, 1, 2, 3
y devuelve "sí".
Herramientas para la Especificación de Analizadores Léxicos
Se han desarrollado algunas herramientas para construir analizadores léxicos a partir de notaciones de
propósito especial basadas en expresiones regulares. Ya se ha estudiado el uso de expresiones regulares
en la especificación de patrones de componentes léxicos. Antes de considerar los algoritmos para compilar
expresiones regulares en programas de concordancia de patrones, se da un ejemplo de una herramienta
que pueda ser utilizada por dicho algoritmo.
En esta sección se describe una herramienta concreta, llamada LEX, muy utilizada en la especificación de
analizadores léxicos para varios lenguajes. Esa herramienta se denomina compilador LEX, y la
especificación de su entrada, lenguaje LEX. El estudio de una herramienta existente permitirá mostrar cómo.,
utilizando expresiones regulares, se puede combinar la especificación de patrones con acciones, por
ejemplo, haciendo entradas en una tabla de símbolos, cuya ejecución se pueda pedir a un analizador
léxico. Se pueden utilizar las especificaciones tipo LEX aunque no se disponga de un compilador LEX.
Figura 1.Creación de analizador léxico con LEX

Por lo general, se utiliza el LEX de la forma representada en la figura. Primero, se prepara una
especificación del analizador léxico creando un programa lex.l en lenguaje LEX. Después lex . l se pasa
por el compilador LEX para producir el programa en C lex.yy.c. El programa lex.yy.c consta de una
representación tabular de un diagrama de transiciones construido a partir de las expresiones regulares
de lex.l. junto con una rutina estándar que utiliza la tabla para reconocer lexemas. Las acciones
asociadas a las expresiones regulares de lex son partes de código en C y se transfieren directamente a
lex.yy.c. Por último, lex.yy.e se ejecuta en el compilador de C para producir un programa objeto a. out.
Que es el analizador léxico que transforma un archivo de entrada en una secuencia de componentes
léxicos.
Especificaciones en LEX
Un programa en LEX consta de tres partes:
Declaraciones
%%
Reglas de traducción
%%
Funciones auxiliares
La sección de declaraciones incluye declaraciones de variables, constantes manifiestas y
definiciones regulares. (Una constante manifiesta es un identificador que se declara para
representar una constante)
Las definiciones regulares se utilizan como componentes de las expresiones regulares que
aparecen en las reglas de traducción.
Las reglas de traducción de un programa en LEX son proposiciones de la forma
P1 {acción1}
P2 {acción2}
… …
Pn {acciónn}
Donde pi es una expresión regular y cada acción es un fragmento de programa que describe cuál ha de
ser la acción del analizador léxico cuando el patrón p1 concuerda con un lexema. En LEX, las acciones se
escriben en C, en general, sin embargo, pueden estar en cualquier lenguaje de implantación.
La tercera sección contiene todos los procedimientos auxiliares que puedan necesitar las acciones. A veces,
estos procedimientos se pueden compilar por separado y cargar con el analizador léxico.
Un analizador léxico creado por LEX se comporta en sincronía con un analizador sintáctico como sigue.
Cuando es activado por el analizador sintáctico, el analizador léxico comienza a leer su entrada restante,
un carácter a La vez, hasta que encuentre el mayor prefijo de la entrada que concuerde con una de las
expresiones regulares p1. Entonces, ejecuta la acción1, Generalmente, acción1 devolverá el control al
analizador sintáctico. Sin embargo, si no lo hace, el analizador léxico se dispone a encontrar más lexemas,
basta que una acción hace que el control regrese al analizador sintáctico. La búsqueda repetida de
lexemas hasta encontrar una instrucción return explícita permite al analizador léxico procesar espacios en
blanco y comentarios de manera apropiada.
El analizador léxico devuelve una única cantidad, el componente léxico, al analizador sintáctico. Para
pasar un valor de atributo con la información del lexema, se puede asignar una variable global llamada
yylval.
Los analizadores léxicos, para ciertas construcciones de lenguajes de programación, necesitan ver
adelantadamente más allá del final de un lexema antes de que puedan determinar un token con
certeza. En Lex, se puede escribir un patrón de la forma r1/r2, donde r1 y r2 son expresiones regulares,
que significa que una cadena se corresponde con r1, pero sólo si está seguida por una cadena que se
corresponde con r2. La expresión regular r2, después del operador lookahead "/", indica el contexto
derecho para una correspondencia; se usa únicamente para restringir una correspondencia, no para ser
parte de la correspondencia.
Recuperación de errores lexicográficos: Los programas pueden contener diversos tipos de errores, que
pueden ser:
• Errores lexicográficos: Que veremos a continuación.
• Errores sintácticos: Por ejemplo, una expresión aritmética con mayor numero de paréntesis de
apertura que de cierre.
• Errores semánticos: Por ejemplo, la aplicación de un operador a un tipo de datos incompatible
con el mismo.
• Errores lógicos: Por ejemplo, un bucle sin final.
Cuando se detecta un error, un compilador puede detenerse en ese punto e informar al usuario, o bien
desechar una serie de caracteres del texto fuente y continuar con el análisis, dando al final una lista
completa de todos los errores detectados. En ciertas ocasiones es incluso posible que el compilador corrija
el error, haciendo una interpretación coherente de los caracteres leídos. En estos casos, el compilador emite
una advertencia, indicando la suposición que ha tomado, y continúa el proceso sin afectar a las sucesivas
fases de compilación.
Los errores lexicográficos se producen cuando el analizador no es capaz de generar un token tras leer una
determinada secuencia de caracteres. En general, puede decirse que los errores lexicográficos son a los
lenguajes de programación lo que las faltas de ortografía a los lenguajes naturales. Las siguientes
situaciones producen con frecuencia la aparición de errores lexicográficos:

1. Lectura de un carácter que no pertenece al vocabulario terminal previsto para el autómata. Lo


más normal en este caso es que el autómata ignore estos caracteres extraños y continué el proceso
normalmente. Por ejemplo, pueden dar error en la fase de análisis lexicográfico la inclusión de caracteres
de control de la impresora en el programa fuente para facilitar su listado.
2. Omisión de un carácter. Por ejemplo, si se ha escrito ELS en lugar de ELSE.
3. Se ha introducido un nuevo carácter. Por ejemplo, si escribimos ELSSE en lugar de ELSE.
4. Han sido permutados dos caracteres en el token analizado. Por ejemplo, si escribiéramos ESLE en
lugar de ELSE.
5. Un carácter ha sido cambiado. Por ejemplo, si se escribiera ELZE en vez de ELSE.
Las técnicas de recuperación de errores lexicográficos se basan, en general, en la obtención de los
distintos sinónimos de una determinada cadena que hemos detectado como errónea. Por otra parte, el
analizador sintáctico es capaz en muchos casos de avisar al analizador lexicográfico de cuál es el
token que espera que éste lea.
Para el ejemplo de borrado de un carácter, tenemos que los sinónimos de ELSE son ELS, ELE, ESE, y LSE.
Por tanto, si incluimos en nuestro analizador una rutina de recuperación de errores debidos a omisión
de caracteres, cualquiera de estos sinónimos sería aceptado en lugar del lexema ELSE, se emitiría la
correspondiente advertencia, y el proceso continuaría asumiendo que se ha leído el token
<pal_res_ELSE>.
Análogamente, podemos incluir rutinas para los demás casos. Por ejemplo, si el analizador lee el
lexema ESLE, y no puede construir un token correcto para él mismo, procedería a generar los sinónimos
por intercambio de caracteres (es decir, SELE, ELSE o ESEL) y comprobaría si alguno de ellos es
reconocible. En caso afirmativo, genera el token correspondiente y advierte al usuario del posible
error y de su interpretación automática, continuando con el proceso.
Todos los procedimientos para la recuperación de errores lexicográficos son en la práctica métodos
específicos, y muy dependientes del lenguaje que se pretende compilar.
Material Complementario

Análisis Léxico
https://www.youtube.com/watch?v=pPrBE_czrVc
https://www.youtube.com/watch?v=idnS9MTwfOU
Autómatas
https://www.youtube.com/watch?v=pfJSqvQFOxI
Autómata Finito Determinista
https://www.youtube.com/watch?v=pk17OhAoAOM
https://www.youtube.com/watch?v=P0AxQvJcN2Q