1 /* Print an xml on generated parser, for Bison,
3 Copyright (C) 2007, 2009-2015, 2018-2021 Free Software Foundation,
6 This file is part of Bison, the GNU Compiler Compiler.
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <https://www.gnu.org/licenses/>. */
22 #include "print-xml.h"
31 #include "conflicts.h"
38 #include "muscle-tab.h"
39 #include "path-join.h"
47 static bitset no_reduce_set
;
53 enum { num_escape_bufs
= 3 };
54 static struct escape_buf escape_bufs
[num_escape_bufs
];
57 /*--------------------------------.
58 | Report information on a state. |
59 `--------------------------------*/
62 print_core (FILE *out
, int level
, state
*s
)
64 item_index
*sitems
= s
->items
;
65 size_t snritems
= s
->nitems
;
67 /* Output all the items of a state, not only its kernel. */
68 closure (sitems
, snritems
);
74 xml_puts (out
, level
, "<itemset/>");
78 xml_puts (out
, level
, "<itemset>");
80 for (size_t i
= 0; i
< snritems
; i
++)
83 item_number
*sp1
= ritem
+ sitems
[i
];
84 rule
const *r
= item_rule (sp1
);
85 item_number
*sp
= r
->rhs
;
87 /* Display the lookahead tokens? */
88 if (item_number_is_rule_number (*sp1
))
90 reductions
*reds
= s
->reductions
;
91 int red
= state_reduction_find (s
, r
);
92 /* Print item with lookaheads if there are. */
93 if (reds
->lookaheads
&& red
!= -1)
95 xml_printf (out
, level
+ 1,
96 "<item rule-number=\"%d\" dot=\"%d\">",
98 state_rule_lookaheads_print_xml (s
, r
,
100 xml_puts (out
, level
+ 1, "</item>");
106 xml_printf (out
, level
+ 1,
107 "<item rule-number=\"%d\" dot=\"%d\"/>",
111 xml_puts (out
, level
, "</itemset>");
115 /*-----------------------------------------------------------.
116 | Report the shifts if DISPLAY_SHIFTS_P or the gotos of S on |
118 `-----------------------------------------------------------*/
121 print_transitions (state
*s
, FILE *out
, int level
)
123 transitions
*trans
= s
->transitions
;
127 for (i
= 0; i
< trans
->num
; i
++)
128 if (!TRANSITION_IS_DISABLED (trans
, i
))
133 /* Nothing to report. */
136 xml_puts (out
, level
, "<transitions/>");
140 /* Report lookahead tokens and shifts. */
141 xml_puts (out
, level
, "<transitions>");
143 for (i
= 0; i
< trans
->num
; i
++)
144 if (!TRANSITION_IS_DISABLED (trans
, i
)
145 && TRANSITION_IS_SHIFT (trans
, i
))
147 symbol
*sym
= symbols
[TRANSITION_SYMBOL (trans
, i
)];
148 char const *tag
= sym
->tag
;
149 state
*s1
= trans
->states
[i
];
151 xml_printf (out
, level
+ 1,
152 "<transition type=\"shift\" symbol=\"%s\" state=\"%d\"/>",
153 xml_escape (tag
), s1
->number
);
156 for (i
= 0; i
< trans
->num
; i
++)
157 if (!TRANSITION_IS_DISABLED (trans
, i
)
158 && !TRANSITION_IS_SHIFT (trans
, i
))
160 symbol
*sym
= symbols
[TRANSITION_SYMBOL (trans
, i
)];
161 char const *tag
= sym
->tag
;
162 state
*s1
= trans
->states
[i
];
164 xml_printf (out
, level
+ 1,
165 "<transition type=\"goto\" symbol=\"%s\" state=\"%d\"/>",
166 xml_escape (tag
), s1
->number
);
169 xml_puts (out
, level
, "</transitions>");
173 /*--------------------------------------------------------.
174 | Report the explicit errors of S raised from %nonassoc. |
175 `--------------------------------------------------------*/
178 print_errs (FILE *out
, int level
, state
*s
)
180 errs
*errp
= s
->errs
;
184 for (i
= 0; i
< errp
->num
; ++i
)
185 if (errp
->symbols
[i
])
188 /* Nothing to report. */
191 xml_puts (out
, level
, "<errors/>");
195 /* Report lookahead tokens and errors. */
196 xml_puts (out
, level
, "<errors>");
197 for (i
= 0; i
< errp
->num
; ++i
)
198 if (errp
->symbols
[i
])
200 char const *tag
= errp
->symbols
[i
]->tag
;
201 xml_printf (out
, level
+ 1,
202 "<error symbol=\"%s\">nonassociative</error>",
205 xml_puts (out
, level
, "</errors>");
209 /*-------------------------------------------------------------------.
210 | Report a reduction of RULE on LOOKAHEAD (which can be 'default'). |
211 | If not ENABLED, the rule is masked by a shift or a reduce (S/R and |
213 `-------------------------------------------------------------------*/
216 print_reduction (FILE *out
, int level
, char const *lookahead
,
217 rule
*r
, bool enabled
)
219 if (rule_is_initial (r
))
220 xml_printf (out
, level
,
221 "<reduction symbol=\"%s\" rule=\"accept\" enabled=\"%s\"/>",
222 xml_escape (lookahead
),
223 enabled
? "true" : "false");
225 xml_printf (out
, level
,
226 "<reduction symbol=\"%s\" rule=\"%d\" enabled=\"%s\"/>",
227 xml_escape (lookahead
),
229 enabled
? "true" : "false");
233 /*-------------------------------------------.
234 | Report on OUT the reduction actions of S. |
235 `-------------------------------------------*/
238 print_reductions (FILE *out
, int level
, state
*s
)
240 transitions
*trans
= s
->transitions
;
241 reductions
*reds
= s
->reductions
;
242 rule
*default_reduction
= NULL
;
248 xml_puts (out
, level
, "<reductions/>");
252 if (yydefact
[s
->number
] != 0)
253 default_reduction
= &rules
[yydefact
[s
->number
] - 1];
255 bitset_zero (no_reduce_set
);
256 FOR_EACH_SHIFT (trans
, i
)
257 bitset_set (no_reduce_set
, TRANSITION_SYMBOL (trans
, i
));
258 for (i
= 0; i
< s
->errs
->num
; ++i
)
259 if (s
->errs
->symbols
[i
])
260 bitset_set (no_reduce_set
, s
->errs
->symbols
[i
]->content
->number
);
262 if (default_reduction
)
265 if (reds
->lookaheads
)
266 for (i
= 0; i
< ntokens
; i
++)
268 bool count
= bitset_test (no_reduce_set
, i
);
270 for (j
= 0; j
< reds
->num
; ++j
)
271 if (bitset_test (reds
->lookaheads
[j
], i
))
275 if (reds
->rules
[j
] != default_reduction
)
286 /* Nothing to report. */
289 xml_puts (out
, level
, "<reductions/>");
293 xml_puts (out
, level
, "<reductions>");
295 /* Report lookahead tokens (or $default) and reductions. */
296 if (reds
->lookaheads
)
297 for (i
= 0; i
< ntokens
; i
++)
299 bool defaulted
= false;
300 bool count
= bitset_test (no_reduce_set
, i
);
302 for (j
= 0; j
< reds
->num
; ++j
)
303 if (bitset_test (reds
->lookaheads
[j
], i
))
307 if (reds
->rules
[j
] != default_reduction
)
308 print_reduction (out
, level
+ 1, symbols
[i
]->tag
,
309 reds
->rules
[j
], true);
317 print_reduction (out
, level
+ 1, symbols
[i
]->tag
,
318 default_reduction
, true);
320 print_reduction (out
, level
+ 1, symbols
[i
]->tag
,
321 reds
->rules
[j
], false);
326 if (default_reduction
)
327 print_reduction (out
, level
+ 1,
328 "$default", default_reduction
, true);
330 xml_puts (out
, level
, "</reductions>");
334 /*--------------------------------------------------------------.
335 | Report on OUT all the actions (shifts, gotos, reductions, and |
336 | explicit errors from %nonassoc) of S. |
337 `--------------------------------------------------------------*/
340 print_actions (FILE *out
, int level
, state
*s
)
342 xml_puts (out
, level
, "<actions>");
343 print_transitions (s
, out
, level
+ 1);
344 print_errs (out
, level
+ 1, s
);
345 print_reductions (out
, level
+ 1, s
);
346 xml_puts (out
, level
, "</actions>");
350 /*----------------------------------.
351 | Report all the data on S on OUT. |
352 `----------------------------------*/
355 print_state (FILE *out
, int level
, state
*s
)
358 xml_printf (out
, level
, "<state number=\"%d\">", s
->number
);
359 print_core (out
, level
+ 1, s
);
360 print_actions (out
, level
+ 1, s
);
361 if (s
->solved_conflicts_xml
)
363 xml_puts (out
, level
+ 1, "<solved-conflicts>");
364 fputs (s
->solved_conflicts_xml
, out
);
365 xml_puts (out
, level
+ 1, "</solved-conflicts>");
368 xml_puts (out
, level
+ 1, "<solved-conflicts/>");
369 xml_puts (out
, level
, "</state>");
373 /*-----------------------------------------.
374 | Print information on the whole grammar. |
375 `-----------------------------------------*/
378 print_grammar (FILE *out
, int level
)
381 xml_puts (out
, level
, "<grammar>");
382 grammar_rules_print_xml (out
, level
);
385 xml_puts (out
, level
+ 1, "<terminals>");
386 for (int i
= 0; i
< max_code
+ 1; i
++)
387 if (token_translations
[i
] != undeftoken
->content
->number
)
389 symbol
const *sym
= symbols
[token_translations
[i
]];
390 char const *tag
= sym
->tag
;
391 char const *type
= sym
->content
->type_name
;
392 int precedence
= sym
->content
->prec
;
393 assoc associativity
= sym
->content
->assoc
;
394 xml_indent (out
, level
+ 2);
396 "<terminal symbol-number=\"%d\" token-number=\"%d\""
397 " name=\"%s\" type=\"%s\" usefulness=\"%s\"",
398 token_translations
[i
], i
, xml_escape_n (0, tag
),
399 type
? xml_escape_n (1, type
) : "",
400 reduce_token_unused_in_grammar (token_translations
[i
])
401 ? "unused-in-grammar" : "useful");
403 fprintf (out
, " prec=\"%d\"", precedence
);
404 if (associativity
!= undef_assoc
)
405 fprintf (out
, " assoc=\"%s\"", assoc_to_string (associativity
) + 1);
408 xml_puts (out
, level
+ 1, "</terminals>");
411 xml_puts (out
, level
+ 1, "<nonterminals>");
412 for (symbol_number i
= ntokens
; i
< nsyms
+ nuseless_nonterminals
; i
++)
414 symbol
const *sym
= symbols
[i
];
415 char const *tag
= sym
->tag
;
416 char const *type
= sym
->content
->type_name
;
417 xml_printf (out
, level
+ 2,
418 "<nonterminal symbol-number=\"%d\" name=\"%s\""
420 " usefulness=\"%s\"/>",
421 i
, xml_escape_n (0, tag
),
422 type
? xml_escape_n (1, type
) : "",
423 reduce_nonterminal_useless_in_grammar (sym
->content
)
424 ? "useless-in-grammar" : "useful");
426 xml_puts (out
, level
+ 1, "</nonterminals>");
427 xml_puts (out
, level
, "</grammar>");
431 xml_indent (FILE *out
, int level
)
433 for (int i
= 0; i
< level
; i
++)
438 xml_puts (FILE *out
, int level
, char const *s
)
440 xml_indent (out
, level
);
446 xml_printf (FILE *out
, int level
, char const *fmt
, ...)
450 xml_indent (out
, level
);
452 va_start (arglist
, fmt
);
453 vfprintf (out
, fmt
, arglist
);
460 xml_escape_string (struct escape_buf
*buf
, char const *str
)
462 size_t len
= strlen (str
);
463 size_t max_expansion
= sizeof """ - 1;
465 if (buf
->size
<= max_expansion
* len
)
467 buf
->size
= max_expansion
* len
+ 1;
468 buf
->ptr
= x2realloc (buf
->ptr
, &buf
->size
);
475 default: *p
++ = *str
; break;
476 case '&': p
= stpcpy (p
, "&" ); break;
477 case '<': p
= stpcpy (p
, "<" ); break;
478 case '>': p
= stpcpy (p
, ">" ); break;
479 case '"': p
= stpcpy (p
, """); break;
487 xml_escape_n (int n
, char const *str
)
489 return xml_escape_string (escape_bufs
+ n
, str
);
493 xml_escape (char const *str
)
495 return xml_escape_n (0, str
);
501 FILE *out
= xfopen (spec_xml_file
, "w");
503 fputs ("<?xml version=\"1.0\"?>\n\n", out
);
506 xml_printf (out
, level
,
507 "<bison-xml-report version=\"%s\" bug-report=\"%s\""
509 xml_escape_n (0, VERSION
),
510 xml_escape_n (1, PACKAGE_BUGREPORT
),
511 xml_escape_n (2, PACKAGE_URL
));
514 xml_printf (out
, level
+ 1, "<filename>%s</filename>",
515 xml_escape (grammar_file
));
518 print_grammar (out
, level
+ 1);
520 no_reduce_set
= bitset_create (ntokens
, BITSET_FIXED
);
522 /* print automaton */
524 xml_puts (out
, level
+ 1, "<automaton>");
525 for (state_number i
= 0; i
< nstates
; i
++)
526 print_state (out
, level
+ 2, states
[i
]);
527 xml_puts (out
, level
+ 1, "</automaton>");
529 bitset_free (no_reduce_set
);
531 xml_puts (out
, 0, "</bison-xml-report>");
533 for (int i
= 0; i
< num_escape_bufs
; ++i
)
534 free (escape_bufs
[i
].ptr
);
545 char *xml2html
= xpath_join (pkgdatadir (), "xslt/xml2xhtml.xsl");
546 char *xsltproc
= muscle_percent_define_get ("tool.xsltproc");
547 char const *argv
[11];
549 argv
[i
++] = xsltproc
;
551 argv
[i
++] = spec_html_file
;
552 argv
[i
++] = xml2html
;
553 argv
[i
++] = spec_xml_file
;
555 aver (i
<= ARRAY_CARDINALITY (argv
));
557 if (trace_flag
& trace_tools
)
559 fputs ("running:", stderr
);
560 for (int j
= 0; argv
[j
]; ++j
)
561 fprintf (stderr
, " %s", argv
[j
]);
562 fputc ('\n', stderr
);
568 /* directory */ NULL
,
569 /* ignore_sigpipe */ false,
570 /* null_stdin, null_stdout, null_stderr */ true, true, true,
571 /* slave_process */ true, /* exit_on_error */ false,
572 /* termsigp */ NULL
);
574 complain (NULL
, complaint
, _("%s failed with status %d"), argv
[0], status
);