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
Add all strings to one string and use yy_scan_string
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);
}
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
.