" yyparse / yylex / yyerror未在此范围内声明" - Flex / Bison

时间:2016-07-01 11:05:38

标签: c++ bison flex-lexer

我正在使用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;
}

对于这些错误的来源的任何帮助或启发将不胜感激:)

2 个答案:

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

事实上,除非您从其他模块引用它们,否则无需将yyerroryyparse声明为extern "C" 。您确实在yyparse文件的main()中引用flex,但您的野牛文件中也有main(),而您只需要一个main() 。没有迹象表明你从你的flex文件中调用yyerror(),一般来说这不是一个好主意恕我直言。但是,如果您从Flex文件中调用yyerroryyparse,则需要在该文件中声明它们。如果你 将flex生成的扫描程序编译为C ++,那么你的bison文件中extern "C"的声明实际上会产生问题而不是解决问题。

简而言之:

  • extern "C"很少是解决任何野牛/弹性问题的正确方法。

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

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