"yyparse/yylex/yyerror was not declared in this scope" - Flex/Bison
"yyparse/yylex/yyerror was not declared in this scope" - Flex/Bison
我正在 Windows 上使用 Flex 和 Bison 为一种相对简单的语言创建编译器。但是编译器告诉我函数 yyerror 和 yyparse 没有在正确的范围内声明。经过一番阅读后,我发现问题显然是 C 和 C++ 链接的冲突(我正在使用 g++,因为我正在尝试构建抽象语法树)。代码摘录如下。
monty.y:
%{
extern "C" {
int yyparse();
int yylex(void);
void yyerror(char *s){}
int yywrap(void){return 1;}
}
#include <stdio.h>
#include <string.h>
#include "ast\ast.h"
using namespace std;
Program* root;
//extern int yyparse();
main() {
yyparse();
}
%}
monty.l:
%{
#include <stdlib.h>
#include "ast/ast.h"
#include "y.tab.h"
%}
%%
"do" { puts("DO"); return DO; }
"else" { puts("ELSE"); return ELSE; }
"end" { puts("END"); return END; }
"if" { puts("IF"); return IF; }
etc...
%%
int main(void)
{
yyparse();
return 0;
}
任何有关这些错误来源的帮助或启发将不胜感激:)
包含在 %{ ... }%
中的 .y
文件中的代码被逐字复制到生成的解析器文件的顶部 在自动生成的定义 之前功能类似于 yyparse
。因此,您编写的代码(包括 main
的定义和对 yyparse
的调用)出现在任何这些函数的声明或定义之前。这可能是您的错误来源。
请记住,生成的解析器文件不必包含 main
。事实上,您可能需要考虑创建一个包含 main
的单独 C++ 源文件。然后让该文件包含自动生成的 header 以便它看到 yyparse
.
的声明
此外,如果您尝试为此程序编写 C++ 代码,请注意您在 bison 源文件中声明的 main
函数不是有效的 C++,因为它没有 return 类型声明。所有 C++ main
函数必须显式 return 一个 int
.
另请注意,您有两个主要函数,一个在词法分析器文件中,一个在解析器文件中,这会给您的后续操作带来问题。将您的 main
函数分解到它自己的单独文件中,然后包含词法分析器和解析器 header 文件将解决此问题。
最后请注意,如果您确实要生成C++代码,则无需将void
放入main
的参数列表中。 C++ 假定空参数列表表示 "takes no parameters" 并且无需另外说明。
如果将 flex 文件编译为 C++,则无需将 yyerror
和 yyparse
声明为 extern "C"
。
事实上,没有必要将 yyerror
和 yyparse
声明为 extern "C"
,除非您从不同的模块引用它们 .您确实在 flex
文件的 main()
中引用了 yyparse
,但是您的 bison 文件中也有一个 main()
,并且您只需要一个 main()
.没有迹象表明您从 flex 文件中调用了 yyerror()
,通常恕我直言,这不是一个好主意。但是,如果您确实从 flex 文件中调用 yyerror
和 yyparse
,则需要在该文件中声明它们。如果您 将 flex 生成的扫描器编译为 C++,那么在您的 bison 文件中声明为 extern "C"
实际上会产生问题而不是解决问题。
简而言之:
extern "C"
很少是任何 bison/flex 问题的正确解决方案。
flex 生成的扫描器可以用 C++ 编译器编译,即使它们生成为 C 文件。 bison 生成的解析器也是如此,尽管生成 C++ 解析器的用例更多。
如果您使用相同的语言编译扫描器和解析器,将会使您的生活更轻松。
我正在 Windows 上使用 Flex 和 Bison 为一种相对简单的语言创建编译器。但是编译器告诉我函数 yyerror 和 yyparse 没有在正确的范围内声明。经过一番阅读后,我发现问题显然是 C 和 C++ 链接的冲突(我正在使用 g++,因为我正在尝试构建抽象语法树)。代码摘录如下。
monty.y:
%{
extern "C" {
int yyparse();
int yylex(void);
void yyerror(char *s){}
int yywrap(void){return 1;}
}
#include <stdio.h>
#include <string.h>
#include "ast\ast.h"
using namespace std;
Program* root;
//extern int yyparse();
main() {
yyparse();
}
%}
monty.l:
%{
#include <stdlib.h>
#include "ast/ast.h"
#include "y.tab.h"
%}
%%
"do" { puts("DO"); return DO; }
"else" { puts("ELSE"); return ELSE; }
"end" { puts("END"); return END; }
"if" { puts("IF"); return IF; }
etc...
%%
int main(void)
{
yyparse();
return 0;
}
任何有关这些错误来源的帮助或启发将不胜感激:)
包含在 %{ ... }%
中的 .y
文件中的代码被逐字复制到生成的解析器文件的顶部 在自动生成的定义 之前功能类似于 yyparse
。因此,您编写的代码(包括 main
的定义和对 yyparse
的调用)出现在任何这些函数的声明或定义之前。这可能是您的错误来源。
请记住,生成的解析器文件不必包含 main
。事实上,您可能需要考虑创建一个包含 main
的单独 C++ 源文件。然后让该文件包含自动生成的 header 以便它看到 yyparse
.
此外,如果您尝试为此程序编写 C++ 代码,请注意您在 bison 源文件中声明的 main
函数不是有效的 C++,因为它没有 return 类型声明。所有 C++ main
函数必须显式 return 一个 int
.
另请注意,您有两个主要函数,一个在词法分析器文件中,一个在解析器文件中,这会给您的后续操作带来问题。将您的 main
函数分解到它自己的单独文件中,然后包含词法分析器和解析器 header 文件将解决此问题。
最后请注意,如果您确实要生成C++代码,则无需将void
放入main
的参数列表中。 C++ 假定空参数列表表示 "takes no parameters" 并且无需另外说明。
如果将 flex 文件编译为 C++,则无需将 yyerror
和 yyparse
声明为 extern "C"
。
事实上,没有必要将 yyerror
和 yyparse
声明为 extern "C"
,除非您从不同的模块引用它们 .您确实在 flex
文件的 main()
中引用了 yyparse
,但是您的 bison 文件中也有一个 main()
,并且您只需要一个 main()
.没有迹象表明您从 flex 文件中调用了 yyerror()
,通常恕我直言,这不是一个好主意。但是,如果您确实从 flex 文件中调用 yyerror
和 yyparse
,则需要在该文件中声明它们。如果您 将 flex 生成的扫描器编译为 C++,那么在您的 bison 文件中声明为 extern "C"
实际上会产生问题而不是解决问题。
简而言之:
extern "C"
很少是任何 bison/flex 问题的正确解决方案。flex 生成的扫描器可以用 C++ 编译器编译,即使它们生成为 C 文件。 bison 生成的解析器也是如此,尽管生成 C++ 解析器的用例更多。
如果您使用相同的语言编译扫描器和解析器,将会使您的生活更轻松。