Ini parser flex++ / bison++

Description

Bonjour tout le monde !

Voilà les sources d'un parseur de fichier INI généré grâce à flex++ et bison++ . Il n'y a rien d'extraordinaire à faire un parseur avec flex, mais le challenge est tout autre quand on doit le faire avec flex++ et bison++ puis l'intégrer dans une application C++ (et pas seulement pour un but pédagogique). Je livre donc le travail de 4 jours de galère en espérant qu'il puisse servir à d'autres.

Source / Exemple :


######################################################################################################################
parseurINI.l
######################################################################################################################
%{
#define _SKIP_YYFLEXLEXER_
#include "Scanner.h"
#include "ParseurINI.h"
%}

%option noyywrap
%option c++
%option yyclass="Scanner"

%%
\n			{yylineno++;}
[ \t]*			{; /* spaces */}
;[^\n]*			{; /* comments */}
[^ \t\n\r;=\[\]]+	{return YY_ParseurINI_CLASS::CHAINE ;}
.			{return yytext[0] ;}
%%

######################################################################################################################
parseurINI.y
######################################################################################################################
%name ParseurINI
%define LSP_NEEDED

%define CONSTRUCTOR_PARAM istream* pFile
%define CONSTRUCTOR_INIT : scanner(pFile)
%define CONSTRUCTOR_CODE {yyparse() ;}

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

%define MEMBERS \
virtual ~ParseurINI() {} \
private: \
Scanner scanner ;\
map<string, map<string, string> > mapSections ; \
string sectionCourante ;\
public:\
const map<string, string> operator[] (string section) {return mapSections[section] ;}

%define ERROR_BODY {cerr << "error on line : " << scanner.lineno() << ", last token : '" << scanner.YYText() << "'" << endl;}

%header{
  // Inspiré de :
  // https://www.mirbsd.org/htman/i386/man1/lex.htm
  // http://pwet.fr/man/linux/commandes/bison
  // http://docs.linux.cz/programming/c++/www.icce.rug.nl/documents/cplusplus/cplusplus19.html#l362
  // Et beaucoup de courage !

#include <map>
#include <string>
#include <iostream>
#include <fstream>
#include "Scanner.h"
#include <string.h>

  using namespace std;
%}

%union { char chaine[500];}
%token <chaine> CHAINE
%type <chaine> chaine

%start fichier
%%

fichier:

	| section fichier
	| regle fichier
	;

section:
'[' chaine ']'		{sectionCourante = $2;}
	;

regle:
chaine '=' chaine	{(mapSections[sectionCourante])[$1] = $3;}
	;

chaine:
CHAINE			{strcpy($$, scanner.YYText());}
        ;
%%

######################################################################################################################
Scanner.h
######################################################################################################################
#ifndef _SCANNER_H_
#define _SCANNER_H_

#if ! defined(_SKIP_YYFLEXLEXER_)
#include <FlexLexer.h>
#endif

using namespace std ;

class Scanner: public yyFlexLexer
{
 public:
  Scanner (istream* pFile) : yyFlexLexer(pFile) {}
  int yylex();
};

#endif

######################################################################################################################
Main.cpp
######################################################################################################################
#include <map>
#include <string>
#include <vector>
#include <iostream>

#include "ParseurINI.h"

using namespace std;

int main()
{
  try
    {
      ifstream config ("config.ini") ;
      // &cin for stdin
      ParseurINI parseur(&config) ;

      map<string, string> sectionMain = parseur["Main"] ;
      cout << "Serveur MySQL : " << sectionMain["ServeurMySQL"] << endl ;

    }
  catch(string s)
    {
      cout << s << "\n" ;
      return 1 ;
    }
  catch(...)
    {
      cout << "Erreur innatendue\n" ;
      return 1 ;
    }

  return 0 ;
}

######################################################################################################################
Makefile
######################################################################################################################
COMPILE := -c
FLAGS := -Wall
CC := g++
EXEC := main.exe

all: ParseurINI.o lex.yy.o Main.o
	${CC} ${FLAGS} $^ -o ${EXEC}

%.o:%.cpp
	${CC} ${FLAGS} ${COMPILE} $^ -o $@

ParseurINI.o: parseurINI.l parseurINI.y Scanner.h
	bison++ -o ParseurINI.cpp -h ParseurINI.h -d parseurINI.y
	flex++ parseurINI.l
	g++ ${COMPILE} lex.yy.cc
	g++ ${COMPILE} ParseurINI.cpp

clean:
	rm -f *~ *.o *.gch ParseurINI.h ParseurINI.cpp lex.yy.cc ${EXEC}

Conclusion :


Les fichiers ont été crées sous Debian GNU/Linux donc attention à l'encodage.
g++ 4.3.2
flex++ 2.5.35
bison++ 1.21.9-1

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.