]> git.saurik.com Git - bison.git/blob - src/print-xml.c
maint: s/strncpy/memcpy/, when equivalent
[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
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 static struct escape_buf escape_bufs[3];
49
50
51 /*--------------------------------.
52 | Report information on a state. |
53 `--------------------------------*/
54
55 static void
56 print_core (FILE *out, int level, state *s)
57 {
58 size_t i;
59 item_number *sitems = s->items;
60 size_t snritems = s->nitems;
61
62 /* Output all the items of a state, not only its kernel. */
63 closure (sitems, snritems);
64 sitems = itemset;
65 snritems = nitemset;
66
67 if (!snritems) {
68 xml_puts (out, level, "<itemset/>");
69 return;
70 }
71
72 xml_puts (out, level, "<itemset>");
73
74 for (i = 0; i < snritems; i++)
75 {
76 bool printed = false;
77 item_number *sp;
78 item_number *sp1;
79 rule_number r;
80
81 sp1 = sp = ritem + sitems[i];
82
83 while (*sp >= 0)
84 sp++;
85
86 r = item_number_as_rule_number (*sp);
87 sp = rules[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, &rules[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 rules[r].number, sp1 - sp);
100 state_rule_lookahead_tokens_print_xml (s, &rules[r],
101 out, level + 2);
102 xml_puts (out, level + 1, "</item>");
103 printed = true;
104 }
105 }
106
107 if (!printed)
108 {
109 xml_printf (out, level + 1,
110 "<item rule-number=\"%d\" point=\"%d\"/>",
111 rules[r].number,
112 sp1 - sp);
113 }
114 }
115 xml_puts (out, level, "</itemset>");
116 }
117
118
119 /*-----------------------------------------------------------.
120 | Report the shifts if DISPLAY_SHIFTS_P or the gotos of S on |
121 | OUT. |
122 `-----------------------------------------------------------*/
123
124 static void
125 print_transitions (state *s, FILE *out, int level)
126 {
127 transitions *trans = s->transitions;
128 int n = 0;
129 int i;
130
131 for (i = 0; i < trans->num; i++)
132 if (!TRANSITION_IS_DISABLED (trans, i))
133 {
134 n++;
135 }
136
137 /* Nothing to report. */
138 if (!n) {
139 xml_puts (out, level, "<transitions/>");
140 return;
141 }
142
143 /* Report lookahead tokens and shifts. */
144 xml_puts (out, level, "<transitions>");
145
146 for (i = 0; i < trans->num; i++)
147 if (!TRANSITION_IS_DISABLED (trans, i)
148 && TRANSITION_IS_SHIFT (trans, i))
149 {
150 symbol *sym = symbols[TRANSITION_SYMBOL (trans, i)];
151 char const *tag = sym->tag;
152 state *s1 = trans->states[i];
153
154 xml_printf (out, level + 1,
155 "<transition type=\"shift\" symbol=\"%s\" state=\"%d\"/>",
156 xml_escape (tag), s1->number);
157 }
158
159 for (i = 0; i < trans->num; i++)
160 if (!TRANSITION_IS_DISABLED (trans, i)
161 && !TRANSITION_IS_SHIFT (trans, i))
162 {
163 symbol *sym = symbols[TRANSITION_SYMBOL (trans, i)];
164 char const *tag = sym->tag;
165 state *s1 = trans->states[i];
166
167 xml_printf (out, level + 1,
168 "<transition type=\"goto\" symbol=\"%s\" state=\"%d\"/>",
169 xml_escape (tag), s1->number);
170 }
171
172 xml_puts (out, level, "</transitions>");
173 }
174
175
176 /*--------------------------------------------------------.
177 | Report the explicit errors of S raised from %nonassoc. |
178 `--------------------------------------------------------*/
179
180 static void
181 print_errs (FILE *out, int level, state *s)
182 {
183 errs *errp = s->errs;
184 bool count = false;
185 int i;
186
187 for (i = 0; i < errp->num; ++i)
188 if (errp->symbols[i])
189 count = true;
190
191 /* Nothing to report. */
192 if (!count) {
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 xml_puts (out, level, "<reductions/>");
291 return;
292 }
293
294 xml_puts (out, level, "<reductions>");
295
296 /* Report lookahead tokens (or $default) and reductions. */
297 if (reds->lookahead_tokens)
298 for (i = 0; i < ntokens; i++)
299 {
300 bool defaulted = false;
301 bool count = bitset_test (no_reduce_set, i);
302
303 for (j = 0; j < reds->num; ++j)
304 if (bitset_test (reds->lookahead_tokens[j], i))
305 {
306 if (! count)
307 {
308 if (reds->rules[j] != default_reduction)
309 print_reduction (out, level + 1, symbols[i]->tag,
310 reds->rules[j], true);
311 else
312 defaulted = true;
313 count = true;
314 }
315 else
316 {
317 if (defaulted)
318 print_reduction (out, level + 1, symbols[i]->tag,
319 default_reduction, true);
320 defaulted = false;
321 print_reduction (out, level + 1, symbols[i]->tag,
322 reds->rules[j], false);
323 }
324 }
325 }
326
327 if (default_reduction)
328 print_reduction (out, level + 1,
329 "$default", default_reduction, true);
330
331 xml_puts (out, level, "</reductions>");
332 }
333
334
335 /*--------------------------------------------------------------.
336 | Report on OUT all the actions (shifts, gotos, reductions, and |
337 | explicit erros from %nonassoc) of S. |
338 `--------------------------------------------------------------*/
339
340 static void
341 print_actions (FILE *out, int level, state *s)
342 {
343 xml_puts (out, level, "<actions>");
344 print_transitions (s, out, level + 1);
345 print_errs (out, level + 1, s);
346 print_reductions (out, level + 1, s);
347 xml_puts (out, level, "</actions>");
348 }
349
350
351 /*----------------------------------.
352 | Report all the data on S on OUT. |
353 `----------------------------------*/
354
355 static void
356 print_state (FILE *out, int level, state *s)
357 {
358 fputc ('\n', out);
359 xml_printf (out, level, "<state number=\"%d\">", s->number);
360 print_core (out, level + 1, s);
361 print_actions (out, level + 1, s);
362 if (s->solved_conflicts_xml)
363 {
364 xml_puts (out, level + 1, "<solved-conflicts>");
365 fputs (s->solved_conflicts_xml, out);
366 xml_puts (out, level + 1, "</solved-conflicts>");
367 }
368 else
369 xml_puts (out, level + 1, "<solved-conflicts/>");
370 xml_puts (out, level, "</state>");
371 }
372
373
374 /*-----------------------------------------.
375 | Print information on the whole grammar. |
376 `-----------------------------------------*/
377
378 static void
379 print_grammar (FILE *out, int level)
380 {
381 symbol_number i;
382
383 fputc ('\n', out);
384 xml_puts (out, level, "<grammar>");
385 grammar_rules_print_xml (out, level);
386
387 /* Terminals */
388 xml_puts (out, level + 1, "<terminals>");
389 for (i = 0; i < max_user_token_number + 1; i++)
390 if (token_translations[i] != undeftoken->number)
391 {
392 char const *tag = symbols[token_translations[i]]->tag;
393 int precedence = symbols[token_translations[i]]->prec;
394 assoc associativity = symbols[token_translations[i]]->assoc;
395 xml_indent (out, level + 2);
396 fprintf (out,
397 "<terminal symbol-number=\"%d\" token-number=\"%d\""
398 " name=\"%s\" usefulness=\"%s\"",
399 token_translations[i], i, xml_escape (tag),
400 reduce_token_unused_in_grammar (token_translations[i])
401 ? "unused-in-grammar" : "useful");
402 if (precedence)
403 fprintf (out, " prec=\"%d\"", precedence);
404 if (associativity != undef_assoc)
405 fprintf (out, " assoc=\"%s\"", assoc_to_string (associativity) + 1);
406 fputs ("/>\n", out);
407 }
408 xml_puts (out, level + 1, "</terminals>");
409
410 /* Nonterminals */
411 xml_puts (out, level + 1, "<nonterminals>");
412 for (i = ntokens; i < nsyms + nuseless_nonterminals; i++)
413 {
414 char const *tag = symbols[i]->tag;
415 xml_printf (out, level + 2,
416 "<nonterminal symbol-number=\"%d\" name=\"%s\""
417 " usefulness=\"%s\"/>",
418 i, xml_escape (tag),
419 reduce_nonterminal_useless_in_grammar (i)
420 ? "useless-in-grammar" : "useful");
421 }
422 xml_puts (out, level + 1, "</nonterminals>");
423 xml_puts (out, level, "</grammar>");
424 }
425
426 void
427 xml_indent (FILE *out, int level)
428 {
429 int i;
430 for (i = 0; i < level; i++)
431 fputs (" ", out);
432 }
433
434 void
435 xml_puts (FILE *out, int level, char const *s)
436 {
437 xml_indent (out, level);
438 fputs (s, out);
439 fputc ('\n', out);
440 }
441
442 void
443 xml_printf (FILE *out, int level, char const *fmt, ...)
444 {
445 va_list arglist;
446
447 xml_indent (out, level);
448
449 va_start (arglist, fmt);
450 vfprintf (out, fmt, arglist);
451 va_end (arglist);
452
453 fputc ('\n', out);
454 }
455
456 static char const *
457 xml_escape_string (struct escape_buf *buf, char const *str)
458 {
459 size_t len = strlen (str);
460 size_t max_expansion = sizeof "&quot;" - 1;
461 char *p;
462
463 if (buf->size <= max_expansion * len)
464 {
465 buf->size = max_expansion * len + 1;
466 buf->ptr = x2realloc (buf->ptr, &buf->size);
467 }
468 p = buf->ptr;
469
470 for (; *str; str++)
471 switch (*str)
472 {
473 default: *p++ = *str; break;
474 case '&': p = stpcpy (p, "&amp;" ); break;
475 case '<': p = stpcpy (p, "&lt;" ); break;
476 case '>': p = stpcpy (p, "&gt;" ); break;
477 case '"': p = stpcpy (p, "&quot;"); break;
478 }
479
480 *p = '\0';
481 return buf->ptr;
482 }
483
484 char const *
485 xml_escape_n (int n, char const *str)
486 {
487 return xml_escape_string (escape_bufs + n, str);
488 }
489
490 char const *
491 xml_escape (char const *str)
492 {
493 return xml_escape_n (0, str);
494 }
495
496 void
497 print_xml (void)
498 {
499 state_number i;
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 for (i = 0; i < nstates; i++)
526 print_state (out, level + 2, states[i]);
527 xml_puts (out, level + 1, "</automaton>");
528
529 bitset_free (no_reduce_set);
530 free_closure ();
531
532 xml_puts (out, 0, "</bison-xml-report>");
533
534 free (escape_bufs[0].ptr);
535 free (escape_bufs[1].ptr);
536
537 xfclose (out);
538 }