My main.cpp looks like this:
#include <assert.h>
#include <fstream>
#include <iostream>
#include "astgen.h"
#include "astexec.h"
extern int yyparse();
extern FILE *yyin;
int main()
{
//yydebug = 0;
struct AstElement *a = 0;
FILE *fp ;
fopen_s(&fp,"example.txt","r");
//std::cout<<fp;
if (fp==NULL)
{
std::cout<<"error";
}
yyin=fp;
yyparse();
assert(a);
struct ExecEnviron* e = createEnv();
execAst(e, a);
freeEnv(e);
/* TODO: destroy the AST */
}
When I try to compile this, I get the error: main.obj : error LNK2019: unresolved external symbol "int __cdecl yyparse(void)" (?yyparse@@YAHXZ) referenced in function _main
I am a newbie in flex/bison. Any help would be appreciated. If it helps here is my parser.y file:
%error-verbose /* instruct bison to generate verbose error messages*/
%{
#include "astgen.h"
#define YYDEBUG 1
/* Since the parser must return the AST, it must get a parameter where
* the AST can be stored. The type of the parameter will be void*. */
#define YYPARSE_PARAM astDest
extern int yylex();
%}
%union {
int val;
char op;
char* name;
struct AstElement* ast; /* this is the new member to store AST elements */
}
%token TOKEN_BEGIN TOKEN_END TOKEN_WHILE TOKEN_DO
%token<name> TOKEN_ID
%token<val> TOKEN_NUMBER
%token<op> TOKEN_OPERATOR
%type<ast> program block statements statement assignment expression whileStmt call
%start program
%{
/* Forward declarations */
void yyerror(const char* const message);
%}
%%
program: statement';' { (*(struct AstElement**)astDest) = $1; };
block: TOKEN_BEGIN statements TOKEN_END{ $$ = $2; };
statements: {$$=0;}
| statements statement ';' {$$=makeStatement($1, $2);}
| statements block';' {$$=makeStatement($1, $2);};
statement:
assignment {$$=$1;}
| whileStmt {$$=$1;}
| block {$$=$1;}
| call {$$=$1;}
assignment: TOKEN_ID '=' expression {$$=makeAssignment($1, $3);}
expression: TOKEN_ID {$$=makeExpByName($1);}
| TOKEN_NUMBER {$$=makeExpByNum($1);}
| expression TOKEN_OPERATOR expression {$$=makeExp($1, $3, $2);}
whileStmt: TOKEN_WHILE expression TOKEN_DO statement{$$=makeWhile($2, $4);};
call: TOKEN_ID '(' expression ')' {$$=makeCall($1, $3);};
%%
#include "astexec.h"
#include <stdlib.h>
void yyerror(const char* const message)
{
fprintf(stderr, "Parse error:%s\n", message);
exit(1);
}
EDIT 1: I am using winflexbison in VS 2012 environment to generate my parser and the lexer. The process for the build is rather simple. All that is required to be done is to add the <appropriate>_custom_build.targets
to build customizations for the project in VS and just build solution. A reference to the documentation can be found here @ winflexbison for Visual studio.
I would also like to point out that I followed the same method to build a sample flex and bison file and later integrated in a project. That worked fine for me.
What am I doing wrong here?
You need to use Bison to generate a C file from your grammar file. Then you need to compile that C file (which will be named
y.tab.c
by default) and link it with your C file that contains your definition ofmain
.Your bison input includes a well-commented but obsolete definition [note 1]:
As the comment indicates, this will cause the prototype for
yyparse
to be:However, in your
main
function, you've declaredSince you are compiling this with C++, the
yyparse
declared inmain.cpp
and invoked bymain
is not the same function as theyyparse
declared inparser.tab.h
and defined inparser.tab.cpp
. Consequently, you get a linker error.Had you put
#include "parser.tab.h"
into yourmain.cpp
file instead of manually declaringyyparse
, you would probably have seen a more easily-understood error message, although I can't vouch for error messages produced by VS 2012.Notes:
YYPARSE_PARAM
has been deprecated since bison version 1.875, well more than a decade ago, and it currently only works with yacc-compatible parsers. You should use the%parse-param
declaration, which works with all bison-produced parsers, and which allows you to specify an actual parameter type rather than having to abandon type safety. See the bison manual for details.