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