1 /* Output Graphviz specification of a state machine generated by Bison.
2
3 Copyright (C) 2006-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 /* Written by Paul Eggert and Satya Kiran Popuri. */
21
22 #include <config.h>
23 #include "system.h"
24
25 #include <quotearg.h>
26
27 #include "files.h"
28 #include "gram.h"
29 #include "graphviz.h"
30 #include "tables.h"
31
32 /* Return an unambiguous printable representation for NAME, suitable
33 for C strings. Use slot 2 since the user may use slots 0 and 1. */
34
35 static char *
quote(char const * name)36 quote (char const *name)
37 {
38 return quotearg_n_style (2, c_quoting_style, name);
39 }
40
41 void
start_graph(FILE * fout)42 start_graph (FILE *fout)
43 {
44 fprintf (fout,
45 _("// Generated by %s.\n"
46 "// Report bugs to <%s>.\n"
47 "// Home page: <%s>.\n"
48 "\n"),
49 PACKAGE_STRING,
50 PACKAGE_BUGREPORT,
51 PACKAGE_URL);
52 fprintf (fout,
53 "digraph %s\n"
54 "{\n",
55 quote (grammar_file));
56 fprintf (fout,
57 " node [fontname = courier, shape = box, colorscheme = paired6]\n"
58 " edge [fontname = courier]\n"
59 "\n");
60 }
61
62 void
output_node(int id,char const * label,FILE * fout)63 output_node (int id, char const *label, FILE *fout)
64 {
65 fprintf (fout, " %d [label=\"%s\"]\n", id, label);
66 }
67
68 void
output_edge(int source,int destination,char const * label,char const * style,FILE * fout)69 output_edge (int source, int destination, char const *label,
70 char const *style, FILE *fout)
71 {
72 fprintf (fout, " %d -> %d [style=%s", source, destination, style);
73 if (label)
74 fprintf (fout, " label=%s", quote (label));
75 fputs ("]\n", fout);
76 }
77
78 char const *
escape(char const * name)79 escape (char const *name)
80 {
81 char *q = quote (name);
82 q[strlen (q) - 1] = '\0';
83 return q + 1;
84 }
85
86 static void
no_reduce_bitset_init(state const * s,bitset * no_reduce_set)87 no_reduce_bitset_init (state const *s, bitset *no_reduce_set)
88 {
89 int n;
90 *no_reduce_set = bitset_create (ntokens, BITSET_FIXED);
91 bitset_zero (*no_reduce_set);
92 FOR_EACH_SHIFT (s->transitions, n)
93 bitset_set (*no_reduce_set, TRANSITION_SYMBOL (s->transitions, n));
94 for (n = 0; n < s->errs->num; ++n)
95 if (s->errs->symbols[n])
96 bitset_set (*no_reduce_set, s->errs->symbols[n]->number);
97 }
98
99 static void
conclude_red(struct obstack * out,int source,rule_number ruleno,bool enabled,bool first,FILE * fout)100 conclude_red (struct obstack *out, int source, rule_number ruleno,
101 bool enabled, bool first, FILE *fout)
102 {
103 /* If no lookahead tokens were valid transitions, this reduction is
104 actually hidden, so cancel everything. */
105 if (first)
106 (void) obstack_finish0 (out);
107 else
108 {
109 char const *ed = enabled ? "" : "d";
110 char const *color = enabled ? ruleno ? "3" : "1" : "5";
111
112 /* First, build the edge's head. The name of reduction nodes is "nRm",
113 with n the source state and m the rule number. This is because we
114 don't want all the reductions bearing a same rule number to point to
115 the same state, since that is not the desired format. */
116 fprintf (fout, " %1$d -> \"%1$dR%2$d%3$s\" [",
117 source, ruleno, ed);
118
119 /* (The lookahead tokens have been added to the beginning of the
120 obstack, in the caller function.) */
121 if (! obstack_empty_p (out))
122 {
123 char *label = obstack_finish0 (out);
124 fprintf (fout, "label=\"[%s]\", ", label);
125 obstack_free (out, label);
126 }
127
128 /* Then, the edge's tail. */
129 fprintf (fout, "style=solid]\n");
130
131 /* Build the associated diamond representation of the target rule. */
132 fprintf (fout, " \"%dR%d%s\" [label=\"",
133 source, ruleno, ed);
134 if (ruleno)
135 fprintf (fout, "R%d", ruleno);
136 else
137 fprintf (fout, "Acc");
138
139 fprintf (fout, "\", fillcolor=%s, shape=diamond, style=filled]\n",
140 color);
141 }
142 }
143
144 static bool
print_token(struct obstack * out,bool first,char const * tok)145 print_token (struct obstack *out, bool first, char const *tok)
146 {
147 char const *q = escape (tok);
148
149 if (! first)
150 obstack_sgrow (out, ", ");
151 obstack_sgrow (out, q);
152 return false;
153 }
154
155 void
output_red(state const * s,reductions const * reds,FILE * fout)156 output_red (state const *s, reductions const *reds, FILE *fout)
157 {
158 bitset no_reduce_set;
159 int j;
160 int source = s->number;
161
162 /* Two obstacks are needed: one for the enabled reductions, and one
163 for the disabled reductions, because in the end we want two
164 separate edges, even though in most cases only one will actually
165 be printed. */
166 struct obstack dout;
167 struct obstack eout;
168
169 no_reduce_bitset_init (s, &no_reduce_set);
170 obstack_init (&dout);
171 obstack_init (&eout);
172
173 for (j = 0; j < reds->num; ++j)
174 {
175 bool defaulted = false;
176 bool firstd = true;
177 bool firste = true;
178 rule_number ruleno = reds->rules[j]->number;
179 rule *default_reduction = NULL;
180
181 if (yydefact[s->number] != 0)
182 default_reduction = &rules[yydefact[s->number] - 1];
183
184 /* Build the lookahead tokens lists, one for enabled transitions and one
185 for disabled transistions. */
186 if (default_reduction && default_reduction == reds->rules[j])
187 defaulted = true;
188 if (reds->lookahead_tokens)
189 {
190 int i;
191 for (i = 0; i < ntokens; i++)
192 if (bitset_test (reds->lookahead_tokens[j], i))
193 {
194 if (bitset_test (no_reduce_set, i))
195 firstd = print_token (&dout, firstd, symbols[i]->tag);
196 else
197 {
198 if (! defaulted)
199 firste = print_token (&eout, firste, symbols[i]->tag);
200 bitset_set (no_reduce_set, i);
201 }
202 }
203 }
204
205 /* Do the actual output. */
206 conclude_red (&dout, source, ruleno, false, firstd, fout);
207 conclude_red (&eout, source, ruleno, true, firste && !defaulted, fout);
208 }
209 obstack_free (&dout, 0);
210 obstack_free (&eout, 0);
211 bitset_free (no_reduce_set);
212 }
213
214 void
finish_graph(FILE * fout)215 finish_graph (FILE *fout)
216 {
217 fputs ("}\n", fout);
218 }
219