I'm learning how to use Flex and Bison. I wrote a parser using C++. I got it to compile, but then when I add the options to track token position I get an error.
Here's a little example that generates the same error:
%{
#include <stdio.h>
#include "parser.tab.h"
#define YY_USER_ACTION yylloc->first_line = yylloc->last_line = yylineno; \
yylloc->first_column = yycolumn; \
yycolumn += yyleng;
int yycolumn = 1;
extern "C" int yyparse();
%}
%option bison-locations
%option yylineno
%option noyywrap
NAT [0-9]+
%%
{NAT} { printf("NUM: %d\n", atoi(yytext)); return NUM; }
"\n" yycolumn = 1;
.
%%
int main (int argc, char **argv) {
argc--, argv++;
if (argc > 0)
yyin = fopen(argv[0], "r");
else
yyin = stdin;
yyparse();
}
%{
#include <iostream>
#include <stdio.h>
#define YYSTYPE int
using namespace std;
void yyerror (char const*);
int yylex ();
extern "C" int yyparse ();
%}
%locations
%pure-parser
%token NUM
%%
s : NUM ;
%%
void yyerror(char const* s) {
fprintf(stderr, "%s\n", s);
}
par: parser.tab.c lex.yy.c
g++ lex.yy.c parser.tab.c -o par
parser.tab.c: parser.y
bison -d parser.y
lex.yy.c: lexer.l
flex lexer.l
I get the following error when I try to compile it:
parser.tab.c: In function ‘int yyparse()’:
parser.tab.c:1314:16: error: too many arguments to function ‘int yylex()’
parser.y:9:6: note: declared here
I tried change the declaration of yylex
in parser.y to something like int yylex (YYSTYPE*, YYLTYPE*)
but the name YYLTYPE
is out of scope and tried a few things more without success...
It compiles when the #define YY_USER_ACTION ...
, %option bison-locations
in lexer.l and %locations
and %pure-parser
in parser.y are removed.
How can I get it to work?
You are compiling the generated files with C++, although they are C files. That generally works but there is an issue with the declaration of yylex
. In C,
int yylex();
declares yylex
as a function without specifying anything about its parameter list. (int yylex(void)
would declare it to have no parameters.) That's not possible in C++, so you need to provide the precise parameter list. Unfortunately, the code block containing the definition of yylex
is inserted into the generated code before YYLTYPE
is defined.
A simple solution is to predeclare YYLTYPE as an incomplete type:
struct YYLTYPE;
which lets you use YYLTYPE*
in the declaration of yylex
. YYLTYPE
will eventually be declared as a struct
, unless you've provided your own declaration.
With a sufficiently recent version of bison, you should be able to use the following:
%code requires {
#include <iostream>
#include <stdio.h>
/* If you insist :) */
using namespace std;
}
%code provides {
void yyerror (char const*);
int yylex (YYSTYPE*, YYLTYPE*);
extern "C" int yyparse ();
%}
(This is quite possibly not what you want for a pure parser. But it might be enough to get you started.)