]> git.saurik.com Git - bison.git/blobdiff - src/reduce.c
Copy BYacc's nice way to report the grammar.
[bison.git] / src / reduce.c
index 1e65eee009910df1d04ad56a201b331b7d5a609b..2319b60bf192104f672ff22b0617b62015217824 100644 (file)
@@ -1,5 +1,5 @@
 /* Grammar reduction for Bison.
 /* Grammar reduction for Bison.
-   Copyright 1988, 1989, 2000, 2001  Free Software Foundation, Inc.
+   Copyright (C) 1988, 1989, 2000, 2001, 2002  Free Software Foundation, Inc.
 
    This file is part of Bison, the GNU Compiler Compiler.
 
 
    This file is part of Bison, the GNU Compiler Compiler.
 
    user's parser.  */
 
 #include "system.h"
    user's parser.  */
 
 #include "system.h"
+#include "quotearg.h"
 #include "getargs.h"
 #include "files.h"
 #include "getargs.h"
 #include "files.h"
+#include "symtab.h"
 #include "gram.h"
 #include "complain.h"
 #include "reduce.h"
 #include "reader.h"
 #include "getargs.h"
 #include "gram.h"
 #include "complain.h"
 #include "reduce.h"
 #include "reader.h"
 #include "getargs.h"
+#include "bitset.h"
 
 
-typedef unsigned *BSet;
-typedef short *rule;
+/* Set of all nonterminals which are not useless.  */
+static bitset N;
 
 
+/* Set of all rules which have no useless nonterminals in their RHS.  */
+static bitset P;
 
 
-/* N is set of all nonterminals which are not useless.  P is set of
-   all rules which have no useless nonterminals in their RHS.  V is
-   the set of all accessible symbols.  */
+/* Set of all accessible symbols.  */
+static bitset V;
 
 
-static BSet N, P, V, V1;
+/* Set of symbols used to define rule precedence (so they are
+   `useless', but no warning should be issued).  */
+static bitset V1;
 
 static int nuseful_productions;
 
 static int nuseful_productions;
-static int nuseless_productions;
+int nuseless_productions;
 static int nuseful_nonterminals;
 static int nuseful_nonterminals;
-static int nuseless_nonterminals;
-\f
-static bool
-bits_equal (BSet L, BSet R, int n)
-{
-  int i;
-
-  for (i = n - 1; i >= 0; i--)
-    if (L[i] != R[i])
-      return FALSE;
-  return TRUE;
-}
-
-
-static int
-nbits (unsigned i)
-{
-  int count = 0;
-
-  while (i != 0)
-    {
-      i ^= (i & ((unsigned) (-(int) i)));
-      ++count;
-    }
-  return count;
-}
-
-
-static int
-bits_size (BSet S, int n)
-{
-  int i, count = 0;
-
-  for (i = n - 1; i >= 0; i--)
-    count += nbits (S[i]);
-  return count;
-}
+int nuseless_nonterminals;
 \f
 /*-------------------------------------------------------------------.
 | Another way to do this would be with a set for each production and |
 \f
 /*-------------------------------------------------------------------.
 | Another way to do this would be with a set for each production and |
@@ -92,18 +62,17 @@ bits_size (BSet S, int n)
 `-------------------------------------------------------------------*/
 
 static bool
 `-------------------------------------------------------------------*/
 
 static bool
-useful_production (int i, BSet N0)
+useful_production (int i, bitset N0)
 {
 {
-  rule r;
+  item_number_t *r;
   short n;
 
   /* A production is useful if all of the nonterminals in its appear
      in the set of useful nonterminals.  */
 
   short n;
 
   /* A production is useful if all of the nonterminals in its appear
      in the set of useful nonterminals.  */
 
-  for (r = &ritem[rule_table[i].rhs]; *r > 0; r++)
-    if (ISVAR (n = *r))
-      if (!BITISSET (N0, n - ntokens))
-       return FALSE;
+  for (r = rules[i].rhs; *r >= 0; r++)
+    if (ISVAR (n = *r) && !bitset_test (N0, n - ntokens))
+      return FALSE;
   return TRUE;
 }
 
   return TRUE;
 }
 
@@ -115,13 +84,14 @@ useful_production (int i, BSet N0)
 static void
 useless_nonterminals (void)
 {
 static void
 useless_nonterminals (void)
 {
-  BSet Np, Ns;
+  bitset Np, Ns;
   int i;
 
   /* N is set as built.  Np is set being built this iteration. P is
      set of all productions which have a RHS all in N.  */
 
   int i;
 
   /* N is set as built.  Np is set being built this iteration. P is
      set of all productions which have a RHS all in N.  */
 
-  Np = XCALLOC (unsigned, WORDSIZE (nvars));
+  Np = bitset_create (nvars, BITSET_FIXED);
+
 
   /* The set being computed is a set of nonterminals which can derive
      the empty string or strings consisting of all terminals. At each
 
   /* The set being computed is a set of nonterminals which can derive
      the empty string or strings consisting of all terminals. At each
@@ -141,26 +111,21 @@ useless_nonterminals (void)
 
   while (1)
     {
 
   while (1)
     {
-      for (i = WORDSIZE (nvars) - 1; i >= 0; i--)
-       Np[i] = N[i];
-      for (i = 1; i <= nrules; i++)
-       {
-         if (!BITISSET (P, i))
-           {
-             if (useful_production (i, N))
-               {
-                 SETBIT (Np, rule_table[i].lhs - ntokens);
-                 SETBIT (P, i);
-               }
-           }
-       }
-      if (bits_equal (N, Np, WORDSIZE (nvars)))
+      bitset_copy (Np, N);
+      for (i = 1; i < nrules + 1; i++)
+       if (!bitset_test (P, i)
+           && useful_production (i, N))
+         {
+           bitset_set (Np, rules[i].lhs->number - ntokens);
+           bitset_set (P, i);
+         }
+      if (bitset_equal_p (N, Np))
        break;
       Ns = Np;
       Np = N;
       N = Ns;
     }
        break;
       Ns = Np;
       Np = N;
       N = Ns;
     }
-  XFREE (N);
+  bitset_free (N);
   N = Np;
 }
 
   N = Np;
 }
 
@@ -168,10 +133,10 @@ useless_nonterminals (void)
 static void
 inaccessable_symbols (void)
 {
 static void
 inaccessable_symbols (void)
 {
-  BSet Vp, Vs, Pp;
+  bitset Vp, Vs, Pp;
   int i;
   short t;
   int i;
   short t;
-  rule r;
+  item_number_t *r;
 
   /* Find out which productions are reachable and which symbols are
      used.  Starting with an empty set of productions and a set of
 
   /* Find out which productions are reachable and which symbols are
      used.  Starting with an empty set of productions and a set of
@@ -196,295 +161,233 @@ inaccessable_symbols (void)
      terminals are printed (if running in verbose mode) so that the
      user can know.  */
 
      terminals are printed (if running in verbose mode) so that the
      user can know.  */
 
-  Vp = XCALLOC (unsigned, WORDSIZE (nsyms));
-  Pp = XCALLOC (unsigned, WORDSIZE (nrules + 1));
+  Vp = bitset_create (nsyms, BITSET_FIXED);
+  Pp = bitset_create (nrules + 1, BITSET_FIXED);
 
   /* If the start symbol isn't useful, then nothing will be useful. */
 
   /* If the start symbol isn't useful, then nothing will be useful. */
-  if (!BITISSET (N, start_symbol - ntokens))
-    goto end_iteration;
-
-  SETBIT (V, start_symbol);
-
-  while (1)
+  if (bitset_test (N, axiom->number - ntokens))
     {
     {
-      for (i = WORDSIZE (nsyms) - 1; i >= 0; i--)
-       Vp[i] = V[i];
-      for (i = 1; i <= nrules; i++)
+      bitset_set (V, axiom->number);
+
+      while (1)
        {
        {
-         if (!BITISSET (Pp, i) && BITISSET (P, i) && BITISSET (V, rule_table[i].lhs))
+         bitset_copy (Vp, V);
+         for (i = 1; i < nrules + 1; i++)
            {
            {
-             for (r = &ritem[rule_table[i].rhs]; *r >= 0; r++)
+             if (!bitset_test (Pp, i)
+                 && bitset_test (P, i)
+                 && bitset_test (V, rules[i].lhs->number))
                {
                {
-                 if (ISTOKEN (t = *r) || BITISSET (N, t - ntokens))
-                   {
-                     SETBIT (Vp, t);
-                   }
+                 for (r = rules[i].rhs; *r >= 0; r++)
+                   if (ISTOKEN (t = *r) || bitset_test (N, t - ntokens))
+                     bitset_set (Vp, t);
+                 bitset_set (Pp, i);
                }
                }
-             SETBIT (Pp, i);
            }
            }
+         if (bitset_equal_p (V, Vp))
+           break;
+         Vs = Vp;
+         Vp = V;
+         V = Vs;
        }
        }
-      if (bits_equal (V, Vp, WORDSIZE (nsyms)))
-       {
-         break;
-       }
-      Vs = Vp;
-      Vp = V;
-      V = Vs;
     }
     }
-end_iteration:
 
 
-  XFREE (V);
+  bitset_free (V);
   V = Vp;
 
   /* Tokens 0, 1, and 2 are internal to Bison.  Consider them useful. */
   V = Vp;
 
   /* Tokens 0, 1, and 2 are internal to Bison.  Consider them useful. */
-  SETBIT (V, 0);               /* end-of-input token */
-  SETBIT (V, 1);               /* error token */
-  SETBIT (V, 2);               /* some undefined token */
+  bitset_set (V, eoftoken->number);            /* end-of-input token */
+  bitset_set (V, errtoken->number);            /* error token */
+  bitset_set (V, undeftoken->number);          /* some undefined token */
 
 
-  XFREE (P);
+  bitset_free (P);
   P = Pp;
 
   P = Pp;
 
-  nuseful_productions = bits_size (P, WORDSIZE (nrules + 1));
+  nuseful_productions = bitset_count (P);
   nuseless_productions = nrules - nuseful_productions;
 
   nuseful_nonterminals = 0;
   for (i = ntokens; i < nsyms; i++)
   nuseless_productions = nrules - nuseful_productions;
 
   nuseful_nonterminals = 0;
   for (i = ntokens; i < nsyms; i++)
-    if (BITISSET (V, i))
+    if (bitset_test (V, i))
       nuseful_nonterminals++;
   nuseless_nonterminals = nvars - nuseful_nonterminals;
 
   /* A token that was used in %prec should not be warned about.  */
       nuseful_nonterminals++;
   nuseless_nonterminals = nvars - nuseful_nonterminals;
 
   /* A token that was used in %prec should not be warned about.  */
-  for (i = 1; i < nrules; i++)
-    if (rule_table[i].precsym != 0)
-      SETBIT (V1, rule_table[i].precsym);
+  for (i = 1; i < nrules + 1; i++)
+    if (rules[i].precsym != 0)
+      bitset_set (V1, rules[i].precsym->number);
 }
 
 }
 
+
+/*-------------------------------------------------------------------.
+| Put the useless productions at the end of RULES, and adjust NRULES |
+| accordingly.                                                       |
+`-------------------------------------------------------------------*/
+
 static void
 reduce_grammar_tables (void)
 {
 static void
 reduce_grammar_tables (void)
 {
-/* This is turned off because we would need to change the numbers
-   in the case statements in the actions file.  */
-#if 0
-  /* remove useless productions */
-  if (nuseless_productions > 0)
-    {
-      short np, pn, ni, pi;
-
-      np = 0;
-      ni = 0;
-      for (pn = 1; pn <= nrules; pn++)
-       {
-         if (BITISSET (P, pn))
-           {
-             np++;
-             if (pn != np)
-               {
-                 rule_table[np].lhs = rule_table[pn].lhs;
-                 rline[np] = rline[pn];
-                 rule_table[np].prec = rule_table[pn].prec;
-                 rule_table[np].assoc = rule_table[pn].assoc;
-                 rule_table[np].rhs = rule_table[pn].rhs;
-                 if (rule_table[np].rhs != ni)
-                   {
-                     pi = rule_table[np].rhs;
-                     rule_table[np].rhs = ni;
-                     while (ritem[pi] >= 0)
-                       ritem[ni++] = ritem[pi++];
-                     ritem[ni++] = -np;
-                   }
-               }
-             else
-               {
-                 while (ritem[ni++] >= 0);
-               }
-           }
-       }
-      ritem[ni] = 0;
-      nrules -= nuseless_productions;
-      nitems = ni;
-
-      /* Is it worth it to reduce the amount of memory for the
-         grammar? Probably not.  */
-
-    }
-#endif /* 0 */
-  /* Disable useless productions,
-     since they may contain useless nonterms
-     that would get mapped below to -1 and confuse everyone.  */
-  if (nuseless_productions > 0)
-    {
-      int pn;
-
-      for (pn = 1; pn <= nrules; pn++)
-       {
-         if (!BITISSET (P, pn))
-           {
-             rule_table[pn].lhs = -1;
-           }
-       }
-    }
-
-  /* remove useless symbols */
-  if (nuseless_nonterminals > 0)
-    {
-
-      int i, n;
-/*      short  j; JF unused */
-      short *nontermmap;
-      rule r;
-
-      /* Create a map of nonterminal number to new nonterminal
-        number. -1 in the map means it was useless and is being
-        eliminated.  */
-
-      nontermmap = XCALLOC (short, nvars) - ntokens;
-      for (i = ntokens; i < nsyms; i++)
-       nontermmap[i] = -1;
-
-      n = ntokens;
-      for (i = ntokens; i < nsyms; i++)
-       if (BITISSET (V, i))
-         nontermmap[i] = n++;
-
-      /* Shuffle elements of tables indexed by symbol number.  */
-
-      for (i = ntokens; i < nsyms; i++)
-       {
-         n = nontermmap[i];
-         if (n >= 0)
-           {
-             sassoc[n] = sassoc[i];
-             sprec[n] = sprec[i];
-             tags[n] = tags[i];
-           }
-         else
-           {
-             free (tags[i]);
-           }
-       }
-
-      /* Replace all symbol numbers in valid data structures.  */
+  /* Report and flag useless productions.  */
+  {
+    int r;
+    for (r = 1; r < nrules + 1; r++)
+      {
+       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
+     afterwards.  Kept for later report.  */
+  {
+    int useful = 1;
+    int useless = nrules + 1 - nuseless_productions;
+    rule_t *rules_sorted = XMALLOC (rule_t, nrules + 1) - 1;
+    int i;
+    for (i = 1; i < nrules + 1; ++i)
+      rules_sorted[rules[i].useful ? useful++ : useless++] = rules[i];
+    free (rules + 1);
+    rules = rules_sorted;
+
+    /* Renumber the rules markers in RITEMS.  */
+    for (i = 1; i < nrules + 1; ++i)
+      {
+       item_number_t *rhsp = rules[i].rhs;
+       for (/* Nothing. */; *rhsp >= 0; ++rhsp)
+         /* Nothing. */;
+       *rhsp = -i;
+       rules[i].number = i;
+      }
+    nrules -= nuseless_productions;
+  }
+
+  /* Adjust NRITEMS.  */
+  {
+    int r;
+    int length;
+    for (r = nrules + 1; r < nrules + 1 + nuseless_productions; ++r)
+      {
+       length = rule_rhs_length (&rules[r]);
+       nritems -= length + 1;
+      }
+  }
+}
 
 
-      for (i = 1; i <= nrules; i++)
-       {
-         /* Ignore the rules disabled above.  */
-         if (rule_table[i].lhs >= 0)
-           rule_table[i].lhs = nontermmap[rule_table[i].lhs];
-         if (ISVAR (rule_table[i].precsym))
-           /* Can this happen?  */
-           rule_table[i].precsym = nontermmap[rule_table[i].precsym];
-       }
 
 
-      for (r = ritem; *r; r++)
-       if (ISVAR (*r))
-         *r = nontermmap[*r];
+/*------------------------------.
+| Remove useless nonterminals.  |
+`------------------------------*/
 
 
-      start_symbol = nontermmap[start_symbol];
+static void
+nonterminals_reduce (void)
+{
+  symbol_number_t i, n;
 
 
-      nsyms -= nuseless_nonterminals;
-      nvars -= nuseless_nonterminals;
+  /* Map the nonterminals to their new index: useful first, useless
+     afterwards.  Kept for later report.  */
 
 
-      free (&nontermmap[ntokens]);
-    }
+  symbol_number_t *nontermmap = XCALLOC (symbol_number_t, nvars) - ntokens;
+  n = ntokens;
+  for (i = ntokens; i < nsyms; i++)
+    if (bitset_test (V, i))
+      nontermmap[i] = n++;
+  for (i = ntokens; i < nsyms; i++)
+    if (!bitset_test (V, i))
+      {
+       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.  */
+  {
+    symbol_t **symbols_sorted = XMALLOC (symbol_t *, nvars) - ntokens;
+
+    for (i = ntokens; i < nsyms; i++)
+      symbols[i]->number = nontermmap[i];
+    for (i = ntokens; i < nsyms; i++)
+      symbols_sorted[nontermmap[i]] = symbols[i];
+    for (i = ntokens; i < nsyms; i++)
+      symbols[i] = symbols_sorted[i];
+    free (symbols_sorted + ntokens);
+  }
+
+  {
+    int r;
+    for (r = 1; r < nrules + 1; ++r)
+      {
+       item_number_t *rhsp;
+       for (rhsp = rules[r].rhs; *rhsp >= 0; ++rhsp)
+         if (ISVAR (*rhsp))
+           *rhsp =  symbol_number_as_item_number (nontermmap[*rhsp]);
+      }
+    axiom->number = nontermmap[axiom->number];
+  }
+
+  nsyms -= nuseless_nonterminals;
+  nvars -= nuseless_nonterminals;
+
+  free (nontermmap + ntokens);
 }
 
 
 }
 
 
-/*-----------------------------------------------------------------.
-| Ouput the detailed results of the reductions.  For FILE.output.  |
-`-----------------------------------------------------------------*/
+/*------------------------------------------------------------------.
+| Output the detailed results of the reductions.  For FILE.output.  |
+`------------------------------------------------------------------*/
 
 void
 reduce_output (FILE *out)
 {
 
 void
 reduce_output (FILE *out)
 {
-  int i;
-  rule r;
-  bool b;
-
   if (nuseless_nonterminals > 0)
     {
   if (nuseless_nonterminals > 0)
     {
-      fprintf (out, _("Useless nonterminals:"));
-      fprintf (out, "\n\n");
-      for (i = ntokens; i < nsyms; i++)
-       if (!BITISSET (V, i))
-         fprintf (out, "   %s\n", tags[i]);
+      int i;
+      fprintf (out, "%s\n\n", _("Useless nonterminals:"));
+      for (i = 0; i < nuseless_nonterminals; ++i)
+       fprintf (out, "   %s\n", symbol_tag_get (symbols[nsyms + i]));
+      fputs ("\n\n", out);
     }
     }
-  b = FALSE;
-  for (i = 0; i < ntokens; i++)
-    {
-      if (!BITISSET (V, i) && !BITISSET (V1, i))
+
+  {
+    bool b = FALSE;
+    int i;
+    for (i = 0; i < ntokens; i++)
+      if (!bitset_test (V, i) && !bitset_test (V1, i))
        {
          if (!b)
        {
          if (!b)
-           {
-             fprintf (out, "\n\n");
-             fprintf (out, _("Terminals which are not used:"));
-             fprintf (out, "\n\n");
-             b = TRUE;
-           }
-         fprintf (out, "   %s\n", tags[i]);
+           fprintf (out, "%s\n\n", _("Terminals which are not used:"));
+         b = TRUE;
+         fprintf (out, "   %s\n", symbol_tag_get (symbols[i]));
        }
        }
-    }
+    if (b)
+      fputs ("\n\n", out);
+  }
 
   if (nuseless_productions > 0)
     {
 
   if (nuseless_productions > 0)
     {
-      fprintf (out, "\n\n");
-      fprintf (out, _("Useless rules:"));
-      fprintf (out, "\n\n");
-      for (i = 1; i <= nrules; i++)
+      int i;
+      fprintf (out, "%s\n\n", _("Useless rules:"));
+      for (i = nrules + 1; i < nuseless_productions + nrules + 1; i++)
        {
        {
-         if (!BITISSET (P, i))
-           {
-             fprintf (out, "#%-4d  ", i);
-             fprintf (out, "%s :\t", tags[rule_table[i].lhs]);
-             for (r = &ritem[rule_table[i].rhs]; *r >= 0; r++)
-               fprintf (out, " %s", tags[*r]);
-             fprintf (out, ";\n");
-           }
+         item_number_t *r;
+         fprintf (out, "#%-4d  ", rules[i].user_number - 1);
+         fprintf (out, "%s:", symbol_tag_get (rules[i].lhs));
+         for (r = rules[i].rhs; *r >= 0; r++)
+           fprintf (out, " %s", symbol_tag_get (symbols[*r]));
+         fputs (";\n", out);
        }
        }
+      fputs ("\n\n", out);
     }
     }
-  if (nuseless_nonterminals > 0 || nuseless_productions > 0 || b)
-    fprintf (out, "\n\n");
 }
 \f
 }
 \f
-#if 0                          /* XXX currently unused.  */
-static void
-dump_grammar (FILE *out)
-{
-  int i;
-  rule r;
 
 
-  fprintf (out,
-        "ntokens = %d, nvars = %d, nsyms = %d, nrules = %d, nitems = %d\n\n",
-        ntokens, nvars, nsyms, nrules, nitems);
-  fprintf (out, _("Variables\n---------\n\n"));
-  fprintf (out, _("Value  Sprec    Sassoc    Tag\n"));
-  for (i = ntokens; i < nsyms; i++)
-    fprintf (out, "%5d  %5d  %5d  %s\n", i, sprec[i], sassoc[i], tags[i]);
-  fprintf (out, "\n\n");
-  fprintf (out, _("Rules\n-----\n\n"));
-  for (i = 1; i <= nrules; i++)
-    {
-      fprintf (out, "%-5d(%5d%5d)%5d : (@%-5d)",
-              i,
-              rule_table[i].prec,
-              rule_table[i].assoc,
-              rule_table[i].lhs,
-              rule_table[i].rhs);
-      for (r = &ritem[rule_table[i].rhs]; *r > 0; r++)
-       fprintf (out, "%5d", *r);
-      fprintf (out, " [%d]\n", -(*r));
-    }
-  fprintf (out, "\n\n");
-  fprintf (out, _("Rules interpreted\n-----------------\n\n"));
-  for (i = 1; i <= nrules; i++)
-    {
-      fprintf (out, "%-5d  %s :", i, tags[rule_table[i].lhs]);
-      for (r = &ritem[rule_table[i].rhs]; *r > 0; r++)
-       fprintf (out, " %s", tags[*r]);
-      fputc ('\n', out);
-    }
-  fprintf (out, "\n\n");
-}
-#endif
 
 
 
 
 
 
@@ -496,24 +399,27 @@ static void
 reduce_print (void)
 {
   if (yacc_flag && nuseless_productions)
 reduce_print (void)
 {
   if (yacc_flag && nuseless_productions)
-    fprintf (stderr, _("%d rules never reduced\n"), nuseless_productions);
+    fprintf (stderr, ngettext ("%d rule never reduced\n",
+                              "%d rules never reduced\n",
+                              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, _("%d useless nonterminal%s"),
-              nuseless_nonterminals,
-              (nuseless_nonterminals == 1 ? "" : "s"));
-    }
+    fprintf (stderr, ngettext ("%d useless nonterminal",
+                              "%d useless nonterminals",
+                              nuseless_nonterminals),
+            nuseless_nonterminals);
+
   if (nuseless_nonterminals > 0 && nuseless_productions > 0)
     fprintf (stderr, _(" and "));
 
   if (nuseless_productions > 0)
   if (nuseless_nonterminals > 0 && nuseless_productions > 0)
     fprintf (stderr, _(" and "));
 
   if (nuseless_productions > 0)
-    {
-      fprintf (stderr, _("%d useless rule%s"),
-              nuseless_productions, (nuseless_productions == 1 ? "" : "s"));
-    }
+    fprintf (stderr, ngettext ("%d useless rule",
+                              "%d useless rules",
+                              nuseless_productions),
+            nuseless_productions);
   fprintf (stderr, "\n");
   fflush (stderr);
 }
   fprintf (stderr, "\n");
   fflush (stderr);
 }
@@ -525,44 +431,40 @@ reduce_grammar (void)
 
   /* Allocate the global sets used to compute the reduced grammar */
 
 
   /* Allocate the global sets used to compute the reduced grammar */
 
-  N = XCALLOC (unsigned, WORDSIZE (nvars));
-  P = XCALLOC (unsigned, WORDSIZE (nrules + 1));
-  V = XCALLOC (unsigned, WORDSIZE (nsyms));
-  V1 = XCALLOC (unsigned, WORDSIZE (nsyms));
+  N = bitset_create (nvars, BITSET_FIXED);
+  P =  bitset_create (nrules + 1, BITSET_FIXED);
+  V = bitset_create (nsyms, BITSET_FIXED);
+  V1 = bitset_create (nsyms, BITSET_FIXED);
 
   useless_nonterminals ();
   inaccessable_symbols ();
 
   reduced = (bool) (nuseless_nonterminals + nuseless_productions > 0);
 
   useless_nonterminals ();
   inaccessable_symbols ();
 
   reduced = (bool) (nuseless_nonterminals + nuseless_productions > 0);
-
   if (!reduced)
     return;
 
   reduce_print ();
 
   if (!reduced)
     return;
 
   reduce_print ();
 
-  if (!BITISSET (N, start_symbol - 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"),
-          tags[start_symbol]);
+          symbol_tag_get (symbols[axiom->number]));
 
 
-  reduce_grammar_tables ();
-#if 0
-  if (verbose_flag)
+  /* First reduce the nonterminals, as they renumber themselves in the
+     whole grammar.  If you change the order, nonterms would be
+     renumbered only in the reduced grammar.  */
+  if (nuseless_nonterminals > 0)
+    nonterminals_reduce ();
+  if (nuseless_productions > 0)
+    reduce_grammar_tables ();
+
+  if (trace_flag)
     {
     {
-      fprintf (out, "REDUCED GRAMMAR\n\n");
-      dump_grammar ();
+      grammar_dump (stderr, "Reduced Grammar");
+
+      fprintf (stderr, "reduced %s defines %d terminals, %d nonterminals\
+, and %d productions.\n",
+              infile, ntokens, nvars, nrules);
     }
     }
-#endif
-
-  if (statistics_flag)
-    fprintf (stderr, _("reduced %s defines %d terminal%s, %d nonterminal%s\
-, and %d production%s.\n"),
-            infile,
-            ntokens,
-            (ntokens == 1 ? "" : "s"),
-            nvars,
-            (nvars == 1 ? "" : "s"),
-            nrules,
-            (nrules == 1 ? "" : "s"));
 }
 
 
 }
 
 
@@ -573,8 +475,8 @@ reduce_grammar (void)
 void
 reduce_free (void)
 {
 void
 reduce_free (void)
 {
-  XFREE (N);
-  XFREE (V);
-  XFREE (V1);
-  XFREE (P);
+  bitset_free (N);
+  bitset_free (V);
+  bitset_free (V1);
+  bitset_free (P);
 }
 }