10.1.6.2 Calc++ Parsing Driver
To support a pure interface with the parser (and the scanner) the
technique of the “parsing context” is convenient: a structure
containing all the data to exchange. Since, in addition to simply
launch the parsing, there are several auxiliary tasks to execute (open
the file for parsing, instantiate the parser etc.), we recommend
transforming the simple parsing context structure into a fully blown
parsing driver class.
The declaration of this driver class, ‘calc++-driver.hh’, is as
follows. The first part includes the CPP guard and imports the
required standard library components, and the declaration of the parser
class.
| #ifndef CALCXX_DRIVER_HH
# define CALCXX_DRIVER_HH
# include <string>
# include <map>
# include "calc++-parser.hh"
|
Then comes the declaration of the scanning function. Flex expects
the signature of yylex
to be defined in the macro
YY_DECL
, and the C++ parser expects it to be declared. We can
factor both as follows.
| // Tell Flex the lexer's prototype ...
# define YY_DECL \
yy::calcxx_parser::token_type \
yylex (yy::calcxx_parser::semantic_type* yylval, \
yy::calcxx_parser::location_type* yylloc, \
calcxx_driver& driver)
// ... and declare it for the parser's sake.
YY_DECL;
|
The calcxx_driver
class is then declared with its most obvious
members.
| // Conducting the whole scanning and parsing of Calc++.
class calcxx_driver
{
public:
calcxx_driver ();
virtual ~calcxx_driver ();
std::map<std::string, int> variables;
int result;
|
To encapsulate the coordination with the Flex scanner, it is useful to
have two members function to open and close the scanning phase.
| // Handling the scanner.
void scan_begin ();
void scan_end ();
bool trace_scanning;
|
Similarly for the parser itself.
| // Run the parser. Return 0 on success.
int parse (const std::string& f);
std::string file;
bool trace_parsing;
|
To demonstrate pure handling of parse errors, instead of simply
dumping them on the standard error output, we will pass them to the
compiler driver using the following two member functions. Finally, we
close the class declaration and CPP guard.
| // Error handling.
void error (const yy::location& l, const std::string& m);
void error (const std::string& m);
};
#endif // ! CALCXX_DRIVER_HH
|
The implementation of the driver is straightforward. The parse
member function deserves some attention. The error
functions
are simple stubs, they should actually register the located error
messages and set error state.
| #include "calc++-driver.hh"
#include "calc++-parser.hh"
calcxx_driver::calcxx_driver ()
: trace_scanning (false), trace_parsing (false)
{
variables["one"] = 1;
variables["two"] = 2;
}
calcxx_driver::~calcxx_driver ()
{
}
int
calcxx_driver::parse (const std::string &f)
{
file = f;
scan_begin ();
yy::calcxx_parser parser (*this);
parser.set_debug_level (trace_parsing);
int res = parser.parse ();
scan_end ();
return res;
}
void
calcxx_driver::error (const yy::location& l, const std::string& m)
{
std::cerr << l << ": " << m << std::endl;
}
void
calcxx_driver::error (const std::string& m)
{
std::cerr << m << std::endl;
}
|