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