]> git.saurik.com Git - bison.git/blob - src/print-xml.c
Pacify ./configure --enable-gcc-warnings.
[bison.git] / src / print-xml.c
1 /* Print an xml on generated parser, for Bison,
2
3 Copyright (C) 2007 Free Software Foundation, Inc.
4
5 This file is part of Bison, the GNU Compiler Compiler.
6
7 Bison 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 2, or (at your option)
10 any later version.
11
12 Bison 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 Bison; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA. */
21
22 #include <config.h>
23 #include "system.h"
24
25 #include <stdarg.h>
26
27 #include <bitset.h>
28 #include <quotearg.h>
29
30 #include "LR0.h"
31 #include "closure.h"
32 #include "conflicts.h"
33 #include "files.h"
34 #include "getargs.h"
35 #include "gram.h"
36 #include "lalr.h"
37 #include "print.h"
38 #include "print-xml.h"
39 #include "reader.h"
40 #include "reduce.h"
41 #include "state.h"
42 #include "symtab.h"
43 #include "tables.h"
44
45 static bitset no_reduce_set;
46
47
48 /*----------------------------.
49 | Print rules never reduced. |
50 `-----------------------------*/
51
52 static void
53 print_rules_never_reduced (FILE *out, int level)
54 {
55 rule_number r;
56 bool count = false;
57
58 for (r = 0; r < nrules + nuseless_productions; r++)
59 {
60 if (rule_never_reduced_p (&rules[r]))
61 {
62 count = true;
63 break;
64 }
65 }
66
67 if (count) {
68 xml_puts (out, level, "<rules-never-reduced>");
69 grammar_rules_partial_print_xml (out, level - 1,
70 false, rule_never_reduced_p);
71 xml_puts (out, level, "</rules-never-reduced>");
72 }
73 else
74 xml_puts (out, level, "<rules-never-reduced/>");
75 }
76
77 /*--------------------------------.
78 | Report information on a state. |
79 `--------------------------------*/
80
81 static void
82 print_core (FILE *out, int level, state *s)
83 {
84 size_t i;
85 item_number *sitems = s->items;
86 size_t snritems = s->nitems;
87
88 /* Output all the items of a state, not only its kernel. */
89 if (report_flag & report_itemsets)
90 {
91 closure (sitems, snritems);
92 sitems = itemset;
93 snritems = nitemset;
94 }
95
96 if (!snritems) {
97 xml_puts (out, level, "<itemset/>");
98 return;
99 }
100
101 xml_puts (out, level, "<itemset>");
102
103 for (i = 0; i < snritems; i++)
104 {
105 item_number *sp;
106 item_number *sp1;
107 rule_number r;
108
109 sp1 = sp = ritem + sitems[i];
110
111 while (*sp >= 0)
112 sp++;
113
114 r = item_number_as_rule_number (*sp);
115
116 xml_printf (out, level + 1, "<rule number=\"%d\">",
117 rules[r].number);
118
119 rule_lhs_print_xml (&rules[r], out, level + 2);
120
121 xml_puts (out, level + 2, "<rhs>");
122 for (sp = rules[r].rhs; sp < sp1; sp++)
123 xml_printf (out, level + 3, "<symbol class=\"%s\">%s</symbol>",
124 symbol_class_get_string (symbols[*sp]),
125 xml_escape (symbols[*sp]->tag));
126 xml_puts (out, level + 3, "<point/>");
127 for (/* Nothing */; *sp >= 0; ++sp)
128 xml_printf (out, level + 3, "<symbol class=\"%s\">%s</symbol>",
129 symbol_class_get_string (symbols[*sp]),
130 xml_escape (symbols[*sp]->tag));
131
132 xml_puts (out, level + 2, "</rhs>");
133
134 /* Display the lookahead tokens? */
135 if (report_flag & report_lookahead_tokens)
136 state_rule_lookahead_tokens_print_xml (s, &rules[r], out, level + 2);
137
138 xml_puts (out, level + 1, "</rule>");
139 }
140 xml_puts (out, level, "</itemset>");
141 }
142
143
144 /*-----------------------------------------------------------.
145 | Report the shifts if DISPLAY_SHIFTS_P or the gotos of S on |
146 | OUT. |
147 `-----------------------------------------------------------*/
148
149 static void
150 print_transitions (state *s, FILE *out, int level)
151 {
152 transitions *trans = s->transitions;
153 int n = 0;
154 int i;
155
156 for (i = 0; i < trans->num; i++)
157 if (!TRANSITION_IS_DISABLED (trans, i))
158 {
159 n++;
160 }
161
162 /* Nothing to report. */
163 if (!n) {
164 xml_puts (out, level, "<transitions/>");
165 return;
166 }
167
168 /* Report lookahead tokens and shifts. */
169 xml_puts (out, level, "<transitions>");
170
171 for (i = 0; i < trans->num; i++)
172 if (!TRANSITION_IS_DISABLED (trans, i)
173 && TRANSITION_IS_SHIFT (trans, i))
174 {
175 symbol *sym = symbols[TRANSITION_SYMBOL (trans, i)];
176 char const *tag = sym->tag;
177 state *s1 = trans->states[i];
178
179 xml_printf (out, level + 1,
180 "<transition type=\"shift\" symbol=\"%s\" state=\"%d\"/>",
181 xml_escape (tag), s1->number);
182 }
183
184 for (i = 0; i < trans->num; i++)
185 if (!TRANSITION_IS_DISABLED (trans, i)
186 && !TRANSITION_IS_SHIFT (trans, i))
187 {
188 symbol *sym = symbols[TRANSITION_SYMBOL (trans, i)];
189 char const *tag = sym->tag;
190 state *s1 = trans->states[i];
191
192 xml_printf (out, level + 1,
193 "<transition type=\"goto\" symbol=\"%s\" state=\"%d\"/>",
194 xml_escape (tag), s1->number);
195 }
196
197 xml_puts (out, level, "</transitions>");
198 }
199
200
201 /*--------------------------------------------------------.
202 | Report the explicit errors of S raised from %nonassoc. |
203 `--------------------------------------------------------*/
204
205 static void
206 print_errs (FILE *out, int level, state *s)
207 {
208 errs *errp = s->errs;
209 bool count = false;
210 int i;
211
212 for (i = 0; i < errp->num; ++i)
213 if (errp->symbols[i])
214 count = true;
215
216 /* Nothing to report. */
217 if (!count) {
218 xml_puts (out, level, "<errors/>");
219 return;
220 }
221
222 /* Report lookahead tokens and errors. */
223 xml_puts (out, level, "<errors>");
224 for (i = 0; i < errp->num; ++i)
225 if (errp->symbols[i])
226 {
227 char const *tag = errp->symbols[i]->tag;
228 xml_printf (out, level + 1,
229 "<error symbol=\"%s\">nonassociative</error>",
230 xml_escape (tag));
231 }
232 xml_puts (out, level, "</errors>");
233 }
234
235
236 /*-------------------------------------------------------------------------.
237 | Report a reduction of RULE on LOOKAHEAD_TOKEN (which can be `default'). |
238 | If not ENABLED, the rule is masked by a shift or a reduce (S/R and |
239 | R/R conflicts). |
240 `-------------------------------------------------------------------------*/
241
242 static void
243 print_reduction (FILE *out, int level, char const *lookahead_token,
244 rule *r, bool enabled)
245 {
246 if (r->number)
247 xml_printf (out, level,
248 "<reduction symbol=\"%s\" rule=\"%d\" enabled=\"%s\"/>",
249 xml_escape (lookahead_token),
250 r->number,
251 enabled ? "true" : "false");
252 else
253 xml_printf (out, level,
254 "<reduction symbol=\"%s\" rule=\"accept\" enabled=\"%s\"/>",
255 xml_escape (lookahead_token),
256 enabled ? "true" : "false");
257 }
258
259
260 /*-------------------------------------------.
261 | Report on OUT the reduction actions of S. |
262 `-------------------------------------------*/
263
264 static void
265 print_reductions (FILE *out, int level, state *s)
266 {
267 transitions *trans = s->transitions;
268 reductions *reds = s->reductions;
269 rule *default_rule = NULL;
270 int report = false;
271 int i, j;
272
273 if (reds->num == 0) {
274 xml_puts (out, level, "<reductions/>");
275 return;
276 }
277
278 if (yydefact[s->number] != 0)
279 default_rule = &rules[yydefact[s->number] - 1];
280
281 bitset_zero (no_reduce_set);
282 FOR_EACH_SHIFT (trans, i)
283 bitset_set (no_reduce_set, TRANSITION_SYMBOL (trans, i));
284 for (i = 0; i < s->errs->num; ++i)
285 if (s->errs->symbols[i])
286 bitset_set (no_reduce_set, s->errs->symbols[i]->number);
287
288 if (default_rule)
289 report = true;
290
291 if (reds->lookahead_tokens)
292 for (i = 0; i < ntokens; i++)
293 {
294 bool count = bitset_test (no_reduce_set, i);
295
296 for (j = 0; j < reds->num; ++j)
297 if (bitset_test (reds->lookahead_tokens[j], i))
298 {
299 if (! count)
300 {
301 if (reds->rules[j] != default_rule)
302 report = true;
303 count = true;
304 }
305 else
306 {
307 report = true;
308 }
309 }
310 }
311
312 /* Nothing to report. */
313 if (!report) {
314 xml_puts (out, level, "<reductions/>");
315 return;
316 }
317
318 xml_puts (out, level, "<reductions>");
319
320 /* Report lookahead tokens (or $default) and reductions. */
321 if (reds->lookahead_tokens)
322 for (i = 0; i < ntokens; i++)
323 {
324 bool defaulted = false;
325 bool count = bitset_test (no_reduce_set, i);
326
327 for (j = 0; j < reds->num; ++j)
328 if (bitset_test (reds->lookahead_tokens[j], i))
329 {
330 if (! count)
331 {
332 if (reds->rules[j] != default_rule)
333 print_reduction (out, level + 1, symbols[i]->tag,
334 reds->rules[j], true);
335 else
336 defaulted = true;
337 count = true;
338 }
339 else
340 {
341 if (defaulted)
342 print_reduction (out, level + 1, symbols[i]->tag,
343 default_rule, true);
344 defaulted = false;
345 print_reduction (out, level + 1, symbols[i]->tag,
346 reds->rules[j], false);
347 }
348 }
349 }
350
351 if (default_rule)
352 print_reduction (out, level + 1,
353 "$default", default_rule, true);
354
355 xml_puts (out, level, "</reductions>");
356 }
357
358
359 /*--------------------------------------------------------------.
360 | Report on OUT all the actions (shifts, gotos, reductions, and |
361 | explicit erros from %nonassoc) of S. |
362 `--------------------------------------------------------------*/
363
364 static void
365 print_actions (FILE *out, int level, state *s)
366 {
367 xml_puts (out, level, "<actions>");
368 print_transitions (s, out, level + 1);
369 print_errs (out, level + 1, s);
370 print_reductions (out, level + 1, s);
371 xml_puts (out, level, "</actions>");
372 }
373
374
375 /*----------------------------------.
376 | Report all the data on S on OUT. |
377 `----------------------------------*/
378
379 static void
380 print_state (FILE *out, int level, state *s)
381 {
382 fputc ('\n', out);
383 xml_printf (out, level, "<state number=\"%d\">", s->number);
384 print_core (out, level + 1, s);
385 print_actions (out, level + 1, s);
386 if ((report_flag & report_solved_conflicts) && s->solved_conflicts_xml)
387 {
388 xml_puts (out, level + 1, "<solved-conflicts>");
389 fputs (s->solved_conflicts_xml, out);
390 xml_puts (out, level + 1, "</solved-conflicts>");
391 }
392 else
393 xml_puts (out, level + 1, "<solved-conflicts/>");
394 xml_puts (out, level, "</state>");
395 }
396
397
398 /*-----------------------------------------.
399 | Print information on the whole grammar. |
400 `-----------------------------------------*/
401
402 static void
403 print_grammar (FILE *out, int level)
404 {
405 symbol_number i;
406
407 fputc ('\n', out);
408 xml_puts (out, level, "<grammar>");
409 grammar_rules_print_xml (out, level);
410
411 /* Terminals */
412 xml_puts (out, level + 1, "<terminals>");
413 for (i = 0; i < max_user_token_number + 1; i++)
414 if (token_translations[i] != undeftoken->number)
415 {
416 char const *tag = symbols[token_translations[i]]->tag;
417 rule_number r;
418 item_number *rhsp;
419
420 xml_printf (out, level + 2,
421 "<terminal type=\"%d\" symbol=\"%s\">",
422 i, xml_escape (tag));
423
424 for (r = 0; r < nrules; r++)
425 for (rhsp = rules[r].rhs; *rhsp >= 0; rhsp++)
426 if (item_number_as_symbol_number (*rhsp) == token_translations[i])
427 {
428 xml_printf (out, level + 3, "<rule>%d</rule>", r);
429 break;
430 }
431 xml_puts (out, level + 2, "</terminal>");
432 }
433 xml_puts (out, level + 1, "</terminals>");
434
435 /* Nonterminals */
436 xml_puts (out, level + 1, "<nonterminals>");
437 for (i = ntokens; i < nsyms; i++)
438 {
439 int left_count = 0, right_count = 0;
440 rule_number r;
441 char const *tag = symbols[i]->tag;
442
443 for (r = 0; r < nrules; r++)
444 {
445 item_number *rhsp;
446 if (rules[r].lhs->number == i)
447 left_count++;
448 for (rhsp = rules[r].rhs; *rhsp >= 0; rhsp++)
449 if (item_number_as_symbol_number (*rhsp) == i)
450 {
451 right_count++;
452 break;
453 }
454 }
455
456 xml_printf (out, level + 2,
457 "<nonterminal type=\"%d\" symbol=\"%s\">",
458 i, xml_escape (tag));
459
460 if (left_count > 0)
461 {
462 xml_puts (out, level + 3, "<left>");
463 for (r = 0; r < nrules; r++)
464 {
465 if (rules[r].lhs->number == i)
466 xml_printf (out, level + 4, "<rule>%d</rule>", r);
467 }
468 xml_puts (out, level + 3, "</left>");
469 }
470
471 if (right_count > 0)
472 {
473 xml_puts (out, level + 3, "<right>");
474 for (r = 0; r < nrules; r++)
475 {
476 item_number *rhsp;
477 for (rhsp = rules[r].rhs; *rhsp >= 0; rhsp++)
478 if (item_number_as_symbol_number (*rhsp) == i)
479 {
480 xml_printf (out, level + 4, "<rule>%d</rule>", r);
481 break;
482 }
483 }
484 xml_puts (out, level + 3, "</right>");
485 }
486
487 xml_puts (out, level + 2, "</nonterminal>");
488 }
489 xml_puts (out, level + 1, "</nonterminals>");
490 xml_puts (out, level, "</grammar>");
491 }
492
493 void
494 xml_puts (FILE *out, int level, char const *s)
495 {
496 int i;
497 level *= 2;
498 for (i = 0; i < level; i++)
499 fputc (' ', out);
500 fputs (s, out);
501 fputc ('\n', out);
502 }
503
504 void
505 xml_printf (FILE *out, int level, char const *fmt, ...)
506 {
507 int i;
508 va_list arglist;
509
510 for (i = 0; i < level; i++)
511 fputc (' ', out);
512
513 va_start (arglist, fmt);
514 vfprintf (out, fmt, arglist);
515 va_end (arglist);
516
517 fputc ('\n', out);
518 }
519
520 struct escape_buf
521 {
522 char *ptr;
523 size_t size;
524 };
525
526 static char const *
527 xml_escape_string (struct escape_buf *buf, char const *str)
528 {
529 size_t len = strlen (str);
530 size_t max_expansion = sizeof "&quot;" - 1;
531 char *p;
532
533 if (buf->size <= max_expansion * len)
534 {
535 buf->size = max_expansion * len + 1;
536 buf->ptr = x2realloc (buf->ptr, &buf->size);
537 }
538 p = buf->ptr;
539
540 for (; *str; str++)
541 switch (*str)
542 {
543 default: *p++ = *str; break;
544 case '&': p = stpcpy (p, "&amp;" ); break;
545 case '<': p = stpcpy (p, "&lt;" ); break;
546 case '>': p = stpcpy (p, "&gt;" ); break;
547 case '"': p = stpcpy (p, "&quot;"); break;
548 }
549
550 *p = '\0';
551 return buf->ptr;
552 }
553
554 char const *
555 xml_escape_n (int n, char const *str)
556 {
557 static struct escape_buf buf[2];
558 return xml_escape_string (buf + n, str);
559 }
560
561 char const *
562 xml_escape (char const *str)
563 {
564 return xml_escape_n (0, str);
565 }
566
567 void
568 print_xml (void)
569 {
570 state_number i;
571 int level = 0;
572
573 FILE *out = xfopen (spec_xml_file, "w");
574
575 fputs ("<?xml version=\"1.0\"?>\n\n", out);
576 xml_printf (out, level, "<bison-xml-report version=\"%s\">",
577 xml_escape (VERSION));
578
579 fputc ('\n', out);
580 xml_printf (out, level + 1, "<filename>%s</filename>",
581 xml_escape (grammar_file));
582
583 /* print reductions */
584 reduce_xml (out, level + 1);
585
586 /* print rules never reduced */
587 print_rules_never_reduced (out, level + 1);
588
589 /* print conflicts */
590 conflicts_output_xml (out, level + 1);
591
592 /* print grammar */
593 print_grammar (out, level + 1);
594
595 if (report_flag & report_itemsets)
596 new_closure (nritems);
597 no_reduce_set = bitset_create (ntokens, BITSET_FIXED);
598
599 /* print automaton */
600 fputc ('\n', out);
601 xml_puts (out, level + 1, "<automaton>");
602 for (i = 0; i < nstates; i++)
603 print_state (out, level + 2, states[i]);
604 xml_puts (out, level + 1, "</automaton>");
605
606 bitset_free (no_reduce_set);
607 if (report_flag & report_itemsets)
608 free_closure ();
609
610 xml_puts (out, 0, "</bison-xml-report>");
611
612 xfclose (out);
613 }