You are on page 1of 12

Compiladores I Prctica 0

Introduccin a Flex y Bison http://webdiis.unizar.es/~rbejar/COMPI/

Rubn Bjar Hernndez Dpto. Informtica e Ingeniera de Sistemas Universidad de Zaragoza

Requisitos: Haberse ledo la introduccin a Flex y Bison que est en la pgina Web de la asignatura (aunque no es necesario mirar la parte de condiciones de arranque de Flex ni la parte de semntica, precedencia de operadores ni la seccin sobre la coleccin de tipos de valores de la parte de Bison). Tambin es conveniente mirar algo de documentacin sobre Make. En la web de la asignatura tenis enlaces a un tutorial y a la documentacin.

Flex y Bison en merlin.unizar.es


Las prcticas se realizarn sobre merlin.unizar.es. En esta mquina los ejecutables correspondientes a Flex y Bison estn en /opt/flex/bin y /opt/bison/bin. Es aconsejable que aadis la siguiente lnea al fichero .profile de vuestra cuenta, si no est ya, para no tener que teclear todo el path a estos ficheros para ejecutarlos (despus podis salir de la cuenta y volver a entrar para que el shell relea el fichero .profile): PATH=$PATH:/opt/flex/bin:/opt/bison/bin Tambin deberis indicar al compilador de C donde est la librera de flex (fl, que est en /opt/flex/lib) al compilar, con una lnea similar a esta: gcc lex.yy.c lfl L/opt/flex/lib o nombre_ejecutable

Uso de Make
A continuacin se muestra un fichero Make, muy bsico, para compilar un fichero de Flex que se llame p0.l
p0: lex.yy.c gcc lex.yy.c lfl L/opt/flex/lib -o p0 lex.yy.c: p0.l flex p0.l

Si llamamos a este Makefile p0_Makefile, por ejemplo, la siguiente lnea de comandos generar el fichero ejecutable p0:
$make f p0_Makefile

En las prcticas de Compiladores I es necesario entregar un Makefile correcto con cada prctica. Tenis un ejemplo ms completo de Makefile en
/users2/COMPI/salidas/ejemploMake

Equivalencia de la notacin de teora y la de Flex


El alfabeto que maneja Flex es el compuesto por los caracteres manejables por el sistema, p.ej., todos los smbolos del cdigo ASCII. En las prcticas trabajaremos con letras (las maysculas y las minsculas son distintos smbolos del alfabeto), nmeros y signos de puntuacin. Algunas equivalencias entre la notacin de teora de lenguajes regulares que usamos y la de Flex se muestran en la siguiente tabla:
2

Teora (concatenacin de e.r., aunque generalmente no ponemos nada) | (unin de e.r.) * (cerradura de Kleene) + (cerradura positiva) ( ) (parntesis) {a,b,c,d,0,1,2} (conjunto formado por los smbolos a,b,c,d,0,1 y 2) |a

Flex No hay smbolo. Las e.r. a concatenar se escriben pegadas como en la notacin de teora. | * + () [abcd012] o tambin [a-d0-2] a? El smbolo a, cero o una veces. No hay equivalente directo en Flex. Para usarlo como parte de una expresin, se usan los smbolos * ? que permiten repetir algo cero veces (ver lnea anterior).

Ejercicio 1 Tutorial de Flex


Vamos a disear un programa con Flex que elimine los caracteres blancos del final de cada lnea del texto de entrada y reduzca a un solo blanco cualquier grupo de blancos del interior de cada lnea (se entiende por blanco el espacio en blanco y el carcter de tabulacin). Ejemplo de entrada:
Este es con varios <EOF> un texto blancos <EOL> <EOL>

Salida:
Este es un texto<EOL> con varios blancos<EOF>

Los fuentes Flex tienen el siguiente formato:


%% patrn1 {accin1} patrn2 {accin2} ...

Donde los patrones son expresiones regulares en formato Flex y las acciones son el cdigo C que se ejecuta cuando Flex encuentra concordancia entre algn patrn y el texto que se le presente. El siguiente fichero Flex resolver el ejercicio. Creadlo y llamadlo ej1.l
%% [\t ]+$ ; /* Blancos a final de linea */ [\t ]+ { printf(" "); /* Grupos de blancos*/ }

El siguiente fuente de Make lo compilar y crear el ejecutable ej1. Llamadlo p0_ej1_Makefile.

ej1: lex.yy.c gcc lex.yy.c lfl L/opt/flex/lib -o ej1 lex.yy.c: ej1.l flex ej1.l

Notad que el Makefile indica que hay que invocar a Flex para convertir ej1.l en un fichero C (lex.yy.c) y luego llamar al compilador gcc para generar el ejecutable ej1. La siguiente lnea genera el ejecutable:
$make f p0_ej1_Makefile

Podis ejecutar el fichero ej1:


$./ej1 _

El cursor parpadea esperando que escribis el texto de entrada. Si escribs por ejemplo ___a____b_____ (sustituyendo los guiones por espacios) y pulsis <Entrar>:
$./ej1 a b a b

El programa sustituye los grupos de espacios por uno solo y elimina los de final de lnea (esto ltimo no se ve; podis modificar el fuente para que en lugar de espacios busque y sustituya guiones para poder comprobarlo mejor). Esta forma de trabajar no es muy cmoda, porque hay que escribir el texto de entrada lnea a lnea. Una solucin es crear un fichero de texto con la entrada y pasrselo al ejecutable. Si por ejemplo hemos creado un fichero llamado entrada.txt, esta lnea de comandos lo procesar completo y escribir la salida por pantalla:
$./ej1 < entrada.txt

Ejercicio 2 - Flex
Elaborar un programa en Flex que copie el archivo de entrada en uno de salida, sustituyendo todo numero entero positivo que sea mltiplo de 7 por el carcter *. Para ello se sugiere construir una e.r. que lea nmeros en decimal, y despus en la accin asociada en Flex comprobar si stos son mltiplos de 7.

Ejercicio 3 - Flex
Elaborar un programa en Flex que cuente el nmero de palabras del texto de entrada que contengan alguna vez la letra w. Cmo sera la e.r.? Y como sera si nos piden las palabras que contengan slo una w?

Ejercicio 4 - Flex
Elaborar un programa en Flex que dada una secuencia de entrada, realice lo siguiente para cada uno de los casos:

Informar del nmero de caracteres, de palabras y de lneas de texto. Reconocer todos los nmeros enteros y calcular e informar de la media de los mismos. Reconocer todos los nmeros reales e informar cuntos de ellos estn comprendidos en el rango entre cero y uno. La principal dificultad de este ejercicio, est en notar que los nmeros son tambin palabras, y adems estn compuestos por caracteres, sin embargo un carcter del fichero de entrada en Flex slo se puede emparejar con, como mucho, un patrn (una e.r.).

Ejercicio 5 - Flex
Elaborar un programa con Flex que dado un fichero de texto, verifique que siempre que se abre un parntesis, se cierra. Si detecta algn error, informar de la lnea donde se produce dicho error. Este ejercicio tiene una dificultad: Es el lenguaje de las palabras sobre el alfabeto {(,)} que son pares de parntesis correctamente anidados regular? Podis demostrarlo? Si no es regular, podemos hacer algo?

Ejercicio 6 Tutorial de Bison


Bison es una herramienta de gran potencia que, en uso conjunto con Flex, permite construir compiladores. Un fichero fuente Bison describe una gramtica libre de contexto. El ejecutable correspondiente nos dice si una entrada textual corresponde o no al lenguaje generado por la gramtica. Es importante notar la diferencia con Flex: en este caso se toma la entrada como una nica palabra para la que hay que ver si est o no en el lenguaje que genera la gramtica. Un fichero fuente Bison es de la forma: %token 1 2 3 ... n %start %% 1; 2; ... k; Donde {1 2 3 ... n} es el alfabeto (conjunto de terminales de la gramtica), es el smbolo inicial (no terminal de la gramtica), y 1... k son las reglas o producciones de la gramtica. Los smbolos terminales se denominan en Bison tokens. Cada regla (produccin) se escribe de la forma: X1: X2 ... Xj; (dos puntos en lugar de la flecha, y termina en punto y coma) donde X1 es una variable (no terminal) y X2 ... Xj son variables (no terminales) y tokens (terminales). No es necesario declarar las variables de la gramtica (conjunto de no terminales de la gramtica), ya que todo lo que no sean tokens (que si se declaran) se consideran variables.

Supongamos que queremos reconocer las palabras del lenguaje formado por las expresiones enteras con parntesis que utilizan + y * (por ejemplo 4, 4 + 2,(4 + 3) * 5 etc.) : Para ello podramos crear una gramtica libre de contexto muy sencilla: ST|T+T|T*T T ENTERO | ( S ) Que traducida a un fuente bsico de Bison sera:
%token PARIZ PARD MAS POR INTEGER %start S %% S: T | T MAS T | T POR T ; T: INTEGER | PARIZ S PARD ;

Pero adems, necesitaramos un fichero fuente de Flex (fuente.l) que lea la entrada estndar y reconozca las ocurrencias de los diferentes tokens de nuestra gramtica, es decir:
%{ #include "y.tab.h" /* GENERADO AUTOMTICAMENTE POR BISON */ %} %% [\-]?[0-9]+ return(INTEGER); \+ \* \( \) \n [ \t] return(MAS); return(POR); return(PARIZ); return(PARD); return(0); {/* ignorar blancos y tabuladores */}

Aadimos algunas definiciones de funciones necesarias al fuente de Bison (fuente.y) , que quedara como sigue:

%token PARIZ PARD MAS POR INTEGER %start S %% S: T | T MAS T | T POR T ; T: INTEGER | PARIZ S PARD ;

%% int yyerror(char* s) { printf("\n%s\n", s); return 0; } main() { yyparse(); }

y compilamos (ojo con el orden):


bison -yd fuente.y flex fuente.l (esto genera y.tab.c e y.tab.h) (esto genera lex.yy.c)

gcc y.tab.c lex.yy.c -lfl -L/opt/flex/lib -o ej6

ej6 contiene ahora un ejecutable que reconoce todas las expresiones enteras bien escritas. Este ejecutable puedes utilizarlo desde teclado como desde un fichero (redirigiendo la entrada, igual que se hace con Flex cuando est solo). Si la entrada es una palabra del lenguaje, no da ninguna salida. Si la entrada no est en el lenguaje, el resultado ser parse error. El siguiente fichero Makefile nos facilitar la compilacin:
LEX=flex YACC=bison CC=gcc ej6: y.tab.o lex.yy.o $(CC) -o ej6 y.tab.o lex.yy.o -ly -lfl -L/opt/flex/lib lex.yy.o: lex.yy.c y.tab.h $(CC) -c lex.yy.c y.tab.o: y.tab.c $(CC) -c y.tab.c y.tab.c y.tab.h: ej6.y $(YACC) -yd ej6.y lex.yy.c: ej6.l y.tab.h $(LEX) ej6.l

Ejercicio 7 Flex/Bison
Utilizad Bison para generar ejecutables que reconozcan los siguientes lenguajes. Esto quiere decir que para las palabras del lenguaje la salida debe ser vaca y para las que no pertenecen al lenguaje parse error. 1) L = { ai bj cj di | i,j 1 }
7

2) L = { 0m 1n | m > n 0 } Nota: cuidado con el nombre que le dais a los tokens en Bison. Si los llamis a, b, c etc., se producen colisiones con algunas variables internas de Flex. Es mejor que los llamis de forma algo ms complicada como t_a, t_b etc.

Ejercicio 8 Flex/Bison y XML


XML es un estndar para la creacin de documentos de texto con una estructura bien definida. Aunque originalmente pensado sobre todo como un formato de intercambio de datos entre plataformas, en la actualidad su uso se ha extendido, y se utiliza como formato nativo para los ficheros en muchas aplicaciones, para la descripcin de servicios Web, como formato de almacenamiento en algunas bases datos, etc. El estndar es accesible desde http://www.w3.org/XML/. En este ejercicio vamos a disear un analizador, bastante limitado, de ficheros XML utilizando Flex y Bison. Nuestro analizador va a limitarse a una parte del aspecto lxico/sintctico del reconocimiento de documentos XML.

Estructura de documentos XML


Los documentos XML tienen una estructura definida con elementos delimitados mediante etiquetas y anidados de una forma apropiada. Las etiquetas XML son, bsicamente, un texto entre los smbolos < y >. En XML se distinguen maysculas de minsculas, as que <ETIQUETA> y <etiqueta> son etiquetas diferentes. Hay etiquetas de apertura y etiquetas de cierre.
<ETIQUETA>Contenido de etiqueta</ETIQUETA>

Puede haber etiquetas que aparezcan sin etiqueta de cierre, pero es obligatorio que stas lleven una barra (/) al final (se les llama elementos vacos):
<ETIQUETA/>

Los elementos pueden tener atributos en sus etiquetas de apertura (o en su nica etiqueta si son elementos vacos). Los atributos tienen valores que deben ir entre comillas, ya sean dobles o simples. Si hay varios atributos, tienen que ir separados por al menos un espacio (o tabulador, fin de lnea...).
<ETIQUETA ATRIBUTO = "Valor" ATRIBUTO2 = Valor2>

Los comentarios se escriben as (pueden ocupar las lneas que se quiera):


<!-- Esto es un comentario en XML -->

XML bien formado


XML tiene una serie de reglas para la construccin de documentos bien formados. Un documento XML bien formado puede tener las etiquetas que queramos, pero debe cumplir con unas reglas sintcticas determinadas:

Los documentos XML deberan empezar con una declaracin de XML que especifique la versin del estndar que cumple el documento (esta declaracin puede llevar otros atributos, pero son opcionales):
<?xml version="1.0"?>

El documento debe tener un elemento raz (y slo uno) que englobe a todos los dems entre una etiqueta de apertura y una de cierre. Los elementos englobados por otro se llaman sub-elementos de ste, o sus hijos. Todas las etiquetas de apertura deben tener su correspondiente etiqueta de cierra para los elementos que contengan a otros, o que contengan datos. Si aparece una etiqueta sola, debe tener una barra (/) al final de su texto (se llama elemento vaco). Entre dos etiquetas puede haber nada, espacios, texto y/o otras etiquetas. No pueden aparecer dentro del texto de un elemento (entre otros):
< (en su lugar poner &lt; )

Los elementos deben anidarse correctamente. Es decir, la etiqueta de cierre de un elemento hijo de otro, debe aparecer antes que la etiqueta de cierre de su elemento padre. Si aparecen atributos en algn elemento tienen que tener un valor, y ste debe ir entre comillas (dobles o simples).

Un ejemplo de documento XML bien formado:


<?xml version="1.0" encoding="ISO-8859-1"?> <Biblioteca> <Libro> La catalogacin de este libro se ha llevado a cabo a partir de informacin histrica recopilada de varias fuentes <Ttulo> El ingenioso hidalgo Don Quijote de la Mancha </Ttulo> <Autor> <Nombre tipo = "Nombre"> Miguel de Cervantes </Nombre> <Nombre tipo = "Apodo"> El Manco de Lepanto </Nombre> </Autor> <Novela tipoNovela = "Caballeras"/> </Libro> <Libro> <Ttulo> Introduccin a la Teora de Autmatas, Lenguajes y Computacin </Ttulo> <Autor> <Nombre tipo = "nombre"> John E. Hopcroft </Nombre> </Autor>

<LibroTexto clasificacin = "Informtica Terica"/> </Libro> </Biblioteca>

XML vlido
Un documento XML vlido es aquel que adems de bien formado, es conforme a cierta estructura previamente establecida. Esta estructura se especifica en forma de definicin de tipo de documento (DTD) o mediante un esquema (Schema) que es el mtodo ms reciente y ms potente. Un DTD o un esquema son fundamentalmente, una gramtica que especifica qu elementos pueden/deben aparecer en un documento XML y como deben estar estructurados (los esquemas son ms potentes y permiten definir con mucha precisin tipos de datos vlidos en los elementos y atributos, cardinalidades complejas etc.). En esta prctica no entraremos para nada en la validez de documentos XML.

Lectura de XML con Flex


A continuacin se proporciona un esqueleto del documento Flex que se usar para el anlisis de ficheros XML. Se indica qu patrones hay que reconocer, y se proporciona un ejemplo comentado. La primera tarea ser completarlo:
%{ #include "y.tab.h" %} ... DEFINICIONES ... %% {OPEN_TAG} {return openTag; /* "<HOLA a='45'>" */} {CLOSE_TAG} {return closeTag; /* "</HOLA>" */} {EMPTY_TAG} {return emptyTag; /* "<HOLA A='12'/>" */} {INSTR} {return instr; /* "<?XML version="1.0"?>" */} {COMMENT} {/*LOS IGNORO*/ /* "<!-- COM -->" */} {SPACES} {/*LOS IGNORO*/ /* " /n /t" */} {CDATA} {return cData; /* "Texto =3,&vale casi todo. \t\n" */} . {return badCar; /* "<"*/}

Notas: Esta no es, ni mucho menos, la nica o la mejor manera de analizar la entrada. Slo es una que funciona razonablemente, es bastante completa y no es muy compleja. Los identificadores de etiqueta son parecidos a los de un lenguaje de programacin tpico, pero admiten expresamente cosas como dos puntos (:). Si una etiqueta admite atributos y lleva varios, deben estar separados por espacios. Ignoramos comentarios y espacios, salvo los que van entre los atributos que los trataremos dentro de la e.r. de la etiqueta que sea, dado que en general podemos organizar las etiquetas en un documento con margen para usar tabulaciones, espacios y fines de lnea para indentarlo, y los comentarios los podemos poner ms o menos donde queramos. La e.r. CDATA se emparejarn con el texto libre que podemos escribir entre etiquetas. Se admite casi cualquier carcter (incluyendo espacios, saltos de lnea,

10

Tratamos de forma distinta espacios y CDATA (que puede llevarlos), porque CDATA debe aparecer en nuestra gramtica, hay sitios donde es aceptable y sitios donde no, y los espacios, en general y salvo entre atributos, podremos ignorarlos y no devolvrselos a Bison, lo que facilita bastante la tarea. Devolvemos especficamente un token cuando encontremos un carcter que no se ha emparejado antes, porque casi con seguridad ser un error del fichero XML y de esta forma es ms sencillo que Bison lo detecte (aunque el token no aparecer en ningn sitio en la gramtica de Bison).

Anlisis sintctico con Bison


Hay que construir una gramtica en Bison que acepte ficheros bien formados XML. Los tokens sern lo que devuelve Flex (estn en el esqueleto que se os da). Notas: En general queremos aceptar ficheros XML de la siguiente forma: INSTR OPEN_TAG RESTO DEL DOCUMENTO (CDATA, ELEMENTOS ANIDADOS, ELEMENTOS VACIOS...) CLOSE_TAG Es decir: requerimos que el documento empiece con una instruccin xml, exigimos que tenga una sola etiqueta de primer nivel (que englobe a todas las dems), y despus permitiremos que tenga cualquier contenido aceptable: CDATA y elementos correctamente anidados. Atencin: no podemos comprobar si la etiqueta de inicio corresponde con la de cierre sin entrar en aspectos ms complejos de Bison, as que aceptaremos como buenos documentos incorrectos como este: <?xml version="1.0"?> <simple> </tonto> Para hacer trazas en Bison, podis utilizar acciones en las reglas. Aunque estas acciones sirven para muchas ms cosas, como depurador os puede servir para localizar problemas en vuestra gramtica. Por ejemplo:
S: {printf(Entra en ELEMENTOS\n);} ELEMENTOS {printf(Entra en FIN\n);} FIN ;

Esto escribir por pantalla una traza del anlisis de la gramtica.

Pruebas
En el directorio /users2/LGA/salidas/pract4 tenis varios ficheros XML que podis usar para hacer pruebas: bueno1.xml hasta bueno4.xml son ficheros de tamao y complejidad creciente que vuestro analizador deber considerar como correctos (y que efectivamente son ficheros XML bien formados, el ltimo de ellos un ejemplo real, mnimamente simplificado, de la descripcin de un servicio web). fallo1.xml hasta fallo6.xlm son ficheros con distintos errores (slo un error en cada fichero) que vuestro analizador deber considerar como incorrectos (y que

11

problema1.xml ilustra el principal problema que tiene el analizador, y es que el fichero es incorrecto (la etiqueta de apertura y de cierre son distintas) pero el analizador lo considerar correcto al no poder tener en cuenta cual es el nombre de las etiquetas.

12

You might also like