Introducción al FLEX

Asignatura: Procesadores de lenguaje 5º IINF Curso 2003-2004

Analizador morfológico
• Realiza la primera fase de reducción al axioma de la gramática • Recibe como entrada el lenguaje fuente y devuelve un vector de unidades sintácticas:
– – – – Identificador Palabra reservada Constantes numéricas y de carácter Símbolos simples y múltiples, etc.

• Elimina la información innecesaria (espacios en blanco, comentarios, etc.)

Prácticas de Procesadores de lenguaje - 2

FLEX
• El programa Flex es una herramienta para construir analizadores morfológicos a partir de un fichero de entrada de instrucciones • Las reglas de reconocimiento de unidades morfológicas tienen la estructura: [patrón] [acción] • Es capaz de modificar su reconocimiento en función del entorno mediante condiciones de arranque

Prácticas de Procesadores de lenguaje - 3

FLEX
• El analizador morfológico generado se llama mediante la función yylex() • El fichero generado se llama lex.yy.c
Código fuente: Fichero.lex FLEX Fichero C generado lex.yy.c (contiene yylex())

C:###BOT_TEXT###gt; flex Fichero.lex C:###BOT_TEXT###gt; dir lex.yy.c
Prácticas de Procesadores de lenguaje - 4

Formato del fichero LEX
• Contiene tres secciones, separadas por una línea que contiene sólo ‘%%’ Definiciones
Previas al uso del analizador Los patrones de entrada y las acciones a realizar cuando se reconocen los patrones Funciones C que se transcriben al fichero de salida lex.yy.c
Prácticas de Procesadores de lenguaje - 5

%%
Reglas

%%
Código de usuario

Formato del fichero de entrada LEX: Definiciones
Definiciones

%%
Reglas

%%
Código de usuario

Prácticas de Procesadores de lenguaje - 6

Formato del fichero de entrada LEX: Definiciones
Contiene cuatro partes: •

%{

Código de usuario Código de usuario: Se transcribe al fichero de salida #include <...
Directivas %} Controlan el comportamiento de Directivas Flex %option ... Definiciones Ayudan a definir patrones Condiciones de arranque Alteran el flujo del analizador

• •

Definiciones DIGITO [0-9] Cond. de arranque %s DEF

%%
Prácticas de Procesadores de lenguaje - 7

Formato del fichero de entrada LEX: Definiciones

Código de usuario
Ø Todo lo que va entre %{ y %} es código C que se transcribe a la cabecera del fichero yy.lex.c

ØEjemplo:

%{ #include <stdio.h> #include <math.h> #include “yy.tab.h”

Variable global por todas las funciones del fichero

#define ID 7 int valor %}
Prácticas de Procesadores de lenguaje - 8

Formato del fichero de entrada LEX: Definiciones Directivas
• Cambian la forma de trabajar de Flex • Ejemplos: %option noyywrap
Permite utilizar Flex sin definir la función yywrap, que maneja el uso de varios ficheros de entrada

%option case-insensitive
El analizador funcionará igual para mayúsculas que minúsculas

%option yylineno
Permite manejar la función yylineno, que almacena el número de línea en que se encuentra

Prácticas de Procesadores de lenguaje - 9

Formato del fichero de entrada LEX: Definiciones

Definiciones
Ø Permiten considerar y nombrar patrones complejos Ø En la sección de reglas se puede hacer uso de estas definiciones mediante su nombre Ø Permiten anidamiento Ø Ejemplos:
ENTERO -?[0-9]+ REAL {ENTERO}\.{ENTERO}

Prácticas de Procesadores de lenguaje - 10

Formato del fichero de entrada LEX: Definiciones Condiciones de arranque
Ø Permiten cambiar el flujo del scanner en distintas circunstancias Ø Existen condiciones de arranque no exclusivas (%s) y exclusivas, que generan entorno especial (%x) Ejemplo: %s DECLARACION, INITIAL %x COMENTARIO

Ø Permiten que una regla se considere únicamente cuando la condición actual coincide con la de dicha regla Ejemplo: <COMENTARIO>[^ ]+\n {;}

Ø La macro BEGIN permite cambiar la condición actual dentro de la acción de una regla Ejemplo: <COMENTARIO>[^ ]+\n {BEGIN INITIAL;}
Prácticas de Procesadores de lenguaje - 11

Formato del fichero de entrada LEX: Reglas
Definiciones

%%
Reglas

%%
Código de usuario

Prácticas de Procesadores de lenguaje - 12

Formato del fichero de entrada LEX: Reglas
• Tienen formato PATRÓN V ACCIÓN [a-z] {return LETRA;} • Los patrones admiten definiciones, expresiones regulares • Las acciones son código C (salvo la palabra clave BEGIN y ECHO) rodeado de llaves. Pueden ocupar varias líneas. • El texto reconocido que concuerda con el patrón está almacenado en la variable yytext
Ejemplo: [0-9]+ {valor = atoi(yytext);}

Prácticas de Procesadores de lenguaje - 13

Formato del fichero de entrada LEX: Reglas - Patrones
Literal Rango Rango negación Numeración ‘x’ [ac-egP-R3-5] [^A-Z] ‘r*’ ‘r+’ ‘r?’ ‘r{2,5}’ Localización Cond. de arranque Fin de fichero Conj. predefinidos ‘^r’ ‘r$’ <s1,s2>r <<EOF>> [:digit:] Equivalente a [0-9] Lo que aparezca El contenido de nombre Uno de a,c,d,e,g,P,Q,R,3,4,5 Cualquiera excepto mayúsc. Cero o más copias de r Una o más copias de r Cero o una copias de r De dos a cinco copias de r r al principio de línea r al final de línea r si Cond. de Arr. s1 ó s2 Expansión definición {nombre}

Prácticas de Procesadores de lenguaje - 14

Manejo del Flex: identificación de patrones
• Flex busca en la entrada el grupo más grande de caracteres que puede identificar con alguno de los patrones definidos Ejemplo: con la entrada abc y el grupo de reglas a {return 1;} ab {return 2;} c {return 3;} Devuelve el valor 4 abc {return 4;} • Si hay dos patrones que identifican el mismo número máximo de caracteres de la entrada, tiene preferencia la regla anterior dentro del fichero de entrada • Si la regla comienza con una condición de arranque sólo se activará si el escáner está en esa condición
Prácticas de Procesadores de lenguaje - 15

Manejo del Flex: Acciones
• Comienza a partir del primer espacio en blanco después del patrón • Son instrucciones en código C • Es aconsejable rodearlas siempre de llaves. Si no, ejecutará sólo la primera de las instrucciones C • La acción especial ‘|’ quiere decir “para esta regla ejecuta la misma acción que en la siguiente” Ejemplo: a | b {return 1}; • Disponibles la variable yytext, con el texto reconocido del patrón, y la variable yyleng, con su longitud • La acción BEGIN (condición de arranque) hace comenzar la condición de arranque especificada • ECHO copia lo reconocido a la salida estándar
Prácticas de Procesadores de lenguaje - 16

Manejo del Flex: Ejemplos de aplicación C.A. 7n , \ REM 2 HOLA Initial Pares COM

par

7 2

%s PARES,INITIAL %x COM %% <INITIAL>[0-9] {BEGIN(PARES);par[0]=atoi(yytext);} <PARES>[0-9] {BEGIN(INITIAL);par[1]=atoi(yytext); return 0;} <PARES>”,” {;} <PARES> [.\n] {return ERROR;} REM {BEGIN(COM);} <COM>. {;} <COM>\n {BEGIN(INITIAL);} \n {;} . {printf(“no entiendo %s”,yytext, return ERROR);
Prácticas de Procesadores de lenguaje - 17

Formato del fichero LEX: Código de usuario
Definiciones

%%
Reglas

%%
Código de usuario

Prácticas de Procesadores de lenguaje - 18

Formato del fichero LEX: Código de usuario
• Código C que FLEX copia directamente en el fichero fuente

lex.yy.c
• Normalmente contiene funciones C de soporte como, por ejemplo, la función main(), funciones que son llamadas por las reglas, rutinas de manejo de la tabla de símbolos, etc. • Ejemplo: %% int main() {
yylex();

} • Si el código es largo, conviene fragmentarlo en distintos ficheros C cuyas cabeceras se incluyen mediante %include en la sección de definiciones
Prácticas de Procesadores de lenguaje - 19

Ejemplo I: fichero LEX para construir un programa que cuenta palabras de un fichero
%{ int contador_caracteres=0, contador _palabras=0, contador _lineas=0; %} word eol \n

Definiciones
[^ \t\n]+

%% {word} {contador_ palabras++; contador_ caracteres += yyleng;} {eol} {contador_ caracteres++; contador_lineas++;} . {contador_ caracteres++;} %% main(int argc, char ** argv) { FILE *file; file=fopen(argv[1],”r”); if (file==NULL) exit(1); yyin=file; yylex(); printf(“%d %d %d\n”, contador_lineas, contador_palabras, contador_caracteres); }

Reglas

Código de usuario

Prácticas de Procesadores de lenguaje - 20

Ejemplo I: construcción y ejecución del programa que cuenta palabras de un fichero
• Paso 1: construcción del analizador morfológico a partir del fichero LEX C:###BOT_TEXT###gt; flex cont_word.lex • Paso 2: compilación del fichero .c resultante C:###BOT_TEXT###gt; gcc lex.yy.c libfl.a –o cont_word.exe • Paso 3: ejecución del programa C:###BOT_TEXT###gt; cont_word fichero_ejemplo.txt C:###BOT_TEXT###gt; 20 70 450

Prácticas de Procesadores de lenguaje - 21

Ejemplo II: Calculadora aritmética - Definiciones
%{ #include <stdio.h> #define OPERAR 2 int valor1,valor2; char operacion; %} ENTERO -?[0-9]+ %s op %%

Variables globales

Definición del tipo básico aritmético

Condición de arranque que permite manejar parejas de operadores

Prácticas de Procesadores de lenguaje - 22

Ejemplo II: Calculadora aritmética - Reglas
Estas reglas esperan un entero y lo asigna a valor1, después un operador y después otro entero que asigna a valor2. Cualquier otra cosa da error
%% [ \t\n] ; Se desprecian los blancos y los cambios de línea <INITIAL>{ENTERO} {BEGIN(op);valor1=atoi(yytext);} <op> {operacion='+';printf("operacion = [%c] ",operacion);} <op>\- {operacion='-';} <op>\* {operacion='*';} <op>{ENTERO} {BEGIN(INITIAL);valor2=atoi(yytext); return OPERAR;}

.

{printf("no entiendo %s\n",yytext);}

<<EOF>> {return 0;} %%

Sólo se admiten caracteres que permitan operar
Prácticas de Procesadores de lenguaje - 23

Ejemplo II: Calculadora aritmética - Código de usuario
%% int main(){ int leido,resultado; yyin=stdin; do{ leido=yylex(); if(leido==0)return(0); Fin de fichero else if(leido!=OPERAR) printf("ERROR\n"); else OPERAR significa que ha switch(operacion){ completado la tripleta valor1, case '+': valor2 y operacion resultado=valor1+valor2; break; case '-': resultado=valor1-valor2; Efectúa la break; operación pedida case '*': resultado=valor1*valor2; } printf("%d %c %d = %d\n",valor1,operacion,valor2,resultado); }while(1); Lo saca por pantalla }
Prácticas de Procesadores de lenguaje - 24

Ejemplo II: Mejoras de la calculadora
• Agregar funciones matemáticas de un parámetro.
– Posiblemente añadiendo otro estado inicial cuando se reconoce la palabra clave (p. ej. seno), y esperando después un parámetro de tipo entero (o, mejor aún, real)

• Posibilidad de utilizar paréntesis
– En número finito y determinado , hay que abrir procesos que luego se resuelven al encontrar el cierre de paréntesis – Se podría combinar con la mejora anterior

• Posibilidad de utilizar variables como memoria
– Al menos una, llamada M, que permite guardar algo en memoria – O más, por ejemplo cuatro, A, B, C, D a las que se puede asignar valores mediante la sentencia de asignación, y luego recuperarlos al escribir la letra
Prácticas de Procesadores de lenguaje - 25

Bibliografía
• Manual del Flex en español

http://lucas.hispalinux.es/ManualesLuCAS/FLEX/flex-es-2.5.pdf (*)
• Lex - A Lexical Analyzer Generator, M. E. Lesk y E. Schmidt (http://www.combo.org/lex_yacc_page/lex.html) (*) • A Compact Guide to Lex & Yacc , Thomas Niemann. (http://epaperpress.com/lexandyacc/) (*) • lex & yacc, Levine, Mason and Brown. O'Reilly & Associates. 1992. • Procesadores de lenguaje. Apuntes de 5º de IINF. Mª Luisa Tavera Otero, 2002-2003 • Compiladores: Principios, Técnicas y Herramientas, Alfred Aho, Ravi Sethi y Jeffrey Ullman. Addison-Wesley Iberoamericana, S.A. (1990).
Prácticas de Procesadores de lenguaje - 26