我正在使用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;
}
对于这些错误的来源的任何帮助或启发将不胜感激:)
答案 0 :(得分:1)
.y
文件中包含在%{ ... }%
中的代码将逐字复制到生成的解析器文件的顶部,然后再自动生成函数的定义,如{{1} }}。因此,您编写的代码(包括yyparse
的定义和对main
的调用)会在声明或定义任何函数之前出现。这可能是您的错误的来源。
请记住,生成的解析器文件不必包含yyparse
。实际上,您可能需要考虑创建一个包含main
的单独C ++源文件。然后,您将该文件包含自动生成的标头,以便它看到main
的声明。
此外,如果您正在尝试为此程序编写C ++代码,请注意您在bison源文件中声明的yyparse
函数无效C ++,因为它没有声明返回类型。所有C ++ main
函数都必须显式返回main
。
另请注意,您有两个主要功能,一个位于lexer文件中,另一个位于解析器文件中,这将导致您前进的问题。将int
函数分解到其自己的单独文件中,然后包含词法分析器和解析器头文件将解决此问题。
最后,请注意,如果您确实生成了C ++代码,则无需将main
放在参数列表中void
。 C ++假设一个空参数列表意味着“不带参数”,并且不需要另外声明。
答案 1 :(得分:0)
如果将flex文件编译为C ++,则无需将yyerror
和yyparse
声明为extern "C"
。
事实上,除非您从其他模块引用它们,否则无需将yyerror
和yyparse
声明为extern "C"
。您确实在yyparse
文件的main()
中引用flex
,但您的野牛文件中也有main()
,而您只需要一个main()
。没有迹象表明你从你的flex文件中调用yyerror()
,一般来说这不是一个好主意恕我直言。但是,如果您从Flex文件中调用yyerror
和yyparse
,则需要在该文件中声明它们。如果你 将flex生成的扫描程序编译为C ++,那么你的bison文件中extern "C"
的声明实际上会产生问题而不是解决问题。
简而言之:
extern "C"
很少是解决任何野牛/弹性问题的正确方法。
flex生成的扫描程序可以使用C ++编译器进行编译,即使它们是作为C文件生成的。 bison生成的解析器也是如此,尽管有更多的用例可以生成C ++解析器。
如果您使用相同的语言编译扫描仪和解析器,您将会更轻松。