2
votes

I'm in the process of creating a compiler for a relatively simple language using Flex and Bison on Windows. However the compiler is telling me thatthe functions yyerror and yyparse weren't declared in the right scope. After some reading I found out that the problem is apparently conflicting C and C++ linkage (I'm using g++ as I'm trying to build an abstract syntax tree). Code excerpts below.

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;
}

Any help or enlightenment as to the source of these errors would be greatly appreciated :)

2

2 Answers

1
votes

The code in a .y file that's enclosed in %{ ... }% is copied verbatim to the top of the generated parser file before the definitions of the autogenerated functions like yyparse. As a result, the code that you've written, including the definition of main and the call to yyparse, appear before any of those functions are declared or defined. This may be the source of your error.

Remember that the generated parser file doesn't have to contain main. In fact, you might want to consider creating a separate C++ source file that contains main. You'd then have that file include the autogenerated header so that it sees the declaration of yyparse.

Additionally, if you are trying to write C++ code for this program, note that the main function you declared in the bison source file is not valid C++ because it doesn't have a return type declared. All C++ main functions must explicitly return an int.

Also notice that you have two main functions, one in the lexer file and one in the parser file, which will cause problems for you going forward. Factoring out your main function into its own separate file that then includes the lexer and parser header files will resolve this issue.

Finally, note that if you are indeed generating C++ code, there's no need to put void in the parameter list to main. C++ assumes that an empty parameter list means "takes no parameters" and there's no need to state otherwise.

0
votes

There is no need to declare yyerror and yyparse as extern "C" if you compile your flex file as C++.

In fact, there is no need to declare yyerror and yyparse as extern "C" unless you refer to them from a different module. You do refer to yyparse in the main() in your flex file, but you also have a main() in your bison file, and you only need one main(). There is no indication that you call yyerror() from your flex file, and in general it is not a good idea IMHO. But if you do call yyerror and yyparse from your flex file, you will need to declare them in that file. And if you are compiling the flex-generated scanner as C++, then the declaration in your bison file as extern "C" will actually create a problem rather than solving one.

In short:

  • extern "C" is rarely the correct solution to any bison/flex problem.

  • flex-generated scanners can be compiled with a C++ compiler even if they are generated as C files. The same is true of bison-generated parsers, although there are more use cases in which generating a C++ parser is useful.

  • You will make your life easier if you compile both your scanner and your parser with the same language.