13
PONTIFICIA UIVERSIDAD CATÓLICA DEL ECUADOR SEDE IBARRA 1. DATOS INFORMATIVOS 1.1 Nombre: Luis Viteri 1.2 Carrera: Sistemas 1.3 Nivel: 5to 1.4 Tema: Compiladores 1.5 Fecha: 24/07/15 2. DESCRIPCION 1) Herramientas para la construcción de procesadores de lenguaje. A continuación se muestran algunas de las herramientas disponibles que pueden utilizarse para la construcción de Procesadores de Lenguaje.

Flex y bison

Embed Size (px)

Citation preview

PONTIFICIA UIVERSIDAD CATÓLICA DEL ECUADOR

SEDE IBARRA

1. DATOS INFORMATIVOS

1.1 Nombre: Luis Viteri

1.2 Carrera: Sistemas

1.3 Nivel: 5to

1.4 Tema: Compiladores

1.5 Fecha: 24/07/15

2. DESCRIPCION

1) Herramientas para la construcción de procesadores de lenguaje.

A continuación se muestran algunas de las herramientas disponibles que pueden utilizarse para la

construcción de Procesadores de Lenguaje.

Aplicación de los lenguajes:

2) Reseña Histórica

1940’s:

– Primeros ordenadores.

– Programación directa en código máquina.

– Nace el ensamblador (traducido manualmente)

– Se automatiza la etapa de ensamblado

1950’s

– (1950) John Backus dirige en IBM un proyecto de lenguaje algebraico

– (1954-1958) Nace el FORTRAN (FORmulae TRANslator)

– Primer compilador de FORTRAN para IBM modelo 704

1950’s (finales):

– F.L. Bauer (Univ. Munich) dirige un proyecto de lenguaje formal

– Se crea un comité conjunto con la Association for Computing Machinery en el que participa

Backus

– Se define IAL (International Algebraic Language)

– Posteriormente se denomina ALGOL 58 (ALGOrithmic Language)

Características de ALGOL 58

– Definición de la notación BNF (Backus-Naur Form)

– Declaración de tipos de variables

– Estructura modular

– Funciones recursivas

– Paso de parámetros por valor o por nombre

– Precursor de Pascal, Ada o Modula

1970’s:

– Se estudian las gramáticas LR

– Se definen los métodos de análisis ascendente SLR y LALR

– Se crean numerosas herramientas de ayuda al diseño de compiladores

– A mediados de la década aparecen las herramientas lex y yacc que se convierten en

estándares de facto al distribuirse con UNIX.

– La Free Software Fundation distribuye estas herramientas bajo los nombres de flex y bison

Generación de código:

– Inicialmente la gestión de la memoria era estática

– Cuando aparecen las funciones recursivas se desarrolla la pila como forma de gestionar

la memoria

– La gestión de memoria dinámica conduce a la definición del montículo (heap) como zona

de gestión de esta memoria

– Surgen nuevos problemas como las referencias pérdidas o la recogida de basura

Últimos avances:

– Optimización de código

– Máquinas virtuales y auge de los lenguajes interpretados

3) Diseño y construcción de un compilador

Análisis léxico

Objetivo:

– Leer caracteres e identificar componentes léxicos (tokens)

– Filtrar comentarios

– Detectar errores léxicos

Ejemplo:

Análisis Sintáctico

Objetivo:

– Verificar estructuras gramaticales

– Detectar errores de sintaxis

Especificación:

– Gramáticas libres de contexto

Ejemplo:

Análisis Semántico

Objetivo:

– Verificar restricciones semánticas (predefinición de variables, consistencia de tipos,

llamadas a funciones)

– Generar un Árbol de Sintaxis Abstracta

Especificación:

– Gramáticas atribuidas

Ejemplo:

Las herramientas Flex y Bison

4) Que es flex y Bison

Flex es un una herramienta que permite generar analizadores léxicos. A partir de un conjunto de

expresiones regulares, Flex busca concordancias en un fichero de entrada y ejecuta acciones

asociadas a estas expresiones. Es compatible casi al 100% con Lex, una herramienta clásica de

Unix para la generación de analizadores léxicos, pero es un desarrollo diferente realizado por GNU

bajo licencia GPL.

Bison es un generador de analizadores sintácticos de propósito general que convierte una

descripción para una gramática independiente del contexto (en realidad de una subclase de éstas,

las LALR) en un programa en C que analiza esa gramática. Es compatible al 100% con Yacc, una

herramienta clásica de Unix para la generación de analizadores léxicos, pero es un desarrollo

diferente realizado por GNU bajo licencia GPL. Todas la gramáticas escritas apropiadamente para

Yacc deberían funcionar con Bison sin ningún cambio. Usándolo junto a Flex esta herramienta

permite construir compiladores de lenguajes.

5) Como se instala Flex y Bison

1) Es necesario obtener el software descargando la versión que necesitamos de las

páginas oficiales

http://gnuwin32.sourceforge.net/packages/flex.htm

2) Instalar el software en la unidad C: (para explicar a partir del punto 4 se tendrá como

hecho que flex y bison han sido instalados en la ruta: C:\GnuWin32\ donde contiene una

subcarpeta llamada bin donde se encuentran los programas respectivos)

3) Flex y bison son aplicaciones de consola, por lo que se deberá entrar al Símbolo del

sistema y tipear líneas de comando para ejecutar Flex.

4) 4. Si deseas que flex y bison se integren al conjunto de variables del entorno (esto te va

a permitir llamar a flex/bison desde cualquier ubicación en la línea de comandos) debes

hacer lo siguiente:

a. Clic derecho en “Mi PC”.

b. Selecciona “Propiedades”

c. Clic en la pestaña “Opciones Avanzadas”

d. Presiona el botón “Variables de entorno”

e. En la ventana de variables de entorno, ubicarse en la sección “Variables del

sistema”

f. luego haz clic en PATH y luego en el botón “Modificar” (si no está hacer clic en

“Nueva” y agregar PATH)

g. En la nueva ventana, escribir la ruta completa al directorio “bin” de la aplicación

flex/bison. Si existe otro valor, separarlos con comas.

h. Aceptar los cambios y luego reiniciar el sistema operativo.

6) Como se compila con Flex y Bison

Luego de escribir las especificaciones de flex y bison realizar lo siguiente.

Si se desea invocar a flex:

o Por ejemplo, si se tiene un archivo de especificación de Flex llamado prueba.l dentro

de una carpeta “archivos” tipear lo siguiente C:\archivos>flex prueba.l

o Luego presionar ENTER

o Se habrá generado un archivo de nombre lex.yy.c dentro de la carpeta donde se

encuentra el archivo prueba.l

Para invocar a Bison en conjunción con flex realizar lo siguiente:

o Por ejemplo, si se tiene un archivo de especificación de Bison y Flex llamado

prueba.y y prueba.l respectivamente dentro de una carpeta “archivos” tipear lo

siguiente

o C:\archivos>bison –d prueba.y

o C:\archivos>flex prueba.l

o Luego al presionar ENTER se generarán tres archivos para su posteriorcompilación:

prueba.tab.h, prueba.tab.c y lex.yy.c.

Para compilar los archivos generados.

Luego de haber generado los archivos .c tipear lo siguiente:

C:\gcc –o pruebaej lex.yy.c

Con esto generará se un archivo llamado “pruebaej.exe”

El argumento –o permite crear el archivo ejecutable

7) 2 Ejemplos de la creación de un compilador utilizando Flex y Bison.

Ejemplo1:

Vamos a realizar un ejemplo de una calculadora sencilla que reconocerá las principales operaciones aritmética (+,-,* y /). Abrimos un editor de texto y pegamos el siguiente código que será nuestro scanner /***************** Definiciones Se colocan las cabeceras, variables y expresiones regulares ********************/ %{ #include <stdio.h> #include <stdlib.h> #include "sintactico.tab.h" int linea=0; %} /* Creamos todas las expresiones regulares Creamos la definición llamada DIGITO, podemos acceder esta definición usando {DIGITO}*/ DIGITO [0-9] NUMERO {DIGITO}+("."{DIGITO}+)? %% /*************** Reglas

*****************/ /* Creamos las reglas que reconocerán las cadenas que acepte Nuestro scanner y retornaremos el token a bison con la funcion return. */ {NUMERO} {yylval.real=atof(yytext); return(NUMERO);} "=" {return(IGUAL);} "+" {return(MAS);} "-" {return(MENOS);} ";" {return(PTOCOMA);} "*" {return(POR);} "/" {return(DIV);} "(" {return(PAA);} ")" {return(PAC);} "\n" {linea++;} [\t\r\f] {} " " {} /* Si en nuestra entrada tiene algún caracter que no pertenece a las reglas anteriores, se genera un error léxico */ . {printf("Error lexico en linea %d",linea);} %% /* Código de Usuario Aquí podemos realizar otras funciones, como por ejemplo ingresar símbolos a nuestra tabal de símbolos o cualquier otra accione del usuario. Todo lo que el usuario coloque en esta sección se copiara al archvi lex.yy.c tal y como esta. */ Guardamos el archivo como lexico.l. Luego creamos un nuevo archivo y colocamos el siguiente código. %{ /******************** Declaraciones en C **********************/ #include <stdio.h> #include <stdlib.h> #include <math.h> extern int yylex(void);

extern char *yytext; extern int linea; extern FILE *yyin; void yyerror(char *s); %} /************************ Declaraciones de Bison *************************/ /* Especifica la coleccion completa de tipos de datos para poder usar varios tipos de datos en los terminales y no terminales*/ %union { float real; } /* Indica la produccion con la que inicia nuestra gramatica*/ %start Exp_l /* Especificacion de termines, podemos especificar tambien su tipo */ %token <real> NUMERO %token MAS %token MENOS %token IGUAL %token PTOCOMA %token POR %token DIV %token PAA %token PAC /* No Terminales, que tambien podemos especificar su tipo */ %type <real> Exp %type <real> Calc %type <real> Exp_l /* Definimos las precedencias de menor a mayor */ %left MAS MENOS %left POR DIV %% /********************** Reglas Gramaticales ***********************/ Exp_l: Exp_l Calc |Calc ; Calc : Exp PTOCOMA {printf ("%4.1f\n",$1)}

; /* con el símbolo de $$ asignamos el valor semántico de toda la acción de la derecha y se la asignamos al no terminal de la izquierda, en la siguiente regla, se la asigna a Exp. Para poder acceder al valor de los terminales y no terminales del lado derecho usamos el símbolo $ y le concatenamos un numero que representa la posición en la que se encuentra es decir si tenemos A --> B NUMERO C Si queremos usar le valor que tiene el no terminal B usamos $1, si queremos usar el valor que tiene NUMERO usamos $2 y así sucesivamente. */ Exp : NUMERO {$$=$1;} |Exp MAS Exp {$$=$1+$3;} |Exp MENOS Exp {$$=$1-$3;} |Exp POR Exp {$$=$1*$3;} |Exp DIV Exp {$$=$1/$3;} |PAA Exp PAC {$$=$2;} ; %% /******************** Codigo C Adicional **********************/ void yyerror(char *s) { printf("Error sintactico %s",s); } int main(int argc,char **argv) { if (argc>1) yyin=fopen(argv[1],"rt"); else yyin=stdin; yyparse(); return 0; } Guardamos este archivo con el nombre sintáctico.y y con eso ya tenemos nuestro scanner y nuestro parser terminado. Para compilar estos archivos usamos los comandos Compilando sintactico.y ~> bison -d sintactico.y

El parámetro –d, crea el fichero t.tab.h, que contiene los identificadores de los tokens de bison usados por flex Compilando lexico.l ~> flex lexico.l Compilando arhivos generados y crear ejecutable ~> cc lex.yy.c sintactico.tab.c -o analizador -lfl -lm Esto nos genera un ejecutable llamado analizador. Muchas veces necesitamos modificar nuestro archivo sintáctico.y o lexico.l y tenemos que compilar todo cada vez que hacemos un cambio, para no estar escribiendo los comandos cada vez que realizamos un cambio, crearemos un script, que al ejecutarlo realizara todos los comandos de compilación. Para eso creamos un nuevo archivo en blanco y escribimos #!/bin/bash bison -d sintactico.y flex lexico.l cc lex.yy.c sintactico.tab.c -o analizador -lfl –lm Guardamos este archivo con cualquier nombre, por ejemplo compilar.sh. Ahora cambiaremos las propiedades de este archivo para poder ejecutar. Le damos clic derecho sobre este archivo y en la pestaña permisos elegimos la opción de “Permitir ejecutar el archivo como un programa”, cerramos esa ventana. Para poder compilar, desde consola nos ubicamos donde se encuentra este archivo .sh y escribimos ./compilar.sh Esto nos genera nuestro ejecutable que podemos correr para poder probar nuestra calculadora. Para ejecutar este ejemplo usamos el comando ./analizador Ingresamos algunas expresiones y el resultado que obtenemos es:

Ejemplo2:

Ante la siguiente entrada a =12+2*cos(3.14)

La salida debe ser:

El valor del identificador a es 10.LABORATORIO DE PROCESADORES DE LENGUAJE CURSO2010-11

Fichero léxico_solo.l

%

{ /* Ejemplo para una pequeña calculadora que permite trabajar con numeros enteros y reales con

las operaciones básicas de suma, resta, producto, division y trigonometricas como el seno y el

coseno*/

#include <stdio.h>

#include <stdlib.h> int nlines=0; %} DIGITO [0-9] ID [a-zA-Z][a-zA-Z0-9_]*

%% {DIGITO}+ {printf("Encontrado TKN_NUM_ENTERO:%d",atoi(yytext));}

{DIGITO}+"."{DIGITO}+ {printf("Encontrado TKN_NUM_REAL:%f",atof(yytext));} "="

{printf("Encontrado TKN_ASIGN: %s",yytext);} ";"

{printf("Encontrado TKN_PTOCOMA: %s",yytext);} "*" {printf("Encontrado TKN_MULT:

%s",yytext);} "/" {printf("Encontrado TKN_DIV: %s",yytext);} "+" {printf("Encontrado TKN_MAS:

%s",yytext);} "-" {printf("Encontrado TKN_MENOS: %s",yytext);} "(" {printf("Encontrado TKN_PAA:

%s",yytext);} ")" {printf("Encontrado TKN_PAC: %s",yytext);} "cos" {printf("Encontrado TKN_COS:

%s",yytext);} "sen" {printf("Encontrado TKN_SEN:%s",yytext);} {ID} {printf("Encontrado TKN_ID:

%s",yytext);} "n" {nlines++;} .LABORATORIO DE PROCESADORES DE LENGUAJE CURSO 2010-11 %%

void main(int argc,char **argv) { if (argc>1) yyin=fopen(argv[1],"rt"); else yyin=stdin; yylex();

printf("nNumero lineas analizadas: %dn", nlines);

} /* para compilar flex lexico.l cc lex.yy.c -o milex -lfl -lm */LABORATORIO DE PROCESADORES DE

LENGUAJE CURSO 2010-11 Fichero léxico.l (versión a enlazar con Bison) %{ /* Ejemplo para una

pequeña calculadora que permite trabajar con las operaciones básicas de suma, resta, producto,

divisiony trigonometricas como el seno y el coseno */ #include <stdio.h> #include <stdlib.h>

#include "sintactico.tab.h" int nlines=0; %} DIGITO [0-9] ID [a-zA-Z][a-zA-Z0-9_]* %%

{DIGITO}+("."{DIGITO}+)? {//printf("Encontrado TKN_NUM: %fn",atof(yytext));

yylval.real=atof(yytext); return(TKN_NUM);} "=" {//printf("Encontrado TKN_ASIGN: %sn",yytext);

return(TKN_ASIGN);} ";" {//printf("Encontrado TKN_PTOCOMA: %sn",yytext);

return(TKN_PTOCOMA);} "*" {//printf("Encontrado TKN_MULT: %sn",yytext); return(TKN_MULT);}

"/" {//printf("Encontrado TKN_DIV: %sn",yytext); return(TKN_DIV);} "+" {//printf("Encontrado

TKN_MAS: %sn",yytext); return(TKN_MAS);} "-" {//printf("Encontrado TKN_MENOS:

%sn",yytext);LABORATORIO DE PROCESADORES DELENGUAJE CURSO 2010-11

return(TKN_MENOS);} "(" {//printf("Encontrado TKN_PAA: %sn",yytext); return(TKN_PAA);} ")"

{//printf("Encontrado TKN_PAC: %sn",yytext); return(TKN_PAC);} "cos" {//printf("Encontrado

TKN_COS: %sn",yytext); return(TKN_COS);} "sen" {//printf("Encontrado TKN_SEN: %sn",yytext);

return(TKN_SEN);} {ID} {//printf("Encontrado TKN_ID: %sn",yytext); return(TKN_ID);} "n"

{nlines++;} . %% /********

Para el lexico solo void main(int argc,char **argv) { if (argc>1) yyin=fopen(argv[1],"rt"); else

yyin=stdin; yylex(); printf("nNumero lineas analizadas: %dn", nlines); } *******/ /* para compilar

flex lexico.l cc lex.yy.c -o milex -lfl -lm */LABORATORIO DE PROCESADORES DE LENGUAJE CURSO

2010-11 Fichero sintactico.y (Bison)

%