]> git.saurik.com Git - bison.git/blame - src/print-xml.c
maint: catch missing gnulib macros.
[bison.git] / src / print-xml.c
CommitLineData
41d7a5f2
PE
1/* Print an xml on generated parser, for Bison,
2
c932d613 3 Copyright (C) 2007, 2009-2012 Free Software Foundation, Inc.
41d7a5f2
PE
4
5 This file is part of Bison, the GNU Compiler Compiler.
6
fea2d6b0 7 This program is free software: you can redistribute it and/or modify
41d7a5f2 8 it under the terms of the GNU General Public License as published by
fea2d6b0
JD
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
41d7a5f2 11
fea2d6b0 12 This program is distributed in the hope that it will be useful,
41d7a5f2
PE
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
fea2d6b0 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
41d7a5f2
PE
19
20#include <config.h>
21#include "system.h"
22
23#include <stdarg.h>
24
25#include <bitset.h>
26#include <quotearg.h>
27
28#include "LR0.h"
29#include "closure.h"
30#include "conflicts.h"
31#include "files.h"
32#include "getargs.h"
33#include "gram.h"
34#include "lalr.h"
35#include "print.h"
36#include "print-xml.h"
37#include "reader.h"
38#include "reduce.h"
39#include "state.h"
40#include "symtab.h"
41#include "tables.h"
42
43static bitset no_reduce_set;
34cdeddf
JD
44struct escape_buf
45{
46 char *ptr;
47 size_t size;
48};
ca7a59e8 49static struct escape_buf escape_bufs[3];
41d7a5f2
PE
50
51
41d7a5f2
PE
52/*--------------------------------.
53| Report information on a state. |
54`--------------------------------*/
55
56static void
57print_core (FILE *out, int level, state *s)
58{
59 size_t i;
60 item_number *sitems = s->items;
61 size_t snritems = s->nitems;
62
63 /* Output all the items of a state, not only its kernel. */
ef1b4273
JD
64 closure (sitems, snritems);
65 sitems = itemset;
66 snritems = nitemset;
41d7a5f2
PE
67
68 if (!snritems) {
69 xml_puts (out, level, "<itemset/>");
70 return;
71 }
72
73 xml_puts (out, level, "<itemset>");
74
75 for (i = 0; i < snritems; i++)
76 {
25f6da67 77 bool printed = false;
41d7a5f2
PE
78 item_number *sp;
79 item_number *sp1;
80 rule_number r;
81
82 sp1 = sp = ritem + sitems[i];
83
84 while (*sp >= 0)
85 sp++;
86
87 r = item_number_as_rule_number (*sp);
25f6da67 88 sp = rules[r].rhs;
41d7a5f2
PE
89
90 /* Display the lookahead tokens? */
ef1b4273 91 if (item_number_is_rule_number (*sp1))
25f6da67
WP
92 {
93 reductions *reds = s->reductions;
94 int red = state_reduction_find (s, &rules[r]);
95 /* Print item with lookaheads if there are. */
96 if (reds->lookahead_tokens && red != -1)
97 {
98 xml_printf (out, level + 1,
99 "<item rule-number=\"%d\" point=\"%d\">",
100 rules[r].number, sp1 - sp);
101 state_rule_lookahead_tokens_print_xml (s, &rules[r],
102 out, level + 2);
103 xml_puts (out, level + 1, "</item>");
104 printed = true;
105 }
106 }
41d7a5f2 107
25f6da67
WP
108 if (!printed)
109 {
110 xml_printf (out, level + 1,
111 "<item rule-number=\"%d\" point=\"%d\"/>",
112 rules[r].number,
113 sp1 - sp);
114 }
41d7a5f2
PE
115 }
116 xml_puts (out, level, "</itemset>");
117}
118
119
120/*-----------------------------------------------------------.
121| Report the shifts if DISPLAY_SHIFTS_P or the gotos of S on |
122| OUT. |
123`-----------------------------------------------------------*/
124
125static void
126print_transitions (state *s, FILE *out, int level)
127{
128 transitions *trans = s->transitions;
129 int n = 0;
130 int i;
131
132 for (i = 0; i < trans->num; i++)
133 if (!TRANSITION_IS_DISABLED (trans, i))
134 {
135 n++;
136 }
137
138 /* Nothing to report. */
139 if (!n) {
140 xml_puts (out, level, "<transitions/>");
141 return;
142 }
143
144 /* Report lookahead tokens and shifts. */
145 xml_puts (out, level, "<transitions>");
146
147 for (i = 0; i < trans->num; i++)
148 if (!TRANSITION_IS_DISABLED (trans, i)
149 && TRANSITION_IS_SHIFT (trans, i))
150 {
151 symbol *sym = symbols[TRANSITION_SYMBOL (trans, i)];
152 char const *tag = sym->tag;
153 state *s1 = trans->states[i];
154
155 xml_printf (out, level + 1,
156 "<transition type=\"shift\" symbol=\"%s\" state=\"%d\"/>",
157 xml_escape (tag), s1->number);
158 }
159
160 for (i = 0; i < trans->num; i++)
161 if (!TRANSITION_IS_DISABLED (trans, i)
162 && !TRANSITION_IS_SHIFT (trans, i))
163 {
164 symbol *sym = symbols[TRANSITION_SYMBOL (trans, i)];
165 char const *tag = sym->tag;
166 state *s1 = trans->states[i];
167
168 xml_printf (out, level + 1,
169 "<transition type=\"goto\" symbol=\"%s\" state=\"%d\"/>",
170 xml_escape (tag), s1->number);
171 }
172
173 xml_puts (out, level, "</transitions>");
174}
175
176
177/*--------------------------------------------------------.
178| Report the explicit errors of S raised from %nonassoc. |
179`--------------------------------------------------------*/
180
181static void
182print_errs (FILE *out, int level, state *s)
183{
184 errs *errp = s->errs;
185 bool count = false;
186 int i;
187
188 for (i = 0; i < errp->num; ++i)
189 if (errp->symbols[i])
190 count = true;
191
192 /* Nothing to report. */
193 if (!count) {
194 xml_puts (out, level, "<errors/>");
195 return;
196 }
197
198 /* Report lookahead tokens and errors. */
199 xml_puts (out, level, "<errors>");
200 for (i = 0; i < errp->num; ++i)
201 if (errp->symbols[i])
202 {
203 char const *tag = errp->symbols[i]->tag;
204 xml_printf (out, level + 1,
205 "<error symbol=\"%s\">nonassociative</error>",
206 xml_escape (tag));
207 }
208 xml_puts (out, level, "</errors>");
209}
210
211
212/*-------------------------------------------------------------------------.
213| Report a reduction of RULE on LOOKAHEAD_TOKEN (which can be `default'). |
214| If not ENABLED, the rule is masked by a shift or a reduce (S/R and |
215| R/R conflicts). |
216`-------------------------------------------------------------------------*/
217
218static void
219print_reduction (FILE *out, int level, char const *lookahead_token,
220 rule *r, bool enabled)
221{
222 if (r->number)
223 xml_printf (out, level,
224 "<reduction symbol=\"%s\" rule=\"%d\" enabled=\"%s\"/>",
225 xml_escape (lookahead_token),
226 r->number,
227 enabled ? "true" : "false");
228 else
229 xml_printf (out, level,
230 "<reduction symbol=\"%s\" rule=\"accept\" enabled=\"%s\"/>",
231 xml_escape (lookahead_token),
232 enabled ? "true" : "false");
233}
234
235
236/*-------------------------------------------.
237| Report on OUT the reduction actions of S. |
238`-------------------------------------------*/
239
240static void
241print_reductions (FILE *out, int level, state *s)
242{
243 transitions *trans = s->transitions;
244 reductions *reds = s->reductions;
620b5727 245 rule *default_reduction = NULL;
41d7a5f2
PE
246 int report = false;
247 int i, j;
248
83b66ddd
AD
249 if (reds->num == 0)
250 {
251 xml_puts (out, level, "<reductions/>");
252 return;
253 }
41d7a5f2
PE
254
255 if (yydefact[s->number] != 0)
620b5727 256 default_reduction = &rules[yydefact[s->number] - 1];
41d7a5f2
PE
257
258 bitset_zero (no_reduce_set);
259 FOR_EACH_SHIFT (trans, i)
260 bitset_set (no_reduce_set, TRANSITION_SYMBOL (trans, i));
261 for (i = 0; i < s->errs->num; ++i)
262 if (s->errs->symbols[i])
263 bitset_set (no_reduce_set, s->errs->symbols[i]->number);
264
620b5727 265 if (default_reduction)
41d7a5f2
PE
266 report = true;
267
268 if (reds->lookahead_tokens)
269 for (i = 0; i < ntokens; i++)
270 {
271 bool count = bitset_test (no_reduce_set, i);
272
273 for (j = 0; j < reds->num; ++j)
274 if (bitset_test (reds->lookahead_tokens[j], i))
275 {
276 if (! count)
277 {
620b5727 278 if (reds->rules[j] != default_reduction)
41d7a5f2
PE
279 report = true;
280 count = true;
281 }
282 else
283 {
284 report = true;
285 }
286 }
287 }
288
289 /* Nothing to report. */
290 if (!report) {
291 xml_puts (out, level, "<reductions/>");
292 return;
293 }
294
295 xml_puts (out, level, "<reductions>");
296
297 /* Report lookahead tokens (or $default) and reductions. */
298 if (reds->lookahead_tokens)
299 for (i = 0; i < ntokens; i++)
300 {
301 bool defaulted = false;
302 bool count = bitset_test (no_reduce_set, i);
303
304 for (j = 0; j < reds->num; ++j)
305 if (bitset_test (reds->lookahead_tokens[j], i))
306 {
307 if (! count)
308 {
620b5727 309 if (reds->rules[j] != default_reduction)
41d7a5f2
PE
310 print_reduction (out, level + 1, symbols[i]->tag,
311 reds->rules[j], true);
312 else
313 defaulted = true;
314 count = true;
315 }
316 else
317 {
318 if (defaulted)
319 print_reduction (out, level + 1, symbols[i]->tag,
620b5727 320 default_reduction, true);
41d7a5f2
PE
321 defaulted = false;
322 print_reduction (out, level + 1, symbols[i]->tag,
323 reds->rules[j], false);
324 }
325 }
326 }
327
620b5727 328 if (default_reduction)
41d7a5f2 329 print_reduction (out, level + 1,
620b5727 330 "$default", default_reduction, true);
41d7a5f2
PE
331
332 xml_puts (out, level, "</reductions>");
333}
334
335
336/*--------------------------------------------------------------.
337| Report on OUT all the actions (shifts, gotos, reductions, and |
338| explicit erros from %nonassoc) of S. |
339`--------------------------------------------------------------*/
340
341static void
342print_actions (FILE *out, int level, state *s)
343{
344 xml_puts (out, level, "<actions>");
345 print_transitions (s, out, level + 1);
346 print_errs (out, level + 1, s);
347 print_reductions (out, level + 1, s);
348 xml_puts (out, level, "</actions>");
349}
350
351
352/*----------------------------------.
353| Report all the data on S on OUT. |
354`----------------------------------*/
355
356static void
357print_state (FILE *out, int level, state *s)
358{
359 fputc ('\n', out);
360 xml_printf (out, level, "<state number=\"%d\">", s->number);
361 print_core (out, level + 1, s);
362 print_actions (out, level + 1, s);
ef1b4273 363 if (s->solved_conflicts_xml)
41d7a5f2
PE
364 {
365 xml_puts (out, level + 1, "<solved-conflicts>");
366 fputs (s->solved_conflicts_xml, out);
367 xml_puts (out, level + 1, "</solved-conflicts>");
368 }
369 else
370 xml_puts (out, level + 1, "<solved-conflicts/>");
371 xml_puts (out, level, "</state>");
372}
373
374
375/*-----------------------------------------.
376| Print information on the whole grammar. |
377`-----------------------------------------*/
378
379static void
380print_grammar (FILE *out, int level)
381{
382 symbol_number i;
383
384 fputc ('\n', out);
385 xml_puts (out, level, "<grammar>");
386 grammar_rules_print_xml (out, level);
387
388 /* Terminals */
389 xml_puts (out, level + 1, "<terminals>");
390 for (i = 0; i < max_user_token_number + 1; i++)
391 if (token_translations[i] != undeftoken->number)
392 {
393 char const *tag = symbols[token_translations[i]]->tag;
408476bc
JD
394 int precedence = symbols[token_translations[i]]->prec;
395 assoc associativity = symbols[token_translations[i]]->assoc;
396 xml_indent (out, level + 2);
397 fprintf (out,
398 "<terminal symbol-number=\"%d\" token-number=\"%d\""
399 " name=\"%s\" usefulness=\"%s\"",
400 token_translations[i], i, xml_escape (tag),
401 reduce_token_unused_in_grammar (token_translations[i])
402 ? "unused-in-grammar" : "useful");
403 if (precedence)
404 fprintf (out, " prec=\"%d\"", precedence);
405 if (associativity != undef_assoc)
406 fprintf (out, " assoc=\"%s\"", assoc_to_string (associativity) + 1);
407 fputs ("/>\n", out);
41d7a5f2
PE
408 }
409 xml_puts (out, level + 1, "</terminals>");
410
411 /* Nonterminals */
412 xml_puts (out, level + 1, "<nonterminals>");
d80fb37a 413 for (i = ntokens; i < nsyms + nuseless_nonterminals; i++)
41d7a5f2 414 {
41d7a5f2 415 char const *tag = symbols[i]->tag;
41d7a5f2 416 xml_printf (out, level + 2,
d80fb37a 417 "<nonterminal symbol-number=\"%d\" name=\"%s\""
d4a26c48 418 " usefulness=\"%s\"/>",
d80fb37a
JD
419 i, xml_escape (tag),
420 reduce_nonterminal_useless_in_grammar (i)
421 ? "useless-in-grammar" : "useful");
41d7a5f2
PE
422 }
423 xml_puts (out, level + 1, "</nonterminals>");
424 xml_puts (out, level, "</grammar>");
425}
426
427void
408476bc 428xml_indent (FILE *out, int level)
41d7a5f2
PE
429{
430 int i;
41d7a5f2 431 for (i = 0; i < level; i++)
a4f75309 432 fputs (" ", out);
408476bc
JD
433}
434
435void
436xml_puts (FILE *out, int level, char const *s)
437{
438 xml_indent (out, level);
41d7a5f2
PE
439 fputs (s, out);
440 fputc ('\n', out);
441}
442
443void
444xml_printf (FILE *out, int level, char const *fmt, ...)
445{
41d7a5f2
PE
446 va_list arglist;
447
408476bc 448 xml_indent (out, level);
41d7a5f2
PE
449
450 va_start (arglist, fmt);
451 vfprintf (out, fmt, arglist);
452 va_end (arglist);
453
454 fputc ('\n', out);
455}
456
41d7a5f2
PE
457static char const *
458xml_escape_string (struct escape_buf *buf, char const *str)
459{
460 size_t len = strlen (str);
461 size_t max_expansion = sizeof "&quot;" - 1;
462 char *p;
463
464 if (buf->size <= max_expansion * len)
465 {
466 buf->size = max_expansion * len + 1;
467 buf->ptr = x2realloc (buf->ptr, &buf->size);
468 }
469 p = buf->ptr;
470
471 for (; *str; str++)
472 switch (*str)
473 {
474 default: *p++ = *str; break;
475 case '&': p = stpcpy (p, "&amp;" ); break;
476 case '<': p = stpcpy (p, "&lt;" ); break;
477 case '>': p = stpcpy (p, "&gt;" ); break;
478 case '"': p = stpcpy (p, "&quot;"); break;
479 }
480
481 *p = '\0';
482 return buf->ptr;
483}
484
485char const *
486xml_escape_n (int n, char const *str)
487{
34cdeddf 488 return xml_escape_string (escape_bufs + n, str);
41d7a5f2
PE
489}
490
491char const *
492xml_escape (char const *str)
493{
494 return xml_escape_n (0, str);
495}
496
497void
498print_xml (void)
499{
500 state_number i;
501 int level = 0;
502
503 FILE *out = xfopen (spec_xml_file, "w");
504
505 fputs ("<?xml version=\"1.0\"?>\n\n", out);
ca7a59e8
JD
506 xml_printf (out, level,
507 "<bison-xml-report version=\"%s\" bug-report=\"%s\""
508 " url=\"%s\">",
509 xml_escape_n (0, VERSION),
510 xml_escape_n (1, PACKAGE_BUGREPORT),
511 xml_escape_n (2, PACKAGE_URL));
41d7a5f2
PE
512
513 fputc ('\n', out);
514 xml_printf (out, level + 1, "<filename>%s</filename>",
515 xml_escape (grammar_file));
516
41d7a5f2
PE
517 /* print grammar */
518 print_grammar (out, level + 1);
519
ef1b4273 520 new_closure (nritems);
41d7a5f2
PE
521 no_reduce_set = bitset_create (ntokens, BITSET_FIXED);
522
523 /* print automaton */
524 fputc ('\n', out);
525 xml_puts (out, level + 1, "<automaton>");
526 for (i = 0; i < nstates; i++)
527 print_state (out, level + 2, states[i]);
528 xml_puts (out, level + 1, "</automaton>");
529
530 bitset_free (no_reduce_set);
ef1b4273 531 free_closure ();
41d7a5f2
PE
532
533 xml_puts (out, 0, "</bison-xml-report>");
534
34cdeddf
JD
535 free (escape_bufs[0].ptr);
536 free (escape_bufs[1].ptr);
537
41d7a5f2
PE
538 xfclose (out);
539}