Question

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:

lexer.l

%{
#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();
}

parser.y

%{
#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);
}

Makefile

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?

Was it helpful?

Solution

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.)

OTHER TIPS

You're using the bison option %pure-parser which changes the way it calls yylex. You need to add the flex %option bison-bridge to your .l file to get flex to use the same calling conventions for yylex

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top