]> git.saurik.com Git - bison.git/blob - src/print-xml.c
* src/getargs.c (version): Update copyright year.
[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 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
155 static void
156 print_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
211 static void
212 print_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
248 static void
249 print_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
270 static void
271 print_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
370 static void
371 print_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
385 static void
386 print_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
408 static void
409 print_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
499 void
500 xml_puts (FILE *out, int level, char const *s)
501 {
502 int i;
503 for (i = 0; i < level; i++)
504 fputs (" ", out);
505 fputs (s, out);
506 fputc ('\n', out);
507 }
508
509 void
510 xml_printf (FILE *out, int level, char const *fmt, ...)
511 {
512 int i;
513 va_list arglist;
514
515 for (i = 0; i < level; i++)
516 fputs (" ", out);
517
518 va_start (arglist, fmt);
519 vfprintf (out, fmt, arglist);
520 va_end (arglist);
521
522 fputc ('\n', out);
523 }
524
525 static char const *
526 xml_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
553 char const *
554 xml_escape_n (int n, char const *str)
555 {
556 return xml_escape_string (escape_bufs + n, str);
557 }
558
559 char const *
560 xml_escape (char const *str)
561 {
562 return xml_escape_n (0, str);
563 }
564
565 void
566 print_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
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
607 free (escape_bufs[0].ptr);
608 free (escape_bufs[1].ptr);
609
610 xfclose (out);
611 }