Branch data Line data Source code
1 : : /* Helper code for graphviz output.
2 : : Copyright (C) 2019-2025 Free Software Foundation, Inc.
3 : : Contributed by David Malcolm <dmalcolm@redhat.com>.
4 : :
5 : : This file is part of GCC.
6 : :
7 : : GCC is free software; you can redistribute it and/or modify it
8 : : under the terms of the GNU General Public License as published by
9 : : the Free Software Foundation; either version 3, or (at your option)
10 : : any later version.
11 : :
12 : : GCC is distributed in the hope that it will be useful, but
13 : : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : General Public License for more details.
16 : :
17 : : You should have received a copy of the GNU General Public License
18 : : along with GCC; see the file COPYING3. If not see
19 : : <http://www.gnu.org/licenses/>. */
20 : :
21 : : #ifndef GCC_GRAPHVIZ_H
22 : : #define GCC_GRAPHVIZ_H
23 : :
24 : : #include "pretty-print.h" /* for ATTRIBUTE_GCC_PPDIAG. */
25 : :
26 : : namespace xml { class node; }
27 : :
28 : : namespace dot {
29 : :
30 : : /* A class for writing .dot output to a pretty_printer with
31 : : indentation to show nesting. */
32 : :
33 : : class writer {
34 : : public:
35 : : writer (pretty_printer &pp);
36 : :
37 : 1260 : void indent () { m_indent++; }
38 : 1260 : void outdent () { m_indent--; }
39 : :
40 : : void write_indent ();
41 : :
42 : 193 : void write_character (char ch)
43 : : {
44 : 193 : pp_character (&m_pp, ch);
45 : 125 : }
46 : 263 : void write_string (const char *str)
47 : : {
48 : 263 : pp_string (&m_pp, str);
49 : 155 : }
50 : 60 : void write_newline ()
51 : : {
52 : 60 : pp_newline (&m_pp);
53 : : }
54 : :
55 : 58927 : pretty_printer *get_pp () const { return &m_pp; }
56 : :
57 : : private:
58 : : pretty_printer &m_pp;
59 : : int m_indent;
60 : : };
61 : :
62 : : // An AST for the dot language
63 : : // See https://graphviz.org/doc/info/lang.html
64 : :
65 : : // Forward decls
66 : :
67 : : struct id;
68 : : struct node_id;
69 : : struct port;
70 : : struct kv_pair;
71 : : struct graph;
72 : : struct attr_list;
73 : : struct stmt_list;
74 : : struct stmt;
75 : : struct node_stmt;
76 : : struct attr_stmt;
77 : : struct kv_stmt;
78 : : struct edge_stmt;
79 : : struct subgraph;
80 : :
81 : : // Decls
82 : :
83 : 437 : struct ast_node
84 : : {
85 : 263 : virtual ~ast_node () {}
86 : : virtual void print (writer &w) const = 0;
87 : :
88 : : void dump () const;
89 : : };
90 : :
91 : 198 : struct id : public ast_node
92 : : {
93 : : enum class kind
94 : : {
95 : : identifier,
96 : : quoted,
97 : : html
98 : : };
99 : :
100 : : id (std::string str);
101 : :
102 : : /* For HTML labels: see https://graphviz.org/doc/info/shapes.html#html */
103 : : id (const xml::node &n);
104 : :
105 : : void print (writer &w) const final override;
106 : :
107 : : static bool is_identifier_p (const char *);
108 : :
109 : : std::string m_str;
110 : : enum kind m_kind;
111 : : };
112 : :
113 : : /* ID '=' ID */
114 : :
115 : : struct kv_pair : ast_node
116 : : {
117 : 31 : kv_pair (id key, id value)
118 : 62 : : m_key (std::move (key)),
119 : 31 : m_value (std::move (value))
120 : : {
121 : 31 : }
122 : :
123 : : void print (writer &w) const final override;
124 : :
125 : : id m_key;
126 : : id m_value;
127 : : };
128 : :
129 : : /* attr_list: '[' [ a_list ] ']' [ attr_list ] */
130 : :
131 : 38 : struct attr_list : public ast_node
132 : : {
133 : : void print (writer &w) const;
134 : 31 : void add (id key, id value)
135 : : {
136 : 31 : m_kvs.push_back ({std::move (key), std::move (value)});
137 : 31 : }
138 : :
139 : : std::vector<kv_pair> m_kvs;
140 : : };
141 : :
142 : : /* stmt_list : [ stmt [ ';' ] stmt_list ] */
143 : :
144 : 5 : struct stmt_list : public ast_node
145 : : {
146 : : void print (writer &w) const final override;
147 : 31 : void add_stmt (std::unique_ptr<stmt> s)
148 : : {
149 : 31 : m_stmts.push_back (std::move (s));
150 : : }
151 : : void add_edge (node_id src_id, node_id dst_id);
152 : : void add_attr (id key, id value);
153 : :
154 : : std::vector<std::unique_ptr<stmt>> m_stmts;
155 : : };
156 : :
157 : : /* graph : [ strict ] (graph | digraph) [ ID ] '{' stmt_list '}' */
158 : :
159 : : struct graph : public ast_node
160 : : {
161 : 5 : graph ()
162 : 5 : : m_id (nullptr)
163 : : {
164 : : }
165 : :
166 : 4 : graph (id id_)
167 : 4 : : m_id (std::make_unique<id> (std::move (id_)))
168 : : {
169 : : }
170 : :
171 : : void print (writer &w) const final override;
172 : :
173 : 30 : void add_stmt (std::unique_ptr<stmt> s)
174 : : {
175 : 30 : m_stmt_list.add_stmt (std::move (s));
176 : 30 : }
177 : :
178 : : std::unique_ptr<id> m_id; // optional
179 : : stmt_list m_stmt_list;
180 : : };
181 : :
182 : : /* Abstract base class.
183 : : stmt : node_stmt
184 : : | edge_stmt
185 : : | attr_stmt
186 : : | ID '=' ID ("kv_stmt")
187 : : | subgraph */
188 : :
189 : 39 : struct stmt
190 : : {
191 : : virtual ~stmt () {}
192 : : virtual void print (writer &w) const = 0;
193 : : };
194 : :
195 : 38 : struct stmt_with_attr_list : public stmt
196 : : {
197 : : void set_attr (id key, id value)
198 : : {
199 : : m_attrs.add (std::move (key), std::move (value));
200 : : }
201 : : void set_label (dot::id label);
202 : :
203 : : attr_list m_attrs;
204 : : };
205 : :
206 : : struct node_stmt : public stmt_with_attr_list
207 : : {
208 : 21 : node_stmt (id id_)
209 : 21 : : m_id (id_)
210 : : {
211 : : }
212 : :
213 : : void print (writer &w) const final override;
214 : :
215 : : id m_id;
216 : : };
217 : :
218 : : struct attr_stmt : public stmt_with_attr_list
219 : : {
220 : : enum class kind { graph, node, edge };
221 : :
222 : 5 : attr_stmt (enum kind kind_)
223 : 5 : : m_kind (kind_)
224 : : {
225 : : }
226 : :
227 : : void print (writer &w) const final override;
228 : :
229 : : enum kind m_kind;
230 : : };
231 : :
232 : : /* "ID '=' ID" as a stmt. */
233 : :
234 : : struct kv_stmt : public stmt
235 : : {
236 : 0 : kv_stmt (kv_pair kv)
237 : 0 : : m_kv (std::move (kv))
238 : : {}
239 : :
240 : : void print (writer &w) const final override;
241 : :
242 : : kv_pair m_kv;
243 : : };
244 : :
245 : : /* node_id : ID [ port ] */
246 : :
247 : : enum class compass_pt
248 : : {
249 : : n, ne, e, se, s, sw, w, nw, c
250 : : /* "_" clashes with intl macro */
251 : : };
252 : :
253 : : /* port : ':' ID [ ':' compass_pt ]
254 : : | ':' compass_pt
255 : : */
256 : :
257 : : struct port : public ast_node
258 : : {
259 : 26 : port (id id_)
260 : 26 : : m_id (std::make_unique<id> (std::move (id_))),
261 : 26 : m_compass_pt (nullptr)
262 : : {
263 : : }
264 : :
265 : : port (enum compass_pt compass_pt_)
266 : : : m_id (nullptr),
267 : : m_compass_pt (std::make_unique<compass_pt> (compass_pt_))
268 : : {
269 : : }
270 : :
271 : 0 : port (id id_,
272 : : enum compass_pt compass_pt_)
273 : 0 : : m_id (std::make_unique<id> (std::move (id_))),
274 : 0 : m_compass_pt (std::make_unique<compass_pt> (compass_pt_))
275 : : {
276 : 0 : }
277 : :
278 : 76 : port (const port &other)
279 : 76 : : m_id (nullptr),
280 : 76 : m_compass_pt (nullptr)
281 : : {
282 : 76 : if (other.m_id)
283 : 76 : m_id = std::make_unique<id> (*other.m_id);
284 : 76 : if (other.m_compass_pt)
285 : 0 : m_compass_pt = std::make_unique<enum compass_pt> (*other.m_compass_pt);
286 : 76 : }
287 : :
288 : : void print (writer &w) const final override;
289 : :
290 : : std::unique_ptr<id> m_id; // would be std::optional
291 : : std::unique_ptr<enum compass_pt> m_compass_pt; // would be std::optional
292 : : };
293 : :
294 : : struct node_id : public ast_node
295 : : {
296 : 8 : node_id (id id_)
297 : 8 : : m_id (id_),
298 : 4 : m_port (nullptr)
299 : : {
300 : : }
301 : 26 : node_id (id id_, port port_)
302 : 26 : : m_id (id_),
303 : 26 : m_port (std::make_unique<port> (std::move (port_)))
304 : : {
305 : 26 : }
306 : 62 : node_id (const node_id &other)
307 : 62 : : m_id (other.m_id),
308 : 62 : m_port (nullptr)
309 : : {
310 : 62 : if (other.m_port)
311 : 50 : m_port = std::make_unique<port> (*other.m_port);
312 : 62 : }
313 : :
314 : : void print (writer &w) const final override;
315 : :
316 : : id m_id;
317 : : std::unique_ptr<port> m_port; // would be std::optional
318 : : };
319 : :
320 : : /* The full grammar for edge_stmt is:
321 : : edge_stmt : (node_id | subgraph) edgeRHS [ attr_list ]
322 : : edgeRHS : edgeop (node_id | subgraph) [ edgeRHS ]
323 : : This class support the subsets where all are "node_id", rather than
324 : : "subgraph", and doesn't yet support "port" giving effectively:
325 : : node_id (edgeop node_id)+ [ attr_list]
326 : : */
327 : :
328 : : struct edge_stmt : public stmt_with_attr_list
329 : : {
330 : 12 : edge_stmt (node_id src_id, node_id dst_id)
331 : 12 : {
332 : 12 : m_node_ids.push_back (std::move (src_id));
333 : 12 : m_node_ids.push_back (std::move (dst_id));
334 : 12 : }
335 : :
336 : : void print (writer &w) const final override;
337 : :
338 : : std::vector<node_id> m_node_ids; // should have 2 or more elements
339 : : };
340 : :
341 : : /* [ subgraph [ ID ] ] '{' stmt_list '}' */
342 : :
343 : : struct subgraph : public stmt
344 : : {
345 : 1 : subgraph (id id_)
346 : 1 : : m_id (id_)
347 : : {
348 : : }
349 : :
350 : : void print (writer &w) const final override;
351 : :
352 : : void add_stmt (std::unique_ptr<stmt> s)
353 : : {
354 : : m_stmt_list.add_stmt (std::move (s));
355 : : }
356 : 0 : void add_attr (id key, id value)
357 : : {
358 : 0 : m_stmt_list.add_stmt
359 : 0 : (std::make_unique <kv_stmt> (kv_pair (std::move (key),
360 : 0 : std::move (value))));
361 : 0 : }
362 : :
363 : : id m_id;
364 : : stmt_list m_stmt_list;
365 : : };
366 : :
367 : : extern std::unique_ptr<xml::node>
368 : : make_svg_from_graph (const graph &g);
369 : :
370 : : } // namespace dot
371 : :
372 : : /* A class for writing .dot output to a pretty_printer with
373 : : indentation to show nesting. */
374 : :
375 : : class graphviz_out : public dot::writer {
376 : : public:
377 : : graphviz_out (pretty_printer *pp);
378 : :
379 : : void print (const char *fmt, ...)
380 : : ATTRIBUTE_GCC_PPDIAG(2,3);
381 : : void println (const char *fmt, ...)
382 : : ATTRIBUTE_GCC_PPDIAG(2,3);
383 : :
384 : : void begin_tr ();
385 : : void end_tr ();
386 : :
387 : : void begin_td ();
388 : : void end_td ();
389 : :
390 : : void begin_trtd ();
391 : : void end_tdtr ();
392 : : };
393 : :
394 : : #endif /* GCC_GRAPHVIZ_H */
|