mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-09 12:23:04 +00:00
For each start symbol, generate a parsing function with a richer
return value than the usual of yyparse. Reserve a place for the
returned semantic value, in order to avoid having to pass a pointer as
argument to "return" that value. This also makes the call to the
parsing function independent of whether a given start-symbol is typed.
For instance, if the grammar file contains:
%type <int> expression
%start input expression
(so "input" is valueless) we get
typedef struct
{
int yystatus;
} yyparse_input_t;
yyparse_input_t yyparse_input (void);
typedef struct
{
int yyvalue;
int yystatus;
} yyparse_expression_t;
yyparse_expression_t yyparse_expression (void);
This commit also changes the implementation of the parser termination:
when there are multiple start symbols, it is the initial rules that
explicitly YYACCEPT. They do that after having exported the
start-symbol's value (if it is typed):
switch (yyn)
{
case 1: /* $accept: YY_EXPRESSION expression $end */
{ ((*yyvalue).TOK_expression) = (yyvsp[-1].TOK_expression); YYACCEPT; }
break;
case 2: /* $accept: YY_INPUT input $end */
{ YYACCEPT; }
break;
I have tried several ways to deal with termination, and this is the
one that appears the best one to me. It is also the most natural.
* src/scan-code.h, src/scan-code.l (obstack_for_actions): New.
* src/reader.c (grammar_rule_check_and_complete): Generate the actions
of the rules for each start symbol.
* data/skeletons/bison.m4 (b4_symbol_slot): New, with safer semantics
than type and type_tag.
* data/skeletons/yacc.c (b4_accept): New.
Generates the body of the action of the start rules.
(_b4_declare_sub_yyparse): For each start symbol define a dedicated
return type for its parsing function.
Adjust the declaration of its parsing function.
(_b4_define_sub_yyparse): Adjust the definition of the function.
* examples/c/lexcalc/parse.y: Check the case of valueless symbols.
* examples/c/lexcalc/lexcalc.test: Check start symbols.
157 lines
3.7 KiB
Plaintext
157 lines
3.7 KiB
Plaintext
/* Parser for lexcalc. -*- C -*-
|
|
|
|
Copyright (C) 2018-2020 Free Software Foundation, Inc.
|
|
|
|
This file is part of Bison, the GNU Compiler Compiler.
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
// Prologue (directives).
|
|
%expect 0
|
|
|
|
// Emitted in the header file, after the definition of YYSTYPE.
|
|
%code provides
|
|
{
|
|
// Tell Flex the expected prototype of yylex.
|
|
#define YY_DECL \
|
|
yytoken_kind_t yylex (YYSTYPE* yylval, YYLTYPE *yylloc, int *nerrs)
|
|
YY_DECL;
|
|
|
|
void yyerror (YYLTYPE *loc, int *nerrs, const char *msg);
|
|
}
|
|
|
|
// Emitted on top of the implementation file.
|
|
%code top
|
|
{
|
|
#include <stdio.h> // printf.
|
|
#include <stdlib.h> // getenv.
|
|
#include <string.h> // strcmp.
|
|
}
|
|
|
|
// Include the header in the implementation rather than duplicating it.
|
|
%define api.header.include {"parse.h"}
|
|
|
|
// Don't share global variables between the scanner and the parser.
|
|
%define api.pure full
|
|
|
|
// To avoid name clashes (e.g., with C's EOF) prefix token definitions
|
|
// with TOK_ (e.g., TOK_EOF).
|
|
%define api.token.prefix {TOK_}
|
|
|
|
// %token and %type use genuine types (e.g., "%token <int>"). Let
|
|
// %bison define YYSTYPE as a union of all these types.
|
|
%define api.value.type union
|
|
|
|
// Generate detailed error messages.
|
|
%define parse.error detailed
|
|
|
|
// with locations.
|
|
%locations
|
|
|
|
// Enable debug traces (see yydebug in main).
|
|
%define parse.trace
|
|
|
|
// Error count, exchanged between main, yyparse and yylex.
|
|
%param {int *nerrs}
|
|
|
|
%token
|
|
PLUS "+"
|
|
MINUS "-"
|
|
STAR "*"
|
|
SLASH "/"
|
|
LPAREN "("
|
|
RPAREN ")"
|
|
EOL "end of line"
|
|
;
|
|
|
|
%token <int> NUM "number"
|
|
%type <int> exp expression line
|
|
%printer { fprintf (yyo, "%d", $$); } <int>
|
|
|
|
%start input expression
|
|
|
|
// Precedence (from lowest to highest) and associativity.
|
|
%left "+" "-"
|
|
%left "*" "/"
|
|
|
|
%%
|
|
// Rules.
|
|
input:
|
|
%empty
|
|
| input line
|
|
;
|
|
|
|
line:
|
|
exp EOL { $$ = $exp; printf ("%d\n", $$); }
|
|
| error EOL { $$ = 0; yyerrok; }
|
|
;
|
|
|
|
expression:
|
|
exp EOL { $$ = $exp; }
|
|
;
|
|
|
|
exp:
|
|
exp "+" exp { $$ = $1 + $3; }
|
|
| exp "-" exp { $$ = $1 - $3; }
|
|
| exp "*" exp { $$ = $1 * $3; }
|
|
| exp "/" exp
|
|
{
|
|
if ($3 == 0)
|
|
{
|
|
yyerror (&@$, nerrs, "error: division by zero");
|
|
YYERROR;
|
|
}
|
|
else
|
|
$$ = $1 / $3;
|
|
}
|
|
| "(" exp ")" { $$ = $2; }
|
|
| NUM { $$ = $1; }
|
|
;
|
|
%%
|
|
// Epilogue (C code).
|
|
|
|
void yyerror (YYLTYPE *loc, int *nerrs, const char *msg)
|
|
{
|
|
YY_LOCATION_PRINT (stderr, *loc);
|
|
fprintf (stderr, ": %s\n", msg);
|
|
++*nerrs;
|
|
}
|
|
|
|
int main (int argc, const char *argv[])
|
|
{
|
|
int nerrs = 0;
|
|
// Possibly enable parser runtime debugging.
|
|
yydebug = !!getenv ("YYDEBUG");
|
|
int parse_expression_p = 0;
|
|
// Enable parse traces on option -p.
|
|
for (int i = 0; i < argc; ++i)
|
|
if (1 < argc && strcmp (argv[1], "-p") == 0)
|
|
yydebug = 1;
|
|
else if (strcmp (argv[i], "-e") == 0)
|
|
parse_expression_p = 1;
|
|
|
|
if (parse_expression_p)
|
|
{
|
|
yyparse_expression_t res = yyparse_expression (&nerrs);
|
|
if (res.yystatus == 0)
|
|
printf ("expression: %d\n", res.yyvalue);
|
|
else
|
|
printf ("expression: failure\n");
|
|
}
|
|
else
|
|
yyparse_input (&nerrs);
|
|
// Exit on failure if there were errors.
|
|
return !!nerrs;
|
|
}
|