From 28d1ca8f48f7dff1550e6607f7aac33714a664b8 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Sat, 16 Nov 2019 17:26:51 +0100 Subject: [PATCH] diagnostics: yacc reserves %type to nonterminals On %token TOKEN1 %type TOKEN1 TOKEN2 't' %token TOKEN2 %% expr: bison -Wyacc gives input.y:2.15-20: warning: POSIX yacc reserves %type to nonterminals [-Wyacc] 2 | %type TOKEN1 TOKEN2 't' | ^~~~~~ input.y:2.29-31: warning: POSIX yacc reserves %type to nonterminals [-Wyacc] 2 | %type TOKEN1 TOKEN2 't' | ^~~ input.y:2.22-27: warning: POSIX yacc reserves %type to nonterminals [-Wyacc] 2 | %type TOKEN1 TOKEN2 't' | ^~~~~~ The messages appear to be out of order, but they are emitted when the error is found. * src/symtab.h (symbol_class): Add pct_type_sym, used to denote symbols appearing in %type. * src/symtab.c (complain_pct_type_on_token): New. (symbol_class_set): Check that %type is not applied to tokens. (symbol_check_defined): pct_type_sym also means undefined. * src/parse-gram.y (symbol_decl.1): Set the class to pct_type_sym. * src/reader.c (grammar_current_rule_begin): pct_type_sym also means undefined. * tests/input.at (Yacc's %type): New. --- NEWS | 24 ++++++++++++++++++++++++ src/parse-gram.c | 20 +++++++++++++------- src/parse-gram.y | 22 +++++++++++++++------- src/reader.c | 8 ++------ src/symtab.c | 32 +++++++++++++++++++++++++++---- src/symtab.h | 14 ++++++++++---- tests/input.at | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 141 insertions(+), 28 deletions(-) diff --git a/NEWS b/NEWS index 8e6aed95..742ea743 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,30 @@ GNU Bison NEWS * Noteworthy changes in release ?.? (????-??-??) [?] +** New Features + +*** Better POSIX Yacc compatibility diagnostics + + POSIX Yacc restricts %type to nonterminals. This is now diagnosed by + -Wyacc. + + %token TOKEN1 + %type TOKEN1 TOKEN2 't' + %token TOKEN2 + %% + expr: + + gives, with -Wyacc + + input.y:2.15-20: warning: POSIX yacc reserves %type to nonterminals [-Wyacc] + 2 | %type TOKEN1 TOKEN2 't' + | ^~~~~~ + input.y:2.29-31: warning: POSIX yacc reserves %type to nonterminals [-Wyacc] + 2 | %type TOKEN1 TOKEN2 't' + | ^~~ + input.y:2.22-27: warning: POSIX yacc reserves %type to nonterminals [-Wyacc] + 2 | %type TOKEN1 TOKEN2 't' + | ^~~~~~ * Noteworthy changes in release 3.4.90 (2019-10-29) [beta] diff --git a/src/parse-gram.c b/src/parse-gram.c index 18419525..493ed525 100644 --- a/src/parse-gram.c +++ b/src/parse-gram.c @@ -510,11 +510,11 @@ static const yytype_int16 yyrline[] = 453, 457, 467, 468, 469, 470, 474, 475, 480, 481, 485, 486, 490, 491, 492, 505, 514, 518, 522, 530, 531, 535, 548, 549, 561, 565, 569, 577, 579, 584, - 591, 601, 605, 609, 617, 618, 626, 627, 633, 634, - 635, 642, 642, 650, 651, 652, 657, 660, 662, 664, - 666, 668, 670, 672, 674, 676, 681, 682, 691, 715, - 716, 717, 718, 730, 732, 759, 764, 765, 770, 779, - 780, 784, 785 + 591, 601, 605, 609, 617, 622, 634, 635, 641, 642, + 643, 650, 650, 658, 659, 660, 665, 668, 670, 672, + 674, 676, 678, 680, 682, 684, 689, 690, 699, 723, + 724, 725, 726, 738, 740, 767, 772, 773, 778, 787, + 788, 792, 793 }; #endif @@ -2410,11 +2410,17 @@ yyreduce: break; case 84: - { (yyval.yytype_86) = symbol_list_sym_new ((yyvsp[0].symbol), (yylsp[0])); } + { + symbol_class_set ((yyvsp[0].symbol), pct_type_sym, (yylsp[0]), false); + (yyval.yytype_86) = symbol_list_sym_new ((yyvsp[0].symbol), (yylsp[0])); + } break; case 85: - { (yyval.yytype_86) = symbol_list_append ((yyvsp[-1].yytype_86), symbol_list_sym_new ((yyvsp[0].symbol), (yylsp[0]))); } + { + symbol_class_set ((yyvsp[0].symbol), pct_type_sym, (yylsp[0]), false); + (yyval.yytype_86) = symbol_list_append ((yyvsp[-1].yytype_86), symbol_list_sym_new ((yyvsp[0].symbol), (yylsp[0]))); + } break; case 90: diff --git a/src/parse-gram.y b/src/parse-gram.y index ccc3c315..0d1cc3f9 100644 --- a/src/parse-gram.y +++ b/src/parse-gram.y @@ -592,11 +592,11 @@ token_decl_for_prec: ; -/*-----------------------. -| symbol_decls (%type). | -`-----------------------*/ +/*-----------------------------------. +| symbol_decls (argument of %type). | +`-----------------------------------*/ -// A non empty list of typed symbols. +// A non empty list of typed symbols (for %type). symbol_decls: symbol_decl.1[syms] { @@ -612,10 +612,18 @@ symbol_decls: } ; -// One or more token declarations. +// One or more token declarations (for %type). symbol_decl.1: - symbol { $$ = symbol_list_sym_new ($1, @1); } -| symbol_decl.1 symbol { $$ = symbol_list_append ($1, symbol_list_sym_new ($2, @2)); } + symbol + { + symbol_class_set ($symbol, pct_type_sym, @symbol, false); + $$ = symbol_list_sym_new ($symbol, @symbol); + } + | symbol_decl.1 symbol + { + symbol_class_set ($symbol, pct_type_sym, @symbol, false); + $$ = symbol_list_append ($1, symbol_list_sym_new ($symbol, @symbol)); + } ; /*------------------------------------------. diff --git a/src/reader.c b/src/reader.c index cf481fd8..fc6a27e6 100644 --- a/src/reader.c +++ b/src/reader.c @@ -232,12 +232,8 @@ grammar_current_rule_begin (symbol *lhs, location loc, assign_named_ref (current_rule, named_ref_copy (lhs_name)); /* Mark the rule's lhs as a nonterminal if not already so. */ - if (lhs->content->class == unknown_sym) - { - lhs->content->class = nterm_sym; - lhs->content->number = nvars; - ++nvars; - } + if (lhs->content->class == unknown_sym || lhs->content->class == pct_type_sym) + symbol_class_set (lhs, nterm_sym, empty_loc, false); else if (lhs->content->class == token_sym) complain (&loc, complaint, _("rule given for %s, which is a token"), lhs->tag); diff --git a/src/symtab.c b/src/symtab.c index 1b43ef96..73111b51 100644 --- a/src/symtab.c +++ b/src/symtab.c @@ -33,7 +33,6 @@ #include "intprops.h" #include "quote.h" - static struct hash_table *symbol_table = NULL; static struct hash_table *semantic_type_table = NULL; @@ -233,7 +232,14 @@ symbol_print (symbol const *s, FILE *f) { if (s) { - fputs (s->tag, f); + symbol_class c = s->content->class; + fprintf (f, "%s: %s", + c == unknown_sym ? "unknown" + : c == pct_type_sym ? "%type" + : c == token_sym ? "token" + : c == nterm_sym ? "nterm" + : NULL, /* abort. */ + s->tag); SYMBOL_ATTR_PRINT (type_name); SYMBOL_CODE_PRINT (destructor); SYMBOL_CODE_PRINT (printer); @@ -502,15 +508,33 @@ symbol_precedence_set (symbol *sym, int prec, assoc a, location loc) | Set the CLASS associated with SYM. | `------------------------------------*/ +static void +complain_pct_type_on_token (location *loc) +{ + complain (loc, Wyacc, + _("POSIX yacc reserves %%type to nonterminals")); +} + void symbol_class_set (symbol *sym, symbol_class class, location loc, bool declaring) { aver (class != unknown_sym); sym_content *s = sym->content; - if (s->class != unknown_sym && s->class != class) + if (class == pct_type_sym) + { + if (s->class == token_sym) + complain_pct_type_on_token (&loc); + else if (s->class == unknown_sym) + s->class = class; + } + else if (s->class != unknown_sym && s->class != pct_type_sym + && s->class != class) complain_class_redeclared (sym, class, loc); else { + if (class == token_sym && s->class == pct_type_sym) + complain_pct_type_on_token (&sym->location); + if (class == nterm_sym && s->class != nterm_sym) s->number = nvars++; else if (class == token_sym && s->number == NUMBER_UNDEFINED) @@ -579,7 +603,7 @@ static void symbol_check_defined (symbol *sym) { sym_content *s = sym->content; - if (s->class == unknown_sym) + if (s->class == unknown_sym || s->class == pct_type_sym) { complain_symbol_undeclared (sym); s->class = nterm_sym; diff --git a/src/symtab.h b/src/symtab.h index b6e18e61..729f1fb9 100644 --- a/src/symtab.h +++ b/src/symtab.h @@ -38,9 +38,15 @@ /** Symbol classes. */ typedef enum { - unknown_sym, /**< Undefined. */ - token_sym, /**< Terminal. */ - nterm_sym /**< Nonterminal. */ + /** Undefined. */ + unknown_sym, + /** Declared with %type: same as Undefined, but triggered a Wyacc if + applied to a terminal. */ + pct_type_sym, + /** Terminal. */ + token_sym, + /** Nonterminal. */ + nterm_sym } symbol_class; @@ -219,7 +225,7 @@ void symbol_precedence_set (symbol *sym, int prec, assoc a, location loc); /** Set the \c class associated with \c sym. Whether \c declaring means whether this class definition comes - from %nterm or %token. */ + from %nterm or %token (but not %type, prec/assoc, etc.). */ void symbol_class_set (symbol *sym, symbol_class class, location loc, bool declaring); diff --git a/tests/input.at b/tests/input.at index fe03f2e1..00e3a508 100644 --- a/tests/input.at +++ b/tests/input.at @@ -195,6 +195,55 @@ input.y:7.4-9: warning: POSIX Yacc does not support %empty [-Wyacc] AT_CLEANUP +## -------------- ## +## Yacc's %type. ## +## -------------- ## + +AT_SETUP([Yacc's %type]) + +AT_DATA([input.y], +[[%token TOKEN1 +%nterm nterm1 +%type TOKEN1 TOKEN2 "TOKEN3" nterm1 nterm2 nterm3 '+' +%token TOKEN2 +%nterm nterm2 +%% +expr: nterm1 nterm2 nterm3 +nterm1: TOKEN1 +nterm2: TOKEN2 +nterm3: "TOKEN3" +]]) + +AT_BISON_CHECK([-fcaret -Wyacc input.y], [0], [], +[[input.y:2.1-6: warning: POSIX Yacc does not support %nterm [-Wyacc] + 2 | %nterm nterm1 + | ^~~~~~ +input.y:3.14-19: warning: POSIX yacc reserves %type to nonterminals [-Wyacc] + 3 | %type TOKEN1 TOKEN2 "TOKEN3" nterm1 nterm2 nterm3 '+' + | ^~~~~~ +input.y:3.28-35: warning: POSIX Yacc does not support string literals [-Wyacc] + 3 | %type TOKEN1 TOKEN2 "TOKEN3" nterm1 nterm2 nterm3 '+' + | ^~~~~~~~ +input.y:3.28-35: warning: POSIX yacc reserves %type to nonterminals [-Wyacc] + 3 | %type TOKEN1 TOKEN2 "TOKEN3" nterm1 nterm2 nterm3 '+' + | ^~~~~~~~ +input.y:3.58-60: warning: POSIX yacc reserves %type to nonterminals [-Wyacc] + 3 | %type TOKEN1 TOKEN2 "TOKEN3" nterm1 nterm2 nterm3 '+' + | ^~~ +input.y:5.1-6: warning: POSIX Yacc does not support %nterm [-Wyacc] + 5 | %nterm nterm2 + | ^~~~~~ +input.y:3.21-26: warning: POSIX yacc reserves %type to nonterminals [-Wyacc] + 3 | %type TOKEN1 TOKEN2 "TOKEN3" nterm1 nterm2 nterm3 '+' + | ^~~~~~ +input.y:10.9-16: warning: POSIX Yacc does not support string literals [-Wyacc] + 10 | nterm3: "TOKEN3" + | ^~~~~~~~ +]]) + +AT_CLEANUP + + ## ----------------------------- ## ## Invalid symbol declarations. ## ## ----------------------------- ##