Vous êtes sur la page 1sur 18

FACULTAD DE INGENIERIA, UNAM COMPILADORES PROFESOR: ALEJANDRO JIMENEZ HERNANDEZ marzo 2009 PRACTICA FLEX Nombre: Implementacin de un analizador

de lxico en C utilizando: flex, generador de analizadores de lxico

Objetivo: Ejecutar y analizar ejemplos de analizador de lxico utilizando C en la distribucin de Linux de la clase de compiladores. 1. Teora de flex. flex al igual que lex, es un generador de analizadores de lexico o 'scanners'. f lex traduce expresiones regulares a un automata DFA escrito en lenguaje 'C'. ----------| | | | expresiones | | regulares ----->| F l e x |-----> Analizador lxico | | | | | | ----------Un programa escrito en flex tiene una estructura de tres secciones separadas po r el simbolo %% definiciones %% reglas de reconocimiento %% programas de usuario La primera parte de definiciones es opcional y puede contener: - dimensiones de tablas internas de flex - codigo en lenguaje 'C' que es global, escrito dentro de los simbolos %{ y %} - definiciones para reemplazo de textos Las definiciones tienen la forma: NOMBRE DEFINICION, donde NOMBRE es un identifi cador y DEFINICION es el valor que toma. El NOMBRE puede usarse en la seccin de reglas de reconocimiento como {NOMBRE} y sustituye su significado en cada aparic in de NOMBRE. Es como un #define en C. La parte de %% siempre se incluye. La segunda parte de reglas de reconocimiento consiste en una tabla de patrones o expresiones regulares y acciones. A cada patrn corresponde una accin que puede s er una o varias instrucciones en lenguaje 'C'. El formato es: expresion { accin }

Las acciones modifican a yytext, que es un apuntador a la entrada o a la cadena de caracteres que es la entrada, yyleng, es la longitud de yytext. La tercera parte de programas de usuario es opcional y contiene codigo en le nguaje 'C' escrito por el usuario. Cuando el automata se genera como una funcin a utilizarse por otro programa este toma el nombre de 'yylex()'. PATRONES Los patrones se utilizan para formar secuencias de caracteres o expresiones reg ulares y su significado se puede resumir como sigue: - los caracteres se representan a si mismos - el punto '.' representa cualquier caracter menos LF - parentesis de la forma [] cuando encierran secuencias de caracteres definen conjuntos de caracteres que representan a cualquiera de sus componentes o si la secuencia empieza con el smbolo '^' a cualquier caracter que no este en la secue ncia. - el smbolo - entre dos caracteres indica un rango o gama. - * cuando sigue a un patrn representa cero o mas concatenaciones de ese patrn. - + cuando sigue a un patrn representa una o mas concatenaciones de ese patrn. - ? cuando sigue a un patrn representa cero o una concatenacin de ese patrn. - ^ al inicio de un patron representa inicio de linea - ^ al inicio de un patron dentro de parntesis [] es el inverso de ese patrn - $ al fin de un patrn representa fin de linea - | representa alternativas de reglas de produccin - los parentesis ( ) se utilizan para manejar la prioridad de las expresiones. Ejemplos. c encuentra el caracter 'c' [abc] encuentra 'a' o 'b' o 'c' [^A-Z] encuentra un caracter que no sea mayscula. r* cero o ms repeticiones de r r+ una o mas repeticiones de r r? cero o una repeticin de r r{2,5} de 2 a cinco repeticiones de r r{2,} dos o mas repeticiones de r r{4} cuatro repeticiones de r [a-z]ABC una letra minscula seguida de ABC \X caracter de escape \0 caracter nulo \333 nmero con valor octal de 333 \xff nmero con valor hexadecimal ff rs concatenacin r|s alternacin r/s una r si es seguida por una s, la s no es procesada. ^r una 'r' al inicio de lnea r$ una 'r' al fin de lnea <s>r una r en la condicin de inicio r. <s1,s2,s3>r una r en la condicin de inicio s1 o s2 o s3. <*>r una r en cualquier condicin de inicio <<EOF>> fin de archivo <s1,s2><<EOF>> fin de archivo en la condicin de inicio s1 o s2. Dentro de una clase todas los metacaracteres pierden su significado menos el car acter de escape ('\') y los operadores, '-', ']' y '^'.

'*' tiene mayor precedencia que la concatenacin y estas que la alternacin. Las clases de caracteres definidas en

[:alnum:] [:alpha:] [:cntrl:] [:digit:] [:graph:] [:lower:] [:upper:] [:print:] [:punct:] [:space:] [:xdigit:] [:blank:] DIRECTIVAS

smbolos alfanumricos letras secuencias de control dgitos, es lo mismo que [0123456789] caracteres imprimibles y visibles minsculas maysculas cualquier caracter imprimible smbolos de puntuacin espacios, tabs, etc. dgitos hexadecimales. espacios

Existen directivas y funciones especiales que pueden ser incluidas dentro de una accin: ECHO copia yytext en la salida del analizador de lxico BEGIN con una condicin de inicio, posiciona ah al analizador de lxico REJECT indica al autmata ejecutar la segunda regla que indic el usuario para corr esponder con la entrada. YY_FLUSH_BUFFER borra el contenido del buffer de entrada. Cuando el escner vuelve a reconocer un token lo debe llenar con YY_INPUT. las funciones especiales son: yymore() indica al autmata que la prxima vez que se reconozca un patrn, la s alida se concatena a yytext en lugar de reemplazar el valor que tena. yyless(n) Regresa todos excepto los primeros n caracteres de la entrada.

unput(c) Pone el caracter c de regreso en la entrada yyin, por lo que ser el siguiente caracter escaneado. input() lee el siguiente caracter de la entrada.

yyterminate() termina el funcionamiento del escner y regresa un 0 al invocador, indicando que ha terminado. Por default, yyterminate es llamado cuando se encue ntra un fin de archivo. 2. Ayuda de flex. Generadores de analizadores en linux son flex y lex verifique su uso con una ayuda rapida $ flex -h tambien verifique la documentacin con $ man flex

3. Ejemplos usando flex Ejemplo 1. Escriba un programa que elimine el cdigo html del archivo encuesta.htm Una solucin es el programa: -------------------------------%{ /* quita_html.l: programa que quita comentarios de archivos html uso: ./quita_html < archivo.html > archivo.txt */ %} %% "<"[^>\n]*">" %% main() { yylex(); } -------------------------------A los programas en flex se les agrega comunmente la extension 'l' compile las expresiones regulares usando flex: $ flex -oquita_html.c quita_html.l compile el automata resultante usando gcc: $ gcc quita_html.c -o quita_html -lfl la extensin -lfl le indica al compilador gcc, que se incluya la librera que utiliz a flex. para ejecutarlo utilize el archivo de prueba encuesta.html $ ./quita_html < encuesta.html > encuesta.txt Verifique el cdigo en el archivo encuesta.txt. ; /* quita codigo html */

Ejemplo 2. Escriba un programa que agrege el cdigo html del archivo encuesta.txt Una solucin es el programa: --------------------------------

%{ /* texto.l programa para convertir un archivo de tipo texto a html */ %} linea parrafo %% {linea} {parrafo} %% main(int argc, char *argv[]) { register int i; char buffer[80]; extern char *token(); printf("<html>\n"); while (i = yylex()); printf("</html>"); } -------------------------------compilelo usando flex: $ flex -opon_html.c pon_html.l compile con gcc: $ gcc pon_html.c -o pon_html -lfl para ejecutarlo utilize el archivo de prueba encuesta.html $ ./pon_html < encuesta.txt > nueva_encuesta.html Verifique el cdigo en el archivo nueva_encuesta.html {printf("<br>\n");} {printf(".<br>\n");} "\n" ".\n"

Ejemplo 3. Escriba un programa que extraiga el texto de un documento del tipo .d oc Una solucin es el programa: -------------------------------/* doc2txt.l: extrae de un archivo doc el texto */ /* uso: ./doc2txt < archivo.doc */ LETRAS [a-zA-Z]+

DIGITOS OTRO ACENTOS %%

[0-9]+ [\n\t\f\r\v \\\.,=+-_)(?:;]+ []+ /* se definen vocales con acentos y la */

{LETRAS}|{DIGITOS}|{OTRO}|{ACENTOS} . %% main() { yylex(); } -------------------------------se compila con flex: $ flex -odoc2txt.c doc2txt.l compile con gcc: $ gcc doc2txt.c -o doc2txt -lfl

ECHO; ;

para ejecutarlo utilize el archivo de prueba civil.doc $ ./doc2txt < civil.doc El cdigo se despliega en la pantalla.

Ejemplo 4. Otra solucin al problema anterior es el programa tdoc.l, que lee direc tamente la entrada de un archivo. Aqu los macros de flex para imprimir en pantall a ECHO y para leer de la entrada estndard YY_INPUT se reemplazan por otros del us uario. -------------------------------/* tdoc.l: traduce documento word a texto y html uso: tdoc archivo.doc */ %{ FILE *texto,*html,*fin; /* redefine el macro ECHO para que escriba en archivos de salida */ #define ECHO {\ char *ffin;\ fprintf(texto,"%s",yytext);\ fprintf(html,"%s",yytext);\ if((ffin =(char *) strstr(yytext,"\n")) != NULL)\ fprintf(html,"<br>\n");\ }

/* reemplaza lectura de entrada en stdin por archivo */ #define YY_INPUT(buf,result,max_size) \ { int c = getc( fin ) ; \ result = c == EOF ? 0 : 1 ; \ buf[0] = (char) c ; \ } %} %% [^a-zA-Z \341\351\355\363\372\301\311\315\323\332\321\361\n]* %% main(int argc, char *argv[]) { int k=0; char arch_html[80], arch_text[80]; if (argc < 2) { fprintf(stderr, "\nModo de uso: noword <archivo.doc>\n"); exit(EXIT_FAILURE); } fin = fopen(argv[1], "r"); if (fin == NULL) { fprintf(stderr, "No puedo abrir el archivo %s\n", argv[1]); exit(EXIT_FAILURE); } while (argv[1][k]!='.') { arch_html[k]=arch_text[k]=argv[1][k]; k++; } arch_html[k]= arch_text[k]='\0'; strcat(arch_html,".html\0"); strcat(arch_text,".txt\0"); if((html=fopen(arch_html,"w"))==NULL) { printf("No se pudo generar archivo de salida html"); exit(EXIT_FAILURE); } fprintf(html,"<html><body>\n"); if((texto=fopen(arch_text,"w"))==NULL) { printf("No se pudo generar archivo de salida de texto"); return 0; } while(yylex());

fprintf(html,"</body></html>\n"); fclose(texto); fclose(html); } -------------------------------Ejemplo 5. Escriba un programa que reconozca enteros, reales, identificadores y simbolos de comparacin en un archivo cualquiera. Una solucin es el programa: -------------------------------%{ /* reconoce.l: analizador de sintaxis en LEX para reconocer: identificadores, enteros, reales y simbolos de comparacin primera parte de un programa en LEX definiciones de reemplazo de textos */ %} id entero arch %% {id} {entero} {arch} "<" "<=" "=" "<>" ">" ">=" . %% /* funcin principal que reemplaza al parser */ /* el scanner generado por flex se llama yylex() main() { register int char extern char i; buffer[80]; *token(); {printf(" {printf(" {printf(" {printf(" {printf(" {printf(" {printf(" {printf(" {printf(" {printf(" ID ");} ENTERO ");} ARCHIVO ");} LT ");} LE ");} EQ ");} NE ");} GT ");} GE ");} DESCONOCIDO ");} [A-Za-z]([A-Za-z]|[0-9])* [0-9]+ id*\.id*

*/

while (i = yylex()); } -------------------------------para compilarlo $ flex -oreconoce.c reconoce.l $ gcc reconoce.c -o reconoce -lfl para ejecutarlo $ ./reconoce < archivo_con_texto_cualquiera por ejemplo: $ ./reconoce < encuesta.html

Ejemplo 6. Escriba un programa que pueda reconocer tokens del archivo de correo proporcionado. Una solucin es: %{ /* extrae.l: Programa para extraer tokens de archivo de mails */ %} nombre tema otro li %% {nombre}[^\n]* {tema}[^\n]* "http:"[^\n]* . \n %% main() { register int i; char buffer[80]; extern char *token(); while (i = yylex()); printf("%s",yytext); } printf("%s\n",yytext); /* imprime nombre remitente */ printf("%s\n",yytext); /* imprime subject */ printf("%s\n",yytext); /* imprime apuntadores */ /* desecha todas las demas lineas */ /* desecha las lineas sin nada */ From: Subject: . (.*\n)

-------------------------------para compilarlo $ flex -oextrae.c extrae.l $ gcc extrae.c -o extrae -lfl para ejecutarlo $ ./extrae < correo | more -------------------------------TAREA 1. Escriba un programa en el formato Flex que reconosca las palabras reservadas de la siguiente gramatica de SQL. Donde INTEGER representa un entero, IDENTIFIER un identificacor definido por el usuario, REAL un numero flotante, STRING una cadena de caracteres, CHAR es un ca racter y ADD, SUB, MUL y DIV los simbolos +,-,*,/. Para probar este programa utilize el archivo hdesk_b.sql como entrada. inicio de gramatica -------------------sql_prog : module | schemaelements ; schemaelements : schemaelement | schemaelements schemaelement ; schemaelement : basetable | view | privilege ; basetable : CREATE TABLE IDENTIFIER '(' basetableelement_list ')' | CREATE TABLE IDENTIFIER '.' IDENTIFIER '(' basetableelement_list ')' ; basetableelement_list : basetableelement | basetableelement_list ',' basetableelement ; basetableelement : column | unique ;

column : IDENTIFIER type /* column - IDENTIFIER */ | IDENTIFIER type NOT _NULL /* column - IDENTIFIER */ | IDENTIFIER type NOT _NULL UNIQUE ; unique : UNIQUE '(' identifier_list ')' /* column_list - identifier_list */ ; view : CREATE VIEW IDENTIFIER '(' identifier_list ')' AS queryspec WITH N /* column_list */ | CREATE VIEW IDENTIFIER '(' identifier_list ')' AS queryspec /* column_list */ | CREATE VIEW IDENTIFIER AS queryspec WITH N | CREATE VIEW IDENTIFIER AS queryspec | CREATE VIEW IDENTIFIER '.' IDENTIFIER '(' identifier_list ')' AS ITH CHECK OPTION /* column_list */ | CREATE VIEW IDENTIFIER '.' IDENTIFIER '(' identifier_list ')' AS /* column_list */ | CREATE VIEW IDENTIFIER '.' IDENTIFIER AS ITH CHECK OPTION | CREATE VIEW IDENTIFIER '.' IDENTIFIER AS ; privilege : GRANT | GRANT | GRANT | GRANT ION ; privileges privileges privileges privileges ON ON ON ON IDENTIFIER IDENTIFIER IDENTIFIER IDENTIFIER TO grantee_list TO grantee_list WITH GRANT OPTION '.' IDENTIFIER TO grantee_list '.' IDENTIFIER TO grantee_list WITH GRANT OPT CHECK OPTIO

CHECK OPTIO queryspec W queryspec queryspec W queryspec

privileges : ALL PRIVILEGES | ALL | operation_list ; grantee_list : PUBLIC | IDENTIFIER /* user */ | grantee_list ',' PUBLIC | grantee_list ',' IDENTIFIER /* user */ ; operation_list : operation | operation_list ',' operation ; operation : SELECT | INSERT | DELETE | UPDATE | UPDATE '(' identifier_list ')' /* column_list */

; /* modules */ module : MODULE IDENTIFIER LANGUAGE language cursor procedure /* module - IDENTIFIER */ | MODULE IDENTIFIER LANGUAGE language procedure /* module - IDENTIFIER */ | MODULE LANGUAGE language cursor procedure | MODULE LANGUAGE language procedure ; language : COBOL | FORTRAN | PASCAL | PL1 ; cursor : DECLARE IDENTIFIER CURSOR FOR queryexpr orderby /* cursor - IDENTIFIER */ | DECLARE IDENTIFIER CURSOR FOR queryexpr /* cursor - IDENTIFIER */ ; orderby : ORDER BY orderspec_list ; orderspec_list : orderspec | orderspec_list ',' orderspec ; orderspec : INTEGER | INTEGER | pathvar | pathvar ; ASC DESC ASC DESC

procedure : PROCEDURE IDENTIFIER parameter_list ';' statements ';' /* procedure - IDENTI FIER */ ; parameter_list : parameter | parameter_list parameter ; parameter : IDENTIFIER type | SQLCODE ; /* statements

*/ statements : statement | statements statement ; statement : close_stmt | commit_stmt | delete_stmt | fetch_stmt | insert_stmt | open_stmt | roll_stmt | select_stmt | update_stmt ; close_stmt : CLOSE IDENTIFIER /* cursor - IDENTIFIER */ ; commit_stmt : COMMIT WORK ; delete_stmt : DELETE FROM | DELETE FROM | DELETE FROM | DELETE FROM ; IDENTIFIER WHERE CURRENT OF IDENTIFIER IDENTIFIER where IDENTIFIER '.' IDENTIFIER WHERE CURRENT OF IDENTIFIER IDENTIFIER '.' IDENTIFIER where

fetch_stmt : FETCH IDENTIFIER INTO pathvar_list /* cursor */ ; insert_stmt : INSERT INTO IDENTIFIER '(' identifier_list ')' VALUES '(' atomnull_list /* column_list */ | INSERT INTO IDENTIFIER '(' identifier_list ')' queryspec | INSERT INTO IDENTIFIER VALUES '(' atomnull_list /* column_list */ | INSERT INTO IDENTIFIER queryspec | INSERT INTO IDENTIFIER '.' IDENTIFIER '(' identifier_list ')' VALUES '(' mnull_list ')' /* column_list */ | INSERT INTO IDENTIFIER '.' IDENTIFIER '(' identifier_list ')' queryspec | INSERT INTO IDENTIFIER '.' IDENTIFIER VALUES '(' mnull_list ')' /* column_list */ | INSERT INTO IDENTIFIER '.' IDENTIFIER queryspec ; atomnull_list : atomnull | atomnull_list ',' atomnull ; atomnull : atom ')' ')' ato ato

| _NULL ; open_stmt : OPEN IDENTIFIER /* cursor - IDENTIFIER */ ; roll_stmt : ROLLBACK WORK ; select_stmt : SELECT DISTINCT selection INTO pathvar_list tableexpr | SELECT ALL selection INTO pathvar_list tableexpr | SELECT selection INTO pathvar_list tableexpr ; update_stmt : UPDATE IDENTIFIER | UPDATE IDENTIFIER | UPDATE IDENTIFIER | UPDATE IDENTIFIER FIER | UPDATE IDENTIFIER | UPDATE IDENTIFIER ; SET SET SET '.' assignment_list WHERE CURRENT OF IDENTIFIER assignment_list assignment_list where IDENTIFIER SET assignment_list WHERE CURRENT OF IDENTI

'.' IDENTIFIER SET assignment_list '.' IDENTIFIER SET assignment_list where

assignment_list : assignment | assignment_list ',' assignment ; assignment : IDENTIFIER EQ expr /* column - IDENTIFIER */ | IDENTIFIER EQ _NULL /* column - IDENTIFIER */ ; /* query expression */ queryexpr : queryspec | queryexpr UNION ALL queryexpr | queryexpr UNION queryexpr | '(' queryexpr ')' ; queryspec : SELECT DISTINCT selection tableexpr | SELECT ALL selection tableexpr | SELECT selection tableexpr ; selection : expr_list | '*' ; expr_list

: expr | expr_list ',' expr ; tableexpr : from where | from where | from where | from where | from | from | from | from ; groupby having groupby having groupby having groupby having

from : FROM table_range_list ; table_range_list : table_range | table_range_list ',' table_range ; table_range : IDENTIFIER IDENTIFIER /* range variable - IDENTIFIER */ | IDENTIFIER | IDENTIFIER '.' IDENTIFIER IDENTIFIER /* range variable - IDENTIFIER */ | IDENTIFIER '.' IDENTIFIER ; where : WHERE cond ; groupby : GROUP BY pathvar_list ; pathvar_list : pathvar | pathvar_list ',' pathvar ; having : HAVING cond ; /* search condition */ cond : pred | NOT cond | cond AND cond | cond OR cond | '(' cond ')' ;

pred : compare | between | like | null | in | allany | existence ; compare : expr | expr | expr | expr | expr | expr | expr | expr | expr | expr | expr | expr ; EQ NE LT GT LE GE EQ NE LT GT LE GE expr expr expr expr expr expr subq subq subq subq subq subq

subq : subquery | allany subquery ; allany : ALL | ANY | SOME ; between : expr NOT BETWEEN expr AND expr | expr BETWEEN expr AND expr ; like : pathvar NOT LIKE atom | pathvar NOT LIKE atom ESCAPE atom | pathvar LIKE atom | pathvar LIKE atom ESCAPE atom ; null : pathvar IS NOT _NULL | pathvar IS _NULL ; in : | | | ; expr NOT IN subquery expr NOT IN atom_list expr IN subquery expr IN atom_list

atom_list : atom | atom_list ',' atom ; existence : EXISTS subquery ; subquery : '(' SELECT DISTINCT selection tableexpr ')' | '(' SELECT ALL selection tableexpr ')' | '(' SELECT selection tableexpr ')' ; /* expression */ expr : primexpr | expr ADD | expr SUB | expr MUL | expr DIV ;

expr expr expr expr

primexpr : atom | funcref | NEG primexpr | POS primexpr | '(' expr ')' ; atom : pathvar | constant | USER ; funcref : fname | fname | fname | fname ; fname : AVG | MAX | MIN | SUM ; identifier_list : IDENTIFIER | identifier_list ',' IDENTIFIER ; '(' '*' ')' '(' DISTINCT pathvar ')' '(' ALL expr ')' '(' expr ')'

constant : INTEGER_CONST | REAL_CONST | STRING_CONST ; type : INTEGER | REAL | STRING | CHAR '(' INTEGER_CONST ')' | DECIMAL '(' INTEGER_CONST ')' ; pathvar : IDENTIFIER | pathvar '.' IDENTIFIER ;

-------------------fin gramatica