]>
git.saurik.com Git - bison.git/blob - src/reduce.c
   1 /* Grammar reduction for Bison. 
   2    Copyright 1988, 1989, 2000 Free Software Foundation, Inc. 
   4    This file is part of Bison, the GNU Compiler Compiler. 
   6    Bison is free software; you can redistribute it and/or modify 
   7    it under the terms of the GNU General Public License as published by 
   8    the Free Software Foundation; either version 2, or (at your option) 
  11    Bison is distributed in the hope that it will be useful, 
  12    but WITHOUT ANY WARRANTY; without even the implied warranty of 
  13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  14    GNU General Public License for more details. 
  16    You should have received a copy of the GNU General Public License 
  17    along with Bison; see the file COPYING.  If not, write to 
  18    the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
  19    Boston, MA 02111-1307, USA.  */ 
  22 /* Reduce the grammar: Find and eliminate unreachable terminals, 
  23    nonterminals, and productions.  David S. Bakin.  */ 
  25 /* Don't eliminate unreachable terminals: They may be used by the 
  37 typedef unsigned *BSet
; 
  41 /* N is set of all nonterminals which are not useless.  P is set of 
  42    all rules which have no useless nonterminals in their RHS.  V is 
  43    the set of all accessible symbols.  */ 
  45 static BSet N
, P
, V
, V1
; 
  47 static int nuseful_productions
; 
  48 static int nuseless_productions
; 
  49 static int nuseful_nonterminals
; 
  50 static int nuseless_nonterminals
; 
  53 bits_equal (BSet L
, BSet R
, int n
) 
  57   for (i 
= n 
- 1; i 
>= 0; i
--) 
  71       i 
^= (i 
& ((unsigned) (-(int) i
))); 
  79 bits_size (BSet S
, int n
) 
  83   for (i 
= n 
- 1; i 
>= 0; i
--) 
  84     count 
+= nbits (S
[i
]); 
  88 /*-------------------------------------------------------------------. 
  89 | Another way to do this would be with a set for each production and | 
  90 | then do subset tests against N0, but even for the C grammar the    | 
  91 | whole reducing process takes only 2 seconds on my 8Mhz AT.         | 
  92 `-------------------------------------------------------------------*/ 
  95 useful_production (int i
, BSet N0
) 
 100   /* A production is useful if all of the nonterminals in its appear 
 101      in the set of useful nonterminals.  */ 
 103   for (r 
= &ritem
[rrhs
[i
]]; *r 
> 0; r
++) 
 105       if (!BITISSET (N0
, n 
- ntokens
)) 
 111 /*---------------------------------------------------------. 
 112 | Remember that rules are 1-origin, symbols are 0-origin.  | 
 113 `---------------------------------------------------------*/ 
 116 useless_nonterminals (void) 
 121   /* N is set as built.  Np is set being built this iteration. P is 
 122      set of all productions which have a RHS all in N.  */ 
 124   Np 
= XCALLOC (unsigned, WORDSIZE (nvars
)); 
 126   /* The set being computed is a set of nonterminals which can derive 
 127      the empty string or strings consisting of all terminals. At each 
 128      iteration a nonterminal is added to the set if there is a 
 129      production with that nonterminal as its LHS for which all the 
 130      nonterminals in its RHS are already in the set.  Iterate until 
 131      the set being computed remains unchanged.  Any nonterminals not 
 132      in the set at that point are useless in that they will never be 
 133      used in deriving a sentence of the language. 
 135      This iteration doesn't use any special traversal over the 
 136      productions.  A set is kept of all productions for which all the 
 137      nonterminals in the RHS are in useful.  Only productions not in 
 138      this set are scanned on each iteration.  At the end, this set is 
 139      saved to be used when finding useful productions: only 
 140      productions in this set will appear in the final grammar.  */ 
 144       for (i 
= WORDSIZE (nvars
) - 1; i 
>= 0; i
--) 
 146       for (i 
= 1; i 
<= nrules
; i
++) 
 148           if (!BITISSET (P
, i
)) 
 150               if (useful_production (i
, N
)) 
 152                   SETBIT (Np
, rlhs
[i
] - ntokens
); 
 157       if (bits_equal (N
, Np
, WORDSIZE (nvars
))) 
 169 inaccessable_symbols (void) 
 176   /* Find out which productions are reachable and which symbols are 
 177      used.  Starting with an empty set of productions and a set of 
 178      symbols which only has the start symbol in it, iterate over all 
 179      productions until the set of productions remains unchanged for an 
 180      iteration.  For each production which has a LHS in the set of 
 181      reachable symbols, add the production to the set of reachable 
 182      productions, and add all of the nonterminals in the RHS of the 
 183      production to the set of reachable symbols. 
 185      Consider only the (partially) reduced grammar which has only 
 186      nonterminals in N and productions in P. 
 188      The result is the set P of productions in the reduced grammar, 
 189      and the set V of symbols in the reduced grammar. 
 191      Although this algorithm also computes the set of terminals which 
 192      are reachable, no terminal will be deleted from the grammar. Some 
 193      terminals might not be in the grammar but might be generated by 
 194      semantic routines, and so the user might want them available with 
 195      specified numbers.  (Is this true?)  However, the nonreachable 
 196      terminals are printed (if running in verbose mode) so that the 
 199   Vp 
= XCALLOC (unsigned, WORDSIZE (nsyms
)); 
 200   Pp 
= XCALLOC (unsigned, WORDSIZE (nrules 
+ 1)); 
 202   /* If the start symbol isn't useful, then nothing will be useful. */ 
 203   if (!BITISSET (N
, start_symbol 
- ntokens
)) 
 206   SETBIT (V
, start_symbol
); 
 210       for (i 
= WORDSIZE (nsyms
) - 1; i 
>= 0; i
--) 
 212       for (i 
= 1; i 
<= nrules
; i
++) 
 214           if (!BITISSET (Pp
, i
) && BITISSET (P
, i
) && BITISSET (V
, rlhs
[i
])) 
 216               for (r 
= &ritem
[rrhs
[i
]]; *r 
>= 0; r
++) 
 218                   if (ISTOKEN (t 
= *r
) || BITISSET (N
, t 
- ntokens
)) 
 226       if (bits_equal (V
, Vp
, WORDSIZE (nsyms
))) 
 239   /* Tokens 0, 1, and 2 are internal to Bison.  Consider them useful. */ 
 240   SETBIT (V
, 0);                /* end-of-input token */ 
 241   SETBIT (V
, 1);                /* error token */ 
 242   SETBIT (V
, 2);                /* some undefined token */ 
 247   nuseful_productions 
= bits_size (P
, WORDSIZE (nrules 
+ 1)); 
 248   nuseless_productions 
= nrules 
- nuseful_productions
; 
 250   nuseful_nonterminals 
= 0; 
 251   for (i 
= ntokens
; i 
< nsyms
; i
++) 
 253       nuseful_nonterminals
++; 
 254   nuseless_nonterminals 
= nvars 
- nuseful_nonterminals
; 
 256   /* A token that was used in %prec should not be warned about.  */ 
 257   for (i 
= 1; i 
< nrules
; i
++) 
 258     if (rprecsym
[i
] != 0) 
 259       SETBIT (V1
, rprecsym
[i
]); 
 263 reduce_grammar_tables (void) 
 265 /* This is turned off because we would need to change the numbers 
 266    in the case statements in the actions file.  */ 
 268   /* remove useless productions */ 
 269   if (nuseless_productions 
> 0) 
 271       short np
, pn
, ni
, pi
; 
 275       for (pn 
= 1; pn 
<= nrules
; pn
++) 
 277           if (BITISSET (P
, pn
)) 
 283                   rline
[np
] = rline
[pn
]; 
 284                   rprec
[np
] = rprec
[pn
]; 
 285                   rassoc
[np
] = rassoc
[pn
]; 
 291                       while (ritem
[pi
] >= 0) 
 292                         ritem
[ni
++] = ritem
[pi
++]; 
 298                   while (ritem
[ni
++] >= 0); 
 303       nrules 
-= nuseless_productions
; 
 306       /* Is it worth it to reduce the amount of memory for the 
 307          grammar? Probably not.  */ 
 311   /* Disable useless productions, 
 312      since they may contain useless nonterms 
 313      that would get mapped below to -1 and confuse everyone.  */ 
 314   if (nuseless_productions 
> 0) 
 318       for (pn 
= 1; pn 
<= nrules
; pn
++) 
 320           if (!BITISSET (P
, pn
)) 
 327   /* remove useless symbols */ 
 328   if (nuseless_nonterminals 
> 0) 
 332 /*      short  j; JF unused */ 
 336       /* Create a map of nonterminal number to new nonterminal 
 337          number. -1 in the map means it was useless and is being 
 340       nontermmap 
= XCALLOC (short, nvars
) - ntokens
; 
 341       for (i 
= ntokens
; i 
< nsyms
; i
++) 
 345       for (i 
= ntokens
; i 
< nsyms
; i
++) 
 349       /* Shuffle elements of tables indexed by symbol number.  */ 
 351       for (i 
= ntokens
; i 
< nsyms
; i
++) 
 356               sassoc
[n
] = sassoc
[i
]; 
 366       /* Replace all symbol numbers in valid data structures.  */ 
 368       for (i 
= 1; i 
<= nrules
; i
++) 
 370           /* Ignore the rules disabled above.  */ 
 372             rlhs
[i
] = nontermmap
[rlhs
[i
]]; 
 373           if (ISVAR (rprecsym
[i
])) 
 374             /* Can this happen?  */ 
 375             rprecsym
[i
] = nontermmap
[rprecsym
[i
]]; 
 378       for (r 
= ritem
; *r
; r
++) 
 382       start_symbol 
= nontermmap
[start_symbol
]; 
 384       nsyms 
-= nuseless_nonterminals
; 
 385       nvars 
-= nuseless_nonterminals
; 
 387       free (&nontermmap
[ntokens
]); 
 395 /*  short j; JF unused */ 
 399   if (nuseless_nonterminals 
> 0) 
 401       obstack_sgrow (&output_obstack
, _("Useless nonterminals:")); 
 402       obstack_sgrow (&output_obstack
, "\n\n"); 
 403       for (i 
= ntokens
; i 
< nsyms
; i
++) 
 404         if (!BITISSET (V
, i
)) 
 405           obstack_fgrow1 (&output_obstack
, "   %s\n", tags
[i
]); 
 408   for (i 
= 0; i 
< ntokens
; i
++) 
 410       if (!BITISSET (V
, i
) && !BITISSET (V1
, i
)) 
 414               obstack_sgrow (&output_obstack
, "\n\n"); 
 415               obstack_sgrow (&output_obstack
, 
 416                                    _("Terminals which are not used:")); 
 417               obstack_sgrow (&output_obstack
, "\n\n"); 
 420           obstack_fgrow1 (&output_obstack
, "   %s\n", tags
[i
]); 
 424   if (nuseless_productions 
> 0) 
 426       obstack_sgrow (&output_obstack
, "\n\n"); 
 427       obstack_sgrow (&output_obstack
, _("Useless rules:")); 
 428       obstack_sgrow (&output_obstack
, "\n\n"); 
 429       for (i 
= 1; i 
<= nrules
; i
++) 
 431           if (!BITISSET (P
, i
)) 
 433               obstack_fgrow1 (&output_obstack
, "#%-4d  ", i
); 
 434               obstack_fgrow1 (&output_obstack
, "%s :\t", tags
[rlhs
[i
]]); 
 435               for (r 
= &ritem
[rrhs
[i
]]; *r 
>= 0; r
++) 
 436                 obstack_fgrow1 (&output_obstack
, " %s", tags
[*r
]); 
 437               obstack_sgrow (&output_obstack
, ";\n"); 
 441   if (nuseless_nonterminals 
> 0 || nuseless_productions 
> 0 || b
) 
 442     obstack_sgrow (&output_obstack
, "\n\n"); 
 445 #if 0                           /* XXX currently unused.  */ 
 452   obstack_fgrow5 (&output_obstack
, 
 453          "ntokens = %d, nvars = %d, nsyms = %d, nrules = %d, nitems = %d\n\n", 
 454          ntokens
, nvars
, nsyms
, nrules
, nitems
); 
 455   obstack_sgrow (&output_obstack
, 
 456                        _("Variables\n---------\n\n")); 
 457   obstack_sgrow (&output_obstack
, 
 458                        _("Value  Sprec    Sassoc    Tag\n")); 
 459   for (i 
= ntokens
; i 
< nsyms
; i
++) 
 460     obstack_fgrow4 (&output_obstack
, 
 461                     "%5d  %5d  %5d  %s\n", i
, sprec
[i
], sassoc
[i
], tags
[i
]); 
 462   obstack_sgrow (&output_obstack
, "\n\n"); 
 463   obstack_sgrow (&output_obstack
, _("Rules\n-----\n\n")); 
 464   for (i 
= 1; i 
<= nrules
; i
++) 
 466       obstack_fgrow5 (&output_obstack
, "%-5d(%5d%5d)%5d : (@%-5d)", 
 467                       i
, rprec
[i
], rassoc
[i
], rlhs
[i
], rrhs
[i
]); 
 468       for (r 
= &ritem
[rrhs
[i
]]; *r 
> 0; r
++) 
 469         obstack_fgrow1 (&output_obstack
, "%5d", *r
); 
 470       obstack_fgrow1 (&output_obstack
, " [%d]\n", -(*r
)); 
 472   obstack_sgrow (&output_obstack
, "\n\n"); 
 473   obstack_sgrow (&output_obstack
, 
 474                        _("Rules interpreted\n-----------------\n\n")); 
 475   for (i 
= 1; i 
<= nrules
; i
++) 
 477       obstack_fgrow2 (&output_obstack
, "%-5d  %s :", i
, tags
[rlhs
[i
]]); 
 478       for (r 
= &ritem
[rrhs
[i
]]; *r 
> 0; r
++) 
 479         obstack_fgrow1 (&output_obstack
, " %s", tags
[*r
]); 
 480       obstack_grow1 (&output_obstack
, '\n'); 
 482   obstack_sgrow (&output_obstack
, "\n\n"); 
 490   if (yacc_flag 
&& nuseless_productions
) 
 491     fprintf (stderr
, _("%d rules never reduced\n"), nuseless_productions
); 
 493   fprintf (stderr
, _("%s contains "), infile
); 
 495   if (nuseless_nonterminals 
> 0) 
 497       fprintf (stderr
, _("%d useless nonterminal%s"), 
 498                nuseless_nonterminals
, 
 499                (nuseless_nonterminals 
== 1 ? "" : "s")); 
 501   if (nuseless_nonterminals 
> 0 && nuseless_productions 
> 0) 
 502     fprintf (stderr
, _(" and ")); 
 504   if (nuseless_productions 
> 0) 
 506       fprintf (stderr
, _("%d useless rule%s"), 
 507                nuseless_productions
, (nuseless_productions 
== 1 ? "" : "s")); 
 509   fprintf (stderr
, "\n"); 
 514 reduce_grammar (void) 
 518   /* Allocate the global sets used to compute the reduced grammar */ 
 520   N 
= XCALLOC (unsigned, WORDSIZE (nvars
)); 
 521   P 
= XCALLOC (unsigned, WORDSIZE (nrules 
+ 1)); 
 522   V 
= XCALLOC (unsigned, WORDSIZE (nsyms
)); 
 523   V1 
= XCALLOC (unsigned, WORDSIZE (nsyms
)); 
 525   useless_nonterminals (); 
 526   inaccessable_symbols (); 
 528   reduced 
= (bool) (nuseless_nonterminals 
+ nuseless_productions 
> 0); 
 533   if (reduced 
== FALSE
) 
 538   if (!BITISSET (N
, start_symbol 
- ntokens
)) 
 539     fatal (_("Start symbol %s does not derive any sentence"), 
 542   reduce_grammar_tables (); 
 546       obstack_fgrow1 (&output_obstack
, "REDUCED GRAMMAR\n\n"); 
 552     fprintf (stderr
, _("reduced %s defines %d terminal%s, %d nonterminal%s\ 
 553 , and %d production%s.\n"), 
 556              (ntokens 
== 1 ? "" : "s"), 
 558              (nvars 
== 1 ? "" : "s"), 
 560              (nrules 
== 1 ? "" : "s")); 
 563   /* Free the global sets used to compute the reduced grammar */