yyprse()的未解析外部符号

unresolved external symbol for yyparse()

本文关键字:外部 符号 yyprse      更新时间:2023-10-16

我的main.cpp看起来像这样:

#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 */
}

当我试图编译它时,我得到错误:main.obj:error LNK2019: unresolved external symbol "int __cdecl yyparse(void)" (?yyparse@@YAHXZ) referenced in function _main

我是flex/bison的新手。如有任何帮助,我们将不胜感激。如果有帮助的话,这里是我的解析器.y文件:

%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:%sn", message);
    exit(1);
}

EDIT1:我在VS 2012环境中使用winflexbison来生成我的解析器和lexer。构建过程相当简单。所需要做的就是将<appropriate>_custom_build.targets添加到VS中项目构建自定义项中,然后只构建解决方案。该文档的参考资料可以在@winflexbison for Visual studio中找到。

我还想指出,我采用了相同的方法构建了一个示例flex和bison文件,后来集成到了一个项目中。这对我来说很好。

我在这里做错了什么?

您的野牛输入包括一个注释良好但过时的定义[注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

正如注释所示,这将导致yyparse的原型为:

int yyparse(void* astDest);

然而,在main函数中,您已经声明了

extern int yyparse();

由于是用C++编译的,所以main.cpp中声明并由main调用的yyparseparser.tab.h中声明并在parser.tab.cpp中定义的yyparse不是同一个函数。因此,您会得到一个链接器错误。

如果您将#include "parser.tab.h"放入main.cpp文件,而不是手动声明yyparse,您可能会看到一条更容易理解的错误消息,尽管我不能保证VS 2012产生的错误消息。


注:

  1. YYPARSE_PARAM自十多年前的bison 1.875版本以来就一直被弃用,目前它只能与yacc兼容的解析器一起使用。您应该使用%parse-param声明,它适用于所有bison生成的解析器,并且允许您指定实际的参数类型,而不必放弃类型安全性。有关详细信息,请参阅野牛手册

您需要使用Bison从语法文件生成一个C文件。然后,您需要编译该C文件(默认情况下将命名为y.tab.c(,并将其与包含main定义的C文件链接。