/* File: reent.h Copyright (C) 1998 Markus Mottl email: markus.mottl@gmail.com WWW: http://www.ocaml.info This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place --- Suite 330, Boston, MA 02111-1307, USA. ------------------------------------------------------------------- This file contains an example of how a reentrant parser can be written with 'flex' and 'bison'. */ #ifndef REENT_PARSER_H #define REENT_PARSER_H #include #include #include using namespace std; // Parse function of 'bison' is defined externally extern "C" int yyparse(void *); // The error function that 'bison' calls inline void yyerror(char const *what_error) { cerr << what_error << endl; } // Control class for a flex-scanner // It has a pointer to the compiler in which it is contained class sem_flexer : public yyFlexLexer { public: sem_flexer(void *_compiler) : compiler(_compiler) {} void * get_compiler() const { return compiler; } private: void *compiler; }; // Base class for compilers which use 'flex' and 'bison' as scanner/parser class flex_bison_compiler { public: friend int yylex(string *new_token, void *compiler); flex_bison_compiler() : flexer(this) {} // Compiles program from a stream void compile(istream &program_strm = cin) { // Tells 'flex' the right stream flexer.switch_streams(&program_strm, 0); // If there is an error parsing the source if (! parse()) { cerr << "How bad! A parse error has occurred!" << endl; exit(1); } } private: // The scanner used in this compiler (it is a flex-scanner) sem_flexer flexer; int scan() { return flexer.yylex(); } bool parse() { return ! yyparse((void *) this); } }; // Directs the call from 'bison' to the scanner in the right compiler // "new_token" is not needed in this case... inline int yylex(string *new_token, void *compiler) { flex_bison_compiler &what_compiler = *static_cast(compiler); return what_compiler.scan(); } // Definitions for 'flex' and 'bison' // Read the manuals of the two beasties to see what these macros mean! #define yywrap() 1 #define YY_SKIP_YYWRAP #define YYPARSE_PARAM parm #define YYLEX_PARAM parm #define YYSTYPE string // A test compiler class some_compiler : public flex_bison_compiler { public: void just_a_flex_test(string const &some_string) const { cout << "Fine! Flex has found something: " << some_string << endl; } void just_a_bison_test() const { cout << "Cool! Even bison has found something!" << endl; } }; // Important! These are the "shortcuts" which you can use in your // ".l"- and ".y"-files to access the corresponding compiler-object! #define my_flex_compiler (*static_cast (static_cast(this)->get_compiler())) #define my_bison_compiler (*static_cast (parm)) #endif // REENT_PARSER_H