• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Print an xml on generated parser, for Bison,
2 
3    Copyright (C) 2007, 2009-2012 Free Software Foundation, Inc.
4 
5    This file is part of Bison, the GNU Compiler Compiler.
6 
7    This program is free software: you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation, either version 3 of the License, or
10    (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19 
20 #include <config.h>
21 #include "system.h"
22 
23 #include <stdarg.h>
24 
25 #include <bitset.h>
26 
27 #include "LR0.h"
28 #include "closure.h"
29 #include "conflicts.h"
30 #include "files.h"
31 #include "getargs.h"
32 #include "gram.h"
33 #include "lalr.h"
34 #include "print.h"
35 #include "print-xml.h"
36 #include "reader.h"
37 #include "reduce.h"
38 #include "state.h"
39 #include "symtab.h"
40 #include "tables.h"
41 
42 static bitset no_reduce_set;
43 struct escape_buf
44 {
45   char *ptr;
46   size_t size;
47 };
48 static struct escape_buf escape_bufs[3];
49 
50 
51 /*--------------------------------.
52 | Report information on a state.  |
53 `--------------------------------*/
54 
55 static void
print_core(FILE * out,int level,state * s)56 print_core (FILE *out, int level, state *s)
57 {
58   size_t i;
59   item_number *sitems = s->items;
60   size_t snritems = s->nitems;
61 
62   /* Output all the items of a state, not only its kernel.  */
63   closure (sitems, snritems);
64   sitems = itemset;
65   snritems = nitemset;
66 
67   if (!snritems) {
68     xml_puts (out, level, "<itemset/>");
69     return;
70   }
71 
72   xml_puts (out, level, "<itemset>");
73 
74   for (i = 0; i < snritems; i++)
75     {
76       bool printed = false;
77       item_number *sp;
78       item_number *sp1;
79       rule_number r;
80 
81       sp1 = sp = ritem + sitems[i];
82 
83       while (*sp >= 0)
84 	sp++;
85 
86       r = item_number_as_rule_number (*sp);
87       sp = rules[r].rhs;
88 
89       /* Display the lookahead tokens?  */
90       if (item_number_is_rule_number (*sp1))
91 	{
92 	  reductions *reds = s->reductions;
93 	  int red = state_reduction_find (s, &rules[r]);
94 	  /* Print item with lookaheads if there are. */
95 	  if (reds->lookahead_tokens && red != -1)
96 	    {
97 	      xml_printf (out, level + 1,
98 			  "<item rule-number=\"%d\" point=\"%d\">",
99 			  rules[r].number, sp1 - sp);
100 	      state_rule_lookahead_tokens_print_xml (s, &rules[r],
101 						     out, level + 2);
102 	      xml_puts (out, level + 1, "</item>");
103 	      printed = true;
104 	    }
105 	}
106 
107       if (!printed)
108 	{
109 	  xml_printf (out, level + 1,
110 		      "<item rule-number=\"%d\" point=\"%d\"/>",
111 		      rules[r].number,
112 		      sp1 - sp);
113 	}
114     }
115   xml_puts (out, level, "</itemset>");
116 }
117 
118 
119 /*-----------------------------------------------------------.
120 | Report the shifts if DISPLAY_SHIFTS_P or the gotos of S on |
121 | OUT.                                                       |
122 `-----------------------------------------------------------*/
123 
124 static void
print_transitions(state * s,FILE * out,int level)125 print_transitions (state *s, FILE *out, int level)
126 {
127   transitions *trans = s->transitions;
128   int n = 0;
129   int i;
130 
131   for (i = 0; i < trans->num; i++)
132     if (!TRANSITION_IS_DISABLED (trans, i))
133       {
134 	n++;
135       }
136 
137   /* Nothing to report. */
138   if (!n) {
139     xml_puts (out, level, "<transitions/>");
140     return;
141   }
142 
143   /* Report lookahead tokens and shifts.  */
144   xml_puts (out, level, "<transitions>");
145 
146   for (i = 0; i < trans->num; i++)
147     if (!TRANSITION_IS_DISABLED (trans, i)
148 	&& TRANSITION_IS_SHIFT (trans, i))
149       {
150 	symbol *sym = symbols[TRANSITION_SYMBOL (trans, i)];
151 	char const *tag = sym->tag;
152 	state *s1 = trans->states[i];
153 
154 	xml_printf (out, level + 1,
155 		    "<transition type=\"shift\" symbol=\"%s\" state=\"%d\"/>",
156 		    xml_escape (tag), s1->number);
157       }
158 
159   for (i = 0; i < trans->num; i++)
160     if (!TRANSITION_IS_DISABLED (trans, i)
161 	&& !TRANSITION_IS_SHIFT (trans, i))
162       {
163 	symbol *sym = symbols[TRANSITION_SYMBOL (trans, i)];
164 	char const *tag = sym->tag;
165 	state *s1 = trans->states[i];
166 
167 	xml_printf (out, level + 1,
168 		    "<transition type=\"goto\" symbol=\"%s\" state=\"%d\"/>",
169 		    xml_escape (tag), s1->number);
170       }
171 
172   xml_puts (out, level, "</transitions>");
173 }
174 
175 
176 /*--------------------------------------------------------.
177 | Report the explicit errors of S raised from %nonassoc.  |
178 `--------------------------------------------------------*/
179 
180 static void
print_errs(FILE * out,int level,state * s)181 print_errs (FILE *out, int level, state *s)
182 {
183   errs *errp = s->errs;
184   bool count = false;
185   int i;
186 
187   for (i = 0; i < errp->num; ++i)
188     if (errp->symbols[i])
189       count = true;
190 
191   /* Nothing to report. */
192   if (!count) {
193     xml_puts (out, level, "<errors/>");
194     return;
195   }
196 
197   /* Report lookahead tokens and errors.  */
198   xml_puts (out, level, "<errors>");
199   for (i = 0; i < errp->num; ++i)
200     if (errp->symbols[i])
201       {
202 	char const *tag = errp->symbols[i]->tag;
203 	xml_printf (out, level + 1,
204 		    "<error symbol=\"%s\">nonassociative</error>",
205 		    xml_escape (tag));
206       }
207   xml_puts (out, level, "</errors>");
208 }
209 
210 
211 /*-------------------------------------------------------------------------.
212 | Report a reduction of RULE on LOOKAHEAD_TOKEN (which can be `default').  |
213 | If not ENABLED, the rule is masked by a shift or a reduce (S/R and       |
214 | R/R conflicts).                                                          |
215 `-------------------------------------------------------------------------*/
216 
217 static void
print_reduction(FILE * out,int level,char const * lookahead_token,rule * r,bool enabled)218 print_reduction (FILE *out, int level, char const *lookahead_token,
219 		 rule *r, bool enabled)
220 {
221   if (r->number)
222     xml_printf (out, level,
223 		"<reduction symbol=\"%s\" rule=\"%d\" enabled=\"%s\"/>",
224 		xml_escape (lookahead_token),
225 		r->number,
226 		enabled ? "true" : "false");
227   else
228     xml_printf (out, level,
229 		"<reduction symbol=\"%s\" rule=\"accept\" enabled=\"%s\"/>",
230 		xml_escape (lookahead_token),
231 		enabled ? "true" : "false");
232 }
233 
234 
235 /*-------------------------------------------.
236 | Report on OUT the reduction actions of S.  |
237 `-------------------------------------------*/
238 
239 static void
print_reductions(FILE * out,int level,state * s)240 print_reductions (FILE *out, int level, state *s)
241 {
242   transitions *trans = s->transitions;
243   reductions *reds = s->reductions;
244   rule *default_reduction = NULL;
245   int report = false;
246   int i, j;
247 
248   if (reds->num == 0)
249     {
250       xml_puts (out, level, "<reductions/>");
251       return;
252     }
253 
254   if (yydefact[s->number] != 0)
255     default_reduction = &rules[yydefact[s->number] - 1];
256 
257   bitset_zero (no_reduce_set);
258   FOR_EACH_SHIFT (trans, i)
259     bitset_set (no_reduce_set, TRANSITION_SYMBOL (trans, i));
260   for (i = 0; i < s->errs->num; ++i)
261     if (s->errs->symbols[i])
262       bitset_set (no_reduce_set, s->errs->symbols[i]->number);
263 
264   if (default_reduction)
265     report = true;
266 
267   if (reds->lookahead_tokens)
268     for (i = 0; i < ntokens; i++)
269       {
270 	bool count = bitset_test (no_reduce_set, i);
271 
272 	for (j = 0; j < reds->num; ++j)
273 	  if (bitset_test (reds->lookahead_tokens[j], i))
274 	    {
275 	      if (! count)
276 		{
277 		  if (reds->rules[j] != default_reduction)
278 		    report = true;
279 		  count = true;
280 		}
281 	      else
282 		{
283 		  report = true;
284 		}
285 	    }
286       }
287 
288   /* Nothing to report. */
289   if (!report) {
290     xml_puts (out, level, "<reductions/>");
291     return;
292   }
293 
294   xml_puts (out, level, "<reductions>");
295 
296   /* Report lookahead tokens (or $default) and reductions.  */
297   if (reds->lookahead_tokens)
298     for (i = 0; i < ntokens; i++)
299       {
300 	bool defaulted = false;
301 	bool count = bitset_test (no_reduce_set, i);
302 
303 	for (j = 0; j < reds->num; ++j)
304 	  if (bitset_test (reds->lookahead_tokens[j], i))
305 	    {
306 	      if (! count)
307 		{
308 		  if (reds->rules[j] != default_reduction)
309 		    print_reduction (out, level + 1, symbols[i]->tag,
310 				     reds->rules[j], true);
311 		  else
312 		    defaulted = true;
313 		  count = true;
314 		}
315 	      else
316 		{
317 		  if (defaulted)
318 		    print_reduction (out, level + 1, symbols[i]->tag,
319 				     default_reduction, true);
320 		  defaulted = false;
321 		  print_reduction (out, level + 1, symbols[i]->tag,
322 				   reds->rules[j], false);
323 		}
324 	    }
325       }
326 
327   if (default_reduction)
328     print_reduction (out, level + 1,
329 		     "$default", default_reduction, true);
330 
331   xml_puts (out, level, "</reductions>");
332 }
333 
334 
335 /*--------------------------------------------------------------.
336 | Report on OUT all the actions (shifts, gotos, reductions, and |
337 | explicit erros from %nonassoc) of S.                          |
338 `--------------------------------------------------------------*/
339 
340 static void
print_actions(FILE * out,int level,state * s)341 print_actions (FILE *out, int level, state *s)
342 {
343   xml_puts (out, level, "<actions>");
344   print_transitions (s, out, level + 1);
345   print_errs (out, level + 1, s);
346   print_reductions (out, level + 1, s);
347   xml_puts (out, level, "</actions>");
348 }
349 
350 
351 /*----------------------------------.
352 | Report all the data on S on OUT.  |
353 `----------------------------------*/
354 
355 static void
print_state(FILE * out,int level,state * s)356 print_state (FILE *out, int level, state *s)
357 {
358   fputc ('\n', out);
359   xml_printf (out, level, "<state number=\"%d\">", s->number);
360   print_core (out, level + 1, s);
361   print_actions (out, level + 1, s);
362   if (s->solved_conflicts_xml)
363     {
364       xml_puts (out, level + 1, "<solved-conflicts>");
365       fputs (s->solved_conflicts_xml, out);
366       xml_puts (out, level + 1, "</solved-conflicts>");
367     }
368   else
369     xml_puts (out, level + 1, "<solved-conflicts/>");
370   xml_puts (out, level, "</state>");
371 }
372 
373 
374 /*-----------------------------------------.
375 | Print information on the whole grammar.  |
376 `-----------------------------------------*/
377 
378 static void
print_grammar(FILE * out,int level)379 print_grammar (FILE *out, int level)
380 {
381   symbol_number i;
382 
383   fputc ('\n', out);
384   xml_puts (out, level, "<grammar>");
385   grammar_rules_print_xml (out, level);
386 
387   /* Terminals */
388   xml_puts (out, level + 1, "<terminals>");
389   for (i = 0; i < max_user_token_number + 1; i++)
390     if (token_translations[i] != undeftoken->number)
391       {
392 	char const *tag = symbols[token_translations[i]]->tag;
393         int precedence = symbols[token_translations[i]]->prec;
394         assoc associativity = symbols[token_translations[i]]->assoc;
395         xml_indent (out, level + 2);
396         fprintf (out,
397                  "<terminal symbol-number=\"%d\" token-number=\"%d\""
398                  " name=\"%s\" usefulness=\"%s\"",
399                  token_translations[i], i, xml_escape (tag),
400                  reduce_token_unused_in_grammar (token_translations[i])
401                    ? "unused-in-grammar" : "useful");
402         if (precedence)
403           fprintf (out, " prec=\"%d\"", precedence);
404         if (associativity != undef_assoc)
405           fprintf (out, " assoc=\"%s\"", assoc_to_string (associativity) + 1);
406         fputs ("/>\n", out);
407       }
408   xml_puts (out, level + 1, "</terminals>");
409 
410   /* Nonterminals */
411   xml_puts (out, level + 1, "<nonterminals>");
412   for (i = ntokens; i < nsyms + nuseless_nonterminals; i++)
413     {
414       char const *tag = symbols[i]->tag;
415       xml_printf (out, level + 2,
416 		  "<nonterminal symbol-number=\"%d\" name=\"%s\""
417                   " usefulness=\"%s\"/>",
418 		  i, xml_escape (tag),
419                   reduce_nonterminal_useless_in_grammar (i)
420                     ? "useless-in-grammar" : "useful");
421     }
422   xml_puts (out, level + 1, "</nonterminals>");
423   xml_puts (out, level, "</grammar>");
424 }
425 
426 void
xml_indent(FILE * out,int level)427 xml_indent (FILE *out, int level)
428 {
429   int i;
430   for (i = 0; i < level; i++)
431     fputs ("  ", out);
432 }
433 
434 void
xml_puts(FILE * out,int level,char const * s)435 xml_puts (FILE *out, int level, char const *s)
436 {
437   xml_indent (out, level);
438   fputs (s, out);
439   fputc ('\n', out);
440 }
441 
442 void
xml_printf(FILE * out,int level,char const * fmt,...)443 xml_printf (FILE *out, int level, char const *fmt, ...)
444 {
445   va_list arglist;
446 
447   xml_indent (out, level);
448 
449   va_start (arglist, fmt);
450   vfprintf (out, fmt, arglist);
451   va_end (arglist);
452 
453   fputc ('\n', out);
454 }
455 
456 static char const *
xml_escape_string(struct escape_buf * buf,char const * str)457 xml_escape_string (struct escape_buf *buf, char const *str)
458 {
459   size_t len = strlen (str);
460   size_t max_expansion = sizeof "&quot;" - 1;
461   char *p;
462 
463   if (buf->size <= max_expansion * len)
464     {
465       buf->size = max_expansion * len + 1;
466       buf->ptr = x2realloc (buf->ptr, &buf->size);
467     }
468   p = buf->ptr;
469 
470   for (; *str; str++)
471     switch (*str)
472       {
473       default: *p++ = *str; break;
474       case '&': p = stpcpy (p, "&amp;" ); break;
475       case '<': p = stpcpy (p, "&lt;"  ); break;
476       case '>': p = stpcpy (p, "&gt;"  ); break;
477       case '"': p = stpcpy (p, "&quot;"); break;
478       }
479 
480   *p = '\0';
481   return buf->ptr;
482 }
483 
484 char const *
xml_escape_n(int n,char const * str)485 xml_escape_n (int n, char const *str)
486 {
487   return xml_escape_string (escape_bufs + n, str);
488 }
489 
490 char const *
xml_escape(char const * str)491 xml_escape (char const *str)
492 {
493   return xml_escape_n (0, str);
494 }
495 
496 void
print_xml(void)497 print_xml (void)
498 {
499   state_number i;
500   int level = 0;
501 
502   FILE *out = xfopen (spec_xml_file, "w");
503 
504   fputs ("<?xml version=\"1.0\"?>\n\n", out);
505   xml_printf (out, level,
506               "<bison-xml-report version=\"%s\" bug-report=\"%s\""
507               " url=\"%s\">",
508               xml_escape_n (0, VERSION),
509               xml_escape_n (1, PACKAGE_BUGREPORT),
510               xml_escape_n (2, PACKAGE_URL));
511 
512   fputc ('\n', out);
513   xml_printf (out, level + 1, "<filename>%s</filename>",
514 	      xml_escape (grammar_file));
515 
516   /* print grammar */
517   print_grammar (out, level + 1);
518 
519   new_closure (nritems);
520   no_reduce_set =  bitset_create (ntokens, BITSET_FIXED);
521 
522   /* print automaton */
523   fputc ('\n', out);
524   xml_puts (out, level + 1, "<automaton>");
525   for (i = 0; i < nstates; i++)
526     print_state (out, level + 2, states[i]);
527   xml_puts (out, level + 1, "</automaton>");
528 
529   bitset_free (no_reduce_set);
530   free_closure ();
531 
532   xml_puts (out, 0, "</bison-xml-report>");
533 
534   free (escape_bufs[0].ptr);
535   free (escape_bufs[1].ptr);
536 
537   xfclose (out);
538 }
539