Line data Source code
1 : /* Helper code for graphviz output.
2 : Copyright (C) 2019-2026 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 1457 : void indent () { m_indent++; }
38 1457 : void outdent () { m_indent--; }
39 :
40 : void write_indent ();
41 :
42 34564 : void write_character (char ch)
43 : {
44 34564 : pp_character (&m_pp, ch);
45 28275 : }
46 14991 : void write_string (const char *str)
47 : {
48 14991 : pp_string (&m_pp, str);
49 11039 : }
50 1841 : void write_newline ()
51 : {
52 1841 : pp_newline (&m_pp);
53 : }
54 :
55 69994 : 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 35380 : struct ast_node
84 : {
85 23819 : virtual ~ast_node () {}
86 : virtual void print (writer &w) const = 0;
87 :
88 : void dump () const;
89 : };
90 :
91 8650 : 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 3560 : kv_pair (id key, id value)
118 7120 : : m_key (std::move (key)),
119 3560 : m_value (std::move (value))
120 : {
121 3560 : }
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 2316 : struct attr_list : public ast_node
132 : {
133 : void print (writer &w) const;
134 3503 : void add (id key, id value)
135 : {
136 3503 : m_kvs.push_back ({std::move (key), std::move (value)});
137 3503 : }
138 :
139 : std::vector<kv_pair> m_kvs;
140 : };
141 :
142 : /* stmt_list : [ stmt [ ';' ] stmt_list ] */
143 :
144 117 : struct stmt_list : public ast_node
145 : {
146 : void print (writer &w) const final override;
147 1532 : void add_stmt (std::unique_ptr<stmt> s)
148 : {
149 1532 : 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 61 : graph ()
162 61 : : 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 1540 : struct stmt
190 : {
191 : virtual ~stmt () {}
192 : virtual void print (writer &w) const = 0;
193 : };
194 :
195 1426 : struct stmt_with_attr_list : public stmt
196 : {
197 1890 : void set_attr (id key, id value)
198 : {
199 1890 : m_attrs.add (std::move (key), std::move (value));
200 1890 : }
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 698 : node_stmt (id id_)
209 698 : : 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 57 : kv_stmt (kv_pair kv)
237 57 : : 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 : bool
254 : get_compass_pt_from_string (const char *str, enum compass_pt &out);
255 :
256 : /* port : ':' ID [ ':' compass_pt ]
257 : | ':' compass_pt
258 : */
259 :
260 : struct port : public ast_node
261 : {
262 16 : port (id id_)
263 16 : : m_id (std::make_unique<id> (std::move (id_))),
264 16 : m_compass_pt (nullptr)
265 : {
266 : }
267 :
268 90 : port (enum compass_pt compass_pt_)
269 90 : : m_id (nullptr),
270 90 : m_compass_pt (std::make_unique<compass_pt> (compass_pt_))
271 : {
272 : }
273 :
274 0 : port (id id_,
275 : enum compass_pt compass_pt_)
276 0 : : m_id (std::make_unique<id> (std::move (id_))),
277 0 : m_compass_pt (std::make_unique<compass_pt> (compass_pt_))
278 : {
279 0 : }
280 :
281 371 : port (const port &other)
282 371 : : m_id (nullptr),
283 371 : m_compass_pt (nullptr)
284 : {
285 371 : if (other.m_id)
286 56 : m_id = std::make_unique<id> (*other.m_id);
287 371 : if (other.m_compass_pt)
288 315 : m_compass_pt = std::make_unique<enum compass_pt> (*other.m_compass_pt);
289 371 : }
290 :
291 : void print (writer &w) const final override;
292 :
293 : std::unique_ptr<id> m_id; // would be std::optional
294 : std::unique_ptr<enum compass_pt> m_compass_pt; // would be std::optional
295 : };
296 :
297 : struct node_id : public ast_node
298 : {
299 1340 : node_id (id id_)
300 1340 : : m_id (id_),
301 1336 : m_port (nullptr)
302 : {
303 : }
304 106 : node_id (id id_, port port_)
305 106 : : m_id (id_),
306 106 : m_port (std::make_unique<port> (std::move (port_)))
307 : {
308 106 : }
309 3607 : node_id (const node_id &other)
310 3607 : : m_id (other.m_id),
311 3607 : m_port (nullptr)
312 : {
313 3607 : if (other.m_port)
314 265 : m_port = std::make_unique<port> (*other.m_port);
315 3607 : }
316 :
317 : node_id &operator= (const node_id &other)
318 : {
319 : m_id = other.m_id;
320 : if (other.m_port)
321 : m_port = std::make_unique<port> (*other.m_port);
322 : else
323 : m_port = nullptr;
324 : return *this;
325 : }
326 :
327 : void print (writer &w) const final override;
328 :
329 : id m_id;
330 : std::unique_ptr<port> m_port; // would be std::optional
331 : };
332 :
333 : /* The full grammar for edge_stmt is:
334 : edge_stmt : (node_id | subgraph) edgeRHS [ attr_list ]
335 : edgeRHS : edgeop (node_id | subgraph) [ edgeRHS ]
336 : This class support the subsets where all are "node_id", rather than
337 : "subgraph", and doesn't yet support "port" giving effectively:
338 : node_id (edgeop node_id)+ [ attr_list]
339 : */
340 :
341 : struct edge_stmt : public stmt_with_attr_list
342 : {
343 723 : edge_stmt (node_id src_id, node_id dst_id)
344 723 : {
345 723 : m_node_ids.push_back (std::move (src_id));
346 723 : m_node_ids.push_back (std::move (dst_id));
347 723 : }
348 :
349 : void print (writer &w) const final override;
350 :
351 : std::vector<node_id> m_node_ids; // should have 2 or more elements
352 : };
353 :
354 : /* [ subgraph [ ID ] ] '{' stmt_list '}' */
355 :
356 : struct subgraph : public stmt
357 : {
358 57 : subgraph (id id_)
359 57 : : m_id (id_)
360 : {
361 : }
362 :
363 : void print (writer &w) const final override;
364 :
365 : void add_stmt (std::unique_ptr<stmt> s)
366 : {
367 : m_stmt_list.add_stmt (std::move (s));
368 : }
369 5 : void add_attr (id key, id value)
370 : {
371 5 : m_stmt_list.add_stmt
372 10 : (std::make_unique <kv_stmt> (kv_pair (std::move (key),
373 10 : std::move (value))));
374 5 : }
375 :
376 : id m_id;
377 : stmt_list m_stmt_list;
378 : };
379 :
380 : extern std::unique_ptr<xml::node>
381 : make_svg_from_graph (const graph &g);
382 :
383 : } // namespace dot
384 :
385 : /* A class for writing .dot output to a pretty_printer with
386 : indentation to show nesting. */
387 :
388 : class graphviz_out : public dot::writer {
389 : public:
390 : graphviz_out (pretty_printer *pp);
391 :
392 : void print (const char *fmt, ...)
393 : ATTRIBUTE_GCC_PPDIAG(2,3);
394 : void println (const char *fmt, ...)
395 : ATTRIBUTE_GCC_PPDIAG(2,3);
396 :
397 : void begin_tr ();
398 : void end_tr ();
399 :
400 : void begin_td ();
401 : void end_td ();
402 :
403 : void begin_trtd ();
404 : void end_tdtr ();
405 : };
406 :
407 : #endif /* GCC_GRAPHVIZ_H */
|