Home | History | Annotate | Download | only in src
      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 }
    539