Home | History | Annotate | Download | only in src
      1 /* Output a graph of the generated parser, for Bison.
      2 
      3    Copyright (C) 2001-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 "LR0.h"
     24 #include "closure.h"
     25 #include "complain.h"
     26 #include "conflicts.h"
     27 #include "files.h"
     28 #include "getargs.h"
     29 #include "gram.h"
     30 #include "graphviz.h"
     31 #include "lalr.h"
     32 #include "print_graph.h"
     33 #include "reader.h"
     34 #include "state.h"
     35 #include "symtab.h"
     36 
     37 
     38 /*----------------------------.
     39 | Construct the node labels.  |
     40 `----------------------------*/
     41 
     42 /* Print the lhs of a rule in such a manner that there is no vertical
     43    repetition, like in *.output files. */
     44 
     45 static void
     46 print_lhs (struct obstack *oout, rule *previous_rule, rule *r)
     47 {
     48   if (previous_rule && STREQ (previous_rule->lhs->tag, r->lhs->tag))
     49     {
     50       int i;
     51       for (i = 0; i < strlen (r->lhs->tag); ++i)
     52         obstack_1grow (oout, ' ');
     53       obstack_1grow (oout, '|');
     54     }
     55   else
     56     {
     57       obstack_sgrow (oout, escape (r->lhs->tag));
     58       obstack_1grow (oout, ':');
     59     }
     60 }
     61 
     62 static void
     63 print_core (struct obstack *oout, state *s)
     64 {
     65   item_number *sitems = s->items;
     66   rule *previous_rule = NULL;
     67   size_t i;
     68   size_t snritems = s->nitems;
     69 
     70   /* Output all the items of a state, not only its kernel.  */
     71   if (report_flag & report_itemsets)
     72     {
     73       closure (sitems, snritems);
     74       sitems = itemset;
     75       snritems = nitemset;
     76     }
     77 
     78   obstack_printf (oout, _("State %d"), s->number);
     79   obstack_sgrow (oout, "\\n\\l");
     80   for (i = 0; i < snritems; i++)
     81     {
     82       item_number *sp;
     83       item_number *sp1;
     84       rule_number r;
     85 
     86       sp1 = sp = ritem + sitems[i];
     87 
     88       while (*sp >= 0)
     89         sp++;
     90 
     91       r = item_number_as_rule_number (*sp);
     92 
     93       obstack_printf (oout, "%3d ", r);
     94       print_lhs (oout, previous_rule, &rules[r]);
     95       previous_rule = &rules[r];
     96 
     97       for (sp = rules[r].rhs; sp < sp1; sp++)
     98         obstack_printf (oout, " %s", escape (symbols[*sp]->tag));
     99 
    100       obstack_sgrow (oout, " .");
    101 
    102       for (/* Nothing */; *sp >= 0; ++sp)
    103         obstack_printf (oout, " %s", escape (symbols[*sp]->tag));
    104 
    105       /* Experimental feature: display the lookahead tokens. */
    106       if (report_flag & report_lookahead_tokens
    107           && item_number_is_rule_number (*sp1))
    108         {
    109           /* Find the reduction we are handling.  */
    110           reductions *reds = s->reductions;
    111           int redno = state_reduction_find (s, &rules[r]);
    112 
    113           /* Print them if there are.  */
    114           if (reds->lookahead_tokens && redno != -1)
    115             {
    116               bitset_iterator biter;
    117               int k;
    118               char const *sep = "";
    119               obstack_sgrow (oout, "  [");
    120               BITSET_FOR_EACH (biter, reds->lookahead_tokens[redno], k, 0)
    121                 {
    122                   obstack_sgrow (oout, sep);
    123                   obstack_sgrow (oout, escape (symbols[k]->tag));
    124                   sep = ", ";
    125                 }
    126               obstack_1grow (oout, ']');
    127             }
    128         }
    129       obstack_sgrow (oout, "\\l");
    130     }
    131 }
    132 
    133 
    134 /*---------------------------------------------------------------.
    135 | Output in graph_obstack edges specifications in incidence with |
    136 | current node.                                                  |
    137 `---------------------------------------------------------------*/
    138 
    139 static void
    140 print_actions (state const *s, FILE *fgraph)
    141 {
    142   transitions const *trans = s->transitions;
    143   int i;
    144 
    145   if (!trans->num && !s->reductions)
    146     return;
    147 
    148   for (i = 0; i < trans->num; i++)
    149     if (!TRANSITION_IS_DISABLED (trans, i))
    150       {
    151 	state *s1 = trans->states[i];
    152 	symbol_number sym = s1->accessing_symbol;
    153 
    154 	/* Shifts are solid, gotos are dashed, and error is dotted.  */
    155 	char const *style =
    156 	  (TRANSITION_IS_ERROR (trans, i) ? "dotted"
    157 	   : TRANSITION_IS_SHIFT (trans, i) ? "solid"
    158 	   : "dashed");
    159 
    160 	if (TRANSITION_IS_ERROR (trans, i)
    161 	    && strcmp (symbols[sym]->tag, "error") != 0)
    162 	  abort ();
    163 	output_edge (s->number, s1->number,
    164 		     TRANSITION_IS_ERROR (trans, i) ? NULL : symbols[sym]->tag,
    165 		     style, fgraph);
    166       }
    167   /* Display reductions. */
    168   output_red (s, s->reductions, fgraph);
    169 }
    170 
    171 
    172 /*-------------------------------------------------------------.
    173 | Output in FGRAPH the current node specifications and exiting |
    174 | edges.                                                       |
    175 `-------------------------------------------------------------*/
    176 
    177 static void
    178 print_state (state *s, FILE *fgraph)
    179 {
    180   struct obstack node_obstack;
    181 
    182   /* A node's label contains its items.  */
    183   obstack_init (&node_obstack);
    184   print_core (&node_obstack, s);
    185   obstack_1grow (&node_obstack, '\0');
    186   output_node (s->number, obstack_finish (&node_obstack), fgraph);
    187   obstack_free (&node_obstack, 0);
    188 
    189   /* Output the edges.  */
    190   print_actions (s, fgraph);
    191 }
    192 
    193 
    195 void
    196 print_graph (void)
    197 {
    198   state_number i;
    199   FILE *fgraph = xfopen (spec_graph_file, "w");
    200   start_graph (fgraph);
    201 
    202   /* Output nodes and edges. */
    203   new_closure (nritems);
    204   for (i = 0; i < nstates; i++)
    205     print_state (states[i], fgraph);
    206   free_closure ();
    207 
    208   finish_graph (fgraph);
    209   xfclose (fgraph);
    210 }
    211