Search code examples
c++cmakebisonlex

Bison Flex linking problems


There is a parser running on bison & flex. To build and make the whole project cmake is used.

So, from flex file I create lexer.cpp file and from bison file parser.cpp & parser.hpp. The code looks like this :

lexer.flex :

%{
#include "structures/RedirectionExpr.h"
// and about 8 includes like the upper one
#include <iostream>
#include <bits/stdc++.h>
#include "parcer.hpp"

using namespace std;
%}

%option noyywrap
%option c++

%%
/* Some staff */
%%

parser.ypp :

%{
  #include "structures/RedirectionExpr.h"
// and about 8 includes like the upper one, like in lexer.flex

  #include <bits/stdc++.h>
  #include <iostream>

  extern "C" int yylex(void);
  extern "C" int yyparse();
  extern "C" int errors;
  void yyerror (char const *s);
  using namespace std;
%}
%union {
    /* Union types. */ 
}

// %token definitions
// %type definitions for grammar

%%
/* grammar is here */
%%

void yyerror (char const *s) { /* Some code here */ }

int main(int argc, char *argv[])
{
    do {
          yyparse();
    } while (true);
    return 0;
}

Before compilation, I manually create cpp files from .flex and .ypp files:

flex -o lexer.cpp lexer.flex

bison -d -o parser.cpp parser.ypp

To build all this mess, I use cmake:

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(parse)
set(CMAKE_CXX_STANDARD 14)
add_executable(parse 
        src/structures/RedirectionExpr.cpp        
        # other includes of classes used
        src/lexer.cpp
        src/parser.cpp src/parser.hpp
)

So, the problem appears, when linking :

/usr/sbin/ld: CMakeFiles/parse.dir/src/parser.cpp.o: in function `yyparse':
parser.cpp:(.text+0x31a): undefined reference to `yylex'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/parse.dir/build.make:294: parse] Error 1
make[1]: *** [CMakeFiles/Makefile2:76: CMakeFiles/parse.dir/all] Error 2
make: *** [Makefile:84: all] Error 2

As a solution I tried to add %noyywrap option, include parser.hpp into .flex file after than I include additional classes, put extern "C" int yylex(void); line into parser.ypp etc. But right now I have no idea how to fix it. Can you help me with it?

Update

I solved the problem by removing extern "C" and leaving int yylex(void); part in parser.ypp file. You can read more about it here.


Solution

  • It looks to me like you're intending to use the C lexer API. After all, in your parser you say

    extern "C" int yylex(void);
    

    So it's a bit puzzling that you use %option c++ in your flex file. If you do that, you will get the C++ interface, which does not include a "C" yylex().

    I think your easy option would be to delete that %option and change the declaration of yylex to just

    int yylex();
    

    without the extern "C"

    If you really want to use the C++ interfaces, I believe the Bison manual includes an example of using a C++ flex lexer. It's more work but I'm sure it pays off.

    Also, I'm not a CMake user but I'm pretty sure CMake does know how to compile flex/bison projects (see, for example, this answer). It might get confused by the C++ interfaces, but it looks like it's easy to do a traditional C build.