2

I have vector of string which I want to parse in bison. I am supposed to receive this remotely and I don't want to write to a file and read back. My string vector can be very large.

Here's what I tried so far

  1. Add all strings to one string and use yy_scan_string

  2. I also tried adding all strings to buffer and yy_scan_string.

I tried to build the executable as follows:

bison -d logic.y
flex logic.l
g++ logic.tab.c lex.yy.c -lfl -o logic

but I receive the error:

undefined reference to `yy_scan_string'.

Here is my parser:

%{

#include <cstdio>
#include <iostream>
#include <string.h>
#include <vector>
#include <algorithm>
#include <Server.h>
using namespace std;

//stuff from flex that bison needs to know about:
extern "C" int yylex();
typedef struct yy_buffer_state * YY_BUFFER_STATE;
extern "C" int yyparse();
extern "C" YY_BUFFER_STATE yy_scan_string(const char * str);
//extern "C" void yy_delete_buffer(YY_BUFFER_STATE buffer);
extern int line_num;

vector<string> statements;

void yyerror(const char *s);

%}

//C union holding each of the types of tokens that Flex could return
%union { 
    char const *sval;
}

//symbol defination

//end of declaration section
%%        
//Start of grammar section

//grammar

//end of grammar section
%%

int main(int argc, char *argv[]) {
    try
    {
        logicMessage = server.getLogic();

        statements = logicMessage->get_LogicStatements ();       

        string  single = "";

        for (vector<string>::iterator it=statements.begin(); it!=statements.end(); ++it)
            single += *it; 

        char* buffer = new char[single.length()+1];
        strcpy(buffer,single.c_str());

        yy_scan_string(single.c_str());
        yyparse();

        //yy_delete_buffer(buffer);
        return 0;
    }
    catch(IPC_RETURN_CODE IPC_CODE)
    {
        std::cerr<< "IPC Error Code:" <<IPC_CODE;
    }
}

void yyerror(const char *s) {
    cout << "Parse error on line " << line_num << "!  Message: " << s << endl;
    // might as well halt now:
    exit(-1);
}
rici
  • 234,347
  • 28
  • 237
  • 341
Ruturaj
  • 630
  • 1
  • 6
  • 20
  • yy_scan_string will be defined in your scanner; you need to link the parser and the scanner to produce the executable. So the problem is in the way you build the executable. Please show the steps you followed. – rici Mar 20 '15 at 15:09
  • "bison -d logic.y","flex logic.l","g++ logic.tab.c lex.yy.c -lfl -o logic" – Ruturaj Mar 20 '15 at 15:42

2 Answers2

1

You really don't need those extern "C" declarations, and they are complicating your build process.

Both (modern) bison and flex produce code which can be compiled either as C or as C++, although you will find it simpler if you compile both of them the same way. In that case, you will have no need to use extern declarations, since all the external functions will be correctly compiled for the language you are using.

Note that when you compile with g++, files with the extension .c are compiled as C++ programs. Consequently, lex.yy.c is compiled as a C++ program, and the external functions, including yylex and yy_scan_string, have normal C++ linkage (and name mangling), and declaring them as external "C" in a different translation unit will create link errors.

Despite the above, I generally use the -o options to flex and bison to create filenames with appropriate extensions. It can also be useful to use the --header-file option of flex to produce a header file containing declarations for the exported functions, such as yy_scan_string.

rici
  • 234,347
  • 28
  • 237
  • 341
-1

I have read you need to place '"%option reentrant" in the lexer file'. Look here for more information. It seems as though you need to create a yyscan_t type object to pass in as well.

Community
  • 1
  • 1
salnoob
  • 1
  • 1
  • You can use yy_scan_string with either a standard or a reentrant lexer; you need to provide the `yyscan_t` object in the case of a reentrant lexer, but that is all completely orthogonal to this problem. – rici Mar 20 '15 at 16:23