"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++,则无需将 yyerroryyparse 声明为 extern "C"

事实上,没有必要将 yyerroryyparse 声明为 extern "C" ,除非您从不同的模块引用它们 .您确实在 flex 文件的 main() 中引用了 yyparse,但是您的 bison 文件中也有一个 main(),并且您只需要一个 main() .没有迹象表明您从 flex 文件中调用了 yyerror(),通常恕我直言,这不是一个好主意。但是,如果您确实从 flex 文件中调用 yyerroryyparse,则需要在该文件中声明它们。如果您 将 flex 生成的扫描器编译为 C++,那么在您的 bison 文件中声明为 extern "C" 实际上会产生问题而不是解决问题。

简而言之:

  • extern "C" 很少是任何 bison/flex 问题的正确解决方案。

  • flex 生成的扫描器可以用 C++ 编译器编译,即使它们生成为 C 文件。 bison 生成的解析器也是如此,尽管生成 C++ 解析器的用例更多。

  • 如果您使用相同的语言编译扫描器和解析器,将会使您的生活更轻松。