]> git.saurik.com Git - bison.git/blame - src/print-xml.c
2007-10-17 Wojciech Polak <polak@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,
cd4a9a59 432 "<terminal number=\"%d\" name=\"%s\">",
41d7a5f2
PE
433 i, xml_escape (tag));
434
435 for (r = 0; r < nrules; r++)
436 for (rhsp = rules[r].rhs; *rhsp >= 0; rhsp++)
437 if (item_number_as_symbol_number (*rhsp) == token_translations[i])
438 {
439 xml_printf (out, level + 3, "<rule>%d</rule>", r);
440 break;
441 }
442 xml_puts (out, level + 2, "</terminal>");
443 }
444 xml_puts (out, level + 1, "</terminals>");
445
446 /* Nonterminals */
447 xml_puts (out, level + 1, "<nonterminals>");
448 for (i = ntokens; i < nsyms; i++)
449 {
450 int left_count = 0, right_count = 0;
451 rule_number r;
452 char const *tag = symbols[i]->tag;
453
454 for (r = 0; r < nrules; r++)
455 {
456 item_number *rhsp;
457 if (rules[r].lhs->number == i)
458 left_count++;
459 for (rhsp = rules[r].rhs; *rhsp >= 0; rhsp++)
460 if (item_number_as_symbol_number (*rhsp) == i)
461 {
462 right_count++;
463 break;
464 }
465 }
466
467 xml_printf (out, level + 2,
cd4a9a59 468 "<nonterminal number=\"%d\" name=\"%s\">",
41d7a5f2
PE
469 i, xml_escape (tag));
470
471 if (left_count > 0)
472 {
473 xml_puts (out, level + 3, "<left>");
474 for (r = 0; r < nrules; r++)
475 {
476 if (rules[r].lhs->number == i)
477 xml_printf (out, level + 4, "<rule>%d</rule>", r);
478 }
479 xml_puts (out, level + 3, "</left>");
480 }
481
482 if (right_count > 0)
483 {
484 xml_puts (out, level + 3, "<right>");
485 for (r = 0; r < nrules; r++)
486 {
487 item_number *rhsp;
488 for (rhsp = rules[r].rhs; *rhsp >= 0; rhsp++)
489 if (item_number_as_symbol_number (*rhsp) == i)
490 {
491 xml_printf (out, level + 4, "<rule>%d</rule>", r);
492 break;
493 }
494 }
495 xml_puts (out, level + 3, "</right>");
496 }
497
498 xml_puts (out, level + 2, "</nonterminal>");
499 }
500 xml_puts (out, level + 1, "</nonterminals>");
501 xml_puts (out, level, "</grammar>");
502}
503
504void
ad5feac4 505xml_puts (FILE *out, int level, char const *s)
41d7a5f2
PE
506{
507 int i;
41d7a5f2 508 for (i = 0; i < level; i++)
a4f75309 509 fputs (" ", out);
41d7a5f2
PE
510 fputs (s, out);
511 fputc ('\n', out);
512}
513
514void
515xml_printf (FILE *out, int level, char const *fmt, ...)
516{
517 int i;
518 va_list arglist;
519
520 for (i = 0; i < level; i++)
a4f75309 521 fputs (" ", out);
41d7a5f2
PE
522
523 va_start (arglist, fmt);
524 vfprintf (out, fmt, arglist);
525 va_end (arglist);
526
527 fputc ('\n', out);
528}
529
41d7a5f2
PE
530static char const *
531xml_escape_string (struct escape_buf *buf, char const *str)
532{
533 size_t len = strlen (str);
534 size_t max_expansion = sizeof "&quot;" - 1;
535 char *p;
536
537 if (buf->size <= max_expansion * len)
538 {
539 buf->size = max_expansion * len + 1;
540 buf->ptr = x2realloc (buf->ptr, &buf->size);
541 }
542 p = buf->ptr;
543
544 for (; *str; str++)
545 switch (*str)
546 {
547 default: *p++ = *str; break;
548 case '&': p = stpcpy (p, "&amp;" ); break;
549 case '<': p = stpcpy (p, "&lt;" ); break;
550 case '>': p = stpcpy (p, "&gt;" ); break;
551 case '"': p = stpcpy (p, "&quot;"); break;
552 }
553
554 *p = '\0';
555 return buf->ptr;
556}
557
558char const *
559xml_escape_n (int n, char const *str)
560{
34cdeddf 561 return xml_escape_string (escape_bufs + n, str);
41d7a5f2
PE
562}
563
564char const *
565xml_escape (char const *str)
566{
567 return xml_escape_n (0, str);
568}
569
570void
571print_xml (void)
572{
573 state_number i;
574 int level = 0;
575
576 FILE *out = xfopen (spec_xml_file, "w");
577
578 fputs ("<?xml version=\"1.0\"?>\n\n", out);
579 xml_printf (out, level, "<bison-xml-report version=\"%s\">",
580 xml_escape (VERSION));
581
582 fputc ('\n', out);
583 xml_printf (out, level + 1, "<filename>%s</filename>",
584 xml_escape (grammar_file));
585
586 /* print reductions */
587 reduce_xml (out, level + 1);
588
589 /* print rules never reduced */
590 print_rules_never_reduced (out, level + 1);
591
41d7a5f2
PE
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
34cdeddf
JD
612 free (escape_bufs[0].ptr);
613 free (escape_bufs[1].ptr);
614
41d7a5f2
PE
615 xfclose (out);
616}