]> git.saurik.com Git - bison.git/blob - src/print-xml.c
c++: style: use "unsigned", not "unsigned int"
[bison.git] / src / print-xml.c
1 /* Print an xml on generated parser, for Bison,
2
3 Copyright (C) 2007, 2009-2015 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
27 #include "LR0.h"
28 #include "closure.h"
29 #include "conflicts.h"
30 #include "files.h"
31 #include "getargs.h"
32 #include "gram.h"
33 #include "lalr.h"
34 #include "print.h"
35 #include "print-xml.h"
36 #include "reader.h"
37 #include "reduce.h"
38 #include "state.h"
39 #include "symtab.h"
40 #include "tables.h"
41
42 static bitset no_reduce_set;
43 struct escape_buf
44 {
45 char *ptr;
46 size_t size;
47 };
48 enum { num_escape_bufs = 3 };
49 static struct escape_buf escape_bufs[num_escape_bufs];
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 {
70 xml_puts (out, level, "<itemset/>");
71 return;
72 }
73
74 xml_puts (out, level, "<itemset>");
75
76 for (i = 0; i < snritems; i++)
77 {
78 bool printed = false;
79 item_number *sp1 = ritem + sitems[i];
80 item_number *sp = sp1;
81 rule *r;
82
83 while (0 <= *sp)
84 sp++;
85
86 r = &rules[item_number_as_rule_number (*sp)];
87 sp = r->rhs;
88
89 /* Display the lookahead tokens? */
90 if (item_number_is_rule_number (*sp1))
91 {
92 reductions *reds = s->reductions;
93 int red = state_reduction_find (s, r);
94 /* Print item with lookaheads if there are. */
95 if (reds->lookahead_tokens && red != -1)
96 {
97 xml_printf (out, level + 1,
98 "<item rule-number=\"%d\" point=\"%d\">",
99 r->number, sp1 - sp);
100 state_rule_lookahead_tokens_print_xml (s, r,
101 out, level + 2);
102 xml_puts (out, level + 1, "</item>");
103 printed = true;
104 }
105 }
106
107 if (!printed)
108 xml_printf (out, level + 1,
109 "<item rule-number=\"%d\" point=\"%d\"/>",
110 r->number,
111 sp1 - sp);
112 }
113 xml_puts (out, level, "</itemset>");
114 }
115
116
117 /*-----------------------------------------------------------.
118 | Report the shifts if DISPLAY_SHIFTS_P or the gotos of S on |
119 | OUT. |
120 `-----------------------------------------------------------*/
121
122 static void
123 print_transitions (state *s, FILE *out, int level)
124 {
125 transitions *trans = s->transitions;
126 int n = 0;
127 int i;
128
129 for (i = 0; i < trans->num; i++)
130 if (!TRANSITION_IS_DISABLED (trans, i))
131 {
132 n++;
133 }
134
135 /* Nothing to report. */
136 if (!n)
137 {
138 xml_puts (out, level, "<transitions/>");
139 return;
140 }
141
142 /* Report lookahead tokens and shifts. */
143 xml_puts (out, level, "<transitions>");
144
145 for (i = 0; i < trans->num; i++)
146 if (!TRANSITION_IS_DISABLED (trans, i)
147 && TRANSITION_IS_SHIFT (trans, i))
148 {
149 symbol *sym = symbols[TRANSITION_SYMBOL (trans, i)];
150 char const *tag = sym->tag;
151 state *s1 = trans->states[i];
152
153 xml_printf (out, level + 1,
154 "<transition type=\"shift\" symbol=\"%s\" state=\"%d\"/>",
155 xml_escape (tag), s1->number);
156 }
157
158 for (i = 0; i < trans->num; i++)
159 if (!TRANSITION_IS_DISABLED (trans, i)
160 && !TRANSITION_IS_SHIFT (trans, i))
161 {
162 symbol *sym = symbols[TRANSITION_SYMBOL (trans, i)];
163 char const *tag = sym->tag;
164 state *s1 = trans->states[i];
165
166 xml_printf (out, level + 1,
167 "<transition type=\"goto\" symbol=\"%s\" state=\"%d\"/>",
168 xml_escape (tag), s1->number);
169 }
170
171 xml_puts (out, level, "</transitions>");
172 }
173
174
175 /*--------------------------------------------------------.
176 | Report the explicit errors of S raised from %nonassoc. |
177 `--------------------------------------------------------*/
178
179 static void
180 print_errs (FILE *out, int level, state *s)
181 {
182 errs *errp = s->errs;
183 bool count = false;
184 int i;
185
186 for (i = 0; i < errp->num; ++i)
187 if (errp->symbols[i])
188 count = true;
189
190 /* Nothing to report. */
191 if (!count)
192 {
193 xml_puts (out, level, "<errors/>");
194 return;
195 }
196
197 /* Report lookahead tokens and errors. */
198 xml_puts (out, level, "<errors>");
199 for (i = 0; i < errp->num; ++i)
200 if (errp->symbols[i])
201 {
202 char const *tag = errp->symbols[i]->tag;
203 xml_printf (out, level + 1,
204 "<error symbol=\"%s\">nonassociative</error>",
205 xml_escape (tag));
206 }
207 xml_puts (out, level, "</errors>");
208 }
209
210
211 /*-------------------------------------------------------------------------.
212 | Report a reduction of RULE on LOOKAHEAD_TOKEN (which can be 'default'). |
213 | If not ENABLED, the rule is masked by a shift or a reduce (S/R and |
214 | R/R conflicts). |
215 `-------------------------------------------------------------------------*/
216
217 static void
218 print_reduction (FILE *out, int level, char const *lookahead_token,
219 rule *r, bool enabled)
220 {
221 if (r->number)
222 xml_printf (out, level,
223 "<reduction symbol=\"%s\" rule=\"%d\" enabled=\"%s\"/>",
224 xml_escape (lookahead_token),
225 r->number,
226 enabled ? "true" : "false");
227 else
228 xml_printf (out, level,
229 "<reduction symbol=\"%s\" rule=\"accept\" enabled=\"%s\"/>",
230 xml_escape (lookahead_token),
231 enabled ? "true" : "false");
232 }
233
234
235 /*-------------------------------------------.
236 | Report on OUT the reduction actions of S. |
237 `-------------------------------------------*/
238
239 static void
240 print_reductions (FILE *out, int level, state *s)
241 {
242 transitions *trans = s->transitions;
243 reductions *reds = s->reductions;
244 rule *default_reduction = NULL;
245 int report = false;
246 int i, j;
247
248 if (reds->num == 0)
249 {
250 xml_puts (out, level, "<reductions/>");
251 return;
252 }
253
254 if (yydefact[s->number] != 0)
255 default_reduction = &rules[yydefact[s->number] - 1];
256
257 bitset_zero (no_reduce_set);
258 FOR_EACH_SHIFT (trans, i)
259 bitset_set (no_reduce_set, TRANSITION_SYMBOL (trans, i));
260 for (i = 0; i < s->errs->num; ++i)
261 if (s->errs->symbols[i])
262 bitset_set (no_reduce_set, s->errs->symbols[i]->number);
263
264 if (default_reduction)
265 report = true;
266
267 if (reds->lookahead_tokens)
268 for (i = 0; i < ntokens; i++)
269 {
270 bool count = bitset_test (no_reduce_set, i);
271
272 for (j = 0; j < reds->num; ++j)
273 if (bitset_test (reds->lookahead_tokens[j], i))
274 {
275 if (! count)
276 {
277 if (reds->rules[j] != default_reduction)
278 report = true;
279 count = true;
280 }
281 else
282 {
283 report = true;
284 }
285 }
286 }
287
288 /* Nothing to report. */
289 if (!report)
290 {
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 int level = 0;
501
502 FILE *out = xfopen (spec_xml_file, "w");
503
504 fputs ("<?xml version=\"1.0\"?>\n\n", out);
505 xml_printf (out, level,
506 "<bison-xml-report version=\"%s\" bug-report=\"%s\""
507 " url=\"%s\">",
508 xml_escape_n (0, VERSION),
509 xml_escape_n (1, PACKAGE_BUGREPORT),
510 xml_escape_n (2, PACKAGE_URL));
511
512 fputc ('\n', out);
513 xml_printf (out, level + 1, "<filename>%s</filename>",
514 xml_escape (grammar_file));
515
516 /* print grammar */
517 print_grammar (out, level + 1);
518
519 new_closure (nritems);
520 no_reduce_set = bitset_create (ntokens, BITSET_FIXED);
521
522 /* print automaton */
523 fputc ('\n', out);
524 xml_puts (out, level + 1, "<automaton>");
525 {
526 state_number i;
527 for (i = 0; i < nstates; i++)
528 print_state (out, level + 2, states[i]);
529 }
530 xml_puts (out, level + 1, "</automaton>");
531
532 bitset_free (no_reduce_set);
533 free_closure ();
534
535 xml_puts (out, 0, "</bison-xml-report>");
536
537 {
538 int i;
539 for (i = 0; i < num_escape_bufs; ++i)
540 free (escape_bufs[i].ptr);
541 }
542
543 xfclose (out);
544 }