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