]> git.saurik.com Git - bison.git/blame - src/print-xml.c
2007-11-08 Paolo Bonzini <bonzini@gnu.org>
[bison.git] / src / print-xml.c
CommitLineData
41d7a5f2
PE
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
45static bitset no_reduce_set;
34cdeddf
JD
46struct escape_buf
47{
48 char *ptr;
49 size_t size;
50};
51static struct escape_buf escape_bufs[2];
41d7a5f2
PE
52
53
54/*----------------------------.
55| Print rules never reduced. |
56`-----------------------------*/
57
58static void
59print_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
87static void
88print_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 {
25f6da67 111 bool printed = false;
41d7a5f2
PE
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);
25f6da67 122 sp = rules[r].rhs;
41d7a5f2
PE
123
124 /* Display the lookahead tokens? */
a0de5091
JD
125 if (report_flag & report_lookahead_tokens
126 && item_number_is_rule_number (*sp1))
25f6da67
WP
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 }
41d7a5f2 142
25f6da67
WP
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 }
41d7a5f2
PE
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
160static void
161print_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
216static void
217print_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
253static void
254print_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
275static void
276print_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
375static void
376print_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
390static void
391print_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
413static void
414print_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,
32f19b6b
JD
432 "<terminal symbol-number=\"%d\" token-number=\"%d\""
433 " name=\"%s\">",
434 token_translations[i], i, xml_escape (tag));
41d7a5f2
PE
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,
32f19b6b 469 "<nonterminal symbol-number=\"%d\" name=\"%s\">",
41d7a5f2
PE
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
505void
ad5feac4 506xml_puts (FILE *out, int level, char const *s)
41d7a5f2
PE
507{
508 int i;
41d7a5f2 509 for (i = 0; i < level; i++)
a4f75309 510 fputs (" ", out);
41d7a5f2
PE
511 fputs (s, out);
512 fputc ('\n', out);
513}
514
515void
516xml_printf (FILE *out, int level, char const *fmt, ...)
517{
518 int i;
519 va_list arglist;
520
521 for (i = 0; i < level; i++)
a4f75309 522 fputs (" ", out);
41d7a5f2
PE
523
524 va_start (arglist, fmt);
525 vfprintf (out, fmt, arglist);
526 va_end (arglist);
527
528 fputc ('\n', out);
529}
530
41d7a5f2
PE
531static char const *
532xml_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
559char const *
560xml_escape_n (int n, char const *str)
561{
34cdeddf 562 return xml_escape_string (escape_bufs + n, str);
41d7a5f2
PE
563}
564
565char const *
566xml_escape (char const *str)
567{
568 return xml_escape_n (0, str);
569}
570
571void
572print_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
41d7a5f2
PE
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
34cdeddf
JD
613 free (escape_bufs[0].ptr);
614 free (escape_bufs[1].ptr);
615
41d7a5f2
PE
616 xfclose (out);
617}