Configurer Bison et Flex sans variable globale ou statique
je travaille dans un petit langage / IDE. Et j'ai besoin de savoir comment configurer flex et bison pour travailler ensemble, mais sans utiliser de variable globale ou statique. J'ai besoin de passer à bison mon AST pointer. J'ai aussi besoin que bison passe mon AST à flex aussi. C'est un environnement de thread mais je n'ai pas besoin de synchronisation de thread. Et j'ai besoin d'une variable yylineno separete pour chaque appel yyparse (). J'ai lu à propos de l'api %define.pur, %parse-param et % option rentrant. Mais je ne sais pas comment les mettre en œuvre ainsi... merci à l'avance...
j'ai essayé ceci:
scanner.l:
%{
#include <iostream>
#include <sstream>
#include "parser.tab.h"
#define YY_DECL extern "C" int yylex(YYSTYPE * lvalp, yyscan_t scanner)
extern void yyerror(yyscan_t scanner, NBloco * bloco, const char *s);
%}
%option noyywrap
%option yylineno
%option reentrant
%option bison-bridge
%%
//...scanner code
analyseur.y:
%{
#include <iostream>
#include "AST.h"
#ifndef YY_TYPEDEF_YY_SCANNER_T
#define YY_TYPEDEF_YY_SCANNER_T
typedef void* yyscan_t;
#endif
extern "C" int yylex(YYSTYPE * lvalp, yyscan_t scanner);
extern "C" FILE *yyin;
extern int yylineno;
void yyerror(yyscan_t scanner, NBloco * bloco, const char *s);
%}
%union{
//union code
}
%define api.pure full
%lex-param { yyscan_t scanner }
%parse-param { yyscan_t scanner }
%parse-param { NBlock* block}
//tokens...
//types...
%%
//parser code...
Et j'ai obtenu ceci:
parser.y:13:22: warning: 'yylex' initialized and declared 'extern' [enabled by default] extern "C" int yylex(YYSTYPE * lvalp, yyscan_t scanner);
parser.y:13:22: error: 'YYSTYPE' was not declared in this scope
parser.y:13:32: error: 'lvalp' was not declared in this scope extern "C" int yylex(YYSTYPE * lvalp, yyscan_t scanner);
parser.y:13:48: error: expected primary-expression before 'scanner'
extern "C" int yylex(YYSTYPE * lvalp, yyscan_t scanner);
^
parser.y:13:55: error: expression list treated as compound expression in initializer [-fpermissive]
extern "C" int yylex(YYSTYPE * lvalp, yyscan_t scanner);
^
parser.tab.c: In function 'int yyparse(yyscan_t, NBloco*)':
parser.tab.c:932:39: error: 'yylex' cannot be used as a function
# define YYLEX yylex (&yylval, scanner)
parser.tab.c:1618:16: note: in expansion of macro 'YYLEX'
yychar = YYLEX;
// plus d'erreurs...
je dois aussi corriger le yylineno à être par fichier... je suis en se basant sur http://benlynn.blogspot.com.br/2013/12/reentrant-parsers-with-flex-and-bison.html et http://www.lemoda.net/c/reentrant-parser/index.html
1 réponses
tout d'abord, voici un exemple d'analyseur flex entrant et de bison pur qui analyse une grammaire qui correspond à ce qui suit:
()
(())
(()())
()()(())()()
lexer.l
%option bison-bridge
%option bison-locations
%option ecs
%option nodefault
%option noyywrap
%option reentrant
%option stack
%option warn
%option yylineno
%{
#include "parser.h"
%}
%%
"(" { return (LPAREN); }
")" { return (RPAREN); }
[ \f\r\t\v\n]+ /* eat whitespace */
%%
/* don't use lexer.l for code, organize it logically elsewhere */
analyseur.y
%define parse.error verbose
%define api.pure true
%locations
%token-table
%glr-parser
%lex-param {void *scanner}
%parse-param {void *scanner}
%{
/* your top code here */
%}
%union {
int value; // or whatever else here
}
%token LPAREN
%token RPAREN
%%
document
: exprs
exprs
: %empty
| expr exprs
expr
: parens
parens
: LPAREN exprs RPAREN
%%
int
yyerror(YYLTYPE *locp, char *msg) {
if (locp) {
fprintf(stderr, "parse error: %s (:%d.%d -> :%d.%d)\n",
msg,
locp->first_line, locp->first_column,
locp->last_line, locp->last_column
);
/* todo: add some fancy ^^^^^ error handling here */
} else {
fprintf(stderr, "parse error: %s\n", msg);
}
return (0);
}
main.c
#include "parser.h"
#include "lexer.h"
int
main(int argc, char **argv) {
int result;
yyscan_t scanner;
yylex_init(&scanner);
result = (yyparse(scanner));
yylex_destroy(scanner);
return (result);
}
flex --header-file=lexer.h --outfile=lexer.c lexer.l
bison --output-file=parser.c --defines=parser.h --warnings=all --feature=all parser.y
cc lexer.c parser.c main.c -o parser
./parser
Remarque: le bison intégré à OSX est désuet, alors installez 3.x:
brew install bison
Et ensuite l'exécuter comme /usr/local/opt/bison/bin/bison ....
maintenant, migrer vers C++
- copier .l pour .lxx et .y pour .yxx
- changer le nom des fichiers de sortie en *.cxx et *.hxx respectivement.
lexer.lxx
- ajouter
%option c++
- supprimer
reentrant
,bison-bridge
etbison-locations
- modifier tous les jetons comme suit:
LPAREN
yy::parser::token::LPAREN
analyseur.yxx
- ajouter
%skeleton "lalr1.cc"
- supprimer
api.pure
- supprimer
yyerror
main.cxx
- le réécrire en C++
brancher les objets lexer et parser est un exercice pour le lecteur.
Voir aussi: https://github.com/bingmann/flex-bison-cpp-example mais attention, il utilise le vieux bison 2.x interfaces.