utilisation de bison et flex en c++
salut à tous !
voilà mon problème, pour notre projet de fin de semestre en master informatique, nous devons par groupe de 8 créer un compilateur / interprèteur d'un langage appelé minijaja dont la grammaire peut être consultée ici : http://lifc.univ-fcomte.fr/~bouquet/Enseignement/Compilation/minijaja.html
nous avions le choix entre l'utilisation d'un parser javaCC / jjTree ou Flex et Bison. C'est sur ce deuxième élément que s'est porté notre choix : nous utilisons donc Flex et Bison sous un environnement Linux.
voici le contenu de mon fichier utilisé par Flex : terminaux.l
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| %{
#include "terminaux.tab.h"
extern int yylval;
%}
%x COMMENTS
%%
"class" { return CLASS; }
"{" { return BEGINBLOCK; }
"}" { return ENDBLOCK; }
"==" { return EQUAL; }
"=" { return ASSIGN; }
"!" { return NOT; }
"+=" { return PLUSEQUAL; }
";" { return SEMICOLON; }
"[" { return LEFTBRACKET; }
"]" { return RIGHTBRACKET; }
"final" { return FINAL; }
")" { return RIGHTPARENTHESE; }
"(" { return LEFTPARENTHESE; }
"main" { return MAIN; }
"," { return COMMA; }
"++" { return PLUSPLUS; }
"return" { return RETURN; }
"if" { return IF; }
"else" { return ELSE; }
"while" { return WHILE; }
"-" { return MINUS; }
"&&" { return AND; }
"||" { return OR; }
">" { return GREATER; }
"+" { return PLUS; }
"*" { return MULT; }
"/" { return DIVIDE; }
"true" { return TRUE; }
"false" { return FALSE; }
"void" { return VOID; }
"int" { return INTEGER; }
"boolean" { return BOOLEAN; }
[0-9]+ { /*yylval = atoi(yytext);*/ return NUMBER; }
[a-zA-Z_][0-9a-zA-Z_]* { return IDENTIFIER; }
[ \t]+ { ; /* espaces vierges */ }
(\r?\n) { ; /* ligne vide : reconnait les CR-LF (windows) et les LF (unix) */ }
"//".*\n { ; /* commentaires */ }
"/*" { BEGIN COMMENTS; }
<COMMENTS>. |
<COMMENTS>\n { ; }
<COMMENTS>"*/" { BEGIN 0; }
. { /*yyerror("illegal token");*/ }
%% |
voici le contenu de mon fichier utilisé par Bison : terminaux.y
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
| %{
#include <stdio.h>
void yyerror(char * msg) {
fprintf(stderr, "%s\n", msg);
}
%}
/* l'element par lequel commence l'analyse,
ce ne doit pas etre un token */
%start root
%token CLASS
%token BEGINBLOCK
%token ENDBLOCK
%token EQUAL
%token ASSIGN
%token NOT
%token PLUSEQUAL
%token SEMICOLON
%token LEFTBRACKET
%token RIGHTBRACKET
%token FINAL
%token RIGHTPARENTHESE
%token LEFTPARENTHESE
%token MAIN
%token COMMA
%token PLUSPLUS
%token RETURN
%token IF
%token ELSE
%token WHILE
%token MINUS
%token AND
%token OR
%token GREATER
%token PLUS
%token MULT
%token DIVIDE
%token TRUE
%token FALSE
%token VOID
%token INTEGER
%token BOOLEAN
%token NUMBER
%token IDENTIFIER
%%
root:
classe
;
classe:
CLASS ident BEGINBLOCK decls methmain ENDBLOCK
;
ident:
IDENTIFIER
;
decls:
| decl SEMICOLON decls
;
decl:
var
| methode
;
vars:
| var SEMICOLON vars
;
var:
typemeth ident vexp
| typemeth ident LEFTBRACKET exp RIGHTBRACKET
| FINAL type ident vexp
;
vexp:
| ASSIGN exp
;
methode:
typemeth ident LEFTPARENTHESE entetes RIGHTPARENTHESE BEGINBLOCK vars instrs ENDBLOCK
;
methmain:
MAIN BEGINBLOCK vars instrs ENDBLOCK
;
entetes:
| entete COMMA entetes
| entete
;
entete:
type ident
;
instrs:
| instr SEMICOLON instrs
;
instr:
ident1 ASSIGN exp
| ident1 PLUSEQUAL exp
| ident1 PLUSPLUS
| ident LEFTPARENTHESE listexp RIGHTPARENTHESE
| RETURN exp
| IF exp BEGINBLOCK instrs ENDBLOCK
| IF exp BEGINBLOCK instrs ENDBLOCK ELSE BEGINBLOCK instrs ENDBLOCK
| WHILE exp BEGINBLOCK instrs ENDBLOCK
;
listexp:
| exp COMMA listexp
| exp
;
exp:
NOT exp1
| MINUS exp1
| exp AND exp1
| exp OR exp1
| exp1
;
exp1:
exp1 EQUAL exp2
| exp1 GREATER exp2
| exp2
;
exp2: exp2 PLUS terme
| exp2 MINUS terme
| terme
;
terme:
terme MULT fact
| terme DIVIDE fact
| fact
;
fact:
ident1
| ident LEFTPARENTHESE listexp RIGHTPARENTHESE
| TRUE
| FALSE
| NUMBER
| LEFTPARENTHESE exp RIGHTPARENTHESE
;
ident1:
ident
| ident LEFTBRACKET exp RIGHTBRACKET
;
typemeth:
VOID
| type
;
type:
INTEGER
| BOOLEAN
;
%%
main() {
yyparse();
} |
voici les commandes que j'exécute pour tester la grammaire :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| ~/compil2 $ flex terminaux.l && bison -d terminaux.y
~/compil2 $ gcc -o test lex.yy.c terminaux.tab.c -ll
~/compil2 $ ./test
class C {
/* un commentaire
* sur plusieurs lignes.
*/
int x = 2;
int y = 3;
int somme(int a, int b) {
return x + y;
};
main {
int z = somme(x, y);
}
}
~/compil2 $ |
comme vous pouvez le voir, la génération de l'analyseur s'effectue très bien en C. seulement, notre projet doit utiliser du C++, c'est une contrainte du cahier des charges. Est il possible de créer cet analyseur en C++ depuis Flex et Bison ? j'ai vaguement entendu parler de Flex++ et Bison++, est une bonne solution ?
Nous devrons stocker l'arbre syntaxique, et pour cela notre structure (en cours de développement) sera faite en C++. J'avais éventuellement pensé à appeler les fonctions de création de la structure (C++) depuis l'analyseur (C). Est ce possible ?
avez vous déjà utilisé ces outils ? que me conseillez vous ? J'espère que vous pourrez m'aider car c'est très important, sans cet analyseur, nous ne pourrons pas avancer dans notre projet.
:merci: