15
votes

I already looked for my answer but I didn't get any quick response for a simple example.

I want to compile a flex/bison scanner+parser using g++ just because I want to use C++ classes to create AST and similar things.

Searching over internet I've found some exploits, all saying that the only needed thing is to declare some function prototypes using extern "C" in lex file.

So my shady.y file is

%{
#include <stdio.h>
#include "opcodes.h"
#include "utils.h"

void yyerror(const char *s)
{
    fprintf(stderr, "error: %s\n", s);
}

int counter = 0;

extern "C"
{
        int yyparse(void);
        int yylex(void);  
        int yywrap()
        {
                return 1;
        }

}

%}

%token INTEGER FLOAT
%token T_SEMICOL T_COMMA T_LPAR T_RPAR T_GRID T_LSPAR T_RSPAR
%token EOL

%token T_MOV T_NOP


%% 

... GRAMMAR OMITTED ...

%%

main(int argc, char **argv)
{
    yyparse();
}

while shady.l file is

%{
    #include "shady.tab.h"
%}

%%

"MOV"|"mov" { return T_MOV; }
"NOP"|"nop" { return T_NOP; }

";" { return T_SEMICOL; }
"," { return T_COMMA; }
"(" { return T_LPAR; }
")" { return T_RPAR; }
"#" { return T_GRID; }
"[" { return T_LSPAR; }
"]" { return T_RSPAR; }
[1-9][0-9]? { yylval = atoi(yytext); return INTEGER;}
[0-9]+"."[0-9]+ | "."?[0-9]? { yylval.d = atof(yytext); return FLOAT; }
\n { return EOL; }
[ \t] { /* ignore whitespace */ }
. { printf("Mystery character %c\n", *yytext); }

%%

Finally in the makefile I use g++ instead of gcc:

shady: shady.l shady.y
bison -d shady.y -o shady.tab.c
flex shady.l
g++ -o $@ shady.tab.c lex.yy.c -lfl

flex and bison work correctly but upon linking I get the following error:

Undefined symbols:
  "_yylex", referenced from:
  _yyparse in ccwb57x0.o

Of course if I try to change anything about the function in bison file it says that yylex is not declared in the scope of yyparse.

Am I trying to solve simply something that is more complex than it seems? Actually I don't need a closed structure to have access to parse and lexer in a object oriented manner, I just want to make it work.

I just want to be able to use C++ in bison file (to create AST) and to call yyparse() from C++ objects..

Thanks in advance

1
Both flex and bison have flags to generate C++, not C.vonbrand
Yuck. It's not a good idea to use impure, non-reentrant C parsers with static global variables in C++. It's much cleaner to use flex and bison in C++ modes respectively. gnu.org/software/bison/manual/…user246672

1 Answers

12
votes

You need the extern "C" {} for yylex to be in shady.l:

%{
    extern "C"
    {
        int yylex(void);
    }

    #include "shady.tab.h"
%}

%%

"MOV"|"mov" { return T_MOV; }
"NOP"|"nop" { return T_NOP; }

...etc...

Also, after adding a dummy grammar rule, I was able to build and run this with just:

  559  flex shady.l
  560  bison -d shady.y
  561  g++ shady.tab.c lex.yy.c