tests: grep -E is not portable
[bison.git] / src / print-graph.c
blob3ddf6a54d3f59a63c18d2d6d2d0ad50c26a11b16
1 /* Output a graph of the generated parser, for Bison.
3 Copyright (C) 2001-2007, 2009-2015, 2018-2021 Free Software
4 Foundation, Inc.
6 This file is part of Bison, the GNU Compiler Compiler.
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <https://www.gnu.org/licenses/>. */
21 #include <config.h>
22 #include "print-graph.h"
24 #include "system.h"
26 #include "closure.h"
27 #include "complain.h"
28 #include "conflicts.h"
29 #include "files.h"
30 #include "getargs.h"
31 #include "gram.h"
32 #include "graphviz.h"
33 #include "lalr.h"
34 #include "lr0.h"
35 #include "reader.h"
36 #include "state.h"
37 #include "symtab.h"
40 /*----------------------------.
41 | Construct the node labels. |
42 `----------------------------*/
44 /* Print the lhs of a rule in such a manner that there is no vertical
45 repetition, like in *.output files. */
47 static void
48 print_core (struct obstack *oout, state *s)
50 item_index const *sitems = s->items;
51 sym_content *previous_lhs = NULL;
52 size_t snritems = s->nitems;
54 /* Output all the items of a state, not just its kernel. */
55 if (report_flag & report_itemsets)
57 closure (sitems, snritems);
58 sitems = itemset;
59 snritems = nitemset;
62 obstack_printf (oout, _("State %d"), s->number);
63 obstack_sgrow (oout, "\\n\\l");
64 for (size_t i = 0; i < snritems; ++i)
66 item_number const *sp1 = ritem + sitems[i];
67 rule const *r = item_rule (sp1);
69 obstack_printf (oout, "%3d ", r->number);
70 if (previous_lhs && UNIQSTR_EQ (previous_lhs->symbol->tag,
71 r->lhs->symbol->tag))
72 obstack_printf (oout, "%*s| ",
73 (int) strlen (previous_lhs->symbol->tag), "");
74 else
76 obstack_backslash (oout, r->lhs->symbol->tag);
77 obstack_printf (oout, ": ");
79 previous_lhs = r->lhs;
81 for (item_number const *sp = r->rhs; sp < sp1; sp++)
83 obstack_backslash (oout, symbols[*sp]->tag);
84 obstack_1grow (oout, ' ');
87 obstack_sgrow (oout, "•");
89 if (0 <= *r->rhs)
90 for (item_number const *sp = sp1; 0 <= *sp; ++sp)
92 obstack_1grow (oout, ' ');
93 obstack_backslash (oout, symbols[*sp]->tag);
95 else
96 obstack_sgrow (oout, " %empty");
98 /* Experimental feature: display the lookahead tokens. */
99 if (report_flag & report_lookaheads
100 && item_number_is_rule_number (*sp1))
102 /* Find the reduction we are handling. */
103 reductions *reds = s->reductions;
104 int redno = state_reduction_find (s, r);
106 /* Print them if there are. */
107 if (reds->lookaheads && redno != -1)
109 bitset_iterator biter;
110 int k;
111 char const *sep = "";
112 obstack_sgrow (oout, " [");
113 BITSET_FOR_EACH (biter, reds->lookaheads[redno], k, 0)
115 obstack_sgrow (oout, sep);
116 obstack_backslash (oout, symbols[k]->tag);
117 sep = ", ";
119 obstack_1grow (oout, ']');
122 obstack_sgrow (oout, "\\l");
127 /*---------------------------------------------------------------.
128 | Output in graph_obstack edges specifications in incidence with |
129 | current node. |
130 `---------------------------------------------------------------*/
132 static void
133 print_actions (state const *s, FILE *fgraph)
135 transitions const *trans = s->transitions;
137 if (!trans->num && !s->reductions)
138 return;
140 for (int i = 0; i < trans->num; i++)
141 if (!TRANSITION_IS_DISABLED (trans, i))
143 const state *s1 = trans->states[i];
144 const symbol_number sym = s1->accessing_symbol;
146 /* Shifts are solid, gotos are dashed, and error is dotted. */
147 char const *style =
148 (TRANSITION_IS_ERROR (trans, i) ? "dotted"
149 : TRANSITION_IS_SHIFT (trans, i) ? "solid"
150 : "dashed");
152 if (TRANSITION_IS_ERROR (trans, i)
153 && STRNEQ (symbols[sym]->tag, "error"))
154 abort ();
155 output_edge (s->number, s1->number,
156 TRANSITION_IS_ERROR (trans, i) ? NULL : symbols[sym]->tag,
157 style, fgraph);
159 /* Display reductions. */
160 output_red (s, s->reductions, fgraph);
164 /*-------------------------------------------------------------.
165 | Output in FGRAPH the current node specifications and exiting |
166 | edges. |
167 `-------------------------------------------------------------*/
169 static void
170 print_state (state *s, FILE *fgraph)
172 struct obstack node_obstack;
174 /* A node's label contains its items. */
175 obstack_init (&node_obstack);
176 print_core (&node_obstack, s);
177 output_node (s->number, obstack_finish0 (&node_obstack), fgraph);
178 obstack_free (&node_obstack, 0);
180 /* Output the edges. */
181 print_actions (s, fgraph);
185 void
186 print_graph (void)
188 FILE *fgraph = xfopen (spec_graph_file, "w");
189 start_graph (fgraph);
191 /* Output nodes and edges. */
192 for (int i = 0; i < nstates; i++)
193 print_state (states[i], fgraph);
195 finish_graph (fgraph);
196 xfclose (fgraph);