Está en la página 1de 68

UNIVERSIDAD CRISTIANA EVANGELICA NUEVO MILENIO

(UCENM)

FACULTAD:

INGENERIA EN SISTEMA

ASIGNATURA:

COMPILADORES E INTERPRETES

CATEDRÁTICO:
ING. JOKSAN DAVID AMAYA MARTINEZ

INFORME:
PROYECTO FINAL: ANALIZADOR LEXICO

SEDE:
LA ESPERANZA, INTIBUCA

FECHA:
22/07/2022
COMPILADORES E INTERPRETES

INTEGRANTES

Estrella Carolina Arita Matute

Luis Alonso Garcia Meza

Melvin Fernando Gutierrez

Mario Natanael Mazariego

Ruth Yamileth Perez Mendez

II
COMPILADORES E INTERPRETES

INDICE DEL CONTENIDO

INTRODUCCION........................................................................................IV

1 CAPÍTULO I. OBJETIVOS Y METODOLOGÍA.....................................1

1.1 OBJETIVOS...................................................................................1
1.1.1 GENERALES...........................................................................1
1.1.2 ESPECÍFICOS.........................................................................1
1.2 METODOLOGÍA.............................................................................2
1.2.1 FUENTES PRIMARIAS............................................................2
1.2.2 FUENTES SECUNDARIAS.....................................................3
1.2.3 CONSULTAS PROFESIONALES............................................3
1.3 MARCO REFERENCIAL................................................................4
1.3.1 FUNDAMENTOS TEÓRICOS..................................................4
1.3.2 DIAGRAMAS Y/O PROCESOS.............................................18
1.3.3 CONTENIDO..........................................................................19
1.3.4 ALCANCE..............................................................................34
1.3.5 IMPORTANCIA......................................................................35
2 CAPITULO II. SISTEMATIZACIÓN.....................................................36

2.1 PLAN DE EJECUCIÓN “CAPTURAS”.......................................36


2.2 RESULTADOS.............................................................................44
2.3 DESCRIPCIÓN DE LAS ACTIVIDADES.....................................46
2.4 CRONOGRAMA DE ACTIVIDADES (DIAGRAMA DE GANTT) 49
3 CAPITULO II........................................................................................50

3.1 CONCLUSIONES.........................................................................50
3.2 RECOMENDACIONES................................................................50
3.3 APÉNDICE...................................................................................51
3.4 GLOSARIO...................................................................................55
3.5 BIBLIOGRAFÍA............................................................................58
3.6 ANEXOS.......................................................................................59

III
COMPILADORES E INTERPRETES

INTRODUCCION

El desarrollo del presente proyecto tiene una particular importancia por


conjugar diferentes áreas del conocimiento, haciendo énfasis en el
“Análisis léxico”. Un analizador léxico es un programa, el cual cumple
diferentes funciones específicamente, reconocer un lenguaje, con sus
caracteres de entrada, donde se encuentra la cadena a analizar,
reconocer sub cadenas que correspondan a símbolos del lenguaje y
retornarlos tokens correspondientes y sus atributos. Pero escribir
analizadores léxicos eficientes “amano” puede resultar una tarea tediosa y
complicada, y para evitarla se han creado herramientas de software – los
generadores de analizadores léxicos – que generan automáticamente un
analizador léxico a partir de una especificación provista por el usuario,
pero también se puede realizar mediante programación desde un
determinado lenguaje, como, en este caso, emplearemos el lenguaje C#
2019.

En el presente trabajo abordaremos sobre la construcción de un programa


para realizar el análisis léxico, para ello empezaremos por definir el
lenguaje, sus componentes del lenguaje y sus reglas de sintaxis, además
del programa, sus funciones y su interfaz gráfica. Este analizador léxico
lee caracteres del archivo de entrada, donde se encuentra la cadena a
analizar, reconoce lexemas y retorna tokens.

Este trabajo tiene el objetivo de dar a conocer la lógica y funcionamiento


de un analizador léxico, además de permitir a nosotros, como alumnos,
entender mejor este tema, y de este modo adquirir la idea de la
implementación de un programa que ayude en su solución; y dejarlo listo
para la siguiente fase de la compilación denominada: Análisis Sintáctico.

IV
COMPILADORES E INTERPRETES

1 CAPÍTULO I. OBJETIVOS Y METODOLOGÍA

1.1 OBJETIVOS

1.1.1 GENERALES

Desarrollar un analizador léxico.

1.1.2 ESPECÍFICOS

Definir que es un analizador léxico.

Comprender el funcionamiento y la importancia de un analizador léxico


en el proceso de compilación de código.

Explicar conceptos básicos necesarios para comprender mejor el


trabajo de un analizador léxico (tokens, lexemas, patrones, lenguaje,
tabla de símbolos entre otros.).

Explorar con más detalle el tema desarrollado en clase “analizador


léxico”.

Practicar los conocimientos y habilidades obtenidas en las clases


enfocadas a programación.

1
COMPILADORES E INTERPRETES

1.2 METODOLOGÍA

1.2.1 FUENTES PRIMARIAS

Son los medios de que se utilizaron para la recolección de información


para la realización del proyecto Analizador léxico, los instrumentos
principales fueron libros, documentos encontrados por Internet, archivos,
enciclopedias virtuales y otros. Teniendo estos instrumentos, que son
significativos para el desarrollo del tema, se investiga y analiza toda la
información encontrada y recopilada.

Jaume, U. (s.f.). repositori.uji.es. Obtenido de


http://repositori.uji.es/xmlui/bitstream/handle/10234/5877/lexico.apun.pdf
Lopez. (2015).
Madrid, L. U. (s.f.). cartagena99. Obtenido de
https://www.cartagena99.com/recursos/alumnos/apuntes/ININF2_M4_U2_T1.
pdf
Millan. (2014).
Oropeza, R. (2015). slideplayer.es. Obtenido de https://slideplayer.es/slide/3893271/
Urbaez, W. (26 de octubre de 2005). desarrolloweb.com. Obtenido de
https://desarrolloweb.com/articulos/2225.php#:~:text=Las%20estructuras
%20condicionales%20comparan%20una,una%20constante%2C%20seg
%C3%BAn%20se%20necesite
villalta, P. (2014). slideshare.ne. Obtenido de
https://es.slideshare.net/pavillalta/compiladores-analisis-lexico-conceptos
wikipedia.org. (2021). Obtenido de https://es.wikipedia.org/wiki/Analizador_sint
%C3%A1ctico

2
COMPILADORES E INTERPRETES

1.2.2 FUENTES SECUNDARIAS

Son los registros escritos que proceden también de un contacto con la


realidad, pero han sido recogidos y muchas veces procesados por sus
investigadores. Esta fuente de información es utilizada pues se denomina
documental y sus fuentes principales son: Internet, las bibliotecas,
librerías etc.

Agruta, E. (2022). slideshare.net. Obtenido de


https://es.slideshare.net/lizzylv/analizador-lexico-13595988
ccia.ugr. (s.f.). ccia.ugr.es. Obtenido de
https://ccia.ugr.es/~jfv/ed1/c/cdrom/cap2/cap26.htm#:~:text=Los
%20operadores%20son%20s%C3%ADmbolos%20que,que%20%C3%A9stas
%20devuelvan%20alg%C3%BAn%20valor
cidecame. (s.f.). Obtenido de
http://cidecame.uaeh.edu.mx/lcc/mapa/PROYECTO/libro32/index.html
ecured. (2020). ecured.cu. Obtenido de https://www.ecured.cu/Analizador_l
%C3%A9xico

1.2.3 CONSULTAS PROFESIONALES


No se encontraron consultas profesionales

3
COMPILADORES E INTERPRETES

1.3 MARCO REFERENCIAL

1.3.1 FUNDAMENTOS TEÓRICOS

1. ¿QUÉ ES UN EL ANALIZADOR LÉXICO?

El analizador léxico, también conocido como analizador morfológico o


scanner, es el elemento del compilador encargado de la división del
código fuente en un conjunto de unidades sintácticas con sentido lógico, a
las cuales llamaremos por su nombre en inglés: tokens (a los que también
nos referiremos como componentes léxicos). Así pues, esta parte del
análisis de un programa será el paso previo, el que aporte la información
necesaria para su posterior desarrollo, al análisis sintáctico. (Millan, 2014)

2. EL PAPEL DEL ANALIZADOR LÉXICO (SCANNER)

Se trata de la primera fase de un compilador. Su misión es leer los


caracteres de entrada y producir, como salida, una secuencia de tokens
que utilizará el parser (analizador sintáctico) para realizar el análisis
sintáctico.

En cuanto a la forma de interaccionar las fases léxica y sintáctica,


podemos apreciar dos posibles alternativas:

1) El analizador léxico opera a petición del analizador sintáctico, devol-


viendo un componente léxico según el analizador sintáctico lo va nece-
sitando, para avanzar en la gramática.

Así, cuando recibe la orden obtén el siguiente componente léxico, el


analizador léxico lee los caracteres de entrada hasta identificar

4
COMPILADORES E INTERPRETES

el siguiente componente léxico y lo devuelve al analizador


sintáctico.

2) La segunda opción es que la fase léxica haga un análisis de todos los


componentes léxicos del código fuente. Cuando esta haya finalizado,
el analizador léxico devolverá una estructura con todos los tokens (in-
dicando tipo de componente, posición dentro del código fuente...).

El analizador sintáctico empleará esta estructura con los distintos


componentes léxicos, para avanzar en su gramática libre de contexto.
(Lopez, 2015)

3. ALGUNAS FUNCIONES QUE REALIZA EL ANALIZADOR


LÉXICO
1. Eliminar los comentarios del programa.
2. Eliminar espacios en blanco, tabuladores, retorno de carro, etc. y en
general, todo aquello que carezca de significado según la sintaxis del
lenguaje.
3. Reconocer los identificadores de usuario, números, palabras reserva-
das del lenguaje..., y tratarlos correctamente con respecto a la tabla de
símbolos (solo en los casos que debe de tratar con la tabla de símbo-
los).
4. Llevar la cuenta del número de línea por la que va leyendo, por si se
produce algún error, dar información sobre donde se ha producido.
5. Avisar de errores léxicos. Por ejemplo, si @ no pertenece al lenguaje,
avisar de un error.
6. Puede hacer funciones de preprocesador. (Lopez, 2015)

5
COMPILADORES E INTERPRETES

4. ¿POR QUÉ SEPARAR EL ANÁLISIS LÉXICO DEL ANÁLI-


SIS SINTÁCTICO?

Existen varias razones para separar las fases del análisis léxico y el
sintáctico:

1. La separación nos permite simplificar cada parte. Por ejemplo, un


parser que maneje comentarios y espacios en blanco es mucho más difícil
de construir que otro en el que el analizador léxico los filtre. Si estamos
diseñando un lenguaje nuevo, la separación entre convenios sintácticos y
léxicos nos conducirá a un diseño más limpio.

2. Se mejora la eficiencia del compilador. Puesto que la tarea de leer el


lenguaje fuente y partirlo en tokens ocupa mucho tiempo, si se separa el
analizador léxico, podremos diseñarlo de forma sofisticada con técnicas
de manejo de buffers de entrada y de reconocimiento de patrones.

3. Aumenta la portabilidad del compilador. Las peculiaridades del alfabeto


de entrada y otras anomalías específicas de los teclados pueden quedar
restringidas al analizador léxico. (Millan, 2014)

5. TOKENS, 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

6
COMPILADORES E INTERPRETES

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. (cidecame, s.f.)

6. DESCRIPCIONES DECLARATIVAS DE LOS TOKENS;


EXPRESIONES REGULARES

Para describir los patrones que forman un token se suelen utilizar los
diagramas sintácticos (en caso de describirlos con lápiz y papel) y las
expresiones regulares (en el caso de usar una máquina de escribir).
Vamos a definir algunos de los términos utilizados en el análisis y en la
descripción de tokens.

Alfabeto o clase de caracteres: Conjunto finito de símbolos. Por


ejemplo, el conjunto {0, 1} es el alfabeto binario, mientras que los
conjuntos ASCII y EBCDIC son ejemplos de alfabetos de computadores.

Palabra (string o cadena) sobre un alfabeto: Secuencia finita de


símbolos del alfabeto. En teoría de lenguajes formales se suelen utilizar
los términos sentencia y palabra como sinónimos de string. La longitud de
un string S (se suele escribir | S |) es el número de símbolos que ocurren
en el string. Por ejemplo, la palabra “manzana” es una cadena de longitud
7. |manzana|= 7. (Millan, 2014)

La cadena vacía ε es un caso particular de cadena que no tiene ningún


símbolo.

Operaciones entre cadenas: Si x e y son dos palabras, llamamos


concatenación de x e y (y lo escribimos xy ) a la palabra formada al añadir
y al final de x. Por ejemplo si x = rompe e y = cabezas entonces xy =
rompecabezas. El string vacío funciona como elemento neutro de esta
operación:

xε=εx=x

7
COMPILADORES E INTERPRETES

Podemos considerar la concatenación como un producto y definir la


potenciación así:

 Definimos s0 como ε.
 Para i > 0 definimos si=s i−1 s . Es decir: s1=s , s2=ss , s3=sss , . . . etc.

Lenguaje: Cualquier conjunto de cadenas sobre un alfabeto dado. Esta


definición es muy amplia, e incluye lenguajes abstractos como ∅ (el
conjunto vacío), o el conjunto {ε} que es el conjunto cuyo único elemento
es la cadena vacía. También serían lenguajes el conjunto de todos los
programas en Pascal bien escritos, o el conjunto de todas las frases bien
formadas del español. Notar que esta definición no asigna ningún
significado a las palabras del lenguaje.

Operaciones sobre lenguajes Existen varias operaciones que se


pueden realizar sobre los lenguajes, para el análisis léxico nos interesan
la unión, concatenación y clausura. (Millan, 2014)

DEFINICIONES REGULARES

En Pascal un identificador está formado por una letra seguida de cero o


más letras o dígitos. Ahora mostraremos una notación llamada
expresiones regulares que nos permite definir lo anterior con precisión.
Utilizaremos la notación tal y como se utiliza en el programa LEX. En ella
un identificador de Pascal se describe así:

{letra} ({letra} | {dígito}) *

La barra vertical aquí significa "OR", los paréntesis se usan para agrupar
sub expresiones, el asterisco significa "cero o más casos de" la expresión
entre paréntesis. Las llaves las utilizaremos con dos significados
diferentes: para indicar el conjunto compuesto por los strings del interior, y
otras veces para indicar que lo que hay dentro no hay que tomarlo
textualmente. El significado que utilicemos estará claro por el contexto.
Así {letra} indica un carácter alfabético y no la palabra “letra”. La
yuxtaposición indica concatenación.

8
COMPILADORES E INTERPRETES

Según todo esto la expresión regular anterior puede leerse: Una letra
seguida de 0 o más instancias de letras o dígitos.

Cada 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 sub expresiones de r. Así definimos:

1. ε es una expresión regular para indicar el conjunto formado por la ca-


dena vacía, {ε}.
2. Si a fuese un símbolo del alfabeto, entonces a es una expresión regu-
lar para indicar el conjunto formado por la cadena “a”. Es decir {“a”}.
De esta manera utilizamos el mismo símbolo a con tres significados di-
ferentes: Un símbolo de un alfabeto (a), una expresión regular (a), y el
conjunto formado por la cadena “a”. Los tres tienen un significado di-
ferente y, en cada momento, quedará claro por el contexto a cuál nos
referimos.
3. Supongamos que r y s son dos expresiones regulares que denotan los
lenguajes L(r) y L(s). Entonces:

- (r) |(s) es una expresión regular para denotar L(r) ∪ L(s).

- (r)(s) es una expresión regular para denotar L(r)L(s).

- (r)* es una expresión regular que denota a (L(r)) *.

- (r) + es una expresión regular para denotar (L(r)) +.

- (r)? es una expresión para denotar {ε} ∪ L(r). Es decir, cero o 1


ocurrencias de L(r). (Millan, 2014)

- (r) es una expresión regular para indicar L(r). Es decir, podemos colocar
paréntesis extras alrededor de cualquier expresión regular que queramos.

A los lenguajes descritos por las expresiones regulares se les denomina


conjuntos regulares o lenguajes regulares. Las reglas anteriores son
un ejemplo de definición recursiva. Las reglas primera y segunda forman

9
COMPILADORES E INTERPRETES

la base de la definición (el caso base), mientras que las reglas del punto
tercero constituyen el paso recursivo.

Podemos evitar paréntesis innecesarios si adoptamos el convenio de que:

1. Los operadores unarios *, + y? tienen la máxima prioridad.

2. La concatenación es la segunda operación en prioridad y es asociativa


por la izquierda: ABC = (ab)c.

3. La operación | tiene la prioridad mínima y también es asociativa por la


izquierda: a | b | c = (a | b) |c.

Con estos convenios la expresión regular (a) | ((b) * (c)) es equivalente a


la expresión: a | b * c. Ambas expresiones indican el conjunto de los
strings formados por una única a o por cero o más b seguidas de una c.

DEFINICIONES REGULARES

A menudo, y por comodidad, deseamos dar nombres a ciertas


expresiones regulares para, posteriormente, poder utilizar dichos nombres
como si fuesen símbolos. (Millan, 2014)

Llamamos definición regular a una secuencia de definiciones de la


forma:

d 1 →r 1

d 2 →r 2

...

d n →r n

Donde cada d i representa un nombre diferente y cada r i una expresión


regular. En la expresión regular r i podrían aparecer los símbolos del
alfabeto y también los nombres d j, j<i definidos con anterioridad. Aquí no
se permiten definiciones recursivas. Cuando utilicemos los nombres los
encerraremos entre llaves {...} para distinguirlos de las cadenas formadas
por las letras que constituyen el nombre.

10
COMPILADORES E INTERPRETES

Por ejemplo, la siguiente Definición regular describe un flotante en Pascal.

dígito → 0|1|2|3|4|5|6|7|8|9

entero → {dígito}+ fracción "."{entero}

exponente → e("+"|"-")?{entero}

flotante → {entero}{fracción}?{exponente}?

Utilizamos las comillas "" para encerrar aquellos caracteres que pueden
tener un significado de meta carácter. Por ejemplo, “(+” podría ser
interpretado como 1 o más ocurrencias del paréntesis que abre. Si lo que
queremos es indicar el carácter “+” lo encerramos entre comillas así:
“("+"”. También utilizamos los paréntesis cuadrados y el guion para
abreviar una clase de caracteres. Por ejemplo 0|1|2|3|4|...|9 se puede
abreviar por [0-9]. Mientras que [a-z] representa la clase de todas las
letras minúsculas y constituye una abreviatura para a|b|c|...|z.

CONJUNTOS NO REGULARES

La mayoría de los lenguajes no pueden ser descritos por una Definición


regular. Por ejemplo, las expresiones regulares no pueden describir
construcciones balanceadas o anidadas. Así que no se puede describir
mediante ninguna expresión regular el conjunto de todos los paréntesis
balanceados, pero sí puede ser descrito mediante una gramática libre de
contexto. (Estas gramáticas las definiremos en el tema siguiente). (Millan,
2014)

Los strings que se repiten tampoco pueden ser descritos por ninguna
Definición regular. Así que el conjunto formado por:

{wcw ∨w es una cadena que se repite a los dos extremos de la letra c }

No puede ser descrito por ninguna Definición regular, pero tampoco


puede ser descrito por ninguna gramática libre de contexto.

7. AUTÓMATAS FINITOS

11
COMPILADORES E INTERPRETES

Un autómata finito (AF) o máquina de estado finito es un modelo


computacional que realiza cómputos en forma automática sobre una
entrada para producir una salida.

Este modelo está conformado por un alfabeto, un conjunto de estados y


un conjunto de transiciones entre dichos estados. Su funcionamiento se
basa en una función de transición, que recibe a partir de un estado inicial
una cadena de caracteres pertenecientes al alfabeto (la entrada), y que va
leyendo dicha cadena a medida que el autómata se desplaza de un
estado a otro, para finalmente detenerse en un estado final o de
aceptación, que representa la salida.

La finalidad de los autómatas finitos es la de reconocer lenguajes


regulares, que corresponden a los lenguajes formales más simples según
la Jerarquía de Chomsky. (Lopez, 2015)

autómata finito determinista [AFD]. Un autómata finito determinista, M,


es una quíntupla M = (Q, ∑, δ, q 0, F) donde:

1. Q es un conjunto finito de estados.


2. ∑ es un alfabeto de entrada.
3. δ: Q x → Q es la función de transición que determina, para cada par
formado por un estado y un símbolo de entrada, el estado siguiente al
que pasa el autómata.
4. q 0 es el estado inicial.
5. F ⊆ Q es el conjunto de estados finales o de aceptación.

Ejemplo: Dado el autómata M = (Q, ∑, δ, q 0, F) donde q = {q 0 ,q 1 ,q 2}, ∑=


{a, b}, F = {q 2} y la función de transición es.

Δ a b

q0 q1 q2

q1 q1 q2

12
COMPILADORES E INTERPRETES

q2 q1 q0

Podemos ver su representacion grafica de la siguiente forma

Autómata finito no determinista [AFN]. Un autómata finito no


determinista, M, es una quíntupla M = (Q, ∑, δ, q 0 F) donde:

1. Q es un conjunto finito de estados.


2. ∑ es un alfabeto de entrada.
3. δ: Q x ∑ → P(Q) es la función de transición que determina, para cada
par formado por un estado y un símbolo de entrada, el conjunto de es-
tados siguientes a los que puede pasar el autómata. (Millan, 2014)
4. q 0 es el estado inicial. (Lopez, 2015)
5. F ⊆ Q es el conjunto de estados finales o de aceptación.

Ejemplo: Dado el autómata M = (Q, ∑, δ, q 0, F), donde q = {q 0 ,q 1 ,q 2}, ∑ =


{a, b, c}, F = {q 2} y la función de transición es:

δ a b c

q0 q1 ε ε

q1 ε q1 q2

13
COMPILADORES E INTERPRETES

q2 ε ε ε

Podemos construir el siguiente diagrama de transición:

8. ATRIBUTOS DE LOS COMPONENTES LÉXICOS

Cuando existe más de un lexema que puede corresponderse con un


mismo patrón, entonces el analizador léxico debe suministrar, a las
siguientes fases del compilador, información adicional sobre el lexema
concreto que ha cuadrado con el patrón. Por ejemplo, ambas cadenas “0”
y “1” se corresponden con el patrón para CTENUM, pero es esencial para
el generador de código el conocer cuál ha sido exactamente el string
concreto que ha cuadrado. El analizador léxico almacena esta información
adicional en los atributos del token. (Millan, 2014)

Mientras que los tokens influyen en las decisiones del análisis sintáctico,
los atributos influyen en la traducción de los tokens. Por lo general, en la
práctica se suele utilizar un único atributo para todo token de tipo ID. Este
atributo consiste en la cadena con su nombre. Por razones de diagnóstico
podemos estar interesados en el lexema de un identificador y en el
número de línea en el que se ha visto por primera vez. En la tabla de
símbolos pueden almacenarse ambas informaciones.

Por ejemplo, a continuación, mostramos los tokens y sus atributos para la


sentencia de Pascal: “e: = m * c 2”.

Token atributo
ID Cadena con el nombre del identificador e
ASING —

14
COMPILADORES E INTERPRETES

ID Cadena con el nombre del identificador


m
OP_MULT —
ID Cadena con el nombre del identificador c
OP_POT —
CTNUM Valor entero 2

Se nota que, para algunos tokens, no hay necesidad de un valor de


atributo ya que el primer componente es suficiente para identificar al
lexema (solo hay uno que cuadre con el patrón). Al token CTENUM se le
ha asignado como atributo su valor numérico. También podría ocurrir que
el compilador almacenara la cadena que forma el número en la tabla de
símbolos y hacer que el atributo sea un puntero a su entrada en dicha
tabla de símbolos.

9. ERRORES LÉXICOS

En el nivel léxico se pueden detectar pocos errores ya que el analizador


léxico tiene una visión muy localista del programa. Por ejemplo, si la
primera vez que encontramos el string “f i” en un programa C es en la
siguiente sentencia: “f i (a == f (x)) ...” el analizador léxico no puede
determinar si fi constituye una equivocación a la hora de escribir la
palabra clave “i f” o si, por el contrario, se trata del identificador que
nombra a una función que aún no ha sido declarada. Puesto que “f i” es
un identificador válido, el analizador léxico debe devolver el token de un
identificador (ID) y dejar que sea otra fase del compilador la que maneje el
error. (Millan, 2014)

De todas maneras, suponga que llegamos a una situación en que el


analizador léxico es incapaz de proseguir porque ninguno de los tokens
cuadra con el principio de la entrada que queda por procesar. Entonces,
la estrategia más sencilla para recuperarse es la estrategia del pánico
(panic mode), por la que borramos todos los caracteres de la entrada

15
COMPILADORES E INTERPRETES

hasta que se detecta un token que esté bien formado. Esta estrategia
puede que, a veces, lleve a confundir al analizador sintáctico, pero, por
otra parte, hay grandes probabilidades de que sea la más adecuada en un
ordenador interactivo.

Existen otras posibles estrategias de recuperación de errores como son:

1. Borrar un carácter extraño.


2. Insertar un carácter que falta.
3. Reemplazar un carácter incorrecto por otro correcto.
4. Intercambiar el orden de dos caracteres que estén juntos.

Estas transformaciones intentan arreglar la entrada haciéndole una única


transformación, lo cual en la práctica puede dar buenos resultados.
Experimentalmente se han construido algunos compiladores que
intentaban arreglar la entrada haciéndole más de una única
transformación y buscando el menor número de transformaciones que
convierten a la entrada en un token válido, pero se trata de estrategias
demasiado costosas de implementar en la práctica. (Millan, 2014) (Lopez,
2015)

10. CARACTERÍSTICAS DE LAS RUTINAS DE I /O DE UN


ANALIZADOR LÉXICO

El analizador léxico es la única fase del compilador que accede al


programa fuente. Por lo tanto, hace falta:

1. Acceso a disco eficiente.

El analizador léxico es la única fase que lee, carácter a carácter, el


programa fuente; es posible que se invierta una parte considerable del
tiempo de compilación en esta fase a pesar de que las otras son
conceptualmente más complicadas. Por lo tanto, es importante tener en
cuenta la velocidad del análisis léxico. En particular es importante la
utilización de un buffer para la entrada.

16
COMPILADORES E INTERPRETES

2. Rutinas rápidas, con el mínimo posible de copia de la cadena de entra-


da.
3. Admitir varios caracteres para mirar por adelantado.
4. Permitir devolver varios caracteres.

El número de caracteres que deben leerse por adelantado antes de que


un analizador léxico pueda determinar que se ha detectado un lexema
para un cierto patrón, varía de un lenguaje fuente a otro. En algunos
casos basta con un único carácter por anticipado, así, por ejemplo, al ir
leyendo el string “123*25” carácter a carácter, al llegar al asterisco “*”
se puede anunciar que se ha detectado el entero “123”, pero en dicho
momento ya hemos leído un carácter de más que hay que devolver a la
entrada porque forma parte del token siguiente. En otros lenguajes y
circunstancias, el número de caracteres que hay que leer por anticipado
es indeterminado.

5. Lexemas de longitud razonable. Algunos lenguajes tienen una longitud


máxima para los identificadores, pero en otros o esta no existe o es
muy grande.
6. Estar accesible, tanto el lexema actual como el lexema anterior.

Existen tres formas tradicionales de implementar un analizador léxico:

1. Utilizar un generador de analizadores léxicos, como el generador


FLEX (o LEX). En este caso el generador provee automáticamente las
rutinas de lectura con manejo de un buffer.
2. Escribir el analizador en un lenguaje convencional de programación de
sistemas. Por ejemplo, en lenguaje C. Utilizando las facilidades de en-
trada y salida del lenguaje. La función usual de entrada del lenguaje C,
getchar (), al igual que la de C + + cin.get (), utiliza automáticamente
un buffer para la entrada.
3. Escribir el analizador léxico en lenguaje ensamblador, manejando ex-
plícitamente la lectura de la entrada.

17
COMPILADORES E INTERPRETES

Desafortunadamente cuanto más difícil de implementar más rápido suele


resultar el analizador resultante. (Millan, 2014)

1.3.2 DIAGRAMAS Y/O PROCESOS

Código fuente

Analizador léxico

Tokens

Analizador sintáctico

Árbol sintáctico
Tabla de
símbolos
Analizador semántico

Árbol con anotaciones

Gestión de
errores Generador de código intermedio

Código de intermedio

Optimizador

Código optimizado

Generador del código

(Madrid, s.f.) Código objetivo

Dame el siguiente
componente léxico

Programa Analizador Analizador 18


fuente
léxico Toma Sintáctico
componente
léxico
COMPILADORES E INTERPRETES

(ecured, 2020)

1.3.3 CONTENIDO

IMPLEMENTACIÓN DEL ANALIZADOR LÉXICO

Hasta ahora hemos visto como especificar los lenguajes asociados a las
diferentes categorías léxicas. Sin embargo, el analizador léxico no se
utiliza para comprobar si una cadena pertenece o no a un lenguaje. Lo
que debe hacer es dividir la entrada en una serie de componente léxicos,
realizando en cada uno de ellos determinadas acciones. Algunas de estas
acciones son: comprobar alguna restricción adicional (por ejemplo, que el
valor de un literal entero este dentro de un rango), preparar los atributos
del componente y emitir u omitir dicho componente. Así pues, la
especificación del analizador léxico debería incluir por cada categoría
léxica del lenguaje el conjunto de atributos y acciones asociadas. (Jaume,
s.f.)

Un ejemplo serıa:

Expresión
Categoría Acciones Atributos
Regular
Calcular valor
Comprobar
Entero [0–9] + Valor
rango
Emitir
Calcular valor
Comprobar
Real [0–9] +\.[0–9] + Valor
rango
Emitir
Identificador [a–zA–Z][a–zA–Z0–9] Copiar lexema Lexema

19
COMPILADORES E INTERPRETES

∗ emitir
Asignación := Emitir
Rango \.\. Emitir
Blanco [ \t\n] + Omitir

eof Emitir

LA ESTRATEGIA AVARICIOSA

Inicialmente puede parecer que podemos especificar completamente el


analizador dando una lista de expresiones regulares para las distintas
categorías. Sin embargo, debemos definir algo más: como esperamos
que se unan estas categorías para formar la entrada. Analicemos el
siguiente fragmento de un programa utilizando las categorías anteriores:

En principio, esperamos encontrar la siguiente secuencia de componentes


léxicos:

Sin embargo, no hemos definido ningún criterio por el que la secuencia no


pudiera ser esta:

Lo que se suele hacer es emplear la denominada “estrategia avariciosa”:


en cada momento se busca en la parte de la entrada no analizada el
prefijo más largo que pertenezca al lenguaje asociado a alguna categoría
léxica. De esta manera, la división de la entrada coincide con la que
esperamos. (Jaume, s.f.)

MAQUINA DISCRIMINADORA DETERMINISTA

20
COMPILADORES E INTERPRETES

Para reconocer simultáneamente las distintas categorías léxicas


utilizaremos un tipo de autómata muy similar a los AFDs: la maquina
discriminadora determinista (MDD). El funcionamiento.

De las MDDs es muy similar al de los AFDs, las diferencias son dos:
además de cadenas completas, aceptan prefijos de la entrada y tienen
asociadas acciones a los estados finales. Estudiaremos la construcción a
partir del ejemplo de especificación anterior. Empezamos por añadir a
cada expresión regular un símbolo especial: (Jaume, s.f.)

Categoría Expresión regular


Entero [0–9] +#entero

21
COMPILADORES E INTERPRETES

Real [0–9] +\.[0–9] +#real


Identificador [a–zA–Z][a–zA–Z0–9] ∗#ident
Asignación :=#asig
Rango \.\.#rango
Blanco [ \t\n] +#blanco

eof

Después unimos todas las expresiones en una sola:

Ahora construimos el AFD asociado a esta expresión regular. Este AFD lo


puedes ver en la figura 1.

Por construcción, los únicos arcos que pueden llegar a un estado final
serán los etiquetados con símbolos especiales. Lo que hacemos ahora es
eliminar los estados finales (en realidad solo habría uno) y los arcos con
símbolos especiales. Como nuevos estados finales dejamos aquellos
desde los que partían arcos con símbolos especiales. A estos estados
asociaremos las acciones correspondientes al reconocimiento de las
categorías léxicas. Nuestro ejemplo queda como se ve en la figura 2.
(Jaume, s.f.)

22
COMPILADORES E INTERPRETES

TRATAMIENTO DE ERRORES:

Hemos visto que, si la MDD no puede transitar desde un determinado


estado y no ha pasado por estado final alguno, se ha detectado un error
léxico. Tenemos que tratarlo de alguna manera adecuada.
Desafortunadamente, es difícil saber cuál ha sido el error. Si seguimos
con el ejemplo anterior, podemos preguntarnos la causa del error ante la
entrada a.3. Podría suceder que estuviésemos escribiendo un real y
hubiésemos sustituido el primer digito por la a. Por otro lado, podría ser
un rango mal escrito por haber borrado el segundo punto. También podría
suceder que el punto sobrase y quiso éramos escribir el identificador a3.
Como puedes ver, a ‘un en un caso tan sencillo es imposible saber que ha
pasado. Una posible estrategia ante los errores seria definir una
“distancia” entre programas y buscar el programa más próximo a la
entrada encontrada. Desgraciadamente, esto resulta bastante costoso y
las ganancias en la práctica suelen ser mínimas. (Jaume, s.f.)

La estrategia que seguiremos es la siguiente: Emitir un mensaje de error y


detener la generación de código. Devolver al flujo de entrada todos los
caracteres le leídos desde que se detectó el ´ultimo componente léxico.
Eliminar el primer carácter. Continuar el análisis. Siguiendo estos pasos,
ante la entrada a.3, primero se emitiría un identificador, después se
señalaría el error al leer el 3. Se devolverían el tres y el punto a la
entrada. Se eliminaría el punto y se seguiría el análisis emitiendo un
entero.

23
COMPILADORES E INTERPRETES

DETECCION DE ERRORES EN LAS ACCIONES


ASOCIADAS:

Otros errores que se detectan en el nivel léxico son aquellos que solo
pueden encontrarse al ejecutar las acciones asociadas a las categorías.
Un ejemplo es el de encontrar números fuera de rango. En principio es
posible escribir una expresión regular para, por ejemplo, los enteros de 32
bits. Sin embargo, esta expresión resulta excesivamente complicada y se
puede hacer la comprobación fácilmente mediante una simple
comparación. Esta es la estrategia que hemos seguido en nuestro
ejemplo. Aquí sí que es de esperar un mensaje de error bastante
informativo y una buena recuperación: basta con emitir la categoría con
un valor predeterminado (por ejemplo, cero). (Jaume, s.f.)

ALGUNAS CATEGORÍAS ESPECIALES:

Ahora comentaremos algunas categorías que suelen estar presentes en


muchos lenguajes y que tienen ciertas peculiaridades.

Categorías que se suelen omitir:

Hemos visto en nuestros ejemplos que los espacios generalmente no


tienen significado. Esto hace que sea habitual tener una expresión del tipo
[ \t\n] + con omitir como acción asociada. Aún así, el analizador léxico sí
que suele tenerlos en cuenta para poder dar mensajes de error. En
particular, es bueno llevar la cuenta de los \n para informar de la línea del
error. En algunos casos, también se tienen en cuenta los espacios para
poder dar la posición del error dentro de la línea.

Otra categoría que es generalmente omitida es el comentario. Como en el


caso anterior, el analizador léxico suele analizar los comentarios para
comprobar cuantos fines de línea están incluidos en ellos y poder informar
adecuadamente de la posición de los errores.

El fin de fichero:

24
COMPILADORES E INTERPRETES

Aunque ha aparecido como un símbolo más al hablar de las expresiones


regulares, lo cierto es que el fin de fichero no suele ser un carácter más.
Dependiendo del lenguaje en que estemos programando o incluso
dependiendo de las rutinas que tengamos, el fin de fichero aparecerá de
una manera u otra. En algunos casos es un valor especial (por ejemplo,
en la función etc. de C), en otros debe consultarse explícitamente (por
ejemplo, en Pascal) y en otros consiste en la devolución de la cadena
vacía (por ejemplo, en Python). Como esto son detalles de
implementación, nosotros mostraremos explícitamente el fin de fichero
como si fuera un carácter e o f. Es más, en ocasiones ni siquiera
tendremos un fichero que finalice. Puede suceder, por ejemplo, que
estemos analizando la entrada línea a línea y lo que nos interesa es que
se termina la cadena que representa la línea. También puede suceder
que estemos en un sistema interactivo y analicemos una cadena
introducida por el usuario. Para unificar todos los casos, supondremos
que el analizador léxico indica que ya no tiene más entrada que analizar
mediante la emisión de esta categoría y no utilizaremos e o f como parte
de ninguna expresión regular compuesta. (Jaume, s.f.)

Las palabras clave

De manera implícita, hemos supuesto que las expresiones regulares que


empleamos para especificar las categorías léxicas definen lenguajes
disjuntos dos a dos. Aunque esta es la situación ideal, en diversas
ocasiones puede suponer una fuente de incomodidades. El caso más
claro es el que sucede con las palabras clave y su relación con los
identificadores. Es habitual que los identificadores y las palabras clave
tengan “la misma forma”. Por ejemplo, supongamos que los
identificadores son cadenas no vacías de letras minúsculas y que if es
una palabra clave. ¿Qué sucede al ver la cadena if? La respuesta
depende en primer lugar del lenguaje. En bastantes lenguajes, las
palabras clave son reservadas, por lo que el analizador léxico deberá
clasificar la cadena if en la categoría léxica if. Sin embargo, en lenguajes
como PL/I, el siguiente fragmento. (Jaume, s.f.)

25
COMPILADORES E INTERPRETES

Es perfectamente válido. En este caso, el analizador léxico necesita


información sintáctica para decidir si then es una palabra reservada o un
identificador. Si decidimos que las palabras clave son reservadas,
tenemos que resolver dos problemas:

Cómo lo reflejamos en la especificación del analizador léxico. Cómo lo


reflejamos al construir la MDD. Puede parecer que el primer problema
está resuelto; simplemente se escriben las expresiones regulares
adecuadas. Sin embargo, las expresiones resultantes pueden ser
bastante complicadas. Intentemos escribir la expresión para el caso
anterior, es decir, identificadores consistentes en cadenas de letras
minúsculas, pero sin incluir la cadena if. La expresión es:

Este sistema no solo es incómodo para escribir, facilitando la aparición de


errores, también hace que añadir una nueva palabra clave sea una
pesadilla. Lo que se hace en la práctica es utilizar un sistema de
prioridades. En nuestro caso, cuando un lexema pueda clasificarse en dos
categorías léxicas distintas, escogeremos la categoría que aparece en
primer lugar en la especificación. Así para las palabras del ejercicio,
nuestra especificación podría ser:

Expresión
Categoría Acciones Atributos
regular
if if emitir
then then emitir
else else emitir
Copiar lexema
identificador [a–z] + lexema
emitir

26
COMPILADORES E INTERPRETES

Ahora que sabemos cómo especificar el analizador para estos casos, nos
queda ver la manera de construir la MDD. En principio, podemos pensar
en aplicar directamente la construcción de la MDD sobre esta
especificación. Sin embargo, este método resulta excesivamente
complicado. Por ello veremos otra estrategia que simplifica la
construcción de la MDD con el precio de algunos cálculos extra. Para ver
lo complicada que puede resultar la construcción directa, volvamos al
caso en que sólo tenemos identificadores formados por letras minúsculas
y una palabra reservada: if. Empezamos por escribir la expresión regular
con las marcas especiales: (Jaume, s.f.)

Con esta expresión construimos la MDD:

Vemos que la ambigüedad aparece en el estado ¨ C, que tiene dos


posibles acciones. Hemos decidido que if tiene preferencia sobre
identificador, así que dejamos el autómata de esta manera:

27
COMPILADORES E INTERPRETES

Vemos que incluso para algo tan sencillo, el autómata se complica.


Evidentemente, a medida que crece el número de palabras reservadas, la
complejidad también aumenta.

La solución que podemos adoptar es la siguiente:

EL INTERFAZ DEL ANALIZADOR LÉXICO

¿Cómo sería la comunicación del analizador léxico con el sintáctico?


Como ya comentamos en el tema de estructura del compilador, el
analizador sintáctico iría pidiendo componentes léxicos a medida que los
necesite. Así pues, lo mínimo que deberá ofrecer el analizador léxico es
una función (o método en caso de que utilicemos un objeto para
construirlo) que permita ir recuperando el componente léxico actual.
Puede ser cómodo dividir esta lectura en dos partes:

Una función que indique cual es el ´ultimo componente leído. Esta función
no avanza la lectura.

Una función que avance la lectura hasta encontrar otro componente y lo


devuelva.

Dado que la primera es generalmente trivial (bastara con devolver el


contenido de alguna variable local o de un atributo), veremos cómo
implementar la segunda. Además de estas funciones, existen una serie de
funciones auxiliares que debe proporcionar el analizador:

28
COMPILADORES E INTERPRETES

Una función (o método) para especificar cuál será el flujo de caracteres de


entrada. Generalmente, esta función permitirá especificar el fichero desde
el que leeremos. En caso de que el analizador sea un objeto, la
especificación del flujo de entrada puede ser uno de los parámetros del
constructor. (Jaume, s.f.)

Una función (o método) para averiguar en qué línea del fichero nos
encontramos. Esto facilita la emisión de mensajes de error. Para dar
mejores mensajes, puede también devolver el carácter dentro de la línea.

Relacionada con la anterior, en algunos analizadores podemos pedir que


escriba la línea actual con alguna marca para señalar el error.

Si el analizador léxico necesita información del sintáctico, puede ser


necesario utilizar funciones para comunicarla. La complejidad o necesidad
de estas funciones variara segundas las necesidades del lenguaje. Así, si
nuestro lenguaje permite la inclusión de ficheros (como las directivas
#include de C), será necesario poder cambiar con facilidad el flujo de
entrada (o, alternativamente, crear más de un analizador léxico). (Jaume,
s.f.)

EL FLUJO DE ENTRADA

Hasta ahora hemos asumido más o menos implícitamente que los


caracteres que utilizaba el analizador léxico provenían de algún fichero.
En realidad, esto no es necesariamente así. Puede suceder que
provengan de la entrada est´andar5, o de una cadena (por ejemplo, en
caso de que estemos procesando los argumentos del programa). Para
evitar entrar en estos detalles, podemos suponer que existe un módulo u
objeto que utiliza el analizador léxico para obtener los caracteres. Este
módulo deberá ofrecer al menos los siguientes servicios:

Un método para especificar desde dónde se leen los caracteres (fichero,


cadena, dispositivo. . .).

Un método para leer el siguiente carácter.

29
COMPILADORES E INTERPRETES

Un método para devolver uno o más caracteres a la entrada.

Según las características del lenguaje para el que estemos escribiendo el


compilador, la devolución de caracteres será más o menos complicada.
En su forma más simple, bastara una variable para guardar un carácter.
En otros casos, será necesario incluir alguna estructura de datos, que
será una pila o una cola, para poder guardar más de un carácter. A la
hora de leer un carácter, lo primero que habrá que hacer es comprobar si
esta variable está o no vacía y después devolver el carácter
correspondiente. Un aspecto importante es la eficiencia de la lectura
desde disco. No es raro que una implementación eficiente de las
siguientes fases del compilador haga que la lectura de disco sea el factor
determinante para el tiempo total de compilación. Por ello es necesario
que se lean los caracteres utilizando algún almacén intermedio o buffer. Si
se utiliza un lenguaje de programación de alto nivel, es normal que las
propias funciones de lectura tengan ya implementado un sistema de
buffer. Sin embargo, suele ser necesario ajustar alguno de sus
parámetros. Aprovechando que los ordenadores actuales tienen memoria
suficiente, la mejor estrategia puede ser leer completamente el fichero en
memoria y tratarlo como una gran cadena. En algunos casos esto no es
posible. Por ejemplo, si se está preparando un sistema interactivo o si se
pretende poder utilizar el programa como filtro. (Jaume, s.f.)

IMPLEMENTACIÓN MEDIANTE CONTROL DE FLUJO

En este caso, el propio programa refleja la estructura de la MDD.


Lógicamente, aquí sólo podemos dar un esquema. La estructura global
del programa es simplemente un bucle que lee un carácter y ejecuta el
código asociado al estado actual.

El código asociado a un estado dependerá de si este es o no final. En


caso de que lo sea, tenemos que guardárnoslo en la variable uf y
actualizar él. Después tenemos que comprobar las transiciones y, si no
hay transiciones posibles, devolver c al flujo de entrada y ejecutar las
acciones asociadas al estado. Si las acciones terminan en omitir, hay que

30
COMPILADORES E INTERPRETES

devolver la maquina al estado inicial, en caso de que haya que emitir,


saldremos de la rutina.

El código para los estados no finales es ligeramente más complicado,


porque si no hay transiciones debemos retroceder hasta el ´ultimo final. El
condigo correspondiente está en la figura 6. Ten en cuenta que, si se está
implementando a mano el analizador, suele ser muy fácil encontrar
mejoras sencillas que aumentarán la eficiencia del código. Por ejemplo,
muchas veces hay estados que transitan hacia sí mismos, lo que se
puede modelar con un bucle más interno.

En otros casos, si se lleva cuidado, no es necesario guardar el ´ultimo


estado final porque sólo habrá una posibilidad cuando no podamos
transitar. Por todo esto, es bueno que después (o antes) de aplicar las
reglas mecánicamente, reflexiones acerca de las particularidades de tu
autómata y cómo puedes aprovecharlas (Jaume, s.f.)

FUNCIONES DEL ANÁLIZADOR LÉXICO

Gestionar el fichero que contiene el código fuente, entendiéndose por ello


el abrirlo, leerlo y cerrarlo

31
COMPILADORES E INTERPRETES

Eliminar comentarios, tabuladores, espacios en blanco, saltos de línea.

Relacionar los errores con las líneas del programa

Expansión de macros.

Inclusión de ficheros.

Reconocimiento de las directivas de compilación. (Oropeza, 2015)

Introducir identificadores en la tabla de símbolos (esta función es


opcional, pudiendo realizarse también por parte del analizador sintáctico).

VENTAJAS:

La búsqueda de caracteres es lenta y al enfatiza el comportamiento


separarla de la semántica se puede dependiente del tiempo del sistema.
dedicar tiempo a su mejora.

Este tipo de modelo sólo importaba

Se logra un sistema más simple para una categoría de sistemas No se


entrega más información del conocido como sistemas de tiempo-
requerida al análisis semántico. real; como ejemplo de estos sistemas se
tienen el control de procesos, Por ejemplo, es más fácil analizar fichas
sistemas de conmutación telefónica, tales como palabras llave,
identificadores sistemas de captura de datos de alta y operadores en
lugar de fichas que son velocidad y sistemas de control y los caracteres
terminales de conjunto de mando militares. símbolos utilizados por el
lenguaje (A, B, C, ... etc.). La primera ficha para una Los componentes de
un DTE son: expresión DO WHILE será DO en lugar de D que el análisis
puede considerar o ESTADOS: comportamiento del como parte de un
lazo en lugar de un sistema que es observable en el identificador que
comienza con D. tiempo. Los sistemas tienen un estado inicial, pero
pueden tener

32
COMPILADORES E INTERPRETES

Se hace más portátil el sistema puesto múltiples estados finales que las
peculiaridades del alfabeto de (mutuamente excluyentes). entrada se
pueden restringir al analizador léxico. o Cambios de estados: condiciones

Existen herramientas especializadas que y acciones. ayudan en la


construcción de analizadores léxicos cuando la etapa de análisis léxico y
semántico están separadas. (Agruta, pág. 1)

RECONOCEDORES Y ANALIZADORES LÉXICOS:

En ocasiones, habrá concordancia para más de un patrón.

El reconocedor elegirá el lexema más largo que haya concordado.

Si hay dos o más patrones que concuerdan con el lexema más largo, se
elige el primer patrón de la lista (¡Prioridad!!!).

Durante el proceso de reconocimiento, se debe llevar un registro de la


última vez que se alcanzó un estado final con dos o más patrones.

Procesadores de Lenguaje (Oropeza, 2015)

33
COMPILADORES E INTERPRETES

1.3.4 ALCANCE

El proyecto gira alrededor del tema “Analizador Léxico” donde se


realizarán estudios descriptivos debido a que se describirán
características del analizador léxico, su base es un programa que recibe
como entrada el código fuente de otro programa (secuencia de
caracteres) y produce una salida compuesta de tokens (componentes
léxicos acompañados de un código) o símbolos. Estos tokens sirven para
una posterior etapa del proceso de traducción, siendo la entrada para el
analizador sintáctico, Seguidamente, se realizarán estudios
correlacionado puesto que es necesario realizar una implementación.
Debido a que ambas presentan estructuras definidas, se pretende buscar
su correlación para que el intérprete sea capaz de realizar la
transformación previamente mencionada. Finalmente, con el dominio del
tema se procederá a desarrollar un ejemplo práctico de su funcionamiento
utilizando el lenguaje C# y el IDE visual studio 2019 para su respectiva
construcción, en el programa podremos agregar los elementos que
queramos que pertenezcan al lenguaje ya sea palabras reservadas,
signos de puntuación, operadores de asignación, de comparación,
aritméticos y símbolos especiales, se podrán modificar libremente también
tendremos acceso a un editor de texto donde podremos ingresar los
lexemas y en tiempo real se ira construyendo la tabla de símbolos del

34
COMPILADORES E INTERPRETES

analizador léxico. También se agregarán colores a las palabras


reservadas, errores y comentarios, esta función es del editor de texto,
pero estimamos conveniente su aplicación para este proyecto.

1.3.5 IMPORTANCIA

El estudiante que eligió el campo de la informática, ingeniería en


sistemas, u otras carreras a fin, conforme avanza en su formación
académica ira adquiriendo innumerables conocimientos relacionados al
desarrollo de software, siendo sin duda un campo bastante amplio pero
que tiene ciertos temas que se deben de manejar lo mejor posible. Se
debe estar consciente que la evolución de la tecnología se ha llevado a
cabo gracias a las computadoras y gracias al desarrollo de un sin número
de proyectos de tecnología. Por lo tanto, el mundo actual está construido
a base de software y el software está construido en algún un lenguaje de
programación. Hay que mencionar que el lenguaje de programación
escrito pasa por un proceso para poder ser interpretado por el
computador. Entonces la importancia de este proyecto radica en que el
estudiante domine los conocimientos relacionados a la primera fase de
compilación de código denominado Análisis Léxico, que sepa ¿qué es?,
¿cómo funciona?, ¿qué elementos están involucrados en esta fase? Y
todo lo relacionado al mismo. Todo lo anterior mencionado son
conocimientos fundamentales que deben ser dominados por un
estudiante de ingeniería en sistemas o carreras a fin.

35
COMPILADORES E INTERPRETES

2 CAPITULO II. SISTEMATIZACIÓN

2.1 PLAN DE EJECUCIÓN “CAPTURAS”

El desarrollo del proyecto (analizador léxico) tendrá las siguientes fases

Fase 1: Definición de las características que tendrá la aplicación

Fase 2: Desarrollo de la aplicación:

Fase 3: Pruebas de funcionamiento

DEFINICIÓN DE LAS CARACTERÍSTICAS DEL PROGRAMA


ANALIZADOR LÉXICO.

Acordamos lo siguiente:

Sera desarrollado con el lenguaje C#, IDE visual studio 2019.

Al ser un analizador léxico deberá de funcionar como tal, tendremos una


ventana principal donde se encontraran 3 pestañas; la primera pestaña
será lenguaje X, un apartado para definir nuestro posible lenguaje, este
lenguaje será aceptado por nuestro analizador léxico y contendrá
secciones para agregar palabras reservadas, signos de puntuación,
operadores aritméticos, operadores relacionales, operadores de

36
COMPILADORES E INTERPRETES

asignación y símbolos especiales, para agregar elementos a estos


diferentes grupos bastara con editar la lista, inicialmente se cargaran
elementos definidos por nosotros (default) pero se tendrá la libertad de
editar como el usuario estime conveniente, también se tendrá un botón
para limpiar todo el contenido de las secciones mencionadas
anteriormente.

Por defecto hemos definido como identificadores a cualquier cadena de


texto que inicie con mayúscula o no, seguido de cualquier cantidad de
números.

Por defecto también hemos definido que nuestro lenguaje aceptara


números, y números decimales. También cadenas de texto que hemos
definido como cualquier contenido dentro de ‘ ’.

Entonces en caso de dejar sin elementos las otras secciones aceptadas


por el lenguaje, nuestro analizador léxico solo devolverá tokens del tipo:
identificadores, números, números decimales y cadenas lo demás será
considerado un error.

La pestaña central “Analizador Léxico” en esta se va a localizar nuestro


analizador léxico, una vez definido el lenguaje podremos ir a esta sección
donde en la parte izquierda tendremos nuestra entrada de código fuente y
a la derecha la tabla de símbolos que genera el analizador léxico, la tabla
de símbolos contendrá el lexema, el token subdividido en dos columnas
una para el componente léxico y otra para el código del componente y
las últimas dos columnas sirven para ver la columna y la línea en la que
se encuentran nuestros lexemas aceptados por el lenguaje. Hay que
recalcar también que este analizador léxico llevara a cabo todo su trabajo
en tiempo real ósea que conforme nuestra entrada de texto vaya
cambiando también ira cambiando nuestra tabla de símbolos. En caso de
error ósea ingresar algún carácter que no pertenece a nuestro lenguaje
deberá mostrar error.

37
COMPILADORES E INTERPRETES

Las palabras reservadas serán marcadas en color azul en tiempo real,


por ejemplo, si la palabra INICIAR está definida como una palabra
reservada del lenguaje, al momento de terminar de escribirla en el editor
de texto la mostrara de color azul.

Los lexemas considerados como error serán marcados con color rojo en
el editor de texto y también en la tabla de símbolos.

Los comentarios serán marcados de color verde y estos son omitidos por
el analizador léxico por lo tanto no deben aparecer en la tabla de
símbolos. Para escribir comentarios definimos // toda la línea /*todo
incluidos los saltos de línea */

El limitador, separador de lexemas en este proyecto será “ ” un espacio


en blanco.

En esta pestaña también tendremos un botón de limpiar, para borrar todo


el contenido de la entrada de texto

La última pestaña “Acerca de” será meramente informativa donde se dan


breves detalles de ¿quiénes desarrollaron la aplicación?, ¿para qué? y
¿Por qué?, y ¿dónde se desarrolló?

DESARROLLO DE LA APLICACIÓN.

Ventana de Lenguaje X

38
COMPILADORES E INTERPRETES

Pestaña del lenguaje compuesta por una serie de richbox para ingresar
los elementos de cada componente léxico y el botón de limpiar.

El código hará que tome los elementos de cada richtextbox y los pase a
un arreglo en tiempo real también, entonces esta operación se mandara a
llamar en el evento de cambio de texto de cada uno, cada que se pulse o
ingrese un carácter se ejecutara este método, cuando nos referimos a
operación nos referimos a que se eliminaran los espacios y saltos de línea
similar a la parte del texto de entrada, y tomara únicamente los caracteres
de cada línea, luego estos caracteres serán enviados a un arreglo, para

39
COMPILADORES E INTERPRETES

posteriormente comparar si se están ingresando en la sección de entrada


del analizador léxico.

Estos métodos son los que se encargan de extraer los elementos de los
richtextbox y almacenarlos en un arreglo para que luego sean
comparados con los lexemas ingresados en la entrada de texto.

El código para los demás elementos será prácticamente el mismo,


actualmente solo tenemos el de signos de puntuación:

40
COMPILADORES E INTERPRETES

los demás los agregaremos en el transcurso de la semana….

Código para limpiar los richtextbox

41
COMPILADORES E INTERPRETES

PESTAÑA DE ANALIZADOR LÉXICO

Código que toma los datos en tiempo real de la entrada de texto:

Elimina los espacios y los saltos de línea (aún falta que omita los
comentarios) y manda los lexemas ingresados a otro método para que
se consulte que tipo de token va a devolver y también su código (aún falta
también). Hay que mencionar que estos métodos son invocados en el
evento de cambio de texto.

42
COMPILADORES E INTERPRETES

Como se puede ver en el código eliminamos los saltos de línea y los


espacios en blanco para dejar libre nuestro lexema y también estos datos
los mandamos a nuestra tabla de símbolos datagriew en este caso (aún
falta para el código del token.)

El lexema es enviado al método analizar, que es el encargado de verificar


si pertenece al lenguaje y que token debe asignársele, (este método aún
está en construcción, actualmente funciona para; identificadores,
números, números decimales, cadenas de texto, palabras reservadas,
signos de puntuación)

43
COMPILADORES E INTERPRETES

Botón para limpiar la sección de entrada de texto:

EN ESTE PUNTO AUN NOS FALTAN

Terminar las ultimas partes para que reconozca los otros elementos del
lenguaje y establecer las validaciones al ingresar los elementos, mejorar
la interfaz, limpiar el código, agregar la función de los colores, agregar
guías informativas para el usuario y la sección acerca de.

44
COMPILADORES E INTERPRETES

2.2 RESULTADOS

Vamos a definir un par de palabras reservadas y unos signos de


puntuación:

Tenemos nuestra tabla de símbolos

45
COMPILADORES E INTERPRETES

Cuando este completo agregaremos más capturas de los resultados…

46
COMPILADORES E INTERPRETES

2.3 DESCRIPCIÓN DE LAS ACTIVIDADES

Entrega de lineamientos de proyecto

El grupo recibió los lineamientos que debíamos seguir para la elaboración


del informe de proyecto de la clase de compiladores e intérpretes, fueron
recibidos el 04 de julio del año 2022, en este archivo se detallan las
fechas de entrega, el informe será entregado el 18 de julio y las
correcciones se recibirán el 25 de julio del presente año posteriormente se
defenderá el proyecto.

Inicio del proyecto

Como grupo iniciamos el proyecto el 5 de julio del año 2022, se desarrolló


una reunión breve (meet) donde definimos ciertas actividades y
asignaciones a cada integrante del grupo.

Definición de actividades

El día 6 y 7 de julio definimos que actividades se llevarían a cabo para el


desarrollo del proyecto (meet).

Investigación a fondo del tema- Búsqueda de información

Para el desarrollo del informe se necesita llevar a cabo investigaciones


acerca del tema a tratar en este caso es el analizador léxico. Esta
actividad se llevó a cabo entre los días 6 y 7 de julio del año 2022, Una
vez investigado el tema y definido nuestras fuentes de información
seguimos a la siguiente actividad.

Elaboración de informe

Ya todos relacionados con el tema procedimos a asignar a cada


integrante del grupo que sección del informe desarrollaría. Esta actividad
fue desarrollada del 7 al 15 de julio.

47
COMPILADORES E INTERPRETES

Investigación para el desarrollo del programa “analizador léxico”

Una cosa es manejar el tema a tratar y otra es el desarrollo de la


aplicación que simule un analizador léxico, entonces en esta actividad
definida de 7 de julio al 8 de julio procedimos a investigar diferentes
metodologías para el desarrollo relacionadas al tema donde encontramos
un sin número de ejemplos en la web, unos más complejos que otros y
desarrollados en diferentes lenguajes de programación (java, c++, c#
entre otros).

Definición de la metodología para el desarrollo de la aplicación

Una vez informados acerca de posibles rutas para el desarrollo definimos


en que lenguaje de programación desarrollaríamos la aplicación. En
nuestro caso definimos el lenguaje C# y como IDE Visual Studio 2019.
Tenemos muchas razones para trabajar con estas herramientas entre las
que podríamos mencionar; estamos un poco familiarizados con visual
studio 2019 y con el lenguaje C# (lo hemos usado antes para otros
proyectos.) y se adapta a las características que las hemos definido en la
fase 1 del plan de ejecución. Esta actividad fue desarrollada el 8 de julio
del presente año.

Actividad desarrollo de la aplicación.

Una vez definidas las características y funcionamiento de la aplicación se


procederán al desarrollo de la misma, enfocándonos primero en el
funcionamiento antes que en la apariencia.

El cómo se desarrolló está planteado con más detalle en el plan de


ejecución en la fase 2, esta actividad tiene lugar entre el 11 de julio y 17
de julio, sin embargo, se presentará en el informe la aplicación funcional,
pero sin algunas características, esto debido a que el día de presentación
de informe es el 18 de julio, pero las características faltantes se agregarán
lo más antes posible al informe.

48
COMPILADORES E INTERPRETES

Presentación de avance del informe 18/07/2022

Una vez terminado el informe será enviado a la PVA a la espera de recibir


las correcciones.

Correcciones de informe

Luego de entregar el informe el 18 de julio recibiremos las correcciones


por parte del catedrático el 25 de julio del año en curso. Luego se
procederá a hacer las correcciones señaladas.

Presentación del proyecto.

La presentación del proyecto será el día 1 de agosto en la hora clase


mediante Google meet.

49
COMPILADORES E INTERPRETES

2.4 CRONOGRAMA DE ACTIVIDADES (DIAGRAMA


DE GANTT)

PROYECTO DE CLASE COMPILADORES E INTERPRETES I


FECHA DE DURACIÓN
NOMBRE DE LA ACTIVIDAD FECHA FIN
INICIO EN DÍAS
Lineamientos del proyecto 4-jul 1 4-jul
Inicio del proyecto 5-jul 1 5-jul
Elaboración de actividades 6-jul 2 7-jul
Búsqueda de información 6-jul 2 7-jul
Elaboración de informe 7-jul 9 15-jul
Investigación para la metodología para el
7-jul 2 8-jul
desarrollo de la aplicación
Definición de la metodología para el
8-jul 1 8-jul
desarrollo de la aplicación
Desarrollo de la aplicación 11-jul 7 17-jul
Presentación de avance del informe 18-jul 1 18-jul
Correcciones de informe 19-jul 7 25-jul
Presentación del proyecto 1-ago 1 1-ago

50
COMPILADORES E INTERPRETES

3 CAPITULO II.

3.1 CONCLUSIONES

Los analizadores léxicos sirven en gran parte para resolver problemas


que pueden surgir a causa de que el programa no tenga congruencia o no
esté bien estructurado.

El analizador léxico tiene varias funciones importantes, se encarga de la


eliminación de los espacios en blanco de cualquier cadena que analiza,
reconoce los identificadores y palabras claves y contantes.
Posteriormente se encarga de construir los lexemas que constituyen un
lenguaje de programación. Las funciones en general de un análisis léxico
es leer el programa fuente como un archivo de caracteres y dividirlo en
tokens. Los tokens son palabras reservadas de un lenguaje, secuencia
de caracteres que representa una unidad de información en el programa
fuente.

3.2 RECOMENDACIONES

Al momento de hacer un código para un analizador léxico se deben de


tener en cuenta todos los posibles casos que la expresión pueda aceptar,
así como saber que variables, expresiones y operadores aceptar a
nuestro analizador.

Es recomendado el uso del Lenguaje C# para desarrollar un analizador


léxico pues, es un lenguaje muy complejo y con un sin número de
recursos

51
COMPILADORES E INTERPRETES

3.3 APÉNDICE

Temas adicionales

Este apéndice contiene temas adicionales que pueden ser cubiertos


juntos o que pueden ser abordados después pero que se relacionan con
el tema abordado en este informe.

Temas Cubiertos en este apéndice

- Diagramas sintácticos
- Diagrama de transiciones
- Analizador sintáctico
- Analizador Semántico

Diagramas Sintácticos

Se trata de otro método gráfico de definir patrones léxicos. También


pueden utilizarse al nivel sintáctico si se permiten definiciones circulares.
Los caracteres del alfabeto, digamos a, se representan encerrados en un
círculo o caja redondeada, mientras que un sub diagrama se representa
por una caja de ángulos rectos:

Las operaciones alternativo (unión) y secuencia (concatenación) se repre-


sentan así:

52
COMPILADORES E INTERPRETES

Las clausuras positivas y de Kleene se representan como sigue: Clausura


positiva (transitiva) Clausura de Kleene (reflexiva)
-

Sigue un ejemplo de cómo serían los diagramas sintácticos para el ejem-


plo de la página 32 de una constante flotante en Pascal:

La idea es recorrer los diagramas de todas las maneras posibles


siguiendo las flechas. En cada recorrido vamos juntando los caracteres
que encontramos y esto nos dará diferentes cadenas pertenecientes a
nuestro lenguaje.

Diagrama de transiciones

D i a g r a m a s de transición La función de transición de un autómata


finito se suele representar en forma de grafo. Como un paso previo a la
construcción del analizador léxico vamos a construir un diagrama de
transición mostrando las acciones que se deben realizar cuando se
ejecute el analizador léxico al ser llamado por el analizador sintáctico.

- El diagrama se dibuja escribiendo círculos numerados, que representan


los estados, y flechas con etiquetas que unen estos estados. A estas

53
COMPILADORES E INTERPRETES

flechas las llamaremos vértices. Las etiquetas muestran los caracteres


que pueden aparecer en la entrada una vez que hemos alcanzado un
cierto estado.

Analizador sintáctico

La tarea del analizador sintáctico es determinar la estructura sintáctica de


un programa, a partir de los tokens producidos por el analizador léxico y,
ya sea de manera explícita o implícita, construir un árbol gramatical o
árbol sintáctico que represente esta estructura.

Analizador semántico

El análisis semántico es la fase del compilador que, como se comentó en


capítulos anteriores, comprueba la corrección semántica del programa.
Para ello se añadirán distintas propiedades a la fase de análisis sintáctico.

La semántica se refiere a los aspectos del significado, sentido o


interpretación del significado de un determinado elemento, símbolo,
palabra, expresión o representación formal.

54
COMPILADORES E INTERPRETES

Por tanto, el análisis semántico trata de determinar el tipo de los


resultados intermedios, comprobar que los argumentos que tiene un
operador pertenecen al conjunto de los operadores posibles, y sí son
compatibles entre sí, etc. En definitiva, comprobará que el significado de
lo que se va leyendo es válido.

Distinguir entre construcciones sintácticas y semánticas es muy sencillo,


ya que las primeras usualmente son independientes del contexto (como
añadir un “;” al finalizar cada instrucción) y las segundas suelenser
dependientes (como que una variable tenga que ser de un tipo concreto
en una expresión o que esté definida previamente).

55
COMPILADORES E INTERPRETES

3.4 GLOSARIO
ATRIBUTO: Características propias de cada token, por tanto, se les
denomina atributos del token.

ALFABETO: Conjunto finito de símbolos no vacío que conforman una


gramática, se representan por (sigma).

AUTÓMATA: Es una construcción lógica que recibe como entrada una


cadena de símbolos y produce una salida indicando si la salida es una
cadena que pertenece a un determinado lenguaje.

AUTÓMATA FINITO: Son formas matemáticas para describir las


diferentes clases particulares de algoritmos. En el mundo de la
computación permiten reconocer cadenas de símbolos, por eso se usan
en la etapa de léxico de los compiladores. (villalta, 2014)

DIAGRAMA DE TRANSICIÓN: Es el conjunto de secuencias de entrada


que representan gráficamente los símbolos validos por la gramática, es
una representación de los universales autómatas que aparecen en la
matemática y otras ciencias.

CADENA: Se define como una secuencia de símbolos de un lenguaje


determinado. Por ejemplo 0001, abcd, a+4*b, 11000, etc. Una cadena
siempre tiene una longitud que esta denotada por la cantidad de símbolos
independientes que la conforman. Cuando la cadena es vacía se
representa como I λ I = 0.

EXPRESIÓN REGULAR: Representan patrones de cadenas de


caracteres. Se conocen más como metalenguajes que sirven para
describir los lenguajes regulares.

ESTRUCTURAS DE CONDICIÓN: Las estructuras condicionales


comparan una variable contra otro(s)valor (es), para que, en base al
resultado de esta comparación, se siga un curso de acción dentro del

56
COMPILADORES E INTERPRETES

programa. Cabe mencionar que la comparación se puede hacer contra


otra variable o contra una constante, según se necesite. (Urbaez, 2005)

GRAMÁTICA: Se define como un ente formal para especificar de una


manera finita el conjunto de cadenas de símbolos que constituyen un
lenguaje.

LÉXICO: El léxico de un lenguaje natural está constituido por todas las


palabras y símbolos que lo componen. Para un lenguaje de programación
la definición también es válida.

En un lenguaje de programación el léxico lo constituyen todos los


elementos individuales del lenguaje, denominados frecuentemente en
inglés tokens. Así son tokens: las palabras reservadas del lenguaje, los
símbolos que denotan los distintos tipos de operadores, identificadores
(de variables, de funciones, de procedimientos, de tipos, etc.),
separadores de sentencias y otros.

LEXEMA: 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.

LENGUAJE Un lenguaje es un conjunto de palabras que se puede


representar con un determinado alfabeto.

OPERADOR: Los operadores son símbolos que indican cómo se deben


manipular los operandos. Los operadores junto con los operandos forman
una expresión, que es una fórmula que define el cálculo de un valor. Los
operandos pueden ser constantes, variables o llamadas a funciones,
siempre que éstas devuelvan algún valor. El compilador evalúa los
operadores, algunos de izquierda a derecha, otros de derecha a
izquierda, siguiendo un orden de precedencia. Este orden se puede
alterar utilizando paréntesis para forzar al compilador a evaluar primero
las partes que se deseen. (ccia.ugr, s.f.)

PATRÓN: 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

57
COMPILADORES E INTERPRETES

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.

SINTAXIS: En los lenguajes de programación, sintaxis es un conjunto de


reglas formales que especifican la composición de los programas a base
de letras, dígitos y otros caracteres.

SEMÁNTICA: Semántica en los lenguajes de programación es el conjunto


de reglas que especifican el significado de cualquier sentencia,
sintácticamente correcta y escrita en un determinado lenguaje.

SINTÁCTICO: Es un programa informático que analiza una cadena de


símbolos según las reglas de una gramática formal. El término proviene
del latín pars, que significa parte (del discurso). Usualmente hace uso de
un compilador, en cuyo caso, transforma una entrada en un árbol
sintáctico de derivación. (wikipedia.org, 2021)

SÍMBOLO: Entidad abstracta que no se va a definir pues se deja como


axioma. Normalmente son letras de alfabetos, números o caracteres
especiales como +, -, *, I, etc. No necesariamente serán uno solo, ya que
un símbolo puede ser una combinación como palabras reservadas de un
lenguaje de programación then, end, beging, else, while, etc.

TOKEN: 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.

TABLA DE TRANSICIONES: Es la manera más cercana de representar


los autómatas, consta de filas que representan los estados y las columnas
que representan los símbolos de entrada. Adicionalmente se agregan dos
columnas para representar los tokens y para indicar retrocesos.

58
COMPILADORES E INTERPRETES

3.5 BIBLIOGRAFÍA

Agruta, E. (2022). slideshare.net. Obtenido de


https://es.slideshare.net/lizzylv/analizador-lexico-13595988
ccia.ugr. (s.f.). ccia.ugr.es. Obtenido de
https://ccia.ugr.es/~jfv/ed1/c/cdrom/cap2/cap26.htm#:~:text=Los
%20operadores%20son%20s%C3%ADmbolos%20que,que%20%C3%A9stas
%20devuelvan%20alg%C3%BAn%20valor
cidecame. (s.f.). Obtenido de
http://cidecame.uaeh.edu.mx/lcc/mapa/PROYECTO/libro32/index.html
ecured. (2020). ecured.cu. Obtenido de https://www.ecured.cu/Analizador_l
%C3%A9xico
Jaume, U. (s.f.). repositori.uji.es. Obtenido de
http://repositori.uji.es/xmlui/bitstream/handle/10234/5877/lexico.apun.pdf
Lopez. (2015).
Madrid, L. U. (s.f.). cartagena99. Obtenido de
https://www.cartagena99.com/recursos/alumnos/apuntes/ININF2_M4_U2_T1.
pdf
Millan. (2014).
Oropeza, R. (2015). slideplayer.es. Obtenido de https://slideplayer.es/slide/3893271/
Urbaez, W. (26 de octubre de 2005). desarrolloweb.com. Obtenido de
https://desarrolloweb.com/articulos/2225.php#:~:text=Las%20estructuras
%20condicionales%20comparan%20una,una%20constante%2C%20seg
%C3%BAn%20se%20necesite
villalta, P. (2014). slideshare.ne. Obtenido de
https://es.slideshare.net/pavillalta/compiladores-analisis-lexico-conceptos
wikipedia.org. (2021). Obtenido de https://es.wikipedia.org/wiki/Analizador_sint
%C3%A1ctico

59
COMPILADORES E INTERPRETES

3.6 ANEXOS

60
COMPILADORES E INTERPRETES

61
COMPILADORES E INTERPRETES

62
COMPILADORES E INTERPRETES

63

También podría gustarte