7
votes

I have a problem while compiling my code (undefined reference to 'yylex'). Let's start off with the snippet and I'll describe the details below:

Flex:

%{
#include <stdlib.h>
extern int yylex();
%}
%%
"=" {return EQ;}
"!="    {return NE;}
"<" {return LT;}
">" {return GT;}
":="    {return ASSIGN;}
";" {return SEMICOLON;}
"IF"    {return IF;}
"THEN"{return THEN;}

"END" {return END;}
[_a-z]+ {yylval.text = strdup(yytext); return IDENTIFIER;}
[ \t]+
[0-9]+          {
                yylval.var = atoi (yytext);
                return NUMBER;
                }
[-+/^*'%'()]    {
                return *yytext;
                }
\n              return RESULT;
%%

Bison:

%{
  extern "C"
  {
    int yyparse();
    int yylex(void);
    void yyerror(char *s){}
    int yywrap(void){return 1;}
  }

  #include <iostream>
  #include <vector>
  #include <string>
  #include <stdlib.h>
  #include <map>

  using namespace std;

  vector <string> instructions;
  map <> vars;
%}

%union{
  char* text;
  int var;
}


%token EQ
%token NE
%token ASSIGN
%token SEMICOLON
%token IF
%token THEN
%token <text> IDENTIFIER
%token <var> NUMBER
%token <var> RESULT

%left '+' '-'
%left '*' '/' '%'
%right '^'

%%

exp: NUMBER
| IDENTIFIER
| IDENTIFIER "+" IDENTIFIER
| IDENTIFIER "-" IDENTIFIER
;
%%

int main(void){
  yyparse();
} 

And here's the bash script I use to compile & run the program:

#!/bin/bash
clear
rm launcher lex.yy.cpp *.tab.cpp *.tab.hpp
bison  -d -o list.tab.cpp *.y
flex -o lex.yy.cpp *.l
g++ -o launcher *.cpp -lfl

Just for clear visibility, I'm posting here only the most important part of the code, because the rest is not really necessary here. Anyway, if someone would like to see the whole code, it's posted here: http://pastebin.com/1rS2FBJj. It's a bigger chunk of code and takes more place though.

When I try to compile all files to *.c files and then use gcc, it is all fine. But when I attempt to switch the compiler to g++ and therefore the files to cpp ones, I keep getting this error:

list.tab.cpp: In function ‘int yyparse()’:
list.tab.cpp:1397: warning: deprecated conversion from string constant to ‘char*’
list.tab.cpp:1540: warning: deprecated conversion from string constant to ‘char*’
/tmp/ccdqpQVx.o: In function `yyparse':
list.tab.cpp:(.text+0x252): undefined reference to `yylex'
collect2: ld returned 1 exit status

Could anyone give me a hint please, how would be the best to approach it?

1
Not exactly a fix for the problem, but -fno-const-strings will get rid of the warning.Richard Pennington

1 Answers

14
votes

In your Flex file, you declare this:

extern int yylex();

When compiled as C++, that declares a function with C++ linkage. In your Bison file, you declare this:

extern "C" {
  int yylex();
}

That gives it C linkage. They're two different functions. You define the C++ version (or, rather, Flex defines it for you), but you declare the C version, and the C version is the one the compiler thinks you try to call (in the Bison-generated code). The linker sees that the C version is used, but it cannot find the definition.

Pick one linkage and use it consistently. (I'd choose C++, since it allows omission of the "extern" stuff from the code entirely.)