Creación de un parser con flex y bison en C++

La siguiente receta explica como construir un analizador léxico con Flex y un analizador sintáctico con Bison, utilizando C++. Además, incluye un pequeño Makefile para el enlazado de todos los archivos y un ejemplo mínimo de uso.

Requisitos


  • bison++

El paquete bison++ instalará también lo necesario de flex.

Construcción


scanner.l


Este archivo es el que va contener la especificación Flex del analizador léxico. Si estudias el código siguiente verás
que el analizador es muy simple: sólo reconoce números enteros.

%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();
                  }
%%

Es importante ver que el analizador sintáctico (“Parser”) ya conoce los tokens, por lo que el analizador léxico no tiene más que devolver el token encontrado.

parser.y


A continuación el analizador sintáctico, también sencillo, que sólo consta de una construcción válida para el lenguaje.

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

test.cc


Finalmente, el archivo de prueba que crea el objeto parser que lanzará el comienzo de análisis (léxico y sintáctico).

#include "parser.h"
#include < iostream >
using namespace std;
 
int main(int argc, char ** argv)
{
       Parser parser;
       parser.yyparse();
       return 0;
}

Makefile


Para compilar y enlazar todo es necesario seguir un orden específico. Como muestra el siguiente Makefile, es necesario mantener la consistencia de nombres y crear primero el parser, después el scanner y finalmente el programa de prueba.

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

Referencias

Comentarios

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de Vigilante

Muy sencillito

Me ha entrado envidia y voy a realizar yo la receta usando JFlex y CUP.

error: redefinición de 'class yyFlexLexer'

En primer lugar dar las gracias por este tutorial, me ha venido muy bien para migrar mi Flex/Bison de C a C++

En segundo lugar, quisiera hacer una pequeña aportación:
- Es posible que al compilar os arroje este ERROR:

/usr/include/FlexLexer.h:112: error: redefinición de 'class yyFlexLexer'
/usr/include/FlexLexer.h:112: error: definición previa de 'class yyFlexLexer'

-En mi caso se ha dado utilizando KUbuntu 8.04(64bits) y resulta que es un bug: http://bugs.kde.org/show_bug.cgi?id=67277

-El PROBLEMA es que internamente se hacen varios "includes" a la librería "FlexLexer.h" y no se han definido bien las etiquetas "ifdefined...", por lo que se redefine la clase "yyFlexLexer"

-La SOLUCIÓN más sencilla consiste en insertar la línea:
#undef yyFlexLexer
justo antes de la linea:
#include <FlexLexer.h>
en nuestro fichero ".l"

Un saludo!

Flex

Escribí un artículo hace algún tiempo que me gustaría compartir con ustedes: http://rolandopalermo.blogspot.com/2009/12/como-configurar-flex-en-windo...
Espero que les sea de utilidad, saludos.