]>
git.saurik.com Git - bison.git/blob - src/reduce.c
1 /* Grammar reduction for Bison.
2 Copyright 1988, 1989, 2000, 2001 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
42 /* Set of all nonterminals which are not useless. */
45 /* Set of all rules which have no useless nonterminals in their RHS. */
48 /* Set of all accessible symbols. */
51 /* Set of symbols used to define rule precedence (so they are
52 `useless', but no warning should be issued). */
55 static int nuseful_productions
;
56 static int nuseless_productions
;
57 static int nuseful_nonterminals
;
58 int nuseless_nonterminals
;
65 BITSET_EXECUTE (S
, 0, i
, { ++count
; });
69 /*-------------------------------------------------------------------.
70 | Another way to do this would be with a set for each production and |
71 | then do subset tests against N0, but even for the C grammar the |
72 | whole reducing process takes only 2 seconds on my 8Mhz AT. |
73 `-------------------------------------------------------------------*/
76 useful_production (int i
, bitset N0
)
81 /* A production is useful if all of the nonterminals in its appear
82 in the set of useful nonterminals. */
84 for (r
= &ritem
[rules
[i
].rhs
]; *r
>= 0; r
++)
86 if (!bitset_test (N0
, n
- ntokens
))
92 /*---------------------------------------------------------.
93 | Remember that rules are 1-origin, symbols are 0-origin. |
94 `---------------------------------------------------------*/
97 useless_nonterminals (void)
102 /* N is set as built. Np is set being built this iteration. P is
103 set of all productions which have a RHS all in N. */
105 Np
= bitset_create (nvars
, BITSET_FIXED
);
108 /* The set being computed is a set of nonterminals which can derive
109 the empty string or strings consisting of all terminals. At each
110 iteration a nonterminal is added to the set if there is a
111 production with that nonterminal as its LHS for which all the
112 nonterminals in its RHS are already in the set. Iterate until
113 the set being computed remains unchanged. Any nonterminals not
114 in the set at that point are useless in that they will never be
115 used in deriving a sentence of the language.
117 This iteration doesn't use any special traversal over the
118 productions. A set is kept of all productions for which all the
119 nonterminals in the RHS are in useful. Only productions not in
120 this set are scanned on each iteration. At the end, this set is
121 saved to be used when finding useful productions: only
122 productions in this set will appear in the final grammar. */
127 for (i
= 1; i
<= nrules
; i
++)
128 if (!bitset_test (P
, i
)
129 && useful_production (i
, N
))
131 bitset_set (Np
, rules
[i
].lhs
- ntokens
);
134 if (bitset_equal_p (N
, Np
))
146 inaccessable_symbols (void)
153 /* Find out which productions are reachable and which symbols are
154 used. Starting with an empty set of productions and a set of
155 symbols which only has the start symbol in it, iterate over all
156 productions until the set of productions remains unchanged for an
157 iteration. For each production which has a LHS in the set of
158 reachable symbols, add the production to the set of reachable
159 productions, and add all of the nonterminals in the RHS of the
160 production to the set of reachable symbols.
162 Consider only the (partially) reduced grammar which has only
163 nonterminals in N and productions in P.
165 The result is the set P of productions in the reduced grammar,
166 and the set V of symbols in the reduced grammar.
168 Although this algorithm also computes the set of terminals which
169 are reachable, no terminal will be deleted from the grammar. Some
170 terminals might not be in the grammar but might be generated by
171 semantic routines, and so the user might want them available with
172 specified numbers. (Is this true?) However, the nonreachable
173 terminals are printed (if running in verbose mode) so that the
176 Vp
= bitset_create (nsyms
, BITSET_FIXED
);
177 Pp
= bitset_create (nrules
+ 1, BITSET_FIXED
);
179 /* If the start symbol isn't useful, then nothing will be useful. */
180 if (bitset_test (N
, start_symbol
- ntokens
))
182 bitset_set (V
, start_symbol
);
187 for (i
= 1; i
<= nrules
; i
++)
189 if (!bitset_test (Pp
, i
)
190 && bitset_test (P
, i
)
191 && bitset_test (V
, rules
[i
].lhs
))
193 for (r
= &ritem
[rules
[i
].rhs
]; *r
>= 0; r
++)
194 if (ISTOKEN (t
= *r
) || bitset_test (N
, t
- ntokens
))
199 if (bitset_equal_p (V
, Vp
))
210 /* Tokens 0, 1, and 2 are internal to Bison. Consider them useful. */
211 bitset_set (V
, 0); /* end-of-input token */
212 bitset_set (V
, 1); /* error token */
213 bitset_set (V
, 2); /* some undefined token */
218 nuseful_productions
= bits_size (P
);
219 nuseless_productions
= nrules
- nuseful_productions
;
221 nuseful_nonterminals
= 0;
222 for (i
= ntokens
; i
< nsyms
; i
++)
223 if (bitset_test (V
, i
))
224 nuseful_nonterminals
++;
225 nuseless_nonterminals
= nvars
- nuseful_nonterminals
;
227 /* A token that was used in %prec should not be warned about. */
228 for (i
= 1; i
< nrules
; i
++)
229 if (rules
[i
].precsym
!= 0)
230 bitset_set (V1
, rules
[i
].precsym
);
234 reduce_grammar_tables (void)
236 /* This is turned off because we would need to change the numbers in
237 the case statements in the actions file.
239 We don't disable it via CPP so that it is still checked with the
240 rest of the code, to avoid its becoming completely obsolete.
242 FIXME: I think the comment above demonstrates this code must be
243 turned off for *semantic* parser, not in the general case. Try
244 to understand this better --akim. */
247 /* remove useless productions */
248 if (nuseless_productions
> 0)
250 short np
, pn
, ni
, pi
;
254 for (pn
= 1; pn
<= nrules
; pn
++)
255 if (bitset_test (P
, pn
))
260 rules
[np
].lhs
= rules
[pn
].lhs
;
261 rules
[np
].line
= rules
[pn
].line
;
262 rules
[np
].prec
= rules
[pn
].prec
;
263 rules
[np
].assoc
= rules
[pn
].assoc
;
264 rules
[np
].rhs
= rules
[pn
].rhs
;
265 if (rules
[np
].rhs
!= ni
)
269 while (ritem
[pi
] >= 0)
270 ritem
[ni
++] = ritem
[pi
++];
276 while (ritem
[ni
++] >= 0)
282 nrules
-= nuseless_productions
;
286 /* Is it worth it to reduce the amount of memory for the
287 grammar? Probably not. */
290 /* Disable useless productions. */
291 if (nuseless_productions
> 0)
294 for (pn
= 1; pn
<= nrules
; pn
++)
295 rules
[pn
].useful
= bitset_test (P
, pn
);
300 /*------------------------------.
301 | Remove useless nonterminals. |
302 `------------------------------*/
305 nonterminals_reduce (void)
309 /* Map the nonterminals to their new index: useful first, useless
310 afterwards. Kept for later report. */
312 short *nontermmap
= XCALLOC (short, nvars
) - ntokens
;
314 for (i
= ntokens
; i
< nsyms
; i
++)
315 if (bitset_test (V
, i
))
317 for (i
= ntokens
; i
< nsyms
; i
++)
318 if (!bitset_test (V
, i
))
322 /* Shuffle elements of tables indexed by symbol number. */
324 bucket
**symbols_sorted
= XMALLOC (bucket
*, nvars
) - ntokens
;
326 for (i
= ntokens
; i
< nsyms
; i
++)
327 symbols_sorted
[nontermmap
[i
]] = symbols
[i
];
328 for (i
= ntokens
; i
< nsyms
; i
++)
329 symbols
[i
] = symbols_sorted
[i
];
330 free (symbols_sorted
+ ntokens
);
333 /* Replace all symbol numbers in valid data structures. */
335 for (i
= 1; i
<= nrules
; i
++)
337 rules
[i
].lhs
= nontermmap
[rules
[i
].lhs
];
338 if (ISVAR (rules
[i
].precsym
))
339 /* Can this happen? */
340 rules
[i
].precsym
= nontermmap
[rules
[i
].precsym
];
343 for (i
= 0; i
< nritems
; ++i
)
344 if (ISVAR (ritem
[i
]))
345 ritem
[i
] = nontermmap
[ritem
[i
]];
347 start_symbol
= nontermmap
[start_symbol
];
349 nsyms
-= nuseless_nonterminals
;
350 nvars
-= nuseless_nonterminals
;
352 free (nontermmap
+ ntokens
);
356 /*------------------------------------------------------------------.
357 | Output the detailed results of the reductions. For FILE.output. |
358 `------------------------------------------------------------------*/
361 reduce_output (FILE *out
)
363 if (nuseless_nonterminals
> 0)
366 fprintf (out
, "%s\n\n", _("Useless nonterminals:"));
367 for (i
= 0; i
< nuseless_nonterminals
; ++i
)
368 fprintf (out
, " %s\n", symbols
[nsyms
+ i
]->tag
);
375 for (i
= 0; i
< ntokens
; i
++)
376 if (!bitset_test (V
, i
) && !bitset_test (V1
, i
))
379 fprintf (out
, "%s\n\n", _("Terminals which are not used:"));
381 fprintf (out
, " %s\n", symbols
[i
]->tag
);
387 if (nuseless_productions
> 0)
390 fprintf (out
, "%s\n\n", _("Useless rules:"));
391 for (i
= 1; i
<= nrules
; i
++)
392 if (!rules
[i
].useful
)
395 fprintf (out
, "#%-4d ", i
- 1);
396 fprintf (out
, "%s:", symbols
[rules
[i
].lhs
]->tag
);
397 for (r
= &ritem
[rules
[i
].rhs
]; *r
>= 0; r
++)
398 fprintf (out
, " %s", symbols
[*r
]->tag
);
406 dump_grammar (FILE *out
)
411 fprintf (out
, "REDUCED GRAMMAR\n\n");
413 "ntokens = %d, nvars = %d, nsyms = %d, nrules = %d, nitems = %d\n\n",
414 ntokens
, nvars
, nsyms
, nrules
, nitems
);
415 fprintf (out
, "Variables\n---------\n\n");
416 fprintf (out
, "Value Sprec Sassoc Tag\n");
417 for (i
= ntokens
; i
< nsyms
; i
++)
418 fprintf (out
, "%5d %5d %5d %s\n",
420 symbols
[i
]->prec
, symbols
[i
]->assoc
, symbols
[i
]->tag
);
421 fprintf (out
, "\n\n");
422 fprintf (out
, "Rules\n-----\n\n");
423 fprintf (out
, "Num (Prec, Assoc, Useful, Ritem Range) Lhs -> Rhs (Ritem range) [Num]\n");
424 for (i
= 1; i
<= nrules
; i
++)
427 /* Find the last RHS index in ritems. */
428 for (r
= &ritem
[rules
[i
].rhs
]; *r
>= 0; ++r
)
430 fprintf (out
, "%3d (%2d, %2d, %2d, %2d-%2d) %2d ->",
432 rules
[i
].prec
, rules
[i
].assoc
, rules
[i
].useful
,
433 rules
[i
].rhs
, rules
[i
].rhs
+ rhs_count
- 1,
435 /* Dumped the RHS. */
436 for (r
= &ritem
[rules
[i
].rhs
]; *r
>= 0; r
++)
437 fprintf (out
, "%3d", *r
);
438 fprintf (out
, " [%d]\n", -(*r
) - 1);
440 fprintf (out
, "\n\n");
441 fprintf (out
, "Rules interpreted\n-----------------\n\n");
442 for (i
= 1; i
<= nrules
; i
++)
444 fprintf (out
, "%-5d %s :", i
, symbols
[rules
[i
].lhs
]->tag
);
445 for (r
= &ritem
[rules
[i
].rhs
]; *r
>= 0; r
++)
446 fprintf (out
, " %s", symbols
[*r
]->tag
);
449 fprintf (out
, "\n\n");
454 /*-------------------------------.
455 | Report the results to STDERR. |
456 `-------------------------------*/
461 if (yacc_flag
&& nuseless_productions
)
462 fprintf (stderr
, ngettext ("%d rule never reduced\n",
463 "%d rules never reduced\n",
464 nuseless_productions
),
465 nuseless_productions
);
467 fprintf (stderr
, _("%s contains "), infile
);
469 if (nuseless_nonterminals
> 0)
470 fprintf (stderr
, ngettext ("%d useless nonterminal",
471 "%d useless nonterminals",
472 nuseless_nonterminals
),
473 nuseless_nonterminals
);
475 if (nuseless_nonterminals
> 0 && nuseless_productions
> 0)
476 fprintf (stderr
, _(" and "));
478 if (nuseless_productions
> 0)
479 fprintf (stderr
, ngettext ("%d useless rule",
481 nuseless_productions
),
482 nuseless_productions
);
483 fprintf (stderr
, "\n");
488 reduce_grammar (void)
492 /* Allocate the global sets used to compute the reduced grammar */
494 N
= bitset_create (nvars
, BITSET_FIXED
);
495 P
= bitset_create (nrules
+ 1, BITSET_FIXED
);
496 V
= bitset_create (nsyms
, BITSET_FIXED
);
497 V1
= bitset_create (nsyms
, BITSET_FIXED
);
499 useless_nonterminals ();
500 inaccessable_symbols ();
502 reduced
= (bool) (nuseless_nonterminals
+ nuseless_productions
> 0);
509 if (!bitset_test (N
, start_symbol
- ntokens
))
510 fatal (_("Start symbol %s does not derive any sentence"),
511 symbols
[start_symbol
]->tag
);
513 reduce_grammar_tables ();
514 if (nuseless_nonterminals
> 0)
515 nonterminals_reduce ();
519 dump_grammar (stderr
);
521 fprintf (stderr
, "reduced %s defines %d terminals, %d nonterminals\
522 , and %d productions.\n",
523 infile
, ntokens
, nvars
, nrules
);
528 /*-----------------------------------------------------------.
529 | Free the global sets used to compute the reduced grammar. |
530 `-----------------------------------------------------------*/