First, here's a C reentrant flex parser and pure bison example that parses a grammar that matches the following:
()
(())
(()())
()()(())()()
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 */
parser.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);
}
Building
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
Note: OSX's built-in bison is outdated, so install 3.x:
brew install bison
And then run it like /usr/local/opt/bison/bin/bison ....
Now, to migrate to C++
- copy .l to .lxx and .y to .yxx
- change names for output files to *.cxx and *.hxx respectively.
lexer.lxx
- add
%option c++
- remove
reentrant
,bison-bridge
andbison-locations
- change all tokens like the following:
LPAREN
toyy::parser::token::LPAREN
parser.yxx
- add
%skeleton "lalr1.cc"
- remove
api.pure
- remove
yyerror
main.cxx
- rewrite it for C++
Hooking up the lexer and parser objects is an exercise for the reader.
See also: https://github.com/bingmann/flex-bison-cpp-example but beware it uses the old bison 2.x interfaces.