mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-12 05:43:03 +00:00
examples: calc++: minor improvements
* doc/bison.texi (A Complete C++ Example): Prefer throw exceptions from the scanner. Show the invalid characters. Since the scanner sends exceptions, it no longer needs to report errors, so we can get rid of the driver's routine to report error, do it in yyerror. Use @group/@end group to improve rendering.
This commit is contained in:
@@ -11155,6 +11155,19 @@ public:
|
|||||||
int result;
|
int result;
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
|
@noindent
|
||||||
|
The main routine is of course calling the parser.
|
||||||
|
|
||||||
|
@comment file: calc++/driver.hh
|
||||||
|
@example
|
||||||
|
// Run the parser on file F. Return 0 on success.
|
||||||
|
int parse (const std::string& f);
|
||||||
|
// The name of the file being parsed.
|
||||||
|
std::string file;
|
||||||
|
// Whether to generate parser debug traces.
|
||||||
|
bool trace_parsing;
|
||||||
|
@end example
|
||||||
|
|
||||||
@noindent
|
@noindent
|
||||||
To encapsulate the coordination with the Flex scanner, it is useful to have
|
To encapsulate the coordination with the Flex scanner, it is useful to have
|
||||||
member functions to open and close the scanning phase.
|
member functions to open and close the scanning phase.
|
||||||
@@ -11168,54 +11181,31 @@ member functions to open and close the scanning phase.
|
|||||||
bool trace_scanning;
|
bool trace_scanning;
|
||||||
// The token's location used by the scanner.
|
// The token's location used by the scanner.
|
||||||
yy::location location;
|
yy::location location;
|
||||||
@end example
|
|
||||||
|
|
||||||
@noindent
|
|
||||||
Similarly for the parser itself.
|
|
||||||
|
|
||||||
@comment file: calc++/driver.hh
|
|
||||||
@example
|
|
||||||
// Run the parser on file F.
|
|
||||||
// Return 0 on success.
|
|
||||||
int parse (const std::string& f);
|
|
||||||
// The name of the file being parsed.
|
|
||||||
std::string file;
|
|
||||||
// Whether parser traces should be generated.
|
|
||||||
bool trace_parsing;
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@noindent
|
|
||||||
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.
|
|
||||||
|
|
||||||
@comment file: calc++/driver.hh
|
|
||||||
@example
|
|
||||||
// Error handling.
|
|
||||||
void error (const yy::location& l, const std::string& m);
|
|
||||||
void error (const std::string& m);
|
|
||||||
@};
|
@};
|
||||||
#endif // ! DRIVER_HH
|
#endif // ! DRIVER_HH
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
The implementation of the driver is straightforward. The @code{parse}
|
The implementation of the driver (@file{driver.cc}) is straightforward.
|
||||||
member function deserves some attention. The @code{error} functions
|
|
||||||
are simple stubs, they should actually register the located error
|
|
||||||
messages and set error state.
|
|
||||||
|
|
||||||
@comment file: calc++/driver.cc
|
@comment file: calc++/driver.cc
|
||||||
@example
|
@example
|
||||||
#include "driver.hh"
|
#include "driver.hh"
|
||||||
#include "parser.hh"
|
#include "parser.hh"
|
||||||
|
|
||||||
|
@group
|
||||||
driver::driver ()
|
driver::driver ()
|
||||||
: trace_scanning (false), trace_parsing (false)
|
: trace_parsing (false), trace_scanning (false)
|
||||||
@{
|
@{
|
||||||
variables["one"] = 1;
|
variables["one"] = 1;
|
||||||
variables["two"] = 2;
|
variables["two"] = 2;
|
||||||
@}
|
@}
|
||||||
|
@end group
|
||||||
|
@end example
|
||||||
|
|
||||||
|
The @code{parse} member function deserves some attention.
|
||||||
|
|
||||||
|
@comment file: calc++/driver.cc
|
||||||
|
@example
|
||||||
@group
|
@group
|
||||||
int
|
int
|
||||||
driver::parse (const std::string &f)
|
driver::parse (const std::string &f)
|
||||||
@@ -11230,18 +11220,6 @@ driver::parse (const std::string &f)
|
|||||||
return res;
|
return res;
|
||||||
@}
|
@}
|
||||||
@end group
|
@end group
|
||||||
|
|
||||||
void
|
|
||||||
driver::error (const yy::location& l, const std::string& m)
|
|
||||||
@{
|
|
||||||
std::cerr << l << ": " << m << '\n';
|
|
||||||
@}
|
|
||||||
|
|
||||||
void
|
|
||||||
driver::error (const std::string& m)
|
|
||||||
@{
|
|
||||||
std::cerr << m << '\n';
|
|
||||||
@}
|
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
@node Calc++ Parser
|
@node Calc++ Parser
|
||||||
@@ -11286,11 +11264,12 @@ forward declaration of the driver. @xref{%code Summary}.
|
|||||||
|
|
||||||
@comment file: calc++/parser.yy
|
@comment file: calc++/parser.yy
|
||||||
@example
|
@example
|
||||||
%code requires
|
@group
|
||||||
@{
|
%code requires @{
|
||||||
# include <string>
|
# include <string>
|
||||||
class driver;
|
class driver;
|
||||||
@}
|
@}
|
||||||
|
@end group
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
@noindent
|
@noindent
|
||||||
@@ -11330,10 +11309,11 @@ file; it needs detailed knowledge about the driver.
|
|||||||
|
|
||||||
@comment file: calc++/parser.yy
|
@comment file: calc++/parser.yy
|
||||||
@example
|
@example
|
||||||
%code
|
@group
|
||||||
@{
|
%code @{
|
||||||
# include "driver.hh"
|
# include "driver.hh"
|
||||||
@}
|
@}
|
||||||
|
@end group
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
|
|
||||||
@@ -11413,14 +11393,14 @@ exp:
|
|||||||
@end example
|
@end example
|
||||||
|
|
||||||
@noindent
|
@noindent
|
||||||
Finally the @code{error} member function registers the errors to the driver.
|
Finally the @code{error} member function reports the errors.
|
||||||
|
|
||||||
@comment file: calc++/parser.yy
|
@comment file: calc++/parser.yy
|
||||||
@example
|
@example
|
||||||
void
|
void
|
||||||
yy::parser::error (const location_type& l, const std::string& m)
|
yy::parser::error (const location_type& l, const std::string& m)
|
||||||
@{
|
@{
|
||||||
drv.error (l, m);
|
std::cerr << l << ": " << m << '\n';
|
||||||
@}
|
@}
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
@@ -11524,12 +11504,18 @@ The rules are simple. The driver is used to report errors.
|
|||||||
errno = 0;
|
errno = 0;
|
||||||
long n = strtol (yytext, NULL, 10);
|
long n = strtol (yytext, NULL, 10);
|
||||||
if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE))
|
if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE))
|
||||||
drv.error (loc, "integer is out of range");
|
throw yy::parser::syntax_error (loc, "integer is out of range: "
|
||||||
|
+ std::string(yytext));
|
||||||
return yy::parser::make_NUMBER (n, loc);
|
return yy::parser::make_NUMBER (n, loc);
|
||||||
@}
|
@}
|
||||||
@end group
|
@end group
|
||||||
@{id@} return yy::parser::make_IDENTIFIER (yytext, loc);
|
@{id@} return yy::parser::make_IDENTIFIER (yytext, loc);
|
||||||
. drv.error (loc, "invalid character");
|
@group
|
||||||
|
. @{
|
||||||
|
throw yy::parser::syntax_error
|
||||||
|
(loc, "invalid character: " + std::string(yytext));
|
||||||
|
@}
|
||||||
|
@end group
|
||||||
<<EOF>> return yy::parser::make_END (loc);
|
<<EOF>> return yy::parser::make_END (loc);
|
||||||
%%
|
%%
|
||||||
@end example
|
@end example
|
||||||
@@ -11549,7 +11535,7 @@ driver::scan_begin ()
|
|||||||
yyin = stdin;
|
yyin = stdin;
|
||||||
else if (!(yyin = fopen (file.c_str (), "r")))
|
else if (!(yyin = fopen (file.c_str (), "r")))
|
||||||
@{
|
@{
|
||||||
error ("cannot open " + file + ": " + strerror(errno));
|
std::cerr << "cannot open " << file << ": " << strerror(errno) << '\n';
|
||||||
exit (EXIT_FAILURE);
|
exit (EXIT_FAILURE);
|
||||||
@}
|
@}
|
||||||
@}
|
@}
|
||||||
|
|||||||
Reference in New Issue
Block a user