13
Pontificia Universidad Católica del Ecuador Sede Ibarra Escuela de Ingeniería Compiladores Nombre: Guido Espinosa de los Monteros 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 la Prá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 la Práctica [versión 1.0, Linux] YACC C Generador de Analizadores Sintácticos Ascendentes LR(1) Reseña Histórica Diseño y construcción de un compilador. El software para los primeros computadores estaba primariamente escrito en lenguaje ensamblador. Normalmente para un programador es más productivo usar un lenguaje de alto nivel, y los programas escritos en lenguajes de alto nivel pueden ser reutilizados en distintos tipos de computadores. Aún teniendo en cuenta esto, pasó un tiempo hasta

Flex y Bison

Embed Size (px)

Citation preview

Page 1: Flex y Bison

Pontificia Universidad Católica del Ecuador Sede Ibarra

Escuela de Ingeniería

Compiladores

Nombre: Guido Espinosa de los Monteros

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 la Prá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 la Práctica [versión

1.0, Linux]

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

Reseña Histórica Diseño y construcción de un compilador.

El software para los primeros computadores estaba primariamente escrito en lenguaje

ensamblador. Normalmente para un programador es más productivo usar un lenguaje

de alto nivel, y los programas escritos en lenguajes de alto nivel pueden ser reutilizados

en distintos tipos de computadores. Aún teniendo en cuenta esto, pasó un tiempo hasta

Page 2: Flex y Bison

Pontificia Universidad Católica del Ecuador Sede Ibarra

Escuela de Ingeniería

que los compiladores se establecieran, porque generaban código que no tenía tan buen

rendimiento como los ensambladores escritos a mano, eran enormes proyectos de

desarrollo por sí mismos, y la limitadísima capacidad de memoria de los primeros

computadores creó muchos problemas técnicos para las implementaciones prácticas de

los compiladores.

El primer compilador fue escrito por Grace Hopper, en 1952, para el lenguaje Sistema

A-0. El término compilador fue acuñado por Hopper.1 El equipo FORTRAN dirigido por

John W. Backus de IBM está generalmente acreditado por haber presentado el primer

compilador completo, en 1957. El primer compilador FORTRAN necesitó de 18 años-

persona para su creación.2

En 1960, un compilador FORTRAN extendido, ALTAC, estaba también disponible en el

Philco 2000, por lo que es probable que un programa FORTRAN fuera compilado para

ambas arquitecturas de computadores a mediados de los años 60.3 El primer lenguaje

de alto nivel multiplataforma demostrado fue COBOL. En una demostración en

diciembre de 1960, un programa COBOL fue compilado y ejecutado en el UNIVAC II y el

RCA 501.1

El compilador COBOL para el UNIVAC II fue probablemente el primero en ser escrito en

un lenguaje de alto nivel, llamado FLOW-MATIC, por un equipo dirigido por Grace

Hopper.

Las herramientas Flex y Bison.

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 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 el la sintaxis usada para

describir gramáticas.

Page 3: Flex y Bison

Pontificia Universidad Católica del Ecuador Sede Ibarra

Escuela de Ingeniería

Como se instala Flex y Bison

Page 4: Flex y Bison

Pontificia Universidad Católica del Ecuador Sede Ibarra

Escuela de Ingeniería

Page 5: Flex y Bison

Pontificia Universidad Católica del Ecuador Sede Ibarra

Escuela de Ingeniería

Page 6: Flex y Bison

Pontificia Universidad Católica del Ecuador Sede Ibarra

Escuela de Ingeniería

Como se compila con Flex y Bison

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

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}+)?

Page 7: Flex y Bison

Pontificia Universidad Católica del Ecuador Sede Ibarra

Escuela de Ingeniería

%%

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

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

Page 8: Flex y Bison

Pontificia Universidad Católica del Ecuador Sede Ibarra

Escuela de Ingeniería

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

#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

Page 9: Flex y Bison

Pontificia Universidad Católica del Ecuador Sede Ibarra

Escuela de Ingeniería

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

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;

Page 10: Flex y Bison

Pontificia Universidad Católica del Ecuador Sede Ibarra

Escuela de Ingeniería

}

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.

Page 11: Flex y Bison

Pontificia Universidad Católica del Ecuador Sede Ibarra

Escuela de Ingeniería

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 12: Flex y Bison

Pontificia Universidad Católica del Ecuador Sede Ibarra

Escuela de Ingeniería

%option c++

%option noyywrap

%{

#include <sstream>

#include <cstdlib>

#include "parser.h"

using namespace std;

%}

DIGIT [0-9]

DIGIT1 [1-9]

%%

{DIGIT1}{DIGIT}* {

cout << "Lexer: " << yytext << endl;

return Parser::NUMBER;

}

. {

return Parser::UNKNOWN;

}

<<EOF>> {

yyterminate();

}

%%

%name Parser

%define LSP_NEEDED

%define MEMBERS \

virtual ~Parser() {} \

private: \

yyFlexLexer lexer;

%define LEX_BODY {return lexer.yylex();}

%define ERROR_BODY {cerr << "error encountered at line:

"<<lexer.lineno()<<" last word parsed:"<<lexer.YYText()<<"\n";}

%header{

#include < ostream >

#include < fstream >

#include < FlexLexer.h >

using namespace std;

%}

Page 13: Flex y Bison

Pontificia Universidad Católica del Ecuador Sede Ibarra

Escuela de Ingeniería

%union {

int i_type;

}

%token UNKNOWN

%token < i_type > NUMBER

%type < i_type > number

%start number

%%

number

: NUMBER { $$ = atoi(lexer.YYText()); cout << "Parser value " << $$ <<

endl;}

;

%%

#include "parser.h"

#include < iostream >

using namespace std;

int main(int argc, char ** argv)

{

Parser parser;

parser.yyparse();

return 0;

}

all: test

parser.cc: parser.y

bison++ -d -hparser.h -o $@ $<

scanner.cc: scanner.l

flex++ -d -o$@ $<

test: parser.o scanner.o test.o

g++ -o $@ test.o parser.o scanner.o

clean:

$(RM) *~ *# test *.o *.h

$(RM) parser.cc scanner.cc