You are on page 1of 13

UNIVERSIDAD DE SANCARLOS DE GUATEMALA

Organización de lenguajes y Compiladores 1

Manual Flex y Bison con Qt


Primeros pasos

Creado por: José Manuel González


Alvarez
INTRODUCCION
El siguiente manual presenta una introducción de cómo utilizar conjuntamente
Bison Flex y Qt, se presenta una introducción ambas herramientas, después se explica
la instalación de las misma sobre el sistema operativo Linux, y se concluye con un
ejemplo practico para observar como se utilizan juntas estas herramientas.

Notas del Autor


Este manual solo es una inicialización a esta tecnología así que no se
profundiza, tanto en la sintaxis de la herramienta y se supone un conocimiento mínimo
del lector.

El objetivo primordial, es despertar el interés del lector hacia eta tecnología y


que le sirva como una guía inicial, para uso.

Flex
Que es:
Flex es una herramienta para generar analizadores léxicos: programas que reconocen
patrones en un texto. Flex lee los ficheros de entrada dados, o la entrada estándar si no se le
ha indicado ningún nombre de fichero, con la descripción de un escáner a generar. La
descripción se encuentra en forma de parejas de expresiones regulares y código C,
denominadas reglas. Flex genera como salida un fichero fuente en C.

Instalación:
Puede descargar los paquetes de instalación de la siguiente dirección.

http://flex.sourceforge.net/

A continuación se presenta una instalación desde el sistema operativo Linux utilizando la


distribución Ubuntu.

Primero abra el repositorio (Sistema -> Administración -> Gestor de paquetes Synaptic) y
escriba en el buscador flex, marque el paquete flex como se ve en la imagen.
De clic en aplicar y espere a que termine la instalación. Después abra un terminal y escriba flex
– V le tiene que salir algo parecido a la imagen, listo tiene instalado Flex.

Bison
Que es:
Bison es un generador de analizadores sintácticos propósito general a partir de una
gramática libre de contexto clasificada como LALR (1) este analizador es generado en
código c.
Los analizadores generados por Bison pueden ser utilizados para construir lenguajes
desde pequeños lenguajes como los utilizados en calculadoras de Escritorio, hasta
lenguajes complejos de programación.

Instalación:
Puede descargar los paquetes de instalación de Bison de la siguiente dirección
http://www.gnu.org/software/bison/.

A continuación se presenta una instalación desde el sistema operativo Linux utilizando la


distribución Ubuntu.

Primero abra el repositorio (Sistema -> Administración -> Gestor de paquetes Synaptic) y
escriba en el buscador bison, marque el paquete bison como se ve en la imagen.

De clic en aplicar y espere a que termine la instalación. Después abra un terminal y escriba
bison - -version le tiene que salir algo parecido a la imagen, listo tiene instalado bison.
Descripción del archivo de entrada:
Estructura general de un archivo bison.

%{
Prólogo
%}

Bison declarations

%%
Grammar rules
%%

Epílogo

Prologo:
En esta área van los include y métodos que el programador considere conveniente escribir,
todo en esto en el lenguaje c.

Bison declarations:
Aquí se incluye las opciones que da bison, como la declaración de terminales y no terminales
que usara en la gramatica.

Si se requiere usar un tipo de dato para los terminales y no terminales se usa esta opción
donde se declara, los tipos que se requiera %union{tipodato id;…así sucesivamente} ejemplo

%union{int Str;}

Para declarar un terminal

%token<Tipodato> id; ejemplo %token<Str> nEntero;

Grammar rules:
En esta area se localizan la reglas gramaticales que regiran a nuestro analizador

Sintaxis general;

Noterminal: reglas

Ejemplo:

RESULTADO: RESULTADO Nmas RESULTADO


También se pueden colocar acciones

RESULTADO: RESULTADO Nmas RESULTADO{/*código c. */}

Utilizar Bison y Flex en Qt


La mejor manera de aprender esto es con un ejemplo, así que realizaremos una calculadora
con operaciones básicas suma, resta multiplicación y división, usando Qt, bison y flex.

Objetivo:
Aprender a usar flex y bison con qt atraves de un ejemplo sencillo.
Aprender a usar QFileDialog de Qt, para cargar archivos a bison y ejecutar de ahí.

Descripción general del ejemplo:


Se carga un archivo de entrada con una cadena de operaciones aritméticas ejemplo: “5+5*4”,
este se presenta en un caja de texto, después se da clic en el botón calcular y en una caja de
texto diferente, se presenta los resultados, también se puede cambiar los datos en la caja de
texto y darle a calcular automáticamente guarda los cambios y hace los cálculos.

Interfaz del programa.

Cargando el archivo:

Creando ejemplo paso a paso:


Crear el proyecto en qt
Creando los archivos de analizador léxico y sintactico:

Se da clic derecho sobre el proyecto y en add new, saldrá un cuadro de dialogo como el de la
imagen de abajo se da clic en choose se coloca el nombre y listo.

Nuestro archivo léxico se llama scan.l y el sintactio parser.y


En anexos se coloco el código de el analizador sintatico y lexico.

Compilando los archivos scan y parser.


Abra un terminal sitúes en la carpeta donde esta situado sus archivos.

Para bison escribes lo siguiente:

Bison –o parser.cpp --defines=parser.h parse.y –v

Como se muestra en la imagen.

Para flex:
Flex –header –file=scanner.h –o scanner.cpp scan.l
Para una lista completa de las opciones sobre flex y bison, escribe en consola, flex --help o
bison –help

Añadiendo los archivos:


Ahora das clic derecho sobre la carpeta source y Header, selecciona la opción add Existing,

Vas a tu carpeta donde generaste tus archivos bison y flex, en nuestro caso fue la misma
carpeta de proyecto, te recomiendo que lo hagas ahí. Seleccionas el archivo, el .h es para la
carpeta Header y el .cpp es para la carpeta Sources. Has lo mismo para los cuatro archivos dos
.cpp y dos .h cada par corresponde a tu analizador léxico y sintáctico.

Ahora en tu principal agrega lo siguiente en nuestro caso se llama inicio.

Este metodo agrega el archivo que se analizara


extern int yyrestart(FILE* archivo);
Este método hace el analisis
extern int yyparse();
Este metodo agrega nuestro editor donde se mostraran los resultados
extern void setEditor(QTextEdit* editor);
Este metodo agrega nuestro editor donde se mostraran los errores
extern void setTexEdit(QTextEdit* edit1);
Nota: los dos primeros métodos siempre se deben agregar los otros fueron creados por mí
para imprimir el resultado del análisis.

ANEXO
Les dejo el código de el archivo sca.l, parse.y respectivamente, así como parte de código que
considero interesante.
Guarda un archivo, recibe como parámetro el nombre del archivo,
El contenido que se gurdara lo extrae de la caja de texto
bool inicio::saveFile( QString fileName)
{
QFile file(fileName);
if (!file.open(QFile::WriteOnly | QFile::Text)) {
return false;
}
QTextStream out(&file);
#ifndef QT_NO_CURSOR
QApplication::setOverrideCursor(Qt::WaitCursor);
#endif
out << ui->pantalla->toPlainText();//guardando contenido
#ifndef QT_NO_CURSOR
QApplication::restoreOverrideCursor();
#endif
return true;
}

abre un archivo, recibe como parámetro el nombre del archivo,


Este método es llamado a pulsar el botón abrir de la aplicación.

void inicio::on_pushButton_clicked()
{
nameFile=QFileDialog::getOpenFileName(this,tr("abrir"),tr("/home/jose/Escritorio"),tr("Archiv
o de texto (*.txt)"));
QString file= nameFile;
if(!file.isNull()){
ui->pantalla->setText("");
QFile archivo(file);
if (!archivo.open(QIODevice::ReadOnly | QIODevice::Text))
return;
QTextStream in(&archivo);
while (!in.atEnd()) {
QString line = in.readLine();
ui->pantalla->append(line);
}
}
}
Este método llama al analizador.
void inicio::on_bcalcular_clicked()
{ setEditor(ui->textEdit); //se agrega el editor donde se dan los resultados
setTexEdit(ui->textEdit); //se agrega el editor donde se mostran los errores
//en nuestro caso es el mismo editor.
//la variable nameFile tiene guardado el nombre del documento analizar, que se abrió con el
QFileDialog, el método toLati1().contsData(), retorna un *char, para compatibilidad con el
método fopen
FILE* input = fopen(nameFile.toLatin1().constData(), "r" );
if (input!=NULL){
saveFile(nameFile);
yyrestart(input);
yyparse();
}
}
Archivo scan.l:
%option noyywrap
%option yylineno
%{
#include "parser.h"
#include <iostream>
#include <QString>
#include <QTextEdit>
QTextEdit* salida;
extern void setTexEdit(QTextEdit* edit1);
void setTexEdit(QTextEdit* edit1)
{
salida= edit1;
}

void ImprimirError(QString val)


{salida->append(val);
}
%}

blanco1 [\t\n]*
digito [0-9]
Numero_Entero {digito}+
Numero_Decimal {digito}+"."{digito}+

%%
{blanco1} {/*Se ignoran los blancos*/}
[+] {return (Nmas); }
[-] {return (Nmenos); }
[*] {return (Npor); }
\/ {return (Ndiv); }
[(] {return (Nparen); }
[)] {return (Ncparen); }
{Numero_Entero} {return (Nent); }
{Numero_Decimal} {return (Nfloat); }
. {ImprimirError(QString("Error Lexico en Fila: %1 en
%2").arg(yylineno).arg(yytext));}
%%
Archivo parser.y:
%{
#include "scanner.h"
#include <iostream>
#include <QString>
#include <QTextEdit>
#include <QList>

extern int yylineno;


extern char *yytext;
extern void ImprimirError(QString val);
extern void setEditor(QTextEdit* editor);
QTextEdit* edit;

void imprimir(QString val)


{
edit->setText(val);
}

void setEditor(QTextEdit* editor)


{
edit=editor;
}
int yyerror(const char* mens)
{
ImprimirError(QString("Error Sintactico en Fila: %1, en %2").arg(yylineno).arg(yytext));
return 0;
}

%}
%union{
double STR2;
}
%token<STR2> Nmas
%token<STR2> Nmenos
%token<STR2> Npor
%token<STR2> Ndiv
%token<STR2> Nparen
%token<STR2> Ncparen
%token<STR2> Nent
%token<STR2> Nfloat
%type<STR2> RESULTADO

%left Nmas Nmenos


%left Npor Ndiv
%%
INICIO: RESULTADO {imprimir("Resultado: "+QString::number($<STR2>1))}
;
RESULTADO: RESULTADO Nmas RESULTADO {$<STR2>$ = $<STR2>1+$<STR2>3}
| RESULTADO Nmenos RESULTADO {$<STR2>$ = $<STR2>1-$<STR2>3}
| RESULTADO Npor RESULTADO{$<STR2>$ = $<STR2>1*$<STR2>3}
| RESULTADO Ndiv RESULTADO {$<STR2>$ = $<STR2>1/$<STR2>3}
| Nparen RESULTADO Ncparen {$<STR2>$ = $<STR2>2}
| Nent {$<STR2>$ = $<STR2>1}
| Nfloat {$<STR2>$ = $<STR2>1};
%%

You might also like