Está en la página 1de 23

Contenido

Autómata Finito......................................................................................2
Analizador Léxico...................................................................................6
FUNCIÓN DEL ANALIZADOR LÉXICO..................................................................8

ASPECTOS DEL ANÁLISIS LÉXICO......................................................................9

Manejo De Buffer.................................................................................10
MANEJO DE LOS BUFFERS DE ENTRADA.......................................................11

PAREJAS DE BUFFERS.......................................................................................12

Tabla De Símbolos...............................................................................14
TIPOS DE ESTRUCTURAS DE TABLAS DE SÍMBOLOS...................................15

TABLAS DE SÍMBOLOS LINEALES....................................................................16

ACTUALIZACIÓN Y ACCESO A LA TABLA DE SÍMBOLOS..............................17

TABLA DE SÍMBOLOS HASH.............................................................................18

Manejo De Errores...............................................................................21
Referencias Bibliográficas...................................................................23

pá g. 1 UNIDAD III : ANALISIS LEXICO


Autómata Finito
Un reconocedor de un lenguaje es un programa que toma como entrada una cadena
x y responde “si” si x es una frase del programa y no, si no lo es. Se compila una
expresión regular en un contenedor 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 transacció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 rapados que uno no determinista, un autómata finito
determinista puede ser mucho mayor que un autómata no determinista equivalente

AF = {Q , ∑ ,  q0, F}

Q: Conjunto finito de estados


∑: Alfabeto de estado finito
 Funciones de transición o la tabla de transiciones
q0: Estado inicial
F: Conjunto de estados finales de aceptación

Generalmente se asocia con cada autómata un grafo dirigido, llamado diagrama de


transición de estados. Cada nodo del grafo corresponde a un estado. El estado
inicial se indica mediante una flecha que no tiene nodo origen. Los estados finales
se representan con un círculo doble. Si existe una transición del estado q i al estado
ej para un símbolo de entrada a, existe entonces un arco rotulado a desde el nodo q i
al nodo ej; es decir que (qi, a) = ej, se representa en el diagrama

pá g. 2 UNIDAD III : ANALISIS LEXICO


Ejemplos:

L (G) = {x|x es (ab)* (cd)*}

AFD = {Q, F, ∑, q0}  a b c d


q0 q1 q5 q3 q5
Q = {q0, q1, q2, q3, q4, q5}
q1 q5 q2 q5 q5
∑ = {a, b, c, d} q2 q1 q5 q3 q5
F = {q0, q2, q4} q3 q5 q5 q5 q4
q4 q5 q5 q3 q5
q5 q5 q5 q5 q5

pá g. 3 UNIDAD III : ANALISIS LEXICO


L (G) = {x|x es ((abc)+ d) e}

AFD = {Q, F, ∑, q0}


 a b c d e
Q = {q0, q1, q2, q3, q4, q5, q6} q0 q1 q6 q6 q6 q6
∑ = {a, b, c, d, e}
q1 q6 q2 q6 q6 q6
q2 q6 q6 q3 q6 q6
F = {q5}
q3 q1 q6 q6 q4 q6
q4 q1 q6 q6 q6 q5
q5 q6 q6 q6 q6 q6
q6 q6 q6 q6 q6 q6

pá g. 4 UNIDAD III : ANALISIS LEXICO


L (G) = {x|x es (ab)+ c d* e* f}

AFD = {Q, F, ∑, q0}


 a b c d e f
Q = {q0, q1, q2, q3, q4, q5, q6, q7} q0 q1 q7 q7 q7 q7 q7
∑ = {a, b, c, d, e, f} q1 q7 q2 q7 q7 q7 q7
F = {q4}
q2 q7 q7 q3 q7 q7 q7
q3 q7 q7 q7 q5 q6 q4
q4 q7 q7 q7 q7 q7 q7
q5 q7 q7 q7 q5 q6 q4
q6 q7 q7 q7 q7 q6 q4
q7 q7 q7 q7 q7 q7 q7

pá g. 5 UNIDAD III : ANALISIS LEXICO


Analizador Léxico
El proceso de análisis lexicón o de reconocimiento puede entenderse como la
transformación de un flujo de símbolos “reducidos”. En este caso “reducido”
significa que la entrada es filtrada para eliminar aquellos elementos que solo sirve
para hacer legible el programa.

Entre las funciones características de un analizador léxico están:

 Eliminar espacios, comentarios, etc.

 Reconocer identificadores y palabras clave.

 Reconocer constantes y numerales

 Generar un listado para el compilador

Salto de separadores: Los espacios, tabuladores, comentarios y Saltos de línea se


denominan separadores y pueden ser muy numerosos en un código fuente, pero
no proporcionan información para la traducción; por lo tanto, deben ser
eliminados del código entregado al analizador sintáctico.

Reconocimiento de operadores y nombres: Es fácil reconocer símbolos de


operadores como +,-,*, /, por que constan de un solo carácter. Sin embargo, hay
otros operadores como <, <=, <>, := que comienzan con el mismo carácter y tiene
significados diferentes. En estos casos, el analizador léxico tiene que examinar el
carácter siguiente por anticipado o pre-análisis, para determinar el operador
correcto.

Esto también sucede cuando analiza un número, un identificador o una palabra


clave.

pá g. 6 UNIDAD III : ANALISIS LEXICO


La tarea más difícil para el analizador léxico es distinguir entre identificadores y
palabras clave, lo cual puede hacerse con tablas de símbolos o con una estructura
de datos adicional que contenga todas las palabras reservadas.

Números: El analizador léxico debe transformar un numeral en el símbolo de


numeral y su valor.

Tablas de símbolos: Es una estructura de información para manejar los nombres


(identificadores y apalabras reservadas) del código fuente. Se usa durante la
comprobación semántica o dependiente del contexto, además del proceso de
generación de código. En general, una tabla de símbolos consta de nombres y
atributos.

La información almacenada en una tabla de símbolos varía de un compilador a


otro y de un lenguaje a otro; es decir, la información que se incluirá en ella
depende del lenguaje y del diseñador del compilador. Pero en general, los
atributos pueden ser:

 Tipo o valor de un nombre (constantes) o ambos

 La dimensión o el número de parámetros de un procedimiento

 Un puntero al lugar donde se declara y referencia un nombre

 Algún tipo de dirección, por lo regular un desplazamiento

 Información del alcance (scope) en caso de un lenguaje orientado a bloques

pá g. 7 UNIDAD III : ANALISIS LEXICO


Función Del Analizador Léxico
El analizador léxico es a 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.

Como el analizador léxico es la parte del compilador que lee el texto fuente
también puede realizar ciertas funciones secundarias de la interfaz del usuario
como eliminar del programa fuente comentarios y espacios en blanco en forma de
caracteres TAB y de línea nueva. Otra función es relacionar los 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 la 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 procesador también se pueden aplicar al
hacer el análisis léxico.

En algunas ocasiones, los analizadores léxicos se dividen en una cascada de dos


fases: la primera, llamada “examen” y la segunda, “análisis léxico”. El examinador
se encara de realizar tareas sencillas, mientras que el analizador léxico es quien
realiza las operaciones más complejas.

pá g. 8 UNIDAD III : ANALISIS LEXICO


Aspectos Del Análisis Léxico
Hay varias razones para dividir la fase de análisis de la compilación en análisis
léxico y análisis sintáctico.

1. Un diseño sencillo es quizá la consideración más importante. Separar el


análisis léxico del análisis sintáctico, a menudo permite simplificar una u
otra de dichas fases
2. Se mejora la eficiencia del compilador. Un analizador léxico independiente
permite un procesador especializado y potencialmente más eficiente para
esta función. Gran parte de tiempo se consume en leer el programa fuente
y dividirlos en componentes léxicos.
3. Se mejora la trasnportabilidad del compilador. Las peculiaridades del
alfabeto de entrada y otras anomalías propias de los dispositivos pueden
limitarse al analizador léxico.

Ejemplo:

Diseñe un diagrama de transiciones para reconocer expresiones aritméticas de


longitud arbitraria que comprenden enteros positivos separados por signos de
suma, resta, multiplicación o división

Operador = ‘+’, ‘-‘, ´*’, ó ‘/’

pá g. 9 UNIDAD III : ANALISIS LEXICO


Manejo De Buffer

El analizador léxico y el analizador sintáctico forman un par productor –


consumidor. El analizador léxico produce componentes léxicos y el analizador
sintáctico los consume. Los componentes léxicos producidos se pueden conservar
en un buffer hasta ser consumidos. La interacción entre los dos solo está
restringida por el tamaño del buffer, puesto que el analizador léxico no puede
avanzar cuando el buffer está lleno y el analizador sintáctico no puede proseguir
cuando el buffer está vacío. Por lo general, el buffer contiene solo un componente
léxico. En este caso, la interacción se puede aplicar simplemente haciendo que el
analizador léxico sea un procedimiento llamado por el analizador sintáctico que
devuelva componentes léxicos cuando se le pidan.

La aplicación de la lectura y devolución de caracteres suele hacerse estableciendo


un buffer de entrada. Un bloque de caracteres se lee al buffer de una vez; un
apuntador señala la porción de la entrada ya analizado. La operación de
devolución de carácter se implanta moviendo hacia atrás el apuntador. También
puede ser necesario tener que guardar los caracteres de la entrada para el
informe de errores, pues hay que dar alguna indicación de donde se produjo el
error en el texto de entrada.

Aunque solo sea por razones de eficiencia, está justificado el manejo del buffer
para los caracteres de entrada. La extracción de un bloque de caracteres suele ser
más eficiente que la extracción de un carácter a la vez.

pá g. 10 UNIDAD III : ANALISIS LEXICO


Manejo De Los Buffers De Entrada
Hay tres métodos generales de implantación de un analizador léxico

1. Utilizar un generados de analizadores léxicos

2. Escribir el analizador léxico en un lenguaje convencional de programación

de sistemas, utilizando las posibilidades de entrada y salida de este lenguaje

para leer la entrada

3. Escribir el analizador léxico en lenguaje ensamblador y manejar

explícitamente la lectura de la entrada

Las tres opciones se relacionan en orden de dificultad creciente para el encargado


de la implementación. Lamentablemente, los enfoques más difíciles de implantar
muchas veces dan como resultado analizadores léxicos más rapados.

Como el analizador léxico es la única fase del compilador que lee el programa
fuente carácter a carácter, es posible que consuma mucho tiempo en la fase de
análisis léxico, aunque las fases posteriores sean conceptualmente más complejas.

Así la velocidad del análisis léxico supone un problema en el diseño de


compiladores.

pá g. 11 UNIDAD III : ANALISIS LEXICO


Parejas De Buffers
En muchos lenguajes fuente hay veces en que el analizador léxico necesita pre
analizar varios caracteres, además del lexema para un patrón, antes de poder
anunciar una concordancia. Como se puede consumir mucho tiempo moviendo
caracteres, se han desarrollado técnicas especializadas en el manejo de buffers
para reducir el número de operaciones necesarias para procesar un carácter de
entrada.

Se utiliza un buffer dividido en dos mitades N caracteres de cada una, por lo


general, N es el número de caracteres en un bloque de disco, por ejemplo 1024 o
4096.

Se leen N caracteres de entrada en cada mitad de buffer con una orden de lectura
de sistema, en vez de invocar una instrucción de lectura para cada carácter de
entrada.

Si quedan menos de N caracteres en la entrada, entonces se lee un carácter


especial eof (fin de archivo) en el buffer después de los caracteres de entrada. Es
decir eof marca el final del archivo fuente y es distinto a cualquier carácter de la
entrada.

E = M * C * * 2 eo
f

delantero
Comienzo lexema

Se mantienen dos apuntadores al buffer de entrada.

pá g. 12 UNIDAD III : ANALISIS LEXICO


La cadena de caracteres entre los dos apuntadores apunta al primer carácter del
próximo lexema que hay que encontrar. Uno de ellos, llamado apuntador
delantero examina hacia adelante hasta encontrar una concordancia con un
patrón. Una vez determinado el siguiente lexema, el apuntador delantero se
coloca en el carácter de su extremo derecho.

Después de haber procesado el lexema, ambos apuntadores se colocan en el


carácter situado inmediatamente después del lexema. Con este esquema se
pueden considerar los comentarios y los espacios en blanco como patrones que
no producen componentes léxicos.

Cuando el apuntador delantero está a punto de sobrepasar por la marca


intermedia del buffer, se llena la mitad derecha con N nuevos caracteres de
entrada y el apuntador delantero se regresa al principio del buffer.

Este esquema de manejo de buffer casi siempre funciona muy bien, pero limita a
cantidad de caracteres de pre análisis, y esto puede imposibilitar el
reconocimiento de los componentes léxicos cuando la distancia recorrida por el
apuntador delantero sea mayor que la longitud del buffer.

pá g. 13 UNIDAD III : ANALISIS LEXICO


Tabla De Símbolos
Un compilador necesita guardar y usar la información de los objetos que van
apareciendo en el texto fuente. Esta información se introduce en una estructura
de datos del compilador denominada tabla de símbolos. La información básica
que se guarda por cada objeto es la siguiente:

 Una cadena de caracteres que denota el nombre o identificador del objeto

 Sus atributos

 Su dirección en memoria, o la forma de encontrarla

 Otros posibles campos requeridos por cada compilador e implementación

Podemos pues considerar cada entrada de la tabla de símbolos como un par de la


forma (identificador, información). Cada vez que se detecta un objeto en el texto
fuente, exploraremos la tabla de símbolos para ver si existe ya, es decir, que no es
la primera vez que aparece. Si el objeto es nuevo se introduce a la tabla de
símbolos.

La información contenida en la tabla de símbolos se utilizara principalmente en el


análisis semántico, es decir, en el momento en que comprobemos si la declaración
de un objeto es consistente con el uso que se le está dando. También se utilizara
en fase de generación de código y en el tratamiento de errores.

pá g. 14 UNIDAD III : ANALISIS LEXICO


Tipos De Estructuras De Tablas
De Símbolos
En una tabla de símbolos se crea una nueva entrada durante la compilación cada
vez que se encuentra un nuevo objeto (normalmente en una declaración).
Posteriormente, se añaden datos a esa entrada cuando se encuentra o produce
nueva información sobre ese objeto.

Las operaciones más usuales que se realizan en una tabla se símbolos son:

1. Determinar si ya existe un objeto

2. Añadir un nuevo objeto

3. Acceder a la información asociada a un objeto

4. Añadir o modificar información a un objeto dado

5. Borrar un objeto o grupo de objetos

pá g. 15 UNIDAD III : ANALISIS LEXICO


Tablas De Símbolos Lineales
El método más simple para implementar una tabla de símbolos es la creación de
una matriz lineal (de una dimensión) cuyos elementos son estructuras, una por
cada objeto. Podemos almacenar el identificador del objeto en la estructura
siempre que la longitud máxima del mismo no sea grande. La tabla de símbolos
entonces de la se podría representar de la siguiente manera:


Identificador IDENT1
Identificador INF1
Identificador IDENT2
Identificador INF2

En los casos en que se permitan longitudes grandes para los identificadores, es


mejor utilizar el siguiente sistema:

9 identificador
… Información
11 Identificador
… información

NEWPROG NOMBRELAR
… ..
RA GO

Sistema que cuenta con una zona especial para los identificadores, de forma que
se evitan huecos. El campo identificador de la tabla de símbolos queda compuesto
por dos subcampos: el primero es un puntero a la primera posición del área donde
se encuentra el nombre y el segundo indica el número de caracteres que contiene.

pá g. 16 UNIDAD III : ANALISIS LEXICO


Actualización Y Acceso A La Tabla
De Símbolos
Los objetos que se van introduciendo en el orden en que se van encontrando.

Para la información de un objeto determinado, se realiza una búsqueda secuencial


desde el primer elemento libre (elemento de la matriz que aun esta sin rellenar),
retrocediendo hasta el inicio de la tabla de símbolos.

Para insertar un nuevo objeto, primero se comprueba que no existe ya. Si ya


existe, pudiera ser un error. Si no existe, se introduce en el elemento apuntado
por libre y se incrementa este. En resumen, el esquema de una tabla de símbolos
lineal en un momento dado seria:

IDENT1
info-1
IDENT2
info-2
...
...
IDENTn
info-n
LIBRE

pá g. 17 UNIDAD III : ANALISIS LEXICO


Tabla De Símbolos HASH
Se denomina hash a una función que calcula un número entero para cada
identificador, es decir:

Numero hash (identificador)

El número entero obtenido se utiliza como índice de una tabla denominada tabla
hash. Por otra parte, llamamos tabla de símbolos hash a aquella tabla de
almacenamiento cuyo índice de acceso se obtiene a través de una tabla hash.

Al diseñar la función, habrá que tener en cuenta los calores que los valores que
devuelva tengan una distribución uniforma, que el rango de dichos valores no
supere la dimensión de la tabla hash y que esta dimensión sea un numero primo,
con el cual evitaremos gran numero se sinónimos y colisiones.

Por ejemplo, si se diseña una tabla de 31 elementos, la función hash habrá de


devolver valores comprendidos en el intervalo 0…30. En definitiva, para un
tamaño n, la tabla tendrá un rango de 0 a n-1 y los valores devueltos por la
función deberían estar incluidos en dicho rango.

pá g. 18 UNIDAD III : ANALISIS LEXICO


La implementación de una tabla de símbolos mediante una tabla hash se realiza
mediante dos tablas, una hash y otra lineal de almacenamiento.

IDENT1
info-1
enlace-1
IDENT2
… info-2
2 enlace-2
… IDENT2
… info-2
3 enlace-3

LIBRE

Se utiliza una función hash para el acceso a una tabla de símbolos por el simple
hecho del ahorro de tiempo en las búsquedas. Y la razón de usar dos tablas es
porque con ello evitamos huecos y aprovechamos al 100% el espacio en la tabla
de almacenamiento.

De esta forma, la tabla hash estará compuesta de n punteros que apuntan a las
cabezas de n listas encadenadas situadas en la tabla de almacenamiento. Cada
estructura o entrada de la tabla de símbolos estará en una de estas listas.

pá g. 19 UNIDAD III : ANALISIS LEXICO


Se dice que se produce una colisión o sinónimo en cualquier acceso mediante
hashing, cuando aplicada la función hash a dos o más identificadores, la dirección
resultante es la misma. Para resolver este problema de colisiones, existen varias
soluciones alternativas.

1. Reservar un área de overflow o desbordamiento donde ir metiendo


secuencialmente aquella información cuya dirección haya producido
colisión.

2. Insertar el nuevo registro en una posición n direcciones más adelante. A


esta alternativa se le denomina rehashing, y el numero n se obtiene de
variadas maneras, desde una forma lineal (1,2,3,…) hasta de una forma casi
aleatoria

pá g. 20 UNIDAD III : ANALISIS LEXICO


Manejo De Errores

Hay muchas estrategias generales distintas que puede emplear un analizador para
recuperarse de un error sintáctico. Aunque ninguna de ellas ha demostrado ser de
aceptación universal, algunos métodos tienen una amplia aplicabilidad. Aquí se
introducen las siguientes estrategias:

 En modo pánico

 A nivel de frase

 De producciones de error

 De corrección global

Recuperación en modo de pánico: De los métodos de análisis sintácticos este es el


más sencillo de implantar y puede utilizarlo la mayoría. L descubrir un error, el
analizador desecha símbolos de entrada, de uno en uno, hasta que encuentra uno
perteneciente a un conjunto designado de componentes léxicos de sincronización.

Estos componentes léxicos de sincronización son generalmente delimitadores,


como el punto y coma o la palabra clave end, cuyo papel en el programa fuente
está claro.

Recuperación a nivel de frase: Al descubrir un error, el analizador sintáctico puede


realizar una corrección local de la entrada restante; es decir; puede sustituir un
prefijo de la entrada restante por alguna cadena que permitía continuar al
analizador sintáctico.

Una corrección local típica seria sustituir una coma por un punto y coma, suprimir
un punto y coma sobrante, o insertar un punto y coma que falta. La elección de la
corrección local corresponde al diseñador del compilador.

pá g. 21 UNIDAD III : ANALISIS LEXICO


Producciones de errores: Si se tiene una buena idea de los errores comunes que
pueden encontrarse, se puede aumentar la gramática del lenguaje con
producciones que generen las construcciones erróneas. Entonces, se usa una
gramática aumentada con las producciones del error para construir el analizador.

Si el analizador usa una producción de error, se pueden generar diagnósticos de


error apropiados para indicar la construcción errónea reconocida en la entrada.

Corrección global: Idealmente, sería deseable que un compilador hiciera el


mínimo de cambios posibles al procesar una cadena de entrada incorrecta. Existen
algoritmos para elegir una secuencia mínima de cambios para obtener una
corrección global de menor costo. Dada una cadena de entrada incorrecta x y la
gramática G, estos algoritmos encontraran un árbol de análisis sintáctico para una
cadena relacionada, tal que el número de inserciones, supresiones y
modificaciones de componentes léxicos necesarios para transformar x en y, sea el
mínimo posible.

Referencias Bibliográficas

pá g. 22 UNIDAD III : ANALISIS LEXICO


Compiladores e intérpretes. Un enfoque pragmático

Gonzalo Sánchez Dueñas, Juan A. Valverde Andreu

Ediciones DIAZ DE SANTOS, S.A.

Segunda Edición, 1989

Lenguaje y Compiladores

Iván Pérez

Universidad Católica Andrés Bello

Primera Edición, 2005

Compiladores. Principios, técnicas y herramientas

Alfred V. Aho, Ravi Sethi y Jeffrey D. Ullman

Addison Wesley Iberoamericana, S.A.

Primera edición, 1990

pá g. 23 UNIDAD III : ANALISIS LEXICO

También podría gustarte