ANALIZADOR LEXICO CONSTRUIDO CON UN AUTOMATA FINITO DETERMINISTICO

Page 1

MTI. ROSA IMELDA GARCIA CHI.

TEORIA DE LENGUAJES Y AUTOMATAS

1.5. Análisis léxico.

Analizador léxico El analizador léxico es la primera fase de un compilador. Su función principal es leer caracteres desde la entrada, para identificar el siguiente componente léxico y pasar información relativa a este al analizador sintáctico. Además, realiza funciones tales como guardar el componente en una tabla de símbolos, eliminar blancos y comentarios y detección y recuperación de errores. Típicamente el analizador léxico es una función del analizador sintáctico, la cual es llamada por este ultimo cada vez que requiere el siguiente componente léxico de la secuencia de caracteres de entrada.

SIGCOMP PROGRAMA FUENTE

_-;'IL-·_AN_~_IZAD_co_o_"----:!I~ _

~ L-_~NALIZAD_INt_'A_C_Tl_g_:___J COMPONENTE /~

,",

~

~/

TABLA DE SIMBOlOS

I Figura

1.51

13

-~


1.6. Implementación

de analizadores

léxicos

Descripción de la aplicación Un método para construir un analizador léxico consiste en usar un AFO para describir la conducta de este. Se parte de una tabla descriptiva de los componentes léxicos que va a reconocer el analizador, donde se clasifican los diferentes tipos de componentes. Posteriormente se construye un ArO para reconocer cada una de las diferentes clases de componentes y se integran en un solo diagrama. Finalmente se determina la matriz de transición de estados. Una vez definida la matriz de transición de estados la construcción del analizador consiste en aplicar el algoritmo de reconocimiento de cadenas descrito en la sección anterior y añadir un switch/case para tomar acción de acuerdo al tipo de cadena identificada.

Ejemplo: Construir una anal izador léxico que acepte pnlabras reservadas, identi Iicadorcs, enteros positivos y operadores aritméticos y relacionales. Además debe eliminar blancos y comentarios y almacenará en una tabla de símbolos los identificadores y las constantes. Solución: I

Palabras reservadas.

El analizador reconocerá las siguientes 20 palabras reservadas: PROGRAM i ARRAV) VAR , CONST 1\ BEGIN o

s END ;. INTEGER ~ IF ~ TI-lEN ~ REAL

.0 11

11.. t'\ lA

STEP CASE ELSE CIIAR FOR

,'> TO nI~

11

\'

DO WHILE REPEAT UNTIL

y se considera que están almacenadas en las primeras 20 posiciones de la tabla de símbolos. Observe que bajo este supuesto no es relevante de que palabras se trate, ya que la única información que se requiere es el número total de palabras reservadas. -

14


Tabla de componentes léxicos

La tabla de componentes léxicos incluye tres columnas: componente, clase y tipo. El tipo de componente se usa para diferenciar componentes de una misma clase, como en el caso de los operadores aritméticos. Para las palabras reservadas, identificadores y

constantes, el tipo se especifica mediante la dirección donde se encuentra el componente en la tabla de símbolos (Dir TS).

Componente léxico Palabra reservada Identificadores Constante entera

Clase 1 2 3 4 4 4 4 5 5 5 5 5 5 6 7

+

-

* / < <= <> > >=

-c-

=

.,

15

Tipo DirTS DirTS DirTS 1 2 3 4

.

1

2 3 4 5 6 O O


Autรณmata finito determinista:

1Figura 1.61

16


Descripción de estadDs de recoJlocimi,,'nto En la sigúiente tabla se indica cual es la función de cada estado de reconocimiento y si en el proceso se esta dejando o no un carácter pendiente de procesar. Esto ultimo se debe a que hay algunas situaciones en que el reconocimiento del componente se realiza con el ultimo carácter analizado, como es el caso de los componentes de + y <= . Sin embargo en el caso de los componentes de < o identificador, se requiere leer un carácter adicional para reconocer el componente. En el diagrama del autómata esta situación ocurre en todos los estados de reconocimiento marcados con un asterisco. La información de si ha quedado un carácter pendiente de 'analizar, se debe pasar al analizador sintá~Fo para que sea considerada al llamar de nueva cuenta al analizador léxico. Otro aspecto importante es la numeración de los estados. Se usan las convenciones siguientes: estados que no son de reconocimiento se numeran del O al 99,:~e reconocimiento de componente se numeran del 100 al 199 y de reconocimiento de error del 200 al 299. Con este sistema de numeración de estados, se puede determinar que se ha llegado a un estado de reconocimiento cuando este sea mayor o igual a 100. Para luego a través de un switch/case identificar el tipo de componente de que se trata.

Estado de ~ reconocimiento 100 101 102 103 104 105 106 107 108 109 110 111 112 113 200 201

Componente

Pendiente

/

SI

+

no no no no no

-

* <= -

..

<> <

SI

no

>= > =

SI

no no

-

xr

Identificador Constante entera

.

... Se esperaba un = Carácter inválido

17

SI SI

-

no no no


Observe que no se incluye un estado de reconocimiento para el caso de palabras reservadas. Esto se debe a que en el caso de los identificadores, antes de reportarlos como de esta clase, se buscan en la tabla de símbolos y si se les encuentra en alguno de los primeros 20 lugares se reportan como una palabra reservada. Matriz de transición de estados -\

,\

D 8

L

O

7

1

100

2

2 2 106 108 200 7 112

3 4

.5 6 7 8

100 2 2 106 108

200 7 8

+ 101 100. 2 2 106 108 . 200 111 112

-

*

-c:

/

>

102 103 4 I .... 100 2 1.00. LOO 2 3 ' 2 2 2 2 O 2 106 106 106 _106 108 108 108- - 108 200 '200 200 200 111 lil 111 111 112 112 112 112

5.

• -J

lOO

2 2 105 WS

200 111 112

=

109 100 2 2 104 107110 111 112

..

6 100 2 2 106

b, /n,lt O

200

100 2 2106 108 209

111

111

112

112

lOS

;

Otro

JI3 100 2 2 106

201 100 2 2 106 108 200 111 112

lOS

200 111 112

Analizador léxico:

mainf)

1* Controla el ciclo de llamadas al analizador léxico

{ fp=Abrir _archivo("CODIGO.TXT"); c=getchar(fp); pendiente=l; while ( ! EOF)

¡ •

{ scaní); /* En este punto se tiene la información del 'símbolo identificado en e-

componente, clase y tipo. Además, la tabla de símbolos ya se actualizó }.

----q7

}

scaní)

if (not pend icnte) e= getchar(fp); pendiente

.~ l-\o

o er« !;"

~'\C"1 !it"f"\\- e no

=

/* Si no hay un carácter pendiente de procesar */ /* extrae el siguiente carácter del archivo */

O; componente

=" ";

q

~

= O;

1

~Ó<J'

~ve

\¡ 01 ell,U 1V"'

J t-f

18 \ CI

e c. J~ o,

',,,,¿. 0.1

*/


while { '1= if if

( q < 100 )

m] q ][cJ ; (q != O) componente = componente (q<IOO) c=getchar(fp);

+ e ;.

switch(q) { lOO:elimina_car(componente); 101: clase = 4; tipo = 1; 102: clase = 4; tipo = 2; 103: clase = 4; tipo = 3; 104: clase = 5; tipo = 2; 105: clase = 5; tipo = 3; 106: clilllina_car(componente); 107: clase = 5; tipo = 5; 108: elimina_car(componente); 109: clase = 5; tipo = 6; 110: clase = 6; tipo = O; 113: clase = 7; tipo = O;

clase

= 4; tipo

= 4; pendiente = 1;

clase

= 5; tipo

=

clase

= 5; tipo = 4; pendiente =

1; pendiente = 1; 1;

111:

.

elimina_car(componente); tipo=guarda( com ponente); if( tipo<=:_ 2~) \

/

bu!>(.,,- ' .... \0 )rc;.1o \"

~

.;, ......~ol.:>}

'\{'(j"e ....I"'ÓI(.

~

\.<J

''''''''~,,-w-o .

clase _ 1, ~ else clase== Z: A-----, .'

~

~

.

pe. '.1

l'

lo0rc

r~SC"/"·(O

Jc;

~.f\(.o~Q<

Ieler<

pendiente = 1;

} 112: elimina carfccmponente):

clase = 2; tipo=guarda(componente);

200: Error(" Se esperaba un = "); 201: Error("Carácter

invál ido ");

} }

19

pendiente = 1;


Código

fuente

Estructuras de datos utilizadas Se introduce en un archivo de texto, desde donde se analiza carácter por carácter.

Función de trunsición de estados Tabla de símholos

fp e q componente pendiente clase tipo

Se mantiene en una matriz m] q ]leJ . En esta tnhla se gunrdnn los componentes de tipo palabra reservad a, idcnt ilicador y constante. Todas las pa labras reservadas se deben cargar inicialmente en la tabla. Cada componente identificado se debe darse de alta en la tabla y no se debe repetir el registro: Componente, clase y tipo.

Variables Utilizadas Apunta al archivo con el código fuente Apunta al carácter que se procesa actualmente Contiene el estado actual Cadena en la que se va formando el componente conforme transcurre el análisis. Indica si no se procesó el ultimo carácter en la llamada anterior. Contiene la clase del componente identificado. Contiene el tipo del componente identificado o su dirección en la tabla de símbolos para las palabras reservadas, identificadores y constantes.

GuanJa(componente) Error( mensaje) Elimina Cartcomponcntc)

@ Construya el analizador

Funciones Utilizadas Esta función registra el componente en la tabla de símbolos y regresa la dirección donde lo guardó o donde lo encontró. Función para generar los mensajes de error. Elimina el ultimo carácter que se encadeno en componente

léxico descrito en esta sección. ,

2. Diseñe y construya un analizador léxico para un compilador de lenguaje "C"-A1 ~O<.,

20

'oN>

"A(j\coD 2" í." \


CODIGO EN LENGUAJE C DEL ANALIZADOR LÉXICO CREADO CON UN AUTOMATA FINITO DETERMINISTICO

//PROGRAMA ANALIZADOR LEXICO para el lenguaje C //ROSA IMELDA GARCIA CHI #include <string.h> #include <stdlib.h> #include <stdio.h> #include <conio.h> #include <iostream.h> #include <ctype.h>

int matriz[10][14]={ {8,9,101,102,103,1,4,5,7,6,0,111,201}, {100,100,100,100,2,100,100,100,100,100,100,100,100}, {2,2,2,2,3,2,2,2,2,2,2,2,2}, {2,2,2,2,2,0,2,2,2,2,2,2,2}, {105,105,105,105,105,105,105,105,104,105,105,105,105}, {107,107,107,107,107,107,107,107,106,107,107,107,107}, {200,200,200,200,200,200,200,200,108,200,200,200,200}, {110,110,110,110,110,110,110,110,109,110,110,110,110}, {8,8,112,112,112,112,112,112,112,112,112,112,112}, {113,9,113,113,113,113,113,113,113,113,113,113,113} };

FILE *fp; typedef char string[15];

string ts[100];


int q, clase, tipo,pendiente; char c; int x=5; int y=5; string componente;

class lexico {

int ultimo;

public: //constructor lexico() { llena_reservada(); ultimo=19; }

int trae_indice(char c) { int uno,otro=0;

switch (c) { case '+': uno=2;break; case '-': uno=3;break; case '*': uno=4;break; case '/': uno=5;break; case '<': uno=6;break; case '>': uno=7;break; case '=': uno=8;break; case '!': uno=9;break;


case ' ': case '\n': case '\t': uno=10;break; case ';': uno=11;break; default: otro=1; } /*switch*/ if (isdigit(c)) {uno=1; otro=0;} if (isalpha(c)) {uno=0; otro=0;} if (otro) uno=12; return(uno); }

void elimina_car(string componente) { int longitud;

longitud=strlen(componente); componente[longitud-1]='\0'; }

void llena_reservada() { strcpy(ts[0],"include"); strcpy(ts[1],"define"); strcpy(ts[2],"main"); strcpy(ts[3],"typedef"); strcpy(ts[4],"struct");


strcpy(ts[5],"char"); strcpy(ts[6],"int"); strcpy(ts[7],"float"); strcpy(ts[8],"enum"); strcpy(ts[9],"system"); strcpy(ts[10],"default"); strcpy(ts[11],"continue"); strcpy(ts[12],"function"); strcpy(ts[13],"break"); strcpy(ts[14],"void"); strcpy(ts[15],"fopen"); strcpy(ts[16],"fwrite"); strcpy(ts[17],"feof"); strcpy(ts[18],"while"); strcpy(ts[19],"for"); } //******************************** int guarda(string componente, int ultimo) { int i,encontro,lugar;

for (i=0;i<100;i++) if (strcmpi(componente,ts[i])==0) { encontro=1; lugar=i; break; } else encontro=0;


if (!encontro) { lugar=ultimo; lugar=lugar+1; strcpy(ts[lugar],componente); } return(lugar); }

void imprime() { gotoxy(x,y); printf("%s", componente); gotoxy(x+16,y); printf("%i", clase); gotoxy(x+22,y); printf("%i", tipo); y=y+1; if (y==22) {y=5;x=40;} }

scan() { int r;

if (!pendiente) fread(&c,sizeof(c),1,fp); pendiente=0; strcpy(componente,""); q=0;


while(q<100) {

int largo;

r=trae_indice(c); q=matriz[q][r]; if (q!=0) { largo=strlen(componente); componente[largo]=c; componente[largo+1]='\x0'; } if (q<100) fread(&c,sizeof(c),1,fp); } switch (q) { case 100:elimina_car(componente);clase=4;tipo=4;pendiente=1;break; case 101:clase=4;tipo=1;break; case 102:clase=4;tipo=2;break; case 103:clase=4;tipo=3;break; case 104:clase=5;tipo=2;break; case 105:elimina_car(componente);clase=5;tipo=1;pendiente=1;break; case 106:clase=5;tipo=5;pendiente=1;break; case 107:elimina_car(componente);clase=5;tipo=4;pendiente=1;break; case 108:clase=5;tipo=3; case 109:clase=5;tipo=6;break; case 110:elimina_car(componente);clase=6;tipo=0;pendiente=1;break; case 111:clase=7;tipo=0;break; case 112:


{elimina_car(componente); tipo=guarda(componente,ultimo); if (tipo<20)

//palabra reservada

clase=1; else { clase=2; //identificador ultimo=tipo; } pendiente=1;break;} //constante entera case 113: elimina_car(componente);clase=3;tipo=guarda(componente,ultimo);ultimo=tipo; pendiente=1;break; case 200: cprintf("ERROR - se esperaba un =");break; case 201: cprintf("ERROR - caracter invalido");break; } return(componente, clase, tipo); } }; //clase

void main() { lexico lex; clrscr(); if ((fp=fopen("edito2.txt","r"))==NULL) { clrscr(); cprintf("NO PUEDE ABRIR EL ARCHIVO"); }


else {

fread(&c,sizeof(c),1,fp); pendiente=1; while (!feof(fp)) { lex.scan(); lex.imprime(); } } fclose(fp); getche(); }


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.