You shouldn't be fooling around with yyFlexLexerOnce
. That's internal to the implementation of Flex.
You need to declare every variety of FlexLexer
which you use, ideally precisely once. You also need to declare FlexLexer
itself precisely once. The yyFlexLexerOnce
macro is the way whoever put together the C++ interface for flex scanners chose to make this possible. (Multiple header files would have been my choice, but I'm sure they had their reasons.)
So just forget ever having seen yyFlexLexerOnce
, and do it the way the manual tells you to:
#define yyFlexLexer spFlexLexer
#include "FlexLexer.h"
#undef yyFlexLexer
// This will not normally be in the same header file, but it could be.
#define yyFlexLexer actFlexLexer
#include "FlexLexer.h"
#undef yyFlexLexer
There are two important issues with FlexLexer.h
.
The first one, as illustrated above, is that it is designed to be #include
d more than once, so it does not have a header guard. That means that you have to ensure that it is never included twice with the same preprocessor define of yyFlexLexer
. A good idiom is probably to create a little wrapper:
/*** File: sp_scanner.h ***/
#pragma once
#define yyFlexLexer spFlexLexer
#include "FlexLexer.h"
#undef yyFlexLexer
But that runs into the second issue: yyFlexLexer
is automatically #include
d in the generated scanner implementation file, with an appropriate #define
of yyFlexLexer
. So you must not #include
it (even indirectly) in any inserted code in your .l
scanner definition file.
This creates an annoyance in the not-uncommon case where you have other declarations which are required for the implementation of the scanner. The temptation would be to put these declarations in the sp_lexer.h
header file (as above), but that won't work because you can't #include "sp_lexer.h"
in your scanner definition file. Instead, you need to create yet another header file, and #include
it from both the scanner.l
file and in the sp_lexer.h
file.
Concretely, suppose that you are using the yyclass
option to insert the scanner implementation method in a derived class. Obviously, you need to declare this derived class before the generated scanner, and you will also want to declare this derived class in any consumer of the generated scanner. So you will end up with something like this:
/*** File: sp_scanner_internal.h ***/
#pragma once
namespace sp {
class Scanner : public spFlexLexer {
/* ... */
};
}
/*** File: sp_scanner.h ***/
#pragma once
#define yyFlexLexer spFlexLexer
#include "FlexLexer.h"
#undef yyFlexLexer
#include "sp_scanner_internal.h"
/*** File: sp_scanner.l ***/
%option prefix="sp"
%option outfile="sp_scanner.cpp"
%option yyclass="sp::Scanner"
%{
#include "sp_scanner_internal.h"
#include "sp_parser.h"
%}
I removed the %option header-file
from your example files, because that header file should not be used in C++ projects. See the Flex manual:
The --header-file
option is not compatible with the --c++
option, since the C++ scanner provides its own header in yyFlexLexer.h
.
I also removed #include <iostream>
, since it is included from FlexLexer.h
, but of course it is not a problem if you prefer to keep it.