flex
provides two different ways to generate scanners for
use with C++. The first way is to simply compile a
scanner generated by flex
using a C++ compiler instead of a C
compiler. You should not encounter any compilations
errors (please report any you find to the email address
given in the Author section below). You can then use C++
code in your rule actions instead of C code. Note that
the default input source for your scanner remains yyin
,
and default echoing is still done to yyout
. Both of these
remain `FILE *' variables and not C++ streams
.
You can also use flex
to generate a C++ scanner class, using
the `-+' option, (or, equivalently, `%option c++'), which
is automatically specified if the name of the flex executable ends
in a `+', such as flex++
. When using this option, flex
defaults to generating the scanner to the file `lex.yy.cc' instead
of `lex.yy.c'. The generated scanner includes the header file
`FlexLexer.h', which defines the interface to two C++ classes.
The first class, FlexLexer
, provides an abstract base
class defining the general scanner class interface. It
provides the following member functions:
yytext
.
yyleng
.
yy_flex_debug
(see the Options section above). Note that you
must build the scanner using `%option debug' to include debugging
information in it.
Also provided are member functions equivalent to `yy_switch_to_buffer(), yy_create_buffer()' (though the first argument is an `istream*' object pointer and not a `FILE*', `yy_flush_buffer()', `yy_delete_buffer()', and `yyrestart()' (again, the first argument is a `istream*' object pointer).
The second class defined in `FlexLexer.h' is yyFlexLexer
,
which is derived from FlexLexer
. It defines the following
additional member functions:
yyFlexLexer
object using the given
streams for input and output. If not specified,
the streams default to cin
and cout
, respectively.
yyFlexLexer
and want to access the member functions and variables of
S
inside `yylex()',
then you need to use `%option yyclass="S"'
to inform flex
that you will be using that subclass instead of yyFlexLexer
.
In this case, rather than generating `yyFlexLexer::yylex()',
flex
generates `S::yylex()'
(and also generates a dummy `yyFlexLexer::yylex()'
that calls `yyFlexLexer::LexerError()'
if called).
yyin
to new_in
(if non-nil)
and yyout
to new_out
(ditto), deleting the previous input buffer if yyin
is reassigned.
In addition, yyFlexLexer
defines the following protected
virtual functions which you can redefine in derived
classes to tailor the scanner:
YY_INTERACTIVE
. If you redefine
LexerInput()
and need to take different actions
depending on whether or not the scanner might be
scanning an interactive input source, you can test
for the presence of this name via `#ifdef'.
cerr
and exits.
Note that a yyFlexLexer
object contains its entire
scanning state. Thus you can use such objects to create
reentrant scanners. You can instantiate multiple instances of
the same yyFlexLexer
class, and you can also combine
multiple C++ scanner classes together in the same program
using the `-P' option discussed above.
Finally, note that the `%array' feature is not available to
C++ scanner classes; you must use `%pointer' (the default).
Here is an example of a simple C++ scanner:
// An example of using the flex C++ scanner class. %{ int mylineno = 0; %} string \"[^\n"]+\" ws [ \t]+ alpha [A-Za-z] dig [0-9] name ({alpha}|{dig}|\$)({alpha}|{dig}|[_.\-/$])* num1 [-+]?{dig}+\.?([eE][-+]?{dig}+)? num2 [-+]?{dig}*\.{dig}+([eE][-+]?{dig}+)? number {num1}|{num2} %% {ws} /* skip blanks and tabs */ "/*" { int c; while((c = yyinput()) != 0) { if(c == '\n') ++mylineno; else if(c == '*') { if((c = yyinput()) == '/') break; else unput(c); } } } {number} cout << "number " << YYText() << '\n'; \n mylineno++; {name} cout << "name " << YYText() << '\n'; {string} cout << "string " << YYText() << '\n'; %% Version 2.5 December 1994 44 int main( int /* argc */, char** /* argv */ ) { FlexLexer* lexer = new yyFlexLexer; while(lexer->yylex() != 0) ; return 0; }
If you want to create multiple (different) lexer classes,
you use the `-P' flag (or the `prefix=' option) to rename each
yyFlexLexer
to some other xxFlexLexer
. You then can
include `<FlexLexer.h>' in your other sources once per lexer
class, first renaming yyFlexLexer
as follows:
#undef yyFlexLexer #define yyFlexLexer xxFlexLexer #include <FlexLexer.h> #undef yyFlexLexer #define yyFlexLexer zzFlexLexer #include <FlexLexer.h>
if, for example, you used `%option prefix="xx"' for one of your scanners and `%option prefix="zz"' for the other.
IMPORTANT: the present form of the scanning class is experimental and may change considerably between major releases.