reduce.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. /* Grammar reduction for Bison.
  2. Copyright (C) 1988, 1989 Free Software Foundation, Inc.
  3. This file is part of Bison, the GNU Compiler Compiler.
  4. Bison is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. Bison is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with Bison; see the file COPYING. If not, write to
  14. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  15. /*
  16. * Reduce the grammar: Find and eliminate unreachable terminals,
  17. * nonterminals, and productions. David S. Bakin.
  18. */
  19. /*
  20. * Don't eliminate unreachable terminals: They may be used by the user's
  21. * parser.
  22. */
  23. #include <stdio.h>
  24. #include "system.h"
  25. #include "files.h"
  26. #include "gram.h"
  27. #include "machine.h"
  28. #include "new.h"
  29. extern char **tags; /* reader.c */
  30. extern int verboseflag; /* getargs.c */
  31. static int statisticsflag; /* XXXXXXX */
  32. #ifndef TRUE
  33. #define TRUE (1)
  34. #define FALSE (0)
  35. #endif
  36. typedef int bool;
  37. typedef unsigned *BSet;
  38. typedef short *rule;
  39. /*
  40. * N is set of all nonterminals which are not useless. P is set of all rules
  41. * which have no useless nonterminals in their RHS. V is the set of all
  42. * accessible symbols.
  43. */
  44. static BSet N, P, V, V1;
  45. static int nuseful_productions, nuseless_productions,
  46. nuseful_nonterminals, nuseless_nonterminals;
  47. static void useless_nonterminals();
  48. static void inaccessable_symbols();
  49. static void reduce_grammar_tables();
  50. static void print_results();
  51. static void print_notices();
  52. void dump_grammar();
  53. extern void fatals ();
  54. bool
  55. bits_equal (L, R, n)
  56. BSet L;
  57. BSet R;
  58. int n;
  59. {
  60. int i;
  61. for (i = n - 1; i >= 0; i--)
  62. if (L[i] != R[i])
  63. return FALSE;
  64. return TRUE;
  65. }
  66. int
  67. nbits (i)
  68. unsigned i;
  69. {
  70. int count = 0;
  71. while (i != 0) {
  72. i ^= (i & -i);
  73. ++count;
  74. }
  75. return count;
  76. }
  77. int
  78. bits_size (S, n)
  79. BSet S;
  80. int n;
  81. {
  82. int i, count = 0;
  83. for (i = n - 1; i >= 0; i--)
  84. count += nbits(S[i]);
  85. return count;
  86. }
  87. void
  88. reduce_grammar ()
  89. {
  90. bool reduced;
  91. /* Allocate the global sets used to compute the reduced grammar */
  92. N = NEW2(WORDSIZE(nvars), unsigned);
  93. P = NEW2(WORDSIZE(nrules + 1), unsigned);
  94. V = NEW2(WORDSIZE(nsyms), unsigned);
  95. V1 = NEW2(WORDSIZE(nsyms), unsigned);
  96. useless_nonterminals();
  97. inaccessable_symbols();
  98. reduced = (bool) (nuseless_nonterminals + nuseless_productions > 0);
  99. if (verboseflag)
  100. print_results();
  101. if (reduced == FALSE)
  102. goto done_reducing;
  103. print_notices();
  104. if (!BITISSET(N, start_symbol - ntokens))
  105. fatals("Start symbol %s does not derive any sentence.",
  106. tags[start_symbol]);
  107. reduce_grammar_tables();
  108. /* if (verboseflag) {
  109. fprintf(foutput, "REDUCED GRAMMAR\n\n");
  110. dump_grammar();
  111. }
  112. */
  113. /**/ statisticsflag = FALSE; /* someday getopts should handle this */
  114. if (statisticsflag == TRUE)
  115. fprintf(stderr,
  116. "reduced %s defines %d terminal%s, %d nonterminal%s\
  117. , and %d production%s.\n", infile,
  118. ntokens, (ntokens == 1 ? "" : "s"),
  119. nvars, (nvars == 1 ? "" : "s"),
  120. nrules, (nrules == 1 ? "" : "s"));
  121. done_reducing:
  122. /* Free the global sets used to compute the reduced grammar */
  123. FREE(N);
  124. FREE(V);
  125. FREE(P);
  126. }
  127. /*
  128. * Another way to do this would be with a set for each production and then do
  129. * subset tests against N, but even for the C grammar the whole reducing
  130. * process takes only 2 seconds on my 8Mhz AT.
  131. */
  132. static bool
  133. useful_production (i, N)
  134. int i;
  135. BSet N;
  136. {
  137. rule r;
  138. short n;
  139. /*
  140. * A production is useful if all of the nonterminals in its RHS
  141. * appear in the set of useful nonterminals.
  142. */
  143. for (r = &ritem[rrhs[i]]; *r > 0; r++)
  144. if (ISVAR(n = *r))
  145. if (!BITISSET(N, n - ntokens))
  146. return FALSE;
  147. return TRUE;
  148. }
  149. /* Remember that rules are 1-origin, symbols are 0-origin. */
  150. static void
  151. useless_nonterminals ()
  152. {
  153. BSet Np, Ns;
  154. int i, n;
  155. /*
  156. * N is set as built. Np is set being built this iteration. P is set
  157. * of all productions which have a RHS all in N.
  158. */
  159. Np = NEW2(WORDSIZE(nvars), unsigned);
  160. /*
  161. * The set being computed is a set of nonterminals which can derive
  162. * the empty string or strings consisting of all terminals. At each
  163. * iteration a nonterminal is added to the set if there is a
  164. * production with that nonterminal as its LHS for which all the
  165. * nonterminals in its RHS are already in the set. Iterate until the
  166. * set being computed remains unchanged. Any nonterminals not in the
  167. * set at that point are useless in that they will never be used in
  168. * deriving a sentence of the language.
  169. *
  170. * This iteration doesn't use any special traversal over the
  171. * productions. A set is kept of all productions for which all the
  172. * nonterminals in the RHS are in useful. Only productions not in
  173. * this set are scanned on each iteration. At the end, this set is
  174. * saved to be used when finding useful productions: only productions
  175. * in this set will appear in the final grammar.
  176. */
  177. n = 0;
  178. while (1)
  179. {
  180. for (i = WORDSIZE(nvars) - 1; i >= 0; i--)
  181. Np[i] = N[i];
  182. for (i = 1; i <= nrules; i++)
  183. {
  184. if (!BITISSET(P, i))
  185. {
  186. if (useful_production(i, N))
  187. {
  188. SETBIT(Np, rlhs[i] - ntokens);
  189. SETBIT(P, i);
  190. }
  191. }
  192. }
  193. if (bits_equal(N, Np, WORDSIZE(nvars)))
  194. break;
  195. Ns = Np;
  196. Np = N;
  197. N = Ns;
  198. }
  199. FREE(N);
  200. N = Np;
  201. }
  202. static void
  203. inaccessable_symbols ()
  204. {
  205. BSet Vp, Vs, Pp;
  206. int i, n;
  207. short t;
  208. rule r;
  209. /*
  210. * Find out which productions are reachable and which symbols are
  211. * used. Starting with an empty set of productions and a set of
  212. * symbols which only has the start symbol in it, iterate over all
  213. * productions until the set of productions remains unchanged for an
  214. * iteration. For each production which has a LHS in the set of
  215. * reachable symbols, add the production to the set of reachable
  216. * productions, and add all of the nonterminals in the RHS of the
  217. * production to the set of reachable symbols.
  218. *
  219. * Consider only the (partially) reduced grammar which has only
  220. * nonterminals in N and productions in P.
  221. *
  222. * The result is the set P of productions in the reduced grammar, and
  223. * the set V of symbols in the reduced grammar.
  224. *
  225. * Although this algorithm also computes the set of terminals which are
  226. * reachable, no terminal will be deleted from the grammar. Some
  227. * terminals might not be in the grammar but might be generated by
  228. * semantic routines, and so the user might want them available with
  229. * specified numbers. (Is this true?) However, the nonreachable
  230. * terminals are printed (if running in verbose mode) so that the user
  231. * can know.
  232. */
  233. Vp = NEW2(WORDSIZE(nsyms), unsigned);
  234. Pp = NEW2(WORDSIZE(nrules + 1), unsigned);
  235. /* If the start symbol isn't useful, then nothing will be useful. */
  236. if (!BITISSET(N, start_symbol - ntokens))
  237. goto end_iteration;
  238. SETBIT(V, start_symbol);
  239. n = 0;
  240. while (1)
  241. {
  242. for (i = WORDSIZE(nsyms) - 1; i >= 0; i--)
  243. Vp[i] = V[i];
  244. for (i = 1; i <= nrules; i++)
  245. {
  246. if (!BITISSET(Pp, i) && BITISSET(P, i) &&
  247. BITISSET(V, rlhs[i]))
  248. {
  249. for (r = &ritem[rrhs[i]]; *r >= 0; r++)
  250. {
  251. if (ISTOKEN(t = *r)
  252. || BITISSET(N, t - ntokens))
  253. {
  254. SETBIT(Vp, t);
  255. }
  256. }
  257. SETBIT(Pp, i);
  258. }
  259. }
  260. if (bits_equal(V, Vp, WORDSIZE(nsyms)))
  261. {
  262. break;
  263. }
  264. Vs = Vp;
  265. Vp = V;
  266. V = Vs;
  267. }
  268. end_iteration:
  269. FREE(V);
  270. V = Vp;
  271. /* Tokens 0, 1, and 2 are internal to Bison. Consider them useful. */
  272. SETBIT(V, 0); /* end-of-input token */
  273. SETBIT(V, 1); /* error token */
  274. SETBIT(V, 2); /* illegal token */
  275. FREE(P);
  276. P = Pp;
  277. nuseful_productions = bits_size(P, WORDSIZE(nrules + 1));
  278. nuseless_productions = nrules - nuseful_productions;
  279. nuseful_nonterminals = 0;
  280. for (i = ntokens; i < nsyms; i++)
  281. if (BITISSET(V, i))
  282. nuseful_nonterminals++;
  283. nuseless_nonterminals = nvars - nuseful_nonterminals;
  284. /* A token that was used in %prec should not be warned about. */
  285. for (i = 1; i < nrules; i++)
  286. if (rprecsym[i] != 0)
  287. SETBIT(V1, rprecsym[i]);
  288. }
  289. static void
  290. reduce_grammar_tables ()
  291. {
  292. /* This is turned off because we would need to change the numbers
  293. in the case statements in the actions file. */
  294. #if 0
  295. /* remove useless productions */
  296. if (nuseless_productions > 0)
  297. {
  298. short np, pn, ni, pi;
  299. np = 0;
  300. ni = 0;
  301. for (pn = 1; pn <= nrules; pn++)
  302. {
  303. if (BITISSET(P, pn))
  304. {
  305. np++;
  306. if (pn != np)
  307. {
  308. rlhs[np] = rlhs[pn];
  309. rline[np] = rline[pn];
  310. rprec[np] = rprec[pn];
  311. rassoc[np] = rassoc[pn];
  312. rrhs[np] = rrhs[pn];
  313. if (rrhs[np] != ni)
  314. {
  315. pi = rrhs[np];
  316. rrhs[np] = ni;
  317. while (ritem[pi] >= 0)
  318. ritem[ni++] = ritem[pi++];
  319. ritem[ni++] = -np;
  320. }
  321. } else {
  322. while (ritem[ni++] >= 0);
  323. }
  324. }
  325. }
  326. ritem[ni] = 0;
  327. nrules -= nuseless_productions;
  328. nitems = ni;
  329. /*
  330. * Is it worth it to reduce the amount of memory for the
  331. * grammar? Probably not.
  332. */
  333. }
  334. #endif /* 0 */
  335. /* Disable useless productions,
  336. since they may contain useless nonterms
  337. that would get mapped below to -1 and confuse everyone. */
  338. if (nuseless_productions > 0)
  339. {
  340. int pn;
  341. for (pn = 1; pn <= nrules; pn++)
  342. {
  343. if (!BITISSET(P, pn))
  344. {
  345. rlhs[pn] = -1;
  346. }
  347. }
  348. }
  349. /* remove useless symbols */
  350. if (nuseless_nonterminals > 0)
  351. {
  352. int i, n;
  353. /* short j; JF unused */
  354. short *nontermmap;
  355. rule r;
  356. /*
  357. * create a map of nonterminal number to new nonterminal
  358. * number. -1 in the map means it was useless and is being
  359. * eliminated.
  360. */
  361. nontermmap = NEW2(nvars, short) - ntokens;
  362. for (i = ntokens; i < nsyms; i++)
  363. nontermmap[i] = -1;
  364. n = ntokens;
  365. for (i = ntokens; i < nsyms; i++)
  366. if (BITISSET(V, i))
  367. nontermmap[i] = n++;
  368. /* Shuffle elements of tables indexed by symbol number. */
  369. for (i = ntokens; i < nsyms; i++)
  370. {
  371. n = nontermmap[i];
  372. if (n >= 0)
  373. {
  374. sassoc[n] = sassoc[i];
  375. sprec[n] = sprec[i];
  376. tags[n] = tags[i];
  377. } else {
  378. free(tags[i]);
  379. }
  380. }
  381. /* Replace all symbol numbers in valid data structures. */
  382. for (i = 1; i <= nrules; i++)
  383. {
  384. /* Ignore the rules disabled above. */
  385. if (rlhs[i] >= 0)
  386. rlhs[i] = nontermmap[rlhs[i]];
  387. if (ISVAR (rprecsym[i]))
  388. /* Can this happen? */
  389. rprecsym[i] = nontermmap[rprecsym[i]];
  390. }
  391. for (r = ritem; *r; r++)
  392. if (ISVAR(*r))
  393. *r = nontermmap[*r];
  394. start_symbol = nontermmap[start_symbol];
  395. nsyms -= nuseless_nonterminals;
  396. nvars -= nuseless_nonterminals;
  397. free(&nontermmap[ntokens]);
  398. }
  399. }
  400. static void
  401. print_results ()
  402. {
  403. int i;
  404. /* short j; JF unused */
  405. rule r;
  406. bool b;
  407. if (nuseless_nonterminals > 0)
  408. {
  409. fprintf(foutput, "Useless nonterminals:\n\n");
  410. for (i = ntokens; i < nsyms; i++)
  411. if (!BITISSET(V, i))
  412. fprintf(foutput, " %s\n", tags[i]);
  413. }
  414. b = FALSE;
  415. for (i = 0; i < ntokens; i++)
  416. {
  417. if (!BITISSET(V, i) && !BITISSET(V1, i))
  418. {
  419. if (!b)
  420. {
  421. fprintf(foutput, "\n\nTerminals which are not used:\n\n");
  422. b = TRUE;
  423. }
  424. fprintf(foutput, " %s\n", tags[i]);
  425. }
  426. }
  427. if (nuseless_productions > 0)
  428. {
  429. fprintf(foutput, "\n\nUseless rules:\n\n");
  430. for (i = 1; i <= nrules; i++)
  431. {
  432. if (!BITISSET(P, i))
  433. {
  434. fprintf(foutput, "#%-4d ", i);
  435. fprintf(foutput, "%s :\t", tags[rlhs[i]]);
  436. for (r = &ritem[rrhs[i]]; *r >= 0; r++)
  437. {
  438. fprintf(foutput, " %s", tags[*r]);
  439. }
  440. fprintf(foutput, ";\n");
  441. }
  442. }
  443. }
  444. if (nuseless_nonterminals > 0 || nuseless_productions > 0 || b)
  445. fprintf(foutput, "\n\n");
  446. }
  447. void
  448. dump_grammar ()
  449. {
  450. int i;
  451. rule r;
  452. fprintf(foutput,
  453. "ntokens = %d, nvars = %d, nsyms = %d, nrules = %d, nitems = %d\n\n",
  454. ntokens, nvars, nsyms, nrules, nitems);
  455. fprintf(foutput, "Variables\n---------\n\n");
  456. fprintf(foutput, "Value Sprec Sassoc Tag\n");
  457. for (i = ntokens; i < nsyms; i++)
  458. fprintf(foutput, "%5d %5d %5d %s\n",
  459. i, sprec[i], sassoc[i], tags[i]);
  460. fprintf(foutput, "\n\n");
  461. fprintf(foutput, "Rules\n-----\n\n");
  462. for (i = 1; i <= nrules; i++)
  463. {
  464. fprintf(foutput, "%-5d(%5d%5d)%5d : (@%-5d)",
  465. i, rprec[i], rassoc[i], rlhs[i], rrhs[i]);
  466. for (r = &ritem[rrhs[i]]; *r > 0; r++)
  467. fprintf(foutput, "%5d", *r);
  468. fprintf(foutput, " [%d]\n", -(*r));
  469. }
  470. fprintf(foutput, "\n\n");
  471. fprintf(foutput, "Rules interpreted\n-----------------\n\n");
  472. for (i = 1; i <= nrules; i++)
  473. {
  474. fprintf(foutput, "%-5d %s :", i, tags[rlhs[i]]);
  475. for (r = &ritem[rrhs[i]]; *r > 0; r++)
  476. fprintf(foutput, " %s", tags[*r]);
  477. fprintf(foutput, "\n");
  478. }
  479. fprintf(foutput, "\n\n");
  480. }
  481. static void
  482. print_notices ()
  483. {
  484. extern int fixed_outfiles;
  485. if (fixed_outfiles && nuseless_productions)
  486. fprintf(stderr, "%d rules never reduced\n", nuseless_productions);
  487. fprintf(stderr, "%s contains ", infile);
  488. if (nuseless_nonterminals > 0)
  489. {
  490. fprintf(stderr, "%d useless nonterminal%s",
  491. nuseless_nonterminals,
  492. (nuseless_nonterminals == 1 ? "" : "s"));
  493. }
  494. if (nuseless_nonterminals > 0 && nuseless_productions > 0)
  495. fprintf(stderr, " and ");
  496. if (nuseless_productions > 0)
  497. {
  498. fprintf(stderr, "%d useless rule%s",
  499. nuseless_productions,
  500. (nuseless_productions == 1 ? "" : "s"));
  501. }
  502. fprintf(stderr, ".\n");
  503. fflush(stderr);
  504. }