analisis lexico

13
El proceso del Análisis Léxico El proceso de análisis léxico se refiere al trabajo que realiza el scanner con relación al proceso de compilación. El scanner representa una interfaz entre el programa fuente y el analizador sintáctico o parser. El scanner, a través del examen carácter por carácter del texto, separa el programa fuente en piezas llamadas tokens, los cuales representan los nombres de las variables, operadores, etiquetas, y todo lo que comprende el programa fuente. El parser, usualmente genera un árbol de sintaxis del programa fuente como ha sido definido por una gramática. Las hojas del árbol son símbolos terminales de la gramática. Son esos símbolos terminales o tokens los que el scanner extrae del código fuente y se los pasa al parser. Es posible para el parser usar el conjunto de caracteres terminales del lenguaje como el conjunto de tokens, pero ya que los tokens pueden ser definidos en términos de gramáticas regulares más simples que en las gramáticas más complejas utilizadas por los parsers, es deseable usar scanners. Usar solo parsers es costoso en términos de tiempo de ejecución y requerimientos de memoria, y la complejidad y el tiempo de ejecución puede reducirse con el uso de un scanner. La separación entre análisis léxico (scanning) y análisis sintáctico (parsing) puede tener también otras ventajas. El análisis léxico de caracteres generalmente es lento en los compiladores, y separándolo del componente de análisis semántico de la compilación, el énfasis particular puede darse para hacer más eficiente el proceso. Un analizador de léxico tiene como función principal el tomar secuencias de caracteres o símbolos del alfabeto del lenguaje y ubicarlas dentro de categorías, conocidas como unidades de léxico.

Upload: erick-santiago-guillaumin-perez

Post on 12-Dec-2015

229 views

Category:

Documents


0 download

DESCRIPTION

Informatica y compiladores

TRANSCRIPT

El proceso del Análisis Léxico

El proceso de análisis léxico se refiere al trabajo que realiza el scanner

con relación al proceso de compilación.

El scanner representa una interfaz entre el programa fuente y el

analizador sintáctico o parser.

El scanner, a través del examen carácter por carácter del texto, separa el

programa fuente en piezas llamadas tokens, los cuales representan los

nombres de las variables, operadores, etiquetas, y todo lo que

comprende el programa fuente.

El parser, usualmente genera un árbol de sintaxis del programa fuente

como ha sido definido por una gramática.

Las hojas del árbol son símbolos terminales de la gramática. Son esos

símbolos terminales o tokens los que el scanner extrae del código fuente

y se los pasa al parser.

Es posible para el parser usar el conjunto de caracteres terminales del

lenguaje como el conjunto de tokens, pero ya que los tokens pueden ser

definidos en términos de gramáticas regulares más simples que en las

gramáticas más complejas utilizadas por los parsers, es deseable usar

scanners.

Usar solo parsers es costoso en términos de tiempo de ejecución y

requerimientos de memoria, y la complejidad y el tiempo de ejecución

puede reducirse con el uso de un scanner.

La separación entre análisis léxico (scanning) y análisis sintáctico

(parsing) puede tener también otras ventajas.

El análisis léxico de caracteres generalmente es lento en los

compiladores, y separándolo del componente de análisis semántico de la

compilación, el énfasis particular puede darse para hacer más eficiente el

proceso.

Un analizador de léxico tiene como función principal el tomar secuencias

de caracteres o símbolos del alfabeto del lenguaje y ubicarlas dentro de

categorías, conocidas como unidades de léxico.

Las unidades de léxico son empleadas por el analizador gramatical para

determinar si lo escrito en el programa fuente es correcto o no

gramaticalmente.

Algunas de las unidades de léxico no son empleadas por el analizador

gramatical sino que son descartadas o filtradas.

Tal es el caso de los comentarios, que documentan el programa pero que

no tienen un uso gramatical, o los espacios en blanco, que sirven para

dar legibilidad a lo escrito.

En la terminología empleada en la construcción de un analizador de

léxico se encuentran los siguientes términos.

Patrón Representa la regla para que una secuencia de caracteres sea

considerada cierta unidad de léxico.

Ejemplo: El patrón para un identificador de Pascal es:

Una letra seguida por letras, dígitos o guiones (_)

Lexema

El valor actual de un conjunto de caracteres que satisfacen un patrón.

Ejemplo: Este_es_1_ejemplo

Este es el lexema que satisface el patrón de un identificador

Token o Ficha

El valor asociado a una categoría o unidad de léxico.

Se representa como un número entero o una constante de un byte.

Ejemplo: el token de un identificador puede ser 1 ó id (si id fue definida como

1). Unidades de léxico

Categorías en que se clasifican las cadenas de caracteres válidos en un lenguaje.

Los caracteres válidos reciben el nombre de alfabeto.

Por ejemplo, el alfabeto de Pascal es:

A-Z, a-z, 0-9, _, =, :, ;, ,, , -, ', ", *, /, (, ), [, ], ., <, > y las unidades de léxico para

pascal son:

identificadores

literales numéricas

operadores aritméticos

cadenas de caracteres

separadores

operadores relacionales

operadores lógicos

comentarios

Con respecto al lenguaje para controlar al ROBOT, tenemos que su alfabeto es:

n,o,r,t,e,s, ,u,i,c

y las unidades de léxico son:

órdenes

(norte, sur, este, oeste, inicio)

y espacios en blanco.

El rol del analizador de Léxico

Aunque el analizador de léxico es la primera etapa del proceso de compilación,

no es quien lo inicia.

Pudiera considerarse que el analizador de léxico hace su procesamiento y envía

sus resultados al analizador gramatical, como secuencialmente se aprecia en el

proceso de compilación; no es así:

La compilación empieza con el analizador gramatical quien solicita un token

para realizar su trabajo;

el analizador de léxico reune símbolos y envía el token correspondiente a la

unidad de léxico que conformó al analizador gramatical y espera una nueva

solicitud de token.

Como se aprecia en la figura siguiente, el analizador de léxico está supeditado

por el analizador gramatical.

Durante estas etapas se tiene comunicación con la tabla de símbolos que

concentra información de las entidades empleadas en el programa.

Descripción de Patrones

Un patrón se puede describir:

1. Mediante una descripción informal, en donde se emplea el lenguaje natural

para describir el comportamiento de la regla de léxico.

Por ejemplo: un número entero es una secuencia de uno o más dígitos del 0

al 9.

O un identificador es una letra seguida de letras, dígitos o guiones de

subrayar.

La descripción informal es útil sólo entre humanos;

computacionalmente aún no hay herramientas para construir sobre ellas

analizadores de léxico.

2. Utilizando expresiones regulares.

Una expresión regular es una notación formal que utiliza operaciones sobre el

alfabeto de un lenguaje.

Por ejemplo, se puede definir que un identificador es:

{letra} ({letra} | {dígito} | {guión})*

que interpreta como un elemento del conjunto letra seguido de cero o mas

veces (la cerradura Kleene, representada por el asterisco)

de una letra, dígito o guión (la selección representada por la barra vertical).

Esta notación es formal y computacionalmente útil para construir analizadores

de léxico empleando la herramienta LEX.

3. Utilizando autómatas finitos (diagramas de transición o diagramas

sintácticos), que son representaciones gráficas de las relaciones entre conjuntos

de símbolos (aristas) por medio de estados, a los cuales pueden llegarse o

transitarse por ellos al encontrar un símbolo perteneciente a un conjunto.

El siguiente diagrama puede ser la representación de un identificador:

La utilización del diagrama sirve para aclarar las posibilidades de acción en un

patrón y puede manipularse computacionalmente.

Diagramas de Estado.

Ya que el scanner debe reconocer tokens, debemos buscar la posibilidad de

describir los tokens a manera de reconocimiento y no de manera generativa.

La descripción de los tokens por medio de cómo pueden ser reconocidos (o

aceptados) se hace en términos de un modelo matemático llamado un aceptor

de estado finito.

En lo que resta de esta sección, describiremos un conjunto de tokens por medio

de la especificación de un aceptor que reconocerá ese conjunto.

Cabe aclarar que las gramáticas regulares también pueden utilizarse para este

propósito.

Un aceptor de estado finito o autómata finito puede considerarse como una

máquina consistente de una cabeza de lectura y una caja de control de estado

finito.

La máquina lee una cinta de carácter a la vez, de izquierda a derecha.

Existe un número finito de estados que la máquina puede adoptar.

Cada vez que la máquina lee el siguiente carácter, ocurre en ella un cambio de

estado.

Siempre que un aceptor de estado finito inicia la lectura de una cinta, éste se

encuentra en cierto estado llamado estado inicial.

Algunos de los estados que el aceptor puede adoptar se llaman estados finales,

y si el aceptor intenta leer más allá del final de la cinta mientras se encuentra en

un estado final, la cadena que está en la cinta se dice que fue aceptada por el

autómata finito.

En otras palabras, la cadena pertenece al lenguaje que es aceptado por el

autómata finito.

Diagramas de Estado Finito.

Para representar gráficamente un aceptor de estado finito, también se utilizan

los diagramas de estado finito o diagramas de transición, como el que se

muestra en la siguiente figura y que representa el aceptor para un número con

al menos un dígito después del punto decimal.

Los nodos del diagrama de estado finito representan los estados del aceptor de

estado finito.

En el diagrama anterior, los nodos se han etiquetado con los números 1, 2 y 3.

Los arcos, que van de un estado otro, indican las transiciones de estado.

La flecha y la palabra "Inicio" indican cual de los estados es el estado inicial (en

este caso el estado 1).

El estado etiquetado con el 3 se denomina estado final.

Generalmente los estados finales se representan por medio de dos círculos

concéntricos, pero en nuestro caso, para facilitar su construcción, hemos

utilizado un circulo con línea más gruesa.

Los símbolos sobre los arcos representan los caracteres que, al leerse, obligan al

cambio de un estado a otro.

Un diagrama de transición es una representación gráfica donde se tiene un

conjunto de estados, los cuales pueden ser:

iniciales

finales

intermedios

los cuales pueden tener una o más salidas hacia otro estado.

Los estados se relacionan entre sí con flechas con un nombre (el caracter o

conjunto de caracteres que provoca la transición de un estado a otro).

Un estado final se representa con :

que también recibe el nombre de estado de aceptación.

Para construir un diagrama de transición se debe tener presente:

A cada estado debe llegarse con el mismo conjunto de caracteres en todas las

ocasiones en que haya un transición.

Para llegar a un estado de aceptación debe existir una transición sobre el

caracter que rompe el patrón de la unidad de léxico.

Cuando se construye un analizador de léxico utilizando diagramas de transición

para la especificación de los patrones, se realiza un único diagrama que, a partir

del estado 0, tiene diversas transiciones a cada uno de los patrones de las

unidades de léxico que deba reconocer.

Cada patrón posee un caracter selector, que permite reconocer de manera

única el patrón que deba aplicarse.

Por ejemplo, si queremos reconocer identificadores, comentarios apegados a

las reglas del lenguaje C y el fin de archivo, podriamos contruir el siguiente

diagrama:

Si leo la diapositiva siguiente puedo entender este grafico CLARO..

Las descripciones informales de las unidades de léxico son:

Identificador: Letra seguida de letra, dígitos o guiones

Comentario: Empieza con /* y termina con */.

Entre estos pares puede haber cualquier símbolo

EOF: cuando se encuentra el caracter eof (fin de archivo)

Error: Cualquier símbolo que no cumpla con los patrones anteriores.

Los caracteres selectores para cada patrón son:

Identificador: letra

Comentario: /

EOF: eof

Error: cualquier símbolo diferente a los anteriores.

Las descripciones informales de las unidades de léxico son:

Identificador: Letra seguida de letra, dígitos o guiones

Comentario: Empieza con /* y termina con */.

Entre estos pares puede haber cualquier símbolo

EOF: cuando se encuentra el caracter eof (fin de archivo)

Error: Cualquier símbolo que no cumpla con los patrones anteriores.

Los caracteres selectores para cada patrón son:

Identificador: letra

Comentario: /

EOF: eof

Error: cualquier símbolo diferente a los anteriores.

Estado A-Z 0-9 _ / * eof otro

0 1 13 13 5 13 12 13

1 1 2 3 4 4 4 4

2 1 2 3 4 4 4 4

3 1 2 3 4 4 4 4

4

5 14 14 14 14 6 14 14

6 8 8 8 8 7 15 8

7 10 10 10 9 7 15 10

8 8 8 8 8 7 15 8

9 11 11 11 11 11 11 11

10 8 8 8 8 7 15 8

11

12

13

14

15

Los estados finales o de aceptación de las unidades de léxico quedan sin

información en las columnas ya que no existe una transición al reconocer o aceptar

el patrón.

Note que la designación de otro corresponde a los símbolos diferentes a los

expresamente indicados y que para cada patrón es contextual.

Para poder realizar el análisis de léxico a partir de la información que contiene la

tabla se cuenta con un mecanismo que parte del estado 0 y empieza a recorrer el

diagrama por cada transición posible hasta llegar a un estado final.

El algoritmo del mecanismo se describe a continuación.

Analizador_de_Lexico

INICIO

Estado=0

C=Inspecciona()

Cont=0

Nuevo_Estado=TABLA[Estado, C]

MIENTRAS Nuevo_Estado no sea Estado_Final

REPITE

Avanza()

C=Inspecciona()

Estado=Nuevo_Estado

Nuevo_Estado=TABLA[Estado, C]

Cont=Cont+1

FREPITE

SI Cont es 0 ENTONCES

Avanza()

FSI

Regresa Token (Estado_Nuevo)

FIN

Analizador_de_Lexico

INICIO

Estado=0

C=Inspecciona()

Cont=0

Nuevo_Estado=TABLA[Estado, C]

MIENTRAS Nuevo_Estado no sea Estado_Final

REPITE

Avanza()

C=Inspecciona()

Estado=Nuevo_Estado

Nuevo_Estado=TABLA[Estado, C]

Cont=Cont+1

FREPITE

SI Cont es 0 ENTONCES

Avanza()

FSI

Regresa Token (Estado_Nuevo)

FIN

Si no entiendes el diagrama, entonces en una hoja de papel realizas la 1, 2,

3…pruebas de escritorio CLARO..

La función Analizador_de_Léxico utiliza dos funicones que permiten consumir los

símbolos del programa fuente: Inspecciona y Avanza. Las funciones consideran la

existencia de un apuntador AP que direcciona al caracter próximo a leer.

Inspecciona regresa el caracter apuntado por AP pero no lo incrementa. La función

Avanza no regresa nada pero incrementa el valor de AP para estar en el siguiente

símbolo a leer.