Copy BYacc's nice way to report the grammar.

* src/gram.h, src/gram.c (grammar_rhs_print, grammar_rules_print):
New.
Don't print the rules' location, it is confusing and useless.
(rule_print): Use grammar_rhs_print.
* src/print.c (print_grammar): Use grammar_rules_print.
This commit is contained in:
Akim Demaille
2002-06-15 18:23:12 +00:00
parent ee000ba4fc
commit 6b98e4b563
16 changed files with 328 additions and 151 deletions

View File

@@ -1,3 +1,34 @@
2002-06-15 Akim Demaille <akim@epita.fr>
Copy BYacc's nice way to report the grammar.
* src/gram.h, src/gram.c (grammar_rhs_print, grammar_rules_print):
New.
Don't print the rules' location, it is confusing and useless.
(rule_print): Use grammar_rhs_print.
* src/print.c (print_grammar): Use grammar_rules_print.
2002-06-15 Akim Demaille <akim@epita.fr>
Complete and rationalize `useless thing' warnings.
* src/symtab.h, src/symtab.c (symbol_tag_get, symbol_tag_get_n)
(symbol_tag_print): New.
Use them everywhere in place of accessing directly the tag member.
* src/gram.h, src/gram.c (rule_print): New.
Use it where a rule used to be printed `by hand'.
* src/reduce.c (nonterminals_reduce): Report the use nonterminals.
(reduce_grammar_tables): Report the useless rules.
(reduce_print): Useless things are a warning, not an error.
Report it as such.
* tests/reduce.at (Useless Nonterminals, Useless Rules):
(Reduced Automaton, Underivable Rules): Adjust.
* tests/regression.at (Web2c Report, Web2c Report): Adjust.
* tests/conflicts.at (Unresolved SR Conflicts)
(Solved SR Conflicts): Adjust.
2002-06-15 Akim Demaille <akim@epita.fr> 2002-06-15 Akim Demaille <akim@epita.fr>
Let symbols have a location. Let symbols have a location.

3
NEWS
View File

@@ -42,6 +42,9 @@ Changes in version 1.49b:
Before, Bison reported the useless rules, but, although not used, Before, Bison reported the useless rules, but, although not used,
included them in the parsers. They are now actually removed. included them in the parsers. They are now actually removed.
* Useless rules, useless nonterminals
They are now reported, as a warning, with their locations.
* Incorrect `Token not used' * Incorrect `Token not used'
On a grammar such as On a grammar such as

View File

@@ -191,8 +191,7 @@ new_state (symbol_number_t symbol, size_t core_size, item_number_t *core)
if (trace_flag) if (trace_flag)
fprintf (stderr, "Entering new_state, state = %d, symbol = %d (%s)\n", fprintf (stderr, "Entering new_state, state = %d, symbol = %d (%s)\n",
nstates, symbol, quotearg_style (escape_quoting_style, nstates, symbol, symbol_tag_get (symbols[symbol]));
symbols[symbol]->tag));
if (nstates >= SHRT_MAX) if (nstates >= SHRT_MAX)
fatal (_("too many states (max %d)"), SHRT_MAX); fatal (_("too many states (max %d)"), SHRT_MAX);
@@ -237,8 +236,8 @@ get_state (symbol_number_t symbol, size_t core_size, item_number_t *core)
if (trace_flag) if (trace_flag)
fprintf (stderr, "Entering get_state, state = %d, symbol = %d (%s)\n", fprintf (stderr, "Entering get_state, state = %d, symbol = %d (%s)\n",
this_state->number, symbol, quotearg_style (escape_quoting_style, this_state->number, symbol,
symbols[symbol]->tag)); symbol_tag_get (symbols[symbol]));
/* Add up the target state's active item numbers to get a hash key. /* Add up the target state's active item numbers to get a hash key.
*/ */
@@ -424,8 +423,7 @@ generate_states (void)
if (trace_flag) if (trace_flag)
fprintf (stderr, "Processing state %d (reached by %s)\n", fprintf (stderr, "Processing state %d (reached by %s)\n",
this_state->number, this_state->number,
quotearg_style (escape_quoting_style, symbol_tag_get (symbols[this_state->accessing_symbol]));
symbols[this_state->accessing_symbol]->tag));
/* Set up ruleset and itemset for the transitions out of this /* Set up ruleset and itemset for the transitions out of this
state. ruleset gets a 1 bit for each rule that could reduce state. ruleset gets a 1 bit for each rule that could reduce
now. itemset gets a vector of all the items that could be now. itemset gets a vector of all the items that could be

View File

@@ -59,8 +59,7 @@ print_closure (const char *title, item_number_t *array, size_t size)
item_number_t *rp; item_number_t *rp;
fprintf (stderr, " %2d: .", array[i]); fprintf (stderr, " %2d: .", array[i]);
for (rp = &ritem[array[i]]; *rp >= 0; ++rp) for (rp = &ritem[array[i]]; *rp >= 0; ++rp)
fprintf (stderr, " %s", fprintf (stderr, " %s", symbol_tag_get (symbols[*rp]));
quotearg_style (escape_quoting_style, symbols[*rp]->tag));
fprintf (stderr, " (rule %d)\n", -*rp - 1); fprintf (stderr, " (rule %d)\n", -*rp - 1);
} }
fputs ("\n\n", stderr); fputs ("\n\n", stderr);
@@ -75,13 +74,11 @@ print_firsts (void)
fprintf (stderr, "FIRSTS\n"); fprintf (stderr, "FIRSTS\n");
for (i = ntokens; i < nsyms; i++) for (i = ntokens; i < nsyms; i++)
{ {
fprintf (stderr, "\t%s firsts\n", fprintf (stderr, "\t%s firsts\n", symbol_tag_get (symbols[i]));
quotearg_style (escape_quoting_style, symbols[i]->tag));
for (j = 0; j < nvars; j++) for (j = 0; j < nvars; j++)
if (bitset_test (FIRSTS (i), j)) if (bitset_test (FIRSTS (i), j))
fprintf (stderr, "\t\t%s\n", fprintf (stderr, "\t\t%s\n",
quotearg_style (escape_quoting_style, symbol_tag_get (symbols[j + ntokens]));
symbols[j + ntokens]->tag));
} }
fprintf (stderr, "\n\n"); fprintf (stderr, "\n\n");
} }
@@ -95,17 +92,14 @@ print_fderives (void)
fprintf (stderr, "FDERIVES\n"); fprintf (stderr, "FDERIVES\n");
for (i = ntokens; i < nsyms; i++) for (i = ntokens; i < nsyms; i++)
{ {
fprintf (stderr, "\t%s derives\n", fprintf (stderr, "\t%s derives\n", symbol_tag_get (symbols[i]));
quotearg_style (escape_quoting_style, symbols[i]->tag));
for (j = 0; j < nrules + 1; j++) for (j = 0; j < nrules + 1; j++)
if (bitset_test (FDERIVES (i), j)) if (bitset_test (FDERIVES (i), j))
{ {
item_number_t *rhsp; item_number_t *rhsp;
fprintf (stderr, "\t\t%d:", j - 1); fprintf (stderr, "\t\t%d:", j - 1);
for (rhsp = rules[j].rhs; *rhsp >= 0; ++rhsp) for (rhsp = rules[j].rhs; *rhsp >= 0; ++rhsp)
fprintf (stderr, " %s", fprintf (stderr, " %s", symbol_tag_get (symbols[*rhsp]));
quotearg_style (escape_quoting_style,
symbols[*rhsp]->tag));
fputc ('\n', stderr); fputc ('\n', stderr);
} }
} }

View File

@@ -26,7 +26,7 @@
#include "reduce.h" #include "reduce.h"
#include "reader.h" #include "reader.h"
/* comments for these variables are in gram.h */ /* Comments for these variables are in gram.h. */
item_number_t *ritem = NULL; item_number_t *ritem = NULL;
unsigned int nritems = 0; unsigned int nritems = 0;
@@ -61,6 +61,39 @@ rule_rhs_length (rule_t *rule)
} }
/*-------------------------------.
| Print this RULE's RHS on OUT. |
`-------------------------------*/
void
rule_rhs_print (rule_t *rule, FILE *out)
{
if (*rule->rhs >= 0)
{
item_number_t *r;
for (r = rule->rhs; *r >= 0; r++)
fprintf (out, " %s", symbol_tag_get (symbols[*r]));
fputc ('\n', out);
}
else
{
fprintf (out, " /* %s */\n", _("empty"));
}
}
/*-------------------------.
| Print this RULE on OUT. |
`-------------------------*/
void
rule_print (rule_t *rule, FILE *out)
{
fprintf (out, "%s:", symbol_tag_get (rule->lhs));
rule_rhs_print (rule, out);
}
/*------------------------. /*------------------------.
| Dump RITEM for traces. | | Dump RITEM for traces. |
`------------------------*/ `------------------------*/
@@ -72,8 +105,7 @@ ritem_print (FILE *out)
fputs ("RITEM\n", out); fputs ("RITEM\n", out);
for (i = 0; i < nritems; ++i) for (i = 0; i < nritems; ++i)
if (ritem[i] >= 0) if (ritem[i] >= 0)
fprintf (out, " %s", quotearg_style (escape_quoting_style, fprintf (out, " %s", symbol_tag_get (symbols[ritem[i]]));
symbols[ritem[i]]->tag));
else else
fprintf (out, " (rule %d)\n", -ritem[i] - 1); fprintf (out, " (rule %d)\n", -ritem[i] - 1);
fputs ("\n\n", out); fputs ("\n\n", out);
@@ -101,6 +133,46 @@ ritem_longest_rhs (void)
} }
/*-----------------------------------.
| Print the grammar's rules on OUT. |
`-----------------------------------*/
static inline void
blanks_print (unsigned n, FILE *out)
{
for (/* Nothing*/; n > 0; --n)
fputc (' ', out);
}
void
grammar_rules_print (FILE *out)
{
int r;
symbol_t *last_lhs = NULL;
/* rule # : LHS -> RHS */
fprintf (out, "%s\n\n", _("Grammar"));
for (r = 1; r < nrules + 1; r++)
{
if (last_lhs && last_lhs != rules[r].lhs)
fputc ('\n', out);
fprintf (out, " %3d ", r - 1);
if (last_lhs != rules[r].lhs)
{
last_lhs = rules[r].lhs;
fprintf (out, "%s:", symbol_tag_get (last_lhs));
}
else
{
blanks_print (strlen (symbol_tag_get (last_lhs)), out);
fputc ('|', out);
}
rule_rhs_print (&rules[r], out);
}
fputs ("\n\n", out);
}
/*-------------------. /*-------------------.
| Dump the grammar. | | Dump the grammar. |
`-------------------*/ `-------------------*/
@@ -121,7 +193,7 @@ grammar_dump (FILE *out, const char *title)
fprintf (out, "%5d %5d %5d %s\n", fprintf (out, "%5d %5d %5d %s\n",
i, i,
symbols[i]->prec, symbols[i]->assoc, symbols[i]->prec, symbols[i]->assoc,
quotearg_style (escape_quoting_style, symbols[i]->tag)); symbol_tag_get (symbols[i]));
fprintf (out, "\n\n"); fprintf (out, "\n\n");
fprintf (out, "Rules\n-----\n\n"); fprintf (out, "Rules\n-----\n\n");
fprintf (out, "Num (Prec, Assoc, Useful, Ritem Range) Lhs -> Rhs (Ritem range) [Num]\n"); fprintf (out, "Num (Prec, Assoc, Useful, Ritem Range) Lhs -> Rhs (Ritem range) [Num]\n");
@@ -148,12 +220,8 @@ grammar_dump (FILE *out, const char *title)
fprintf (out, "Rules interpreted\n-----------------\n\n"); fprintf (out, "Rules interpreted\n-----------------\n\n");
for (i = 1; i < nrules + nuseless_productions + 1; i++) for (i = 1; i < nrules + nuseless_productions + 1; i++)
{ {
fprintf (out, "%-5d %s :", fprintf (out, "%-5d ", i);
i, quotearg_style (escape_quoting_style, rules[i].lhs->tag)); rule_print (&rules[i], out);
for (r = rules[i].rhs; *r >= 0; r++)
fprintf (out, " %s",
quotearg_style (escape_quoting_style, symbols[*r]->tag));
fputc ('\n', out);
} }
fprintf (out, "\n\n"); fprintf (out, "\n\n");
} }

View File

@@ -168,15 +168,24 @@ extern int max_user_token_number;
extern int pure_parser; extern int pure_parser;
/* Report the length of the RHS. */ /* Return the length of the RHS. */
int rule_rhs_length PARAMS ((rule_t *rule)); int rule_rhs_length PARAMS ((rule_t *rule));
/* Print this RULE's RHS on OUT. */
void rule_rhs_print PARAMS ((rule_t *rule, FILE *out));
/* Print this RULE on OUT. */
void rule_print PARAMS ((rule_t *rule, FILE *out));
/* Dump RITEM for traces. */ /* Dump RITEM for traces. */
void ritem_print PARAMS ((FILE *out)); void ritem_print PARAMS ((FILE *out));
/* Return the size of the longest rule RHS. */ /* Return the size of the longest rule RHS. */
size_t ritem_longest_rhs PARAMS ((void)); size_t ritem_longest_rhs PARAMS ((void));
/* Print the grammar's rules on OUT. */
void grammar_rules_print PARAMS ((FILE *out));
/* Dump the grammar. */ /* Dump the grammar. */
void grammar_dump PARAMS ((FILE *out, const char *title)); void grammar_dump PARAMS ((FILE *out, const char *title));

View File

@@ -565,7 +565,7 @@ lookaheads_print (FILE *out)
for (k = 0; k < ntokens; ++k) for (k = 0; k < ntokens; ++k)
if (bitset_test (LA[states[i]->lookaheadsp + j], k)) if (bitset_test (LA[states[i]->lookaheadsp + j], k))
fprintf (out, " on %d (%s) -> rule %d\n", fprintf (out, " on %d (%s) -> rule %d\n",
k, quotearg_style (escape_quoting_style, symbols[k]->tag), k, symbol_tag_get (symbols[k]),
LArule[states[i]->lookaheadsp + j]->number - 1); LArule[states[i]->lookaheadsp + j]->number - 1);
} }
fprintf (out, "Lookaheads: END\n"); fprintf (out, "Lookaheads: END\n");

View File

@@ -235,11 +235,11 @@ prepare_tokens (void)
int j = 0; int j = 0;
for (i = 0; i < nsyms; i++) for (i = 0; i < nsyms; i++)
{ {
/* Be sure not to use twice the same quotearg slot. */ /* Be sure not to use twice the same QUOTEARG slot:
SYMBOL_TAG_GET uses slot 0. */
const char *cp = const char *cp =
quotearg_n_style (1, c_quoting_style, quotearg_n_style (1, c_quoting_style,
quotearg_style (escape_quoting_style, symbol_tag_get (symbols[i]));
symbols[i]->tag));
/* Width of the next token, including the two quotes, the coma /* Width of the next token, including the two quotes, the coma
and the space. */ and the space. */
int strsize = strlen (cp) + 2; int strsize = strlen (cp) + 2;

View File

@@ -47,19 +47,6 @@ print_token (int extnum, int token)
} }
#endif #endif
static inline const char *
escape (const char *s)
{
return quotearg_n_style (1, escape_quoting_style, s);
}
/* Be cautious not to use twice the same slot in a single expression. */
static inline const char *
escape2 (const char *s)
{
return quotearg_n_style (2, escape_quoting_style, s);
}
/*--------------------------------. /*--------------------------------.
| Report information on a state. | | Report information on a state. |
@@ -94,15 +81,15 @@ print_core (FILE *out, state_t *state)
sp++; sp++;
rule = -(*sp); rule = -(*sp);
fprintf (out, " %s -> ", escape (rules[rule].lhs->tag)); fprintf (out, " %s -> ", symbol_tag_get (rules[rule].lhs));
for (sp = rules[rule].rhs; sp < sp1; sp++) for (sp = rules[rule].rhs; sp < sp1; sp++)
fprintf (out, "%s ", escape (symbols[*sp]->tag)); fprintf (out, "%s ", symbol_tag_get (symbols[*sp]));
fputc ('.', out); fputc ('.', out);
for (/* Nothing */; *sp >= 0; ++sp) for (/* Nothing */; *sp >= 0; ++sp)
fprintf (out, " %s", escape (symbols[*sp]->tag)); fprintf (out, " %s", symbol_tag_get (symbols[*sp]));
/* Display the lookaheads? */ /* Display the lookaheads? */
if (report_flag & report_lookaheads) if (report_flag & report_lookaheads)
@@ -123,8 +110,7 @@ print_core (FILE *out, state_t *state)
if (bitset_test (LA[state->lookaheadsp + j], k) if (bitset_test (LA[state->lookaheadsp + j], k)
&& LArule[state->lookaheadsp + j]->number == rule) && LArule[state->lookaheadsp + j]->number == rule)
fprintf (out, "%s%s", fprintf (out, "%s%s",
quotearg_style (escape_quoting_style, symbol_tag_get (symbols[k]),
symbols[k]->tag),
--nlookaheads ? ", " : ""); --nlookaheads ? ", " : "");
fprintf (out, "]"); fprintf (out, "]");
} }
@@ -152,7 +138,7 @@ print_shifts (FILE *out, state_t *state)
symbol_number_t symbol = states[state1]->accessing_symbol; symbol_number_t symbol = states[state1]->accessing_symbol;
fprintf (out, fprintf (out,
_(" %-4s\tshift, and go to state %d\n"), _(" %-4s\tshift, and go to state %d\n"),
escape (symbols[symbol]->tag), state1); symbol_tag_get (symbols[symbol]), state1);
} }
if (i > 0) if (i > 0)
@@ -169,7 +155,7 @@ print_errs (FILE *out, state_t *state)
for (i = 0; i < errp->nerrs; ++i) for (i = 0; i < errp->nerrs; ++i)
if (errp->errs[i]) if (errp->errs[i])
fprintf (out, _(" %-4s\terror (nonassociative)\n"), fprintf (out, _(" %-4s\terror (nonassociative)\n"),
escape (symbols[errp->errs[i]]->tag)); symbol_tag_get (symbols[errp->errs[i]]));
if (i > 0) if (i > 0)
fputc ('\n', out); fputc ('\n', out);
@@ -193,7 +179,7 @@ print_gotos (FILE *out, state_t *state)
int state1 = shiftp->shifts[i]; int state1 = shiftp->shifts[i];
symbol_number_t symbol = states[state1]->accessing_symbol; symbol_number_t symbol = states[state1]->accessing_symbol;
fprintf (out, _(" %-4s\tgo to state %d\n"), fprintf (out, _(" %-4s\tgo to state %d\n"),
escape (symbols[symbol]->tag), state1); symbol_tag_get (symbols[symbol]), state1);
} }
fputc ('\n', out); fputc ('\n', out);
@@ -217,7 +203,7 @@ print_reductions (FILE *out, state_t *state)
int rule = redp->rules[0]; int rule = redp->rules[0];
symbol_number_t symbol = rules[rule].lhs->number; symbol_number_t symbol = rules[rule].lhs->number;
fprintf (out, _(" $default\treduce using rule %d (%s)\n\n"), fprintf (out, _(" $default\treduce using rule %d (%s)\n\n"),
rule - 1, escape (symbols[symbol]->tag)); rule - 1, symbol_tag_get (symbols[symbol]));
return; return;
} }
@@ -246,13 +232,13 @@ print_reductions (FILE *out, state_t *state)
for (i = 0; i < ntokens; i++) for (i = 0; i < ntokens; i++)
if (bitset_test (lookaheadset, i)) if (bitset_test (lookaheadset, i))
fprintf (out, _(" %-4s\t[reduce using rule %d (%s)]\n"), fprintf (out, _(" %-4s\t[reduce using rule %d (%s)]\n"),
escape (symbols[i]->tag), symbol_tag_get (symbols[i]),
default_rule->number - 1, default_rule->number - 1,
escape2 (default_rule->lhs->tag)); symbol_tag_get_n (default_rule->lhs, 1));
fprintf (out, _(" $default\treduce using rule %d (%s)\n\n"), fprintf (out, _(" $default\treduce using rule %d (%s)\n\n"),
default_rule->number - 1, default_rule->number - 1,
escape (default_rule->lhs->tag)); symbol_tag_get (default_rule->lhs));
} }
else if (state->nlookaheads >= 1) else if (state->nlookaheads >= 1)
{ {
@@ -302,9 +288,9 @@ print_reductions (FILE *out, state_t *state)
if (state->lookaheadsp + j != default_LA) if (state->lookaheadsp + j != default_LA)
fprintf (out, fprintf (out,
_(" %-4s\treduce using rule %d (%s)\n"), _(" %-4s\treduce using rule %d (%s)\n"),
escape (symbols[i]->tag), symbol_tag_get (symbols[i]),
LArule[state->lookaheadsp + j]->number - 1, LArule[state->lookaheadsp + j]->number - 1,
escape2 (LArule[state->lookaheadsp + j]->lhs->tag)); symbol_tag_get_n (LArule[state->lookaheadsp + j]->lhs, 1));
else else
defaulted = 1; defaulted = 1;
@@ -315,15 +301,15 @@ print_reductions (FILE *out, state_t *state)
if (defaulted) if (defaulted)
fprintf (out, fprintf (out,
_(" %-4s\treduce using rule %d (%s)\n"), _(" %-4s\treduce using rule %d (%s)\n"),
escape (symbols[i]->tag), symbol_tag_get (symbols[i]),
LArule[default_LA]->number - 1, LArule[default_LA]->number - 1,
escape2 (LArule[default_LA]->lhs->tag)); symbol_tag_get_n (LArule[default_LA]->lhs, 1));
defaulted = 0; defaulted = 0;
fprintf (out, fprintf (out,
_(" %-4s\t[reduce using rule %d (%s)]\n"), _(" %-4s\t[reduce using rule %d (%s)]\n"),
escape (symbols[i]->tag), symbol_tag_get (symbols[i]),
LArule[state->lookaheadsp + j]->number - 1, LArule[state->lookaheadsp + j]->number - 1,
escape2 (LArule[state->lookaheadsp + j]->lhs->tag)); symbol_tag_get_n (LArule[state->lookaheadsp + j]->lhs, 1));
} }
} }
} }
@@ -331,7 +317,7 @@ print_reductions (FILE *out, state_t *state)
if (default_LA >= 0) if (default_LA >= 0)
fprintf (out, _(" $default\treduce using rule %d (%s)\n"), fprintf (out, _(" $default\treduce using rule %d (%s)\n"),
default_rule->number - 1, default_rule->number - 1,
escape (default_rule->lhs->tag)); symbol_tag_get (default_rule->lhs));
} }
} }
@@ -389,47 +375,31 @@ static void
print_grammar (FILE *out) print_grammar (FILE *out)
{ {
symbol_number_t i; symbol_number_t i;
int j;
item_number_t *rule; item_number_t *rule;
char buffer[90]; char buffer[90];
int column = 0; int column = 0;
/* rule # : LHS -> RHS */ grammar_rules_print (out);
fprintf (out, "%s\n\n", _("Grammar"));
fprintf (out, " %s\n", _("Number, Line, Rule"));
for (j = 1; j < nrules + 1; j++)
{
fprintf (out, " %3d %3d %s ->",
j - 1, rules[j].location.first_line,
escape (rules[j].lhs->tag));
rule = rules[j].rhs;
if (*rule >= 0)
while (*rule >= 0)
fprintf (out, " %s", escape (symbols[*rule++]->tag));
else
fprintf (out, " /* %s */", _("empty"));
fputc ('\n', out);
}
fputs ("\n\n", out);
/* TERMINAL (type #) : rule #s terminal is on RHS */ /* TERMINAL (type #) : rule #s terminal is on RHS */
fprintf (out, "%s\n\n", _("Terminals, with rules where they appear")); fprintf (out, "%s\n\n", _("Terminals, with rules where they appear"));
for (i = 0; i < max_user_token_number + 1; i++) for (i = 0; i < max_user_token_number + 1; i++)
if (token_translations[i] != undeftoken->number) if (token_translations[i] != undeftoken->number)
{ {
const char *tag = symbol_tag_get (symbols[token_translations[i]]);
int r;
buffer[0] = 0; buffer[0] = 0;
column = strlen (escape (symbols[token_translations[i]]->tag)); column = strlen (tag);
fputs (escape (symbols[token_translations[i]]->tag), out); fputs (tag, out);
END_TEST (50); END_TEST (50);
sprintf (buffer, " (%d)", i); sprintf (buffer, " (%d)", i);
for (j = 1; j < nrules + 1; j++) for (r = 1; r < nrules + 1; r++)
for (rule = rules[j].rhs; *rule >= 0; rule++) for (rule = rules[r].rhs; *rule >= 0; rule++)
if (item_number_as_symbol_number (*rule) == token_translations[i]) if (item_number_as_symbol_number (*rule) == token_translations[i])
{ {
END_TEST (65); END_TEST (65);
sprintf (buffer + strlen (buffer), " %d", j - 1); sprintf (buffer + strlen (buffer), " %d", r - 1);
break; break;
} }
fprintf (out, "%s\n", buffer); fprintf (out, "%s\n", buffer);
@@ -441,12 +411,14 @@ print_grammar (FILE *out)
for (i = ntokens; i < nsyms; i++) for (i = ntokens; i < nsyms; i++)
{ {
int left_count = 0, right_count = 0; int left_count = 0, right_count = 0;
int r;
const char *tag = symbol_tag_get (symbols[i]);
for (j = 1; j < nrules + 1; j++) for (r = 1; r < nrules + 1; r++)
{ {
if (rules[j].lhs->number == i) if (rules[r].lhs->number == i)
left_count++; left_count++;
for (rule = rules[j].rhs; *rule >= 0; rule++) for (rule = rules[r].rhs; *rule >= 0; rule++)
if (item_number_as_symbol_number (*rule) == i) if (item_number_as_symbol_number (*rule) == i)
{ {
right_count++; right_count++;
@@ -455,8 +427,8 @@ print_grammar (FILE *out)
} }
buffer[0] = 0; buffer[0] = 0;
fputs (escape (symbols[i]->tag), out); fputs (tag, out);
column = strlen (escape (symbols[i]->tag)); column = strlen (tag);
sprintf (buffer, " (%d)", i); sprintf (buffer, " (%d)", i);
END_TEST (0); END_TEST (0);
@@ -465,11 +437,11 @@ print_grammar (FILE *out)
END_TEST (50); END_TEST (50);
sprintf (buffer + strlen (buffer), _(" on left:")); sprintf (buffer + strlen (buffer), _(" on left:"));
for (j = 1; j < nrules + 1; j++) for (r = 1; r < nrules + 1; r++)
{ {
END_TEST (65); END_TEST (65);
if (rules[j].lhs->number == i) if (rules[r].lhs->number == i)
sprintf (buffer + strlen (buffer), " %d", j - 1); sprintf (buffer + strlen (buffer), " %d", r - 1);
} }
} }
@@ -479,13 +451,13 @@ print_grammar (FILE *out)
sprintf (buffer + strlen (buffer), ","); sprintf (buffer + strlen (buffer), ",");
END_TEST (50); END_TEST (50);
sprintf (buffer + strlen (buffer), _(" on right:")); sprintf (buffer + strlen (buffer), _(" on right:"));
for (j = 1; j < nrules + 1; j++) for (r = 1; r < nrules + 1; r++)
{ {
for (rule = rules[j].rhs; *rule >= 0; rule++) for (rule = rules[r].rhs; *rule >= 0; rule++)
if (item_number_as_symbol_number (*rule) == i) if (item_number_as_symbol_number (*rule) == i)
{ {
END_TEST (65); END_TEST (65);
sprintf (buffer + strlen (buffer), " %d", j - 1); sprintf (buffer + strlen (buffer), " %d", r - 1);
break; break;
} }
} }

View File

@@ -38,14 +38,11 @@
static graph_t graph; static graph_t graph;
static FILE *fgraph = NULL; static FILE *fgraph = NULL;
static inline const char *
escape (const char *s)
{
return quotearg_n_style (1, escape_quoting_style, s);
}
/*----------------------------.
| Construct the node labels. |
`----------------------------*/
/* This part will construct the label of nodes. */
static void static void
print_core (struct obstack *oout, state_t *state) print_core (struct obstack *oout, state_t *state)
{ {
@@ -78,15 +75,15 @@ print_core (struct obstack *oout, state_t *state)
if (i) if (i)
obstack_1grow (oout, '\n'); obstack_1grow (oout, '\n');
obstack_fgrow1 (oout, " %s -> ", obstack_fgrow1 (oout, " %s -> ",
escape (rules[rule].lhs->tag)); symbol_tag_get (rules[rule].lhs));
for (sp = rules[rule].rhs; sp < sp1; sp++) for (sp = rules[rule].rhs; sp < sp1; sp++)
obstack_fgrow1 (oout, "%s ", escape (symbols[*sp]->tag)); obstack_fgrow1 (oout, "%s ", symbol_tag_get (symbols[*sp]));
obstack_1grow (oout, '.'); obstack_1grow (oout, '.');
for (/* Nothing */; *sp >= 0; ++sp) for (/* Nothing */; *sp >= 0; ++sp)
obstack_fgrow1 (oout, " %s", escape (symbols[*sp]->tag)); obstack_fgrow1 (oout, " %s", symbol_tag_get (symbols[*sp]));
/* Experimental feature: display the lookaheads. */ /* Experimental feature: display the lookaheads. */
if (trace_flag && state->nlookaheads) if (trace_flag && state->nlookaheads)
@@ -107,8 +104,7 @@ print_core (struct obstack *oout, state_t *state)
if (bitset_test (LA[state->lookaheadsp + j], k) if (bitset_test (LA[state->lookaheadsp + j], k)
&& LArule[state->lookaheadsp + j]->number == rule) && LArule[state->lookaheadsp + j]->number == rule)
obstack_fgrow2 (oout, "%s%s", obstack_fgrow2 (oout, "%s%s",
quotearg_style (escape_quoting_style, symbol_tag_get (symbols[k]),
symbols[k]->tag),
--nlookaheads ? ", " : ""); --nlookaheads ? ", " : "");
obstack_sgrow (oout, "]"); obstack_sgrow (oout, "]");
} }
@@ -156,7 +152,7 @@ print_actions (state_t *state, const char *node_name)
edge.color = red; edge.color = red;
else else
edge.color = SHIFT_IS_SHIFT(shiftp, i) ? blue : green; edge.color = SHIFT_IS_SHIFT(shiftp, i) ? blue : green;
edge.label = escape (symbols[symbol]->tag); edge.label = symbol_tag_get (symbols[symbol]);
output_edge (&edge, fgraph); output_edge (&edge, fgraph);
close_edge (fgraph); close_edge (fgraph);
} }

View File

@@ -227,11 +227,19 @@ inaccessable_symbols (void)
static void static void
reduce_grammar_tables (void) reduce_grammar_tables (void)
{ {
/* Flag useless productions. */ /* Report and flag useless productions. */
{ {
int pn; int r;
for (pn = 1; pn < nrules + 1; pn++) for (r = 1; r < nrules + 1; r++)
rules[pn].useful = bitset_test (P, pn); {
rules[r].useful = bitset_test (P, r);
if (!rules[r].useful)
{
LOCATION_PRINT (stderr, rules[r].location);
fprintf (stderr, ": %s: %s: ", _("warning"), _("useless rule"));
rule_print (&rules[r], stderr);
}
}
} }
/* Map the nonterminals to their new index: useful first, useless /* Map the nonterminals to their new index: useful first, useless
@@ -290,7 +298,13 @@ nonterminals_reduce (void)
nontermmap[i] = n++; nontermmap[i] = n++;
for (i = ntokens; i < nsyms; i++) for (i = ntokens; i < nsyms; i++)
if (!bitset_test (V, i)) if (!bitset_test (V, i))
nontermmap[i] = n++; {
nontermmap[i] = n++;
LOCATION_PRINT (stderr, symbols[i]->location);
fprintf (stderr, ": %s: %s: %s\n",
_("warning"), _("useless nonterminal"),
symbol_tag_get (symbols[i]));
}
/* Shuffle elements of tables indexed by symbol number. */ /* Shuffle elements of tables indexed by symbol number. */
@@ -337,8 +351,7 @@ reduce_output (FILE *out)
int i; int i;
fprintf (out, "%s\n\n", _("Useless nonterminals:")); fprintf (out, "%s\n\n", _("Useless nonterminals:"));
for (i = 0; i < nuseless_nonterminals; ++i) for (i = 0; i < nuseless_nonterminals; ++i)
fprintf (out, " %s\n", quotearg_style (escape_quoting_style, fprintf (out, " %s\n", symbol_tag_get (symbols[nsyms + i]));
symbols[nsyms + i]->tag));
fputs ("\n\n", out); fputs ("\n\n", out);
} }
@@ -351,8 +364,7 @@ reduce_output (FILE *out)
if (!b) if (!b)
fprintf (out, "%s\n\n", _("Terminals which are not used:")); fprintf (out, "%s\n\n", _("Terminals which are not used:"));
b = TRUE; b = TRUE;
fprintf (out, " %s\n", quotearg_style (escape_quoting_style, fprintf (out, " %s\n", symbol_tag_get (symbols[i]));
symbols[i]->tag));
} }
if (b) if (b)
fputs ("\n\n", out); fputs ("\n\n", out);
@@ -366,11 +378,9 @@ reduce_output (FILE *out)
{ {
item_number_t *r; item_number_t *r;
fprintf (out, "#%-4d ", rules[i].user_number - 1); fprintf (out, "#%-4d ", rules[i].user_number - 1);
fprintf (out, "%s:", quotearg_style (escape_quoting_style, fprintf (out, "%s:", symbol_tag_get (rules[i].lhs));
rules[i].lhs->tag));
for (r = rules[i].rhs; *r >= 0; r++) for (r = rules[i].rhs; *r >= 0; r++)
fprintf (out, " %s", quotearg_style (escape_quoting_style, fprintf (out, " %s", symbol_tag_get (symbols[*r]));
symbols[*r]->tag));
fputs (";\n", out); fputs (";\n", out);
} }
fputs ("\n\n", out); fputs ("\n\n", out);
@@ -394,7 +404,7 @@ reduce_print (void)
nuseless_productions), nuseless_productions),
nuseless_productions); nuseless_productions);
fprintf (stderr, _("%s contains "), infile); fprintf (stderr, "%s: %s: ", infile, _("warning"));
if (nuseless_nonterminals > 0) if (nuseless_nonterminals > 0)
fprintf (stderr, ngettext ("%d useless nonterminal", fprintf (stderr, ngettext ("%d useless nonterminal",
@@ -437,7 +447,7 @@ reduce_grammar (void)
if (!bitset_test (N, axiom->number - ntokens)) if (!bitset_test (N, axiom->number - ntokens))
fatal (_("Start symbol %s does not derive any sentence"), fatal (_("Start symbol %s does not derive any sentence"),
quotearg_style (escape_quoting_style, symbols[axiom->number]->tag)); symbol_tag_get (symbols[axiom->number]));
/* First reduce the nonterminals, as they renumber themselves in the /* First reduce the nonterminals, as they renumber themselves in the
whole grammar. If you change the order, nonterms would be whole grammar. If you change the order, nonterms would be

View File

@@ -20,6 +20,7 @@
#include "system.h" #include "system.h"
#include "quotearg.h"
#include "hash.h" #include "hash.h"
#include "complain.h" #include "complain.h"
#include "symtab.h" #include "symtab.h"
@@ -60,6 +61,41 @@ symbol_new (const char *tag, location_t location)
} }
/*-----------------------------------------------------------------.
| Return the tag of this SYMBOL in a printable form. Warning: use |
| the first QUOTEARG slot: 0. |
`-----------------------------------------------------------------*/
const char *
symbol_tag_get (symbol_t *symbol)
{
return quotearg_style (escape_quoting_style, symbol->tag);
}
/*------------------------------------------------------------.
| Return the tag of this SYMBOL in a printable form. Use the |
| QUOTEARG slot number N. |
`------------------------------------------------------------*/
const char *
symbol_tag_get_n (symbol_t *symbol, int n)
{
return quotearg_n_style (n, escape_quoting_style, symbol->tag);
}
/*-------------------------------.
| Print the tag of this SYMBOL. |
`-------------------------------*/
void
symbol_tag_print (symbol_t *symbol, FILE *out)
{
fputs (symbol_tag_get (symbol), out);
}
/*------------------------------------------------------------------. /*------------------------------------------------------------------.
| Set the TYPE_NAME associated to SYMBOL. Does nothing if passed 0 | | Set the TYPE_NAME associated to SYMBOL. Does nothing if passed 0 |
| as TYPE_NAME. | | as TYPE_NAME. |

View File

@@ -87,6 +87,17 @@ struct symbol_s
#define NUMBER_UNDEFINED ((symbol_number_t) -1) #define NUMBER_UNDEFINED ((symbol_number_t) -1)
/* Return the tag of this SYMBOL in a printable form. Warning: uses
the QUOTEARG slot 0. */
const char *symbol_tag_get PARAMS ((symbol_t *symbol));
/* Return the tag of this SYMBOL in a printable form. Use the
QUOTEARG slot number N. */
const char *symbol_tag_get_n PARAMS ((symbol_t *symbol, int n));
/* Print the tag of this SYMBOL. */
void symbol_tag_print PARAMS ((symbol_t *symbol, FILE *out));
/* Fetch (or create) the symbol associated to KEY. */ /* Fetch (or create) the symbol associated to KEY. */
symbol_t *getsym PARAMS ((const char *key, location_t location)); symbol_t *getsym PARAMS ((const char *key, location_t location));

View File

@@ -130,6 +130,8 @@ AT_CLEANUP
AT_SETUP([Unresolved SR Conflicts]) AT_SETUP([Unresolved SR Conflicts])
AT_KEYWORDS([report])
AT_DATA([input.y], AT_DATA([input.y],
[[%token NUM OP [[%token NUM OP
%% %%
@@ -147,10 +149,10 @@ AT_CHECK([cat input.output], [],
Grammar Grammar
Number, Line, Rule 0 $axiom: exp $
0 3 $axiom -> exp $
1 3 exp -> exp OP exp 1 exp: exp OP exp
2 3 exp -> NUM 2 | NUM
Terminals, with rules where they appear Terminals, with rules where they appear
@@ -241,6 +243,8 @@ AT_CLEANUP
AT_SETUP([Solved SR Conflicts]) AT_SETUP([Solved SR Conflicts])
AT_KEYWORDS([report])
AT_DATA([input.y], AT_DATA([input.y],
[[%token NUM OP [[%token NUM OP
%right OP %right OP
@@ -254,10 +258,10 @@ AT_CHECK([bison input.y -o input.c --report=all], 0, [], [])
AT_CHECK([cat input.output], [], AT_CHECK([cat input.output], [],
[[Grammar [[Grammar
Number, Line, Rule 0 $axiom: exp $
0 4 $axiom -> exp $
1 4 exp -> exp OP exp 1 exp: exp OP exp
2 4 exp -> NUM 2 | NUM
Terminals, with rules where they appear Terminals, with rules where they appear

View File

@@ -89,7 +89,16 @@ exp: useful;
]]) ]])
AT_CHECK([[bison input.y]], 0, [], AT_CHECK([[bison input.y]], 0, [],
[[input.y contains 9 useless nonterminals [[input.y: warning: 9 useless nonterminals
input.y:4.8-15: warning: useless nonterminal: useless1
input.y:5.8-15: warning: useless nonterminal: useless2
input.y:6.8-15: warning: useless nonterminal: useless3
input.y:7.8-15: warning: useless nonterminal: useless4
input.y:8.8-15: warning: useless nonterminal: useless5
input.y:9.8-15: warning: useless nonterminal: useless6
input.y:10.8-15: warning: useless nonterminal: useless7
input.y:11.8-15: warning: useless nonterminal: useless8
input.y:12.8-15: warning: useless nonterminal: useless9
]]) ]])
AT_CHECK([[sed -n '/^Grammar/q;/^$/!p' input.output]], 0, AT_CHECK([[sed -n '/^Grammar/q;/^$/!p' input.output]], 0,
@@ -133,7 +142,25 @@ useless9: '9';
]]) ]])
AT_CHECK([[bison input.y]], 0, [], AT_CHECK([[bison input.y]], 0, [],
[[input.y contains 9 useless nonterminals and 9 useless rules [[input.y: warning: 9 useless nonterminals and 9 useless rules
input.y:6.1-8: warning: useless nonterminal: useless1
input.y:7.1-8: warning: useless nonterminal: useless2
input.y:8.1-8: warning: useless nonterminal: useless3
input.y:9.1-8: warning: useless nonterminal: useless4
input.y:10.1-8: warning: useless nonterminal: useless5
input.y:11.1-8: warning: useless nonterminal: useless6
input.y:12.1-8: warning: useless nonterminal: useless7
input.y:13.1-8: warning: useless nonterminal: useless8
input.y:14.1-8: warning: useless nonterminal: useless9
input.y:6.9-13: warning: useless rule: useless1: '1'
input.y:7.9-13: warning: useless rule: useless2: '2'
input.y:8.9-13: warning: useless rule: useless3: '3'
input.y:9.9-13: warning: useless rule: useless4: '4'
input.y:10.9-13: warning: useless rule: useless5: '5'
input.y:11.9-13: warning: useless rule: useless6: '6'
input.y:12.9-13: warning: useless rule: useless7: '7'
input.y:13.9-13: warning: useless rule: useless8: '8'
input.y:14.9-13: warning: useless rule: useless9: '9'
]]) ]])
AT_CHECK([[sed -n '/^Grammar/q;/^$/!p' input.output]], 0, AT_CHECK([[sed -n '/^Grammar/q;/^$/!p' input.output]], 0,
@@ -208,7 +235,12 @@ non_productive: non_productive useless_token
]]) ]])
AT_CHECK([[bison not-reduced.y]], 0, [], AT_CHECK([[bison not-reduced.y]], 0, [],
[[not-reduced.y contains 2 useless nonterminals and 3 useless rules [[not-reduced.y: warning: 2 useless nonterminals and 3 useless rules
not-reduced.y:14.1-13: warning: useless nonterminal: not_reachable
not-reduced.y:11.6-19: warning: useless nonterminal: non_productive
not-reduced.y:11.4-57: warning: useless rule: exp: non_productive
not-reduced.y:14.14-56: warning: useless rule: not_reachable: useful
not-reduced.y:17.15-18.63: warning: useless rule: non_productive: non_productive useless_token
]]) ]])
AT_CHECK([[sed -n '/^Grammar/q;/^$/!p' not-reduced.output]], 0, AT_CHECK([[sed -n '/^Grammar/q;/^$/!p' not-reduced.output]], 0,
@@ -275,7 +307,12 @@ indirection: underivable;
]]) ]])
AT_CHECK([[bison input.y]], 0, [], AT_CHECK([[bison input.y]], 0, [],
[[input.y contains 2 useless nonterminals and 3 useless rules [[input.y: warning: 2 useless nonterminals and 3 useless rules
input.y:5.15-25: warning: useless nonterminal: underivable
input.y:6.14-24: warning: useless nonterminal: indirection
input.y:5.13-25: warning: useless rule: exp: underivable
input.y:6.12-24: warning: useless rule: underivable: indirection
input.y:7.12-24: warning: useless rule: indirection: underivable
]]) ]])
AT_CHECK([[sed -n '/^Grammar/q;/^$/!p' input.output]], 0, AT_CHECK([[sed -n '/^Grammar/q;/^$/!p' input.output]], 0,

View File

@@ -112,6 +112,8 @@ AT_CLEANUP
AT_SETUP([Rule Line Numbers]) AT_SETUP([Rule Line Numbers])
AT_KEYWORDS([report])
AT_DATA([input.y], AT_DATA([input.y],
[[%% [[%%
expr: expr:
@@ -148,12 +150,15 @@ AT_CHECK([bison input.y -o input.c -v])
AT_CHECK([cat input.output], [], AT_CHECK([cat input.output], [],
[[Grammar [[Grammar
Number, Line, Rule 0 $axiom: expr $
0 5 $axiom -> expr $
1 5 @1 -> /* empty */ 1 @1: /* empty */
2 2 expr -> 'a' @1 'b'
3 18 @2 -> /* empty */ 2 expr: 'a' @1 'b'
4 15 expr -> @2 'c'
3 @2: /* empty */
4 expr: @2 'c'
Terminals, with rules where they appear Terminals, with rules where they appear
@@ -349,6 +354,8 @@ AT_CLEANUP
AT_SETUP([Web2c Report]) AT_SETUP([Web2c Report])
AT_KEYWORDS([report])
AT_DATA([input.y], AT_DATA([input.y],
[[%token undef_id_tok const_id_tok [[%token undef_id_tok const_id_tok
@@ -375,13 +382,12 @@ AT_CHECK([bison -v input.y])
AT_CHECK([sed -n 's/ *$//;/^$/!p' input.output], 0, AT_CHECK([sed -n 's/ *$//;/^$/!p' input.output], 0,
[[Grammar [[Grammar
Number, Line, Rule 0 $axiom: CONST_DEC_PART $
0 6 $axiom -> CONST_DEC_PART $ 1 CONST_DEC_PART: CONST_DEC_LIST
1 6 CONST_DEC_PART -> CONST_DEC_LIST 2 CONST_DEC_LIST: CONST_DEC
2 10 CONST_DEC_LIST -> CONST_DEC 3 | CONST_DEC_LIST CONST_DEC
3 12 CONST_DEC_LIST -> CONST_DEC_LIST CONST_DEC 4 @1: /* empty */
4 16 @1 -> /* empty */ 5 CONST_DEC: @1 undef_id_tok '=' const_id_tok ';'
5 15 CONST_DEC -> @1 undef_id_tok '=' const_id_tok ';'
Terminals, with rules where they appear Terminals, with rules where they appear
$ (0) 0 $ (0) 0
';' (59) 5 ';' (59) 5
@@ -470,6 +476,8 @@ AT_CLEANUP
AT_SETUP([Web2c Actions]) AT_SETUP([Web2c Actions])
AT_KEYWORDS([report])
AT_DATA([input.y], AT_DATA([input.y],
[[%% [[%%
statement: struct_stat; statement: struct_stat;