18
Steven Tabango PUCESI PONTIFICIA UNIVERSIDAD CATÓLICA DEL ECUADOR SEDE IBARRA ESCUELA DE INGENIERÍA CARRERA DE SISTEMAS NOMBRE: Steven Tabango FECHA: 08/07/2015 TALLER DE COMPILADORES Herramientas para la construcción de procesadores de lenguaje. Herramienta Lenguaje Descripción Bison C Generador de Analizadores Sintácticos Ascendentes tipo YACC COCO/R C/C++ Generador de Analizadores Léxicos y Sintácticos Descendentes Recursivos Flex C Generador de Analizadores Léxicos tipo Lex Lex C Generador de Analizadores Léxicos SDGLL1 exe Sistema Detector de Gramáticas LL(1) y generador de la tabla TS 2006 C/C++ Tipo abstracto de datos Tabla de Símbolos de uso sencillo TS C Tipo abstracto de datos Tabla de Símbolos TS-OO C++ Tipo abstracto de datos orientado a objetos Tabla de Símbolos VASt exe Visualizador de árboles sintácticos partiendo de los ficheros con la gramática y el parse pedidos en laPráctica [versión 2.0, Windows] VASt C++ Visualizador de árboles sintácticos partiendo de los ficheros con la gramática y el parse pedidos en laPráctica [versión 1.0, Linux] YACC C Generador de Analizadores Sintácticos Ascendentes LR(1) Nota: El uso de estas herramientas de Procesadores de Lenguajes no es en absoluto obligatorio (salvo VASt) ni se garantiza su correcto funcionamiento. Se muestran aquí solamente a título informativo. Los profesores de la asignatura no proporcionarán ayuda ni información adicional sobre dichas herramientas. Reseña Histórica Las primeras aplicaciones del procesamiento del lenguaje natural surgieron entre 1940 y 1960, teniendo como interés fundamental la traducción automática de textos entre diferentes idiomas. Los experimentos en

Compiladores - Flex y Bison

Embed Size (px)

Citation preview

Page 1: Compiladores - Flex y Bison

Steven Tabango PUCESI

PONTIFICIA UNIVERSIDAD CATÓLICA DEL ECUADOR SEDE IBARRA

ESCUELA DE INGENIERÍA CARRERA DE SISTEMAS

NOMBRE: Steven Tabango FECHA: 08/07/2015

TALLER DE COMPILADORES

Herramientas para la construcción de procesadores de lenguaje.

Herramienta Lenguaje Descripción

Bison C Generador de Analizadores Sintácticos Ascendentes tipo YACC

COCO/R C/C++ Generador de Analizadores Léxicos y Sintácticos Descendentes Recursivos

Flex C Generador de Analizadores Léxicos tipo Lex

Lex C Generador de Analizadores Léxicos

SDGLL1 exe Sistema Detector de Gramáticas LL(1) y generador de la tabla

TS 2006 C/C++ Tipo abstracto de datos Tabla de Símbolos de uso sencillo

TS C Tipo abstracto de datos Tabla de Símbolos

TS-OO C++ Tipo abstracto de datos orientado a objetos Tabla de Símbolos

VASt

exe

Visualizador de árboles sintácticos partiendo de los ficheros con la gramática y el parse pedidos en laPráctica [versión 2.0, Windows]

VASt

C++ Visualizador de árboles sintácticos partiendo de los ficheros con la gramática y

el parse pedidos en laPráctica [versión 1.0, Linux]

YACC C Generador de Analizadores Sintácticos Ascendentes LR(1)

Nota: El uso de estas herramientas de Procesadores de Lenguajes no es en absoluto obligatorio (salvo VASt) ni se garantiza su correcto funcionamiento. Se muestran aquí solamente a título informativo. Los profesores de la asignatura no proporcionarán ayuda ni información adicional sobre dichas herramientas.

Reseña Histórica

Las primeras aplicaciones del procesamiento del lenguaje natural surgieron entre 1940 y 1960, teniendo como interés fundamental la traducción automática de textos entre diferentes idiomas. Los experimentos en

Page 2: Compiladores - Flex y Bison

Steven Tabango PUCESI

este ámbito se basaban fundamentalmente en la sustitución automática palabra por palabra, por lo que se obtenían traducciones muy rudimentarias, que no proporcionaban unos resultados claros.

Surgió por tanto la necesidad de resolver ambigüedades sintácticas y semánticas, así como la importancia de considerar la información contextual. Los problemas más relevantes en este tiempo fueron la carencia de un orden de la estructura oracional en algunas lenguas, y la dificultad para obtener una representación tanto sintáctica como semántica, pero una vez que se empezaron a tener en cuenta se dio paso a una concepción más realista del lenguaje en la que era necesario contemplar las transformaciones que se producen en la estructura de la frase durante el proceso de traducción.

Los últimos años se caracterizan por la incorporación de técnicas estadísticas y el desarrollo de formalismos adecuados para el tratamiento de la información léxica. Se ha introducido nuevas técnicas de representación del conocimiento muy cercanas a la inteligencia artificial, y las técnicas de procesamiento utilizadas por investigadores procedentes del área de la lingüística e informática son cada vez más próximas.

Diseño y construcción de un compilador

Diseño:

Construcción:

La construcción de un compilador involucra la división del proceso en una serie de fases que variará con su complejidad. Generalmente estas fases se agrupan en dos tareas: el análisis del programa fuente y la síntesis del programa objeto.

Análisis: Se trata de la comprobación de la corrección del programa fuente, e incluye las fases correspondientes al Análisis léxico (que consiste en la descomposición del programa fuente en componentes léxicos), Análisis sintáctico (agrupación de los componentes léxicos en frases gramaticales) y Análisis

Page 3: Compiladores - Flex y Bison

Steven Tabango PUCESI

semántico (comprobación de la validez semántica de las sentencias aceptadas en la fase de Análisis Sintáctico).

Síntesis: Su objetivo es la generación de la salida expresada en el lenguaje objeto y suele estar formado por una o varias combinaciones de fases de Generación de Código (normalmente se trata de código intermedio o de código objeto) y de Optimización de Código (en las que se busca obtener un código lo más eficiente posible).

Que es flex y Bison.

Son dos herramientas útiles para crear programas que reaccionen a una entrada de datos con una estructura y un lenguaje predeterminado, como por ejemplo, podemos crear compiladores, intérpretes y analizadores de línea de comando.

Flex: El Flex define las reglas de reconocimiento de símbolos (Tokens) a partir de expresiones regulares. Cuando un Token es reconocido por uno de estos patrones de agrupamiento se le define una acción, por lo general esta acción es devolver el Tipo y el valor (lexema).

El Flex cuando se utiliza combinado con el Bison, utiliza las definiciones de los Tokens realizadas en el Bison para la comunicación entre ellos,

Bison: GNU bison es un programa generador de analizadores sintácticos de propósito general perteneciente al proyecto GNU disponible para prácticamente todos los sistemas operativos, se usa normalmente acompañado de flex aunque los analizadores léxicos se pueden también obtener de otras formas.

Bison convierte la descripción formal de un lenguaje, escrita como una gramática libre de contexto LALR, en un programa en C, C++, o Java que realiza análisis sintáctico. Es utilizado para crear analizadores para muchos lenguajes, desde simples calculadoras hasta lenguajes complejos. Para utilizar Bison, es necesaria experiencia con la sintaxis usada para describir gramáticas.

Como se instala Flex y Bison

1. Descarga el software disponible en el sitio de la cátedra.

2. Instalar el software en la unidad C: (para explicar a partir del punto 4 se tendrá como hipótesis de 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. Una alternativa es crear un archivo de proceso por lotes (*.bat) que contenga las líneas de comando para la ejecución de Flex y Bison y/o la compilación del archivo generado.

Page 4: Compiladores - Flex y Bison

Steven Tabango PUCESI

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:

• Clic derecho en “Mi PC”.

• Selecciona “Propiedades”

• Clic en la pestaña “Opciones Avanzadas”

• Presiona el botón “Variables de entorno”

• En la ventana de variables de entorno, ubicarse en la sección “Variables del sistema” luego haz clic en PATH y luego en el botón “Modificar” (si no está hacer clic en “Nueva” y agregar PATH) • En la nueva ventana, escribir la ruta completa al directorio “bin” de la aplicación flex/bison. Si existe otro valor, separarlos con comas.

• Aceptar los cambios y luego reiniciar el sistema operativo.

5. Si deseas instalar un compilador de C como MinGwin, deberás integrar la ruta de acceso al compilador a las variables de entorno para facilitar la llamada al programa. Por ejemplo si se instaló MingWin en “C:\Mingw” y dentro de la carpeta “bin” se encuentra “gcc.exe” que es el ejecutable, entonces de deberá agregar (análogo a los pasos anteriores) lo siguiente:

6. Cuando tengas listo podrás llamar a flex/bison desde el símbolo del sistema sin necesidad de ubicarte en la carpeta donde ha sido instalado flex/bison.

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:

Si se desea invocar a bison (recordar que bison trabaja en conjunto con flex):

Page 5: Compiladores - Flex y Bison

Steven Tabango PUCESI

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

Para compilar los archivos generados. Flex: MinGW

Una alternativa es utilizar un compilador para windows como DevC++ o Borland C++ 4.5.

Abriendo el archivo lex.yy.c y luego compilándolo se generará el ejecutable “lex.yy.exe”

BISON y FLEX en conjunción:

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

Page 6: Compiladores - Flex y Bison

Steven Tabango PUCESI

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++;}

Page 7: Compiladores - Flex y Bison

Steven Tabango PUCESI

[\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;

}

Page 8: Compiladores - Flex y Bison

Steven Tabango PUCESI

/* 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;}

Page 9: Compiladores - Flex y Bison

Steven Tabango PUCESI

%%

/********************

Codigo C Adicional

**********************/

void yyerror(char *s)

{

|Exp MAS Exp {$$=$1+$3;}

|Exp MENOS Exp {$$=$1-$3;}

|Exp POR Exp {$$=$1*$3;}

|Exp DIV Exp {$$=$1/$3;}

|PAA Exp PAC {$$=$2;}

;

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

Page 10: Compiladores - Flex y Bison

Steven Tabango PUCESI

#!/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:

Page 11: Compiladores - Flex y Bison

Steven Tabango PUCESI

Ejemplo 2:

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 CURSO 2010-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_]*

Page 12: Compiladores - Flex y Bison

Steven Tabango PUCESI

%%

{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: %d\n", nlines);

Page 13: Compiladores - Flex y Bison

Steven Tabango PUCESI

}

/* 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, division y

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: %f\n",atof(yytext));

yylval.real=atof(yytext);

return(TKN_NUM);}

"=" {//printf("Encontrado TKN_ASIGN: %s\n",yytext);

return(TKN_ASIGN);}

";" {//printf("Encontrado TKN_PTOCOMA: %s\n",yytext);

Page 14: Compiladores - Flex y Bison

Steven Tabango PUCESI

return(TKN_PTOCOMA);}

"*" {//printf("Encontrado TKN_MULT: %s\n",yytext);

return(TKN_MULT);}

"/" {//printf("Encontrado TKN_DIV: %s\n",yytext);

return(TKN_DIV);}

"+" {//printf("Encontrado TKN_MAS: %s\n",yytext);

return(TKN_MAS);}

"-" {//printf("Encontrado TKN_MENOS: %s\n",yytext);LABORATORIO DE PROCESADORES DE LENGUAJE CURSO 2010-11

return(TKN_MENOS);}

"(" {//printf("Encontrado TKN_PAA: %s\n",yytext);

return(TKN_PAA);}

")" {//printf("Encontrado TKN_PAC: %s\n",yytext);

return(TKN_PAC);}

"cos" {//printf("Encontrado TKN_COS: %s\n",yytext);

return(TKN_COS);}

"sen" {//printf("Encontrado TKN_SEN: %s\n",yytext);

return(TKN_SEN);}

{ID} {//printf("Encontrado TKN_ID: %s\n",yytext);

return(TKN_ID);}

"\n" {nlines++;}

.

%%

/********

Page 15: Compiladores - Flex y Bison

Steven Tabango PUCESI

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: %d\n", 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)

%{

/* 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>

#include <math.h>

extern int yylex(void);

Page 16: Compiladores - Flex y Bison

Steven Tabango PUCESI

extern char *yytext;

extern int nlines;

extern FILE *yyin;

void yyerror(char *s);

%}

%union

{

float real;

}

%start Calculadora

%token <real> TKN_NUM

%token TKN_ASIGN

%token TKN_PTOCOMA

%token TKN_MULT

%token TKN_DIV

%token TKN_MAS

%token TKN_MENOS

%token TKN_PAA

%token TKN_PACLABORATORIO DE PROCESADORES DE LENGUAJE CURSO 2010-11

%token TKN_COS

%token TKN_SEN

%token <real> TKN_ID

%type Calculadora

%type <real> Expresion

Page 17: Compiladores - Flex y Bison

Steven Tabango PUCESI

%left TKN_MAS TKN_MENOS

%left TKN_MULT TKN_DIV

%%

Calculadora : TKN_ID { printf("El valor de %s es: ", yytext);}

TKN_ASIGN Expresion TKN_PTOCOMA { printf("%5.2f\n", $4); } ;

Expresion : TKN_NUM {$$=$1;}|

Expresion TKN_MAS Expresion {$$=$1+$3;}|

Expresion TKN_MENOS Expresion {$$=$1-$3;}|

Expresion TKN_MULT Expresion {$$=$1*$3;}|

Expresion TKN_DIV Expresion {$$=$1/$3;} |

TKN_PAA Expresion TKN_PAC {$$=$2;}|

TKN_COS TKN_PAA Expresion TKN_PAC {$$=cos($3);}|

TKN_SEN TKN_PAA Expresion TKN_PAC {$$=sin($3);};

%%

void yyerror(char *s)

{

printf("Error %s",s);

}

int main(int argc,char **argv)

{

if (argc>1)

yyin=fopen(argv[1],"rt");LABORATORIO DE PROCESADORES DE LENGUAJE CURSO 2010-11

else

yyin=stdin;

Page 18: Compiladores - Flex y Bison

Steven Tabango PUCESI

yyparse();

printf("FIN del Analisis. Entrada CORRECTA\n");

printf("Numero lineas analizadas: %d\n", nlines);

return 0;

}

/* para compilar

bison -d sintactico.y

flex lexico.l

cc lex.yy.c sintactico.tab.c -o analizador -lfl -lm

*/