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