]> git.saurik.com Git - bison.git/blob - src/print-xml.c
maint: get gpl-3.0 from gnulib
[bison.git] / src / print-xml.c
1 /* Print an xml on generated parser, for Bison,
2
3 Copyright (C) 2007, 2009-2012 Free Software Foundation, Inc.
4
5 This file is part of Bison, the GNU Compiler Compiler.
6
7 This program 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 3 of the License, or
10 (at your option) any later version.
11
12 This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */
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
43 static bitset no_reduce_set;
44 struct escape_buf
45 {
46 char *ptr;
47 size_t size;
48 };
49 static struct escape_buf escape_bufs[3];
50
51
52 /*--------------------------------.
53 | Report information on a state. |
54 `--------------------------------*/
55
56 static void
57 print_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. */
64 closure (sitems, snritems);
65 sitems = itemset;
66 snritems = nitemset;
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 {
77 bool printed = false;
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);
88 sp = rules[r].rhs;
89
90 /* Display the lookahead tokens? */
91 if (item_number_is_rule_number (*sp1))
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 }
107
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 }
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
125 static void
126 print_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
181 static void
182 print_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
218 static void
219 print_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
240 static void
241 print_reductions (FILE *out, int level, state *s)
242 {
243 transitions *trans = s->transitions;
244 reductions *reds = s->reductions;
245 rule *default_reduction = NULL;
246 int report = false;
247 int i, j;
248
249 if (reds->num == 0)
250 {
251 xml_puts (out, level, "<reductions/>");
252 return;
253 }
254
255 if (yydefact[s->number] != 0)
256 default_reduction = &rules[yydefact[s->number] - 1];
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
265 if (default_reduction)
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 {
278 if (reds->rules[j] != default_reduction)
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 {
309 if (reds->rules[j] != default_reduction)
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,
320 default_reduction, true);
321 defaulted = false;
322 print_reduction (out, level + 1, symbols[i]->tag,
323 reds->rules[j], false);
324 }
325 }
326 }
327
328 if (default_reduction)
329 print_reduction (out, level + 1,
330 "$default", default_reduction, true);
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
341 static void
342 print_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
356 static void
357 print_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);
363 if (s->solved_conflicts_xml)
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
379 static void
380 print_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;
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);
408 }
409 xml_puts (out, level + 1, "</terminals>");
410
411 /* Nonterminals */
412 xml_puts (out, level + 1, "<nonterminals>");
413 for (i = ntokens; i < nsyms + nuseless_nonterminals; i++)
414 {
415 char const *tag = symbols[i]->tag;
416 xml_printf (out, level + 2,
417 "<nonterminal symbol-number=\"%d\" name=\"%s\""
418 " usefulness=\"%s\"/>",
419 i, xml_escape (tag),
420 reduce_nonterminal_useless_in_grammar (i)
421 ? "useless-in-grammar" : "useful");
422 }
423 xml_puts (out, level + 1, "</nonterminals>");
424 xml_puts (out, level, "</grammar>");
425 }
426
427 void
428 xml_indent (FILE *out, int level)
429 {
430 int i;
431 for (i = 0; i < level; i++)
432 fputs (" ", out);
433 }
434
435 void
436 xml_puts (FILE *out, int level, char const *s)
437 {
438 xml_indent (out, level);
439 fputs (s, out);
440 fputc ('\n', out);
441 }
442
443 void
444 xml_printf (FILE *out, int level, char const *fmt, ...)
445 {
446 va_list arglist;
447
448 xml_indent (out, level);
449
450 va_start (arglist, fmt);
451 vfprintf (out, fmt, arglist);
452 va_end (arglist);
453
454 fputc ('\n', out);
455 }
456
457 static char const *
458 xml_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
485 char const *
486 xml_escape_n (int n, char const *str)
487 {
488 return xml_escape_string (escape_bufs + n, str);
489 }
490
491 char const *
492 xml_escape (char const *str)
493 {
494 return xml_escape_n (0, str);
495 }
496
497 void
498 print_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);
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));
512
513 fputc ('\n', out);
514 xml_printf (out, level + 1, "<filename>%s</filename>",
515 xml_escape (grammar_file));
516
517 /* print grammar */
518 print_grammar (out, level + 1);
519
520 new_closure (nritems);
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);
531 free_closure ();
532
533 xml_puts (out, 0, "</bison-xml-report>");
534
535 free (escape_bufs[0].ptr);
536 free (escape_bufs[1].ptr);
537
538 xfclose (out);
539 }