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