From 17fb1d0377493a218b2f4300533cd26e3a9fc22f Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Sat, 16 Jan 2021 09:17:07 +0100 Subject: [PATCH] c: add support for YYNOMEM Suggested by Joe Nelson . https://lists.gnu.org/r/help-bison/2020-12/msg00020.html * data/skeletons/glr.c, data/skeletons/yacc.c (YYNOMEM): New. Use it. (yyexhaustedlab): Rename as... (yynomemlab): this. * tests/calc.at: Check it. * doc/bison.texi: Document it. Fix incorrect statements about non-existing constants for YYERROR etc. --- NEWS | 5 ++++ data/skeletons/glr.c | 8 +++++-- data/skeletons/yacc.c | 23 +++++++++--------- doc/bison.texi | 54 ++++++++++++++++++++++++++++--------------- tests/README.md | 1 + tests/calc.at | 11 +++++++-- 6 files changed, 67 insertions(+), 35 deletions(-) diff --git a/NEWS b/NEWS index e12ba6fa..f2c235eb 100644 --- a/NEWS +++ b/NEWS @@ -64,6 +64,11 @@ GNU Bison NEWS The Java skeleton (lalr1.java) now supports LAC, via the `parse.lac` %define variable. +*** Abort parsing for memory exhaustion (C) + + The user actions may now use YYNOMEM to abort the current parse with + memory exhaustion. + * Noteworthy changes in release 3.7.4 (2020-11-14) [stable] diff --git a/data/skeletons/glr.c b/data/skeletons/glr.c index ab398101..b9334aa2 100644 --- a/data/skeletons/glr.c +++ b/data/skeletons/glr.c @@ -442,7 +442,7 @@ int yychar;])[ enum { YYENOMEM = -2 }; -typedef enum { yyok, yyaccept, yyabort, yyerr } YYRESULTTAG; +typedef enum { yyok, yyaccept, yyabort, yyerr, yynomem } YYRESULTTAG; #define YYCHK(YYE) \ do { \ @@ -898,7 +898,7 @@ yyfill (yyGLRStackItem *yyvsp, int *yylow, int yylow1, yybool yynormal) * and top stack item YYVSP. YYLVALP points to place to put semantic * value ($$), and yylocp points to place for location information * (@@$). Returns yyok for normal return, yyaccept for YYACCEPT, - * yyerr for YYERROR, yyabort for YYABORT. */ + * yyerr for YYERROR, yyabort for YYABORT, yynomem for YYNOMEM. */ static YYRESULTTAG yyuserAction (yyRuleNum yyrule, int yyrhslen, yyGLRStackItem* yyvsp, yyGLRStack* yystackp, YYPTRDIFF_T yyk, @@ -915,6 +915,8 @@ yyuserAction (yyRuleNum yyrule, int yyrhslen, yyGLRStackItem* yyvsp, # define YYACCEPT return yyaccept # undef YYABORT # define YYABORT return yyabort +# undef YYNOMEM +# define YYNOMEM return yynomem # undef YYERROR # define YYERROR return yyerrok, yyerr # undef YYRECOVERING @@ -965,6 +967,7 @@ yyuserAction (yyRuleNum yyrule, int yyrhslen, yyGLRStackItem* yyvsp, # undef yyerrok # undef YYABORT # undef YYACCEPT +# undef YYNOMEM # undef YYERROR # undef YYBACKUP # undef yyclearin @@ -2431,6 +2434,7 @@ yyrecoverSyntaxError (yyGLRStack* yystackp]b4_user_formals[) case yyabort: goto yyabortlab; \ case yyaccept: goto yyacceptlab; \ case yyerr: goto yyuser_error; \ + case yynomem: goto yyexhaustedlab; \ default: goto yybuglab; \ } \ } while (0) diff --git a/data/skeletons/yacc.c b/data/skeletons/yacc.c index 56a050b3..739382ce 100644 --- a/data/skeletons/yacc.c +++ b/data/skeletons/yacc.c @@ -732,6 +732,7 @@ enum { YYENOMEM = -2 }; #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab +#define YYNOMEM goto yyexhaustedlab #define YYRECOVERING() (!!yyerrstatus) @@ -987,7 +988,7 @@ do { \ switch (yy_lac (yyesa, &yyes, &yyes_capacity, yyssp, yytoken)) \ { \ case YYENOMEM: \ - goto yyexhaustedlab; \ + YYNOMEM; \ case 1: \ goto yyerrlab; \ } \ @@ -1707,7 +1708,7 @@ yysetstate: if (yyss + yystacksize - 1 <= yyssp) #if !defined yyoverflow && !defined YYSTACK_RELOCATE - goto yyexhaustedlab; + YYNOMEM; #else { /* Get the current used size of the three stacks, in elements. */ @@ -1738,7 +1739,7 @@ yysetstate: # else /* defined YYSTACK_RELOCATE */ /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) - goto yyexhaustedlab; + YYNOMEM; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; @@ -1749,7 +1750,7 @@ yysetstate: YY_CAST (union yyalloc *, YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); if (! yyptr) - goto yyexhaustedlab; + YYNOMEM; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs);]b4_locations_if([ YYSTACK_RELOCATE (yyls_alloc, yyls);])[ @@ -1980,8 +1981,8 @@ yyerrlab: if (yychar != ]b4_symbol(empty, id)[) YY_LAC_ESTABLISH;]])[ if (yyreport_syntax_error (&yyctx]m4_ifset([b4_parse_param], - [[, ]b4_args(b4_parse_param)])[) == 2) - goto yyexhaustedlab; + [[, ]b4_args(b4_parse_param)])[) == 2) + YYNOMEM; }]], [simple], [[ yyerror (]b4_yyerror_args[YY_("syntax error"));]], @@ -2016,7 +2017,7 @@ yyerrlab: } yyerror (]b4_yyerror_args[yymsgp); if (yysyntax_error_status == YYENOMEM) - goto yyexhaustedlab; + YYNOMEM; }]])[ } ]b4_locations_if([[ @@ -2132,15 +2133,13 @@ yyabortlab: goto yyreturnlab; -#if ]b4_lac_if([[1]], [b4_parse_error_case([simple], [[!defined yyoverflow]], [[1]])])[ -/*-------------------------------------------------. -| yyexhaustedlab -- memory exhaustion comes here. | -`-------------------------------------------------*/ +/*-----------------------------------------------------------. +| yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | +`-----------------------------------------------------------*/ yyexhaustedlab: yyerror (]b4_yyerror_args[YY_("memory exhausted")); yyresult = 2; goto yyreturnlab; -#endif /*----------------------------------------------------------. diff --git a/doc/bison.texi b/doc/bison.texi index e5cc7bd7..586dd5ce 100644 --- a/doc/bison.texi +++ b/doc/bison.texi @@ -5239,10 +5239,10 @@ For instance, if your locations use a file name, you may use @findex %destructor @findex <*> @findex <> -During error recovery (@pxref{Error Recovery}), symbols already pushed -on the stack and tokens coming from the rest of the file are discarded -until the parser falls on its feet. If the parser runs out of memory, -or if it returns via @code{YYABORT} or @code{YYACCEPT}, all the +During error recovery (@pxref{Error Recovery}), symbols already pushed on +the stack and tokens coming from the rest of the file are discarded until +the parser falls on its feet. If the parser runs out of memory, or if it +returns via @code{YYABORT}, @code{YYACCEPT} or @code{YYNOMEM}, all the symbols on the stack must be discarded. Even if the parser succeeds, it must discard the start symbol. @@ -5368,8 +5368,8 @@ the start symbol, when the parser succeeds. @end itemize The parser can @dfn{return immediately} because of an explicit call to -@code{YYABORT} or @code{YYACCEPT}, or failed error recovery, or memory -exhaustion. +@code{YYABORT}, @code{YYACCEPT} or @code{YYNOMEM}, or failed error recovery, +or memory exhaustion. Right-hand side symbols of a rule that explicitly triggers a syntax error via @code{YYERROR} are not discarded automatically. As a rule @@ -7215,6 +7215,11 @@ Return immediately with value 0 (to report success). Return immediately with value 1 (to report failure). @end defmac +@defmac YYNOMEM +@findex YYNOMEM +Return immediately with value 2 (to report memory exhaustion). +@end defmac + If you use a reentrant parser, you can optionally pass additional parameter information to it in a reentrant way. To do so, use the declaration @code{%parse-param}: @@ -7936,6 +7941,11 @@ want to print an error message, call @code{yyerror} explicitly before the @samp{YYERROR;} statement. @xref{Error Recovery}. @end deffn +@deffn {Macro} YYNOMEM @code{;} +Return immediately from @code{yyparse}, indicating memory exhaustion. +@xref{Parser Function}. +@end deffn + @deffn {Macro} YYRECOVERING @findex YYRECOVERING The expression @code{YYRECOVERING ()} yields 1 when the parser @@ -14676,10 +14686,10 @@ api.push-pull both" declaration is used (@pxref{%define Summary}). The @code{Location} and @code{Position} parameters are available only if location tracking is active. -The value returned by the @code{push_parse} method is one of the following -four constants: @code{YYABORT}, @code{YYACCEPT}, @code{YYERROR}, or -@code{YYPUSH_MORE}. This new value, @code{YYPUSH_MORE}, may be returned if -more input is required to finish parsing the grammar. +The value returned by the @code{push_parse} method is one of the following: +0 (success), 1 (abort), 2 (memory exhaustion), or @code{YYPUSH_MORE}. This +new value, @code{YYPUSH_MORE}, may be returned if more input is required to +finish parsing the grammar. If api.push-pull is declared as @code{both}, then the generated parser class will also implement the @code{parse} method. This method's body is a loop @@ -14719,13 +14729,12 @@ section summarizes these differences. @itemize @item -Java lacks a preprocessor, so the @code{YYERROR}, @code{YYACCEPT}, -@code{YYABORT} symbols (@pxref{Table of Symbols}) cannot obviously be -macros. Instead, they should be preceded by @code{return} when they -appear in an action. The actual definition of these symbols is -opaque to the Bison grammar, and it might change in the future. The -only meaningful operation that you can do, is to return them. -@xref{Java Action Features}. +Java lacks a preprocessor, so obviously the @code{YYERROR}, @code{YYACCEPT}, +@code{YYABORT} symbols (@pxref{Table of Symbols}) cannot be macros. +Instead, they should be preceded by @code{return} when they appear in an +action. The actual definition of these symbols is opaque to the Bison +grammar, and it might change in the future. The only meaningful operation +that you can do, is to return them. @xref{Java Action Features}. Note that of these three symbols, only @code{YYACCEPT} and @code{YYABORT} will cause a return from the @code{yyparse} @@ -16006,6 +16015,12 @@ pure push parser, it is a member of @code{yypstate}.) @xref{Error Reporting Function}. @end deffn +@deffn {Macro} YYNOMEM +Macro to pretend that memory is exhausted, by making @code{yyparse} return 2 +immediately. The error reporting function @code{yyerror} is called. +@xref{Parser Function}. +@end deffn + @deffn {Function} yyparse The parser function produced by Bison; call this function to start parsing. @xref{Parser Function}. @@ -16518,12 +16533,13 @@ London, Department of Computer Science, TR-00-12 (December 2000). @c LocalWords: YYUNDEF SymbolKind yypcontext YYENOMEM TOKENMAX getBundle @c LocalWords: ResourceBundle myResources getString getName getToken ylwrap @c LocalWords: getLocation getExpectedTokens reportSyntaxError bistromathic -@c LocalWords: TokenKind Automake's rtti Wcounterexamples Chinawat PLDI +@c LocalWords: TokenKind Automake's rtti Wcounterexamples Chinawat PLDI buf @c LocalWords: Isradisaikul tcite pcite rgbGreen colorGreen rgbYellow Wcex @c LocalWords: colorYellow rgbRed colorRed rgbBlue colorBlue rgbPurple Ddoc @c LocalWords: colorPurple ifhtml ifnothtml situ rcex MERCHANTABILITY Wnone @c LocalWords: diagError diagNotice diagWarning diagOff danglingElseCex -@c LocalWords: nonunifying +@c LocalWords: nonunifying YYNOMEM Wuseless dgettext textdomain domainname +@c LocalWords: dirname typeof writeln YYBISON @c Local Variables: @c ispell-dictionary: "american" diff --git a/tests/README.md b/tests/README.md index 76990a04..53d1a2bf 100644 --- a/tests/README.md +++ b/tests/README.md @@ -32,3 +32,4 @@ The grammar features several special directives: - `!!` YYERROR - `!+` YYACCEPT - `!-` YYABORT +- `!*` YYNOMEM diff --git a/tests/calc.at b/tests/calc.at index 2643d570..e7a5b070 100644 --- a/tests/calc.at +++ b/tests/calc.at @@ -447,7 +447,8 @@ exp: | '-' error { $$ = 0; YYERROR; } | '!' '!' { $$ = 0; YYERROR; } | '!' '+' { $$ = 0; YYACCEPT; } -| '!' '-' { $$ = 0; YYABORT; } +| '!' '-' { $$ = 0; YYABORT; }]AT_C_IF([[ +| '!' '*' { $$ = 0; YYNOMEM; }]])[ ; %% @@ -1224,7 +1225,7 @@ _AT_CHECK_CALC_ERROR([$1], [0], [(* *) + (*) + (*)], # Special actions. # ---------------- -# !+ => YYACCEPT, !- => YYABORT, !! => YYERROR. +# !+ => YYACCEPT, !- => YYABORT, !! => YYERROR, !* => YYNOMEM. # YYACCEPT. # Java lacks the traces at the end for cleaning the stack @@ -1238,6 +1239,12 @@ _AT_CHECK_CALC([], [1 + 2 * 3 + !+ ++], _AT_CHECK_CALC_ERROR([$1], [1], [1 + 2 * 3 + !- ++], [AT_PARAM_IF([final: 0 0 0])], [102]) +AT_C_IF( +[# YYNOMEM. +_AT_CHECK_CALC_ERROR([$1], [2], [1 + 2 * 3 + !* ++], + [AT_PARAM_IF([final: 0 0 1])], + [102], + [1.14: memory exhausted])]) # YYerror.