]> git.saurik.com Git - bison.git/blame - src/print-xml.c
maint: don't use mbsr?chr.
[bison.git] / src / print-xml.c
CommitLineData
41d7a5f2
PE
1/* Print an xml on generated parser, for Bison,
2
34136e65 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
2f658d53 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
2f658d53
JD
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
41d7a5f2 11
2f658d53 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
2f658d53 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>
41d7a5f2
PE
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
42static bitset no_reduce_set;
34cdeddf
JD
43struct escape_buf
44{
45 char *ptr;
46 size_t size;
47};
bc81de36 48static struct escape_buf escape_bufs[3];
41d7a5f2
PE
49
50
41d7a5f2
PE
51/*--------------------------------.
52| Report information on a state. |
53`--------------------------------*/
54
55static void
56print_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. */
ef1b4273
JD
63 closure (sitems, snritems);
64 sitems = itemset;
65 snritems = nitemset;
41d7a5f2
PE
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 {
25f6da67 76 bool printed = false;
41d7a5f2
PE
77 item_number *sp;
78 item_number *sp1;
79 rule_number r;
80
81 sp1 = sp = ritem + sitems[i];
82
83 while (*sp >= 0)
e9690142 84 sp++;
41d7a5f2
PE
85
86 r = item_number_as_rule_number (*sp);
25f6da67 87 sp = rules[r].rhs;
41d7a5f2
PE
88
89 /* Display the lookahead tokens? */
ef1b4273 90 if (item_number_is_rule_number (*sp1))
e9690142
JD
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 }
41d7a5f2 106
25f6da67 107 if (!printed)
e9690142
JD
108 {
109 xml_printf (out, level + 1,
110 "<item rule-number=\"%d\" point=\"%d\"/>",
111 rules[r].number,
112 sp1 - sp);
113 }
41d7a5f2
PE
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
124static void
125print_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 {
e9690142 134 n++;
41d7a5f2
PE
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)
e9690142 148 && TRANSITION_IS_SHIFT (trans, i))
41d7a5f2 149 {
e9690142
JD
150 symbol *sym = symbols[TRANSITION_SYMBOL (trans, i)];
151 char const *tag = sym->tag;
152 state *s1 = trans->states[i];
41d7a5f2 153
e9690142
JD
154 xml_printf (out, level + 1,
155 "<transition type=\"shift\" symbol=\"%s\" state=\"%d\"/>",
156 xml_escape (tag), s1->number);
41d7a5f2
PE
157 }
158
159 for (i = 0; i < trans->num; i++)
160 if (!TRANSITION_IS_DISABLED (trans, i)
e9690142 161 && !TRANSITION_IS_SHIFT (trans, i))
41d7a5f2 162 {
e9690142
JD
163 symbol *sym = symbols[TRANSITION_SYMBOL (trans, i)];
164 char const *tag = sym->tag;
165 state *s1 = trans->states[i];
41d7a5f2 166
e9690142
JD
167 xml_printf (out, level + 1,
168 "<transition type=\"goto\" symbol=\"%s\" state=\"%d\"/>",
169 xml_escape (tag), s1->number);
41d7a5f2
PE
170 }
171
172 xml_puts (out, level, "</transitions>");
173}
174
175
176/*--------------------------------------------------------.
177| Report the explicit errors of S raised from %nonassoc. |
178`--------------------------------------------------------*/
179
180static void
181print_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 {
e9690142
JD
202 char const *tag = errp->symbols[i]->tag;
203 xml_printf (out, level + 1,
204 "<error symbol=\"%s\">nonassociative</error>",
205 xml_escape (tag));
41d7a5f2
PE
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
217static void
218print_reduction (FILE *out, int level, char const *lookahead_token,
e9690142 219 rule *r, bool enabled)
41d7a5f2
PE
220{
221 if (r->number)
222 xml_printf (out, level,
e9690142
JD
223 "<reduction symbol=\"%s\" rule=\"%d\" enabled=\"%s\"/>",
224 xml_escape (lookahead_token),
225 r->number,
226 enabled ? "true" : "false");
41d7a5f2
PE
227 else
228 xml_printf (out, level,
e9690142
JD
229 "<reduction symbol=\"%s\" rule=\"accept\" enabled=\"%s\"/>",
230 xml_escape (lookahead_token),
231 enabled ? "true" : "false");
41d7a5f2
PE
232}
233
234
235/*-------------------------------------------.
236| Report on OUT the reduction actions of S. |
237`-------------------------------------------*/
238
239static void
240print_reductions (FILE *out, int level, state *s)
241{
242 transitions *trans = s->transitions;
243 reductions *reds = s->reductions;
110ef36a 244 rule *default_reduction = NULL;
41d7a5f2
PE
245 int report = false;
246 int i, j;
247
41976786
AD
248 if (reds->num == 0)
249 {
250 xml_puts (out, level, "<reductions/>");
251 return;
252 }
41d7a5f2
PE
253
254 if (yydefact[s->number] != 0)
110ef36a 255 default_reduction = &rules[yydefact[s->number] - 1];
41d7a5f2
PE
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
110ef36a 264 if (default_reduction)
41d7a5f2
PE
265 report = true;
266
267 if (reds->lookahead_tokens)
268 for (i = 0; i < ntokens; i++)
269 {
e9690142
JD
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 }
41d7a5f2
PE
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 {
e9690142
JD
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 }
41d7a5f2
PE
325 }
326
110ef36a 327 if (default_reduction)
41d7a5f2 328 print_reduction (out, level + 1,
e9690142 329 "$default", default_reduction, true);
41d7a5f2
PE
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
340static void
341print_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
355static void
356print_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);
ef1b4273 362 if (s->solved_conflicts_xml)
41d7a5f2
PE
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
378static void
379print_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 {
e9690142 392 char const *tag = symbols[token_translations[i]]->tag;
408476bc
JD
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);
41d7a5f2
PE
407 }
408 xml_puts (out, level + 1, "</terminals>");
409
410 /* Nonterminals */
411 xml_puts (out, level + 1, "<nonterminals>");
d80fb37a 412 for (i = ntokens; i < nsyms + nuseless_nonterminals; i++)
41d7a5f2 413 {
41d7a5f2 414 char const *tag = symbols[i]->tag;
41d7a5f2 415 xml_printf (out, level + 2,
e9690142 416 "<nonterminal symbol-number=\"%d\" name=\"%s\""
d4a26c48 417 " usefulness=\"%s\"/>",
e9690142 418 i, xml_escape (tag),
d80fb37a
JD
419 reduce_nonterminal_useless_in_grammar (i)
420 ? "useless-in-grammar" : "useful");
41d7a5f2
PE
421 }
422 xml_puts (out, level + 1, "</nonterminals>");
423 xml_puts (out, level, "</grammar>");
424}
425
426void
408476bc 427xml_indent (FILE *out, int level)
41d7a5f2
PE
428{
429 int i;
41d7a5f2 430 for (i = 0; i < level; i++)
a4f75309 431 fputs (" ", out);
408476bc
JD
432}
433
434void
435xml_puts (FILE *out, int level, char const *s)
436{
437 xml_indent (out, level);
41d7a5f2
PE
438 fputs (s, out);
439 fputc ('\n', out);
440}
441
442void
443xml_printf (FILE *out, int level, char const *fmt, ...)
444{
41d7a5f2
PE
445 va_list arglist;
446
408476bc 447 xml_indent (out, level);
41d7a5f2
PE
448
449 va_start (arglist, fmt);
450 vfprintf (out, fmt, arglist);
451 va_end (arglist);
452
453 fputc ('\n', out);
454}
455
41d7a5f2
PE
456static char const *
457xml_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
484char const *
485xml_escape_n (int n, char const *str)
486{
34cdeddf 487 return xml_escape_string (escape_bufs + n, str);
41d7a5f2
PE
488}
489
490char const *
491xml_escape (char const *str)
492{
493 return xml_escape_n (0, str);
494}
495
496void
497print_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);
bc81de36
JD
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));
41d7a5f2
PE
511
512 fputc ('\n', out);
513 xml_printf (out, level + 1, "<filename>%s</filename>",
e9690142 514 xml_escape (grammar_file));
41d7a5f2 515
41d7a5f2
PE
516 /* print grammar */
517 print_grammar (out, level + 1);
518
ef1b4273 519 new_closure (nritems);
41d7a5f2
PE
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);
ef1b4273 530 free_closure ();
41d7a5f2
PE
531
532 xml_puts (out, 0, "</bison-xml-report>");
533
34cdeddf
JD
534 free (escape_bufs[0].ptr);
535 free (escape_bufs[1].ptr);
536
41d7a5f2
PE
537 xfclose (out);
538}