doc: c++: document parser::context

* doc/bison.texi (C++ Parser Context): New.

* data/skeletons/lalr1.cc (parser::yysymbol_name): Rename as...
(parser::symbol_name): this.
(A Complete C++ Example): Promote LAC, now that we have it.
Promote parse.error detailed over verbose.
* examples/c++/calc++/calc++.test, tests/local.at: Adjust.
This commit is contained in:
Akim Demaille
2020-04-13 14:18:51 +02:00
parent dc1035bada
commit 42ab6c1e44
4 changed files with 135 additions and 20 deletions

View File

@@ -308,7 +308,7 @@ m4_define([b4_shared_declarations],
]b4_parse_error_bmatch([custom\|detailed], [[ ]b4_parse_error_bmatch([custom\|detailed], [[
/// The user-facing name of the symbol whose (internal) number is /// The user-facing name of the symbol whose (internal) number is
/// YYSYMBOL. No bounds checking. /// YYSYMBOL. No bounds checking.
static const char *yysymbol_name (symbol_kind_type yysymbol); static const char *symbol_name (symbol_kind_type yysymbol);
]])[ ]])[
// Tables. // Tables.
@@ -586,7 +586,7 @@ m4_if(b4_prefix, [yy], [],
/* The user-facing name of the symbol whose (internal) number is /* The user-facing name of the symbol whose (internal) number is
YYSYMBOL. No bounds checking. */ YYSYMBOL. No bounds checking. */
const char * const char *
]b4_parser_class[::yysymbol_name (symbol_kind_type yysymbol) ]b4_parser_class[::symbol_name (symbol_kind_type yysymbol)
{ {
static const char *const yy_sname[] = static const char *const yy_sname[] =
{ {
@@ -1503,7 +1503,7 @@ b4_dollar_popdef])[]dnl
{ {
yyres += ]b4_parse_error_case([verbose], yyres += ]b4_parse_error_case([verbose],
[[yytnamerr_ (yytname_[yyarg[yyi++]])]], [[yytnamerr_ (yytname_[yyarg[yyi++]])]],
[[yysymbol_name (yyarg[yyi++])]])[; [[symbol_name (yyarg[yyi++])]])[;
++yyp; ++yyp;
} }
else else

View File

@@ -325,8 +325,8 @@ The Lexical Analyzer Function @code{yylex}
Error Reporting Error Reporting
* Error Reporting Function:: You must supply a function @code{yyerror}. * Error Reporting Function:: You must supply a @code{yyerror} function.
* Syntax Error Reporting Function:: You can supply a function @code{yyreport_syntax_error}. * Syntax Error Reporting Function:: You can supply a @code{yyreport_syntax_error} function.
Parser Internationalization Parser Internationalization
@@ -408,6 +408,7 @@ C++ Parsers
* C++ Parser Interface:: Instantiating and running the parser * C++ Parser Interface:: Instantiating and running the parser
* C++ Semantic Values:: %union vs. C++ * C++ Semantic Values:: %union vs. C++
* C++ Location Values:: The position and location classes * C++ Location Values:: The position and location classes
* C++ Parser Context:: You can supply a @code{report_syntax_error} function.
* C++ Scanner Interface:: Exchanges between yylex and parse * C++ Scanner Interface:: Exchanges between yylex and parse
* A Complete C++ Example:: Demonstrating their use * A Complete C++ Example:: Demonstrating their use
@@ -7352,8 +7353,8 @@ such as syntax error, or memory exhaustion. How this message is delivered
to the user must be specified by the developer. to the user must be specified by the developer.
@menu @menu
* Error Reporting Function:: You must supply a function @code{yyerror}. * Error Reporting Function:: You must supply a @code{yyerror} function.
* Syntax Error Reporting Function:: You can supply a function @code{yyreport_syntax_error}. * Syntax Error Reporting Function:: You can supply a @code{yyreport_syntax_error} function.
@end menu @end menu
@node Error Reporting Function @node Error Reporting Function
@@ -7465,8 +7466,8 @@ An opaque type that captures the circumstances of the syntax error.
@end deffn @end deffn
@deffn {Type} yysymbol_kind_t @deffn {Type} yysymbol_kind_t
An enum that includes all the symbols, tokens and nonterminals, of the An enum that includes all the grammar symbols, tokens and nonterminals. Its
grammar. Its enumerators are forged from the token and symbol names: enumerators are forged from the symbol names:
@example @example
enum yysymbol_kind_t enum yysymbol_kind_t
@@ -7491,7 +7492,6 @@ typedef enum yysymbol_kind_t yysymbol_kind_t;
@deftypefun {yysymbol_kind_t} yypcontext_token (@code{const yypcontext_t *}@var{ctx}) @deftypefun {yysymbol_kind_t} yypcontext_token (@code{const yypcontext_t *}@var{ctx})
The ``unexpected'' token: the symbol kind of the lookahead token that caused The ``unexpected'' token: the symbol kind of the lookahead token that caused
the syntax error. Return @code{YYSYMBOL_YYEMPTY} if there is no lookahead. the syntax error. Return @code{YYSYMBOL_YYEMPTY} if there is no lookahead.
Can never return @code{YYSYMBOL_YYERROR}, or @code{YYSYMBOL_YYUNDEF}.
@end deftypefun @end deftypefun
@deftypefun {YYLTYPE *} yypcontext_location (@code{const yypcontext_t *}@var{ctx}) @deftypefun {YYLTYPE *} yypcontext_location (@code{const yypcontext_t *}@var{ctx})
@@ -7528,7 +7528,7 @@ yyreport_syntax_error (const yypcontext_t *ctx)
fprintf (stderr, ": syntax error"); fprintf (stderr, ": syntax error");
// Report the tokens expected at this point. // Report the tokens expected at this point.
@{ @{
enum @{ TOKENMAX = 10 @}; enum @{ TOKENMAX = 5 @};
yysymbol_kind_t expected[TOKENMAX]; yysymbol_kind_t expected[TOKENMAX];
int n = yypcontext_expected_tokens (ctx, expected, TOKENMAX); int n = yypcontext_expected_tokens (ctx, expected, TOKENMAX);
if (n < 0) if (n < 0)
@@ -11280,6 +11280,7 @@ The Bison parser in C++ is an object, an instance of the class
* C++ Parser Interface:: Instantiating and running the parser * C++ Parser Interface:: Instantiating and running the parser
* C++ Semantic Values:: %union vs. C++ * C++ Semantic Values:: %union vs. C++
* C++ Location Values:: The position and location classes * C++ Location Values:: The position and location classes
* C++ Parser Context:: You can supply a @code{report_syntax_error} function.
* C++ Scanner Interface:: Exchanges between yylex and parse * C++ Scanner Interface:: Exchanges between yylex and parse
* A Complete C++ Example:: Demonstrating their use * A Complete C++ Example:: Demonstrating their use
@end menu @end menu
@@ -11973,6 +11974,112 @@ files, reused by other parsers as follows:
@end example @end example
@node C++ Parser Context
@subsection C++ Parser Context
When @samp{%define parse.error custom} is used (@pxref{Syntax Error
Reporting Function}), the user must define the following function.
@deftypemethod {parser} {void} report_syntax_error (@code{const context_type&}@var{ctx}) @code{const}
Report a syntax error to the user. Whether it uses @code{yyerror} is up to
the user.
@end deftypemethod
Use the following types and functions to build the error message.
@defcv {Type} {parser} {context}
A type that captures the circumstances of the syntax error.
@end defcv
@defcv {Type} {parser} {symbol_kind_type}
An enum that includes all the grammar symbols, tokens and nonterminals. Its
enumerators are forged from the symbol names:
@example
struct symbol_kind
@{
enum symbol_kind_type
@{
S_YYEMPTY = -2, // No symbol.
S_YYEOF = 0, // "end of file"
S_YYERROR = 1, // error
S_YYUNDEF = 2, // "invalid token"
S_PLUS = 3, // "+"
S_MINUS = 4, // "-"
[...]
S_VAR = 14, // "variable"
S_NEG = 15, // NEG
S_YYACCEPT = 16, // $accept
S_exp = 17, // exp
S_input = 18 // input
@};
@};
typedef symbol_kind::symbol_kind_t symbol_kind_type;
@end example
@end defcv
@deftypemethod {context} {const symbol_type&} lookahead () @code{const}
The ``unexpected'' token: the lookahead that caused the syntax error.
@end deftypemethod
@deftypemethod {context} {symbol_kind_type} token () @code{const}
The symbol kind of the lookahead token that caused the syntax error. Return
@code{symbol_kind::S_YYEMPTY} if there is no lookahead.
@end deftypemethod
@deftypemethod {context} {const location&} location () @code{const}
The location of the syntax error (that of the lookahead).
@end deftypemethod
@deftypemethod {context} int expected_tokens (@code{symbol_kind_type} @var{argv}@code{[]}, @code{int} @var{argc}) @code{const}
Fill @var{argv} with the expected tokens, which never includes
@code{symbol_kind::S_YYEMPTY}, @code{symbol_kind::S_YYERROR}, or
@code{symbol_kind::S_YYUNDEF}.
Never put more than @var{argc} elements into @var{argv}, and on success
return the effective number of tokens stored in @var{argv}. Return 0 if
there are more than @var{argc} expected tokens, yet fill @var{argv} up to
@var{argc}.
If @var{argv} is null, return the size needed to store all the possible
values, which is always less than @code{YYNTOKENS}.
@end deftypemethod
@deftypemethod {parser} {const char *} symbol_name (@code{symbol_kind_t} @var{symbol}) @code{const}
The name of the symbol whose kind is @var{symbol}, possibly translated.
@end deftypemethod
A custom syntax error function looks as follows.
@example
void
yy::parser::report_syntax_error (const context& ctx)
@{
int res = 0;
std::cerr << ctx.location () << ": syntax error";
// Report the tokens expected at this point.
@{
enum @{ TOKENMAX = 5 @};
symbol_kind_type expected[TOKENMAX];
int n = ctx.expected_tokens (ctx, expected, TOKENMAX);
for (int i = 0; i < n; ++i)
std::cerr << i == 0 ? ": expected " : " or "
<< symbol_name (expected[i]);
@}
// Report the unexpected token.
@{
symbol_kind_type lookahead = ctx.token ();
if (lookahead != symbol_kind::S_YYEMPTY)
std::cerr << " before " << symbol_name (lookahead));
@}
std::cerr << '\n';
@}
@end example
You still must provide a @code{yyerror} function, used for instance to
report memory exhaustion.
@node C++ Scanner Interface @node C++ Scanner Interface
@subsection C++ Scanner Interface @subsection C++ Scanner Interface
@c - prefix for yylex. @c - prefix for yylex.
@@ -12332,7 +12439,7 @@ designed the grammar for.
@comment file: calc++/parser.yy @comment file: calc++/parser.yy
@example @example
%skeleton "lalr1.cc" /* -*- C++ -*- */ %skeleton "lalr1.cc" // -*- C++ -*-
%require "@value{VERSION}" %require "@value{VERSION}"
%defines %defines
@end example @end example
@@ -12403,14 +12510,15 @@ Then we request location tracking.
@end example @end example
@noindent @noindent
Use the following two directives to enable parser tracing and verbose error Use the following two directives to enable parser tracing and detailed error
messages. However, verbose error messages can contain incorrect information messages. However, detailed error messages can contain incorrect
(@pxref{LAC}). information if lookahead correction is not enabled (@pxref{LAC}).
@comment file: calc++/parser.yy @comment file: calc++/parser.yy
@example @example
%define parse.trace %define parse.trace
%define parse.error verbose %define parse.error detailed
%define parse.lac full
@end example @end example
@noindent @noindent
@@ -12720,7 +12828,7 @@ driver::scan_begin ()
yyin = stdin; yyin = stdin;
else if (!(yyin = fopen (file.c_str (), "r"))) else if (!(yyin = fopen (file.c_str (), "r")))
@{ @{
std::cerr << "cannot open " << file << ": " << strerror(errno) << '\n'; std::cerr << "cannot open " << file << ": " << strerror (errno) << '\n';
exit (EXIT_FAILURE); exit (EXIT_FAILURE);
@} @}
@} @}

View File

@@ -44,11 +44,18 @@ EOF
run 0 9 run 0 9
cat >input <<EOF
1 +
EOF
run 1 'err: -:2.1: syntax error, unexpected end of file, expecting ( or identifier or number'
# LAC finds many more tokens.
cat >input <<EOF cat >input <<EOF
a := 1 a := 1
d := a + b * c d := a + b * c
EOF EOF
run 1 'err: -:3.1: syntax error, unexpected end of file, expecting ( or identifier or number' run 1 'err: -:3.1: syntax error, unexpected end of file'
cat >input <<EOF cat >input <<EOF

View File

@@ -757,7 +757,7 @@ void
{ {
symbol_kind_type la = ctx.token (); symbol_kind_type la = ctx.token ();
if (la != symbol_kind::S_YYEMPTY) if (la != symbol_kind::S_YYEMPTY)
fprintf (stderr, " on token [%s]", yysymbol_name (la)); std::cerr << " on token [" << symbol_name (la) << ']';
} }
{ {
enum { TOKENMAX = 10 }; enum { TOKENMAX = 10 };
@@ -767,7 +767,7 @@ void
{ {
std::cerr << " (expected:"; std::cerr << " (expected:";
for (int i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
std::cerr << " [" << yysymbol_name (expected[i]) << ']'; std::cerr << " [" << symbol_name (expected[i]) << ']';
std::cerr << ')'; std::cerr << ')';
} }
} }