c++: demonstrate custom error messages in the examples

Let's use c++/glr to demonstrate custom error messages in C++ (not
just in glr2.cc).

* examples/c++/glr/c++-types.yy (report_syntax_error): New.
* examples/c++/glr/c++-types.test: Adjust.
* examples/c/bistromathic/parse.y: Comment changes.
* tests/local.at (AT_YYERROR_DEFINE(c++)): Use a nicer way to print
the lookakead's name.
This commit is contained in:
Akim Demaille
2021-09-07 08:21:40 +02:00
parent a75072476e
commit 2142e59155
6 changed files with 58 additions and 11 deletions

View File

@@ -39,6 +39,15 @@ examples.
Extracted from the documentation: [A Complete C++ Extracted from the documentation: [A Complete C++
Example](https://www.gnu.org/software/bison/manual/html_node/A-Complete-C_002b_002b-Example.html). Example](https://www.gnu.org/software/bison/manual/html_node/A-Complete-C_002b_002b-Example.html).
## glr
This example demonstrates the use of GLR parsers to handle (local)
ambiguities in the C++ language. See the node "Merging GLR Parses" in
Bison's documentation.
It uses (Bison) variants to store objects as semantic values. It also
demonstrates custom error messages in C++.
<!--- <!---
Local Variables: Local Variables:

View File

@@ -4,6 +4,9 @@ This example demonstrates the use of GLR parsers to handle (local)
ambiguities in the C++ language. See the node "Merging GLR Parses" in ambiguities in the C++ language. See the node "Merging GLR Parses" in
Bison's documentation. Bison's documentation.
It uses (Bison) variants to store objects as semantic values. It also
demonstrates custom error messages in C++.
<!--- <!---
Local Variables: Local Variables:
fill-column: 76 fill-column: 76

View File

@@ -47,4 +47,4 @@ run 0 "\
5.0-13: <OR>(<init-declare>(T, y, +(z, q)), =(<cast>(y, T), +(z, q))) 5.0-13: <OR>(<init-declare>(T, y, +(z, q)), =(<cast>(y, T), +(z, q)))
7.0-15: <error> 7.0-15: <error>
9.0-5: +(z, q) 9.0-5: +(z, q)
err: 7.5: syntax error, unexpected identifier, expecting = or + or )" err: 7.5: syntax error on token identifier (expected = or + or ))"

View File

@@ -27,8 +27,8 @@
%locations %locations
%debug %debug
// Nice error messages with details. // Custom error messages.
%define parse.error detailed %define parse.error custom
%code requires %code requires
{ {
@@ -44,9 +44,11 @@
#include <fstream> #include <fstream>
#include <cstring> #include <cstring>
// Merge two semantic values.
static Node static Node
stmt_merge (const Node& x0, const Node& x1); stmt_merge (const Node& x0, const Node& x1);
// Fetch a token.
static yy::parser::symbol_type static yy::parser::symbol_type
yylex (); yylex ();
} }
@@ -100,13 +102,41 @@ declarator
std::istream* input = nullptr; std::istream* input = nullptr;
yy::parser::location_type loc; yy::parser::location_type loc;
// An error reporting function.
/*---------.
| Parser. |
`---------*/
// Generate a custom error message.
void
yy::parser::report_syntax_error (const context& ctx) const
{
std::cerr << ctx.location () << ": syntax error";
if (!ctx.lookahead ().empty ())
std::cerr << " on token " << ctx.lookahead ().name ();
{
enum { TOKENMAX = 10 };
symbol_kind_type expected[TOKENMAX];
int n = ctx.expected_tokens (expected, TOKENMAX);
if (0 < n)
{
for (int i = 0; i < n; ++i)
std::cerr << (i == 0 ? " (expected " : " or ")
<< symbol_name (expected[i]);
std::cerr << ')';
}
}
std::cerr << '\n';
}
// Report the error to the user.
void void
yy::parser::error (const location_type& l, const std::string& m) yy::parser::error (const location_type& l, const std::string& m)
{ {
std::cerr << l << ": " << m << '\n'; std::cerr << l << ": " << m << '\n';
} }
// Fetch the next token.
static yy::parser::symbol_type static yy::parser::symbol_type
yylex () yylex ()
{ {
@@ -168,12 +198,19 @@ yylex ()
} }
} }
// Merge two semantic values as an AST including both alternatives.
static Node static Node
stmt_merge (const Node& x0, const Node& x1) stmt_merge (const Node& x0, const Node& x1)
{ {
return Nterm ("<OR>", x0, x1); return Nterm ("<OR>", x0, x1);
} }
/*-------.
| Main. |
`-------*/
// Parse `file` using parser `parse`.
int int
process (yy::parser& parse, const std::string& file) process (yy::parser& parse, const std::string& file)
{ {

View File

@@ -465,8 +465,9 @@ yyreport_syntax_error (const yypcontext_t *ctx, const user_context *uctx)
} }
// Called by yyparse on error. // Called by yyparse on errors to report the error to the user.
void yyerror (const YYLTYPE *loc, const user_context *uctx, char const *format, ...) void
yyerror (const YYLTYPE *loc, const user_context *uctx, char const *format, ...)
{ {
if (uctx->silent) if (uctx->silent)
return; return;

View File

@@ -823,11 +823,8 @@ void
++*nerrs;]])[]AT_LOCATION_IF([[ ++*nerrs;]])[]AT_LOCATION_IF([[
std::cerr << ctx.location () << ": ";]])[ std::cerr << ctx.location () << ": ";]])[
std::cerr << "syntax error"; std::cerr << "syntax error";
{ if (!ctx.lookahead ().empty ())
symbol_kind_type la = ctx.token (); std::cerr << " on token [" << ctx.lookahead ().name () << ']';
if (la != symbol_kind::S_YYEMPTY)
std::cerr << " on token [" << symbol_name (la) << ']';
}
{ {
enum { TOKENMAX = 10 }; enum { TOKENMAX = 10 };
symbol_kind_type expected[TOKENMAX]; symbol_kind_type expected[TOKENMAX];