aboutsummaryrefslogtreecommitdiff
path: root/gcc/graphviz.h
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/graphviz.h')
-rw-r--r--gcc/graphviz.h359
1 files changed, 347 insertions, 12 deletions
diff --git a/gcc/graphviz.h b/gcc/graphviz.h
index 9a1ca04..5943589 100644
--- a/gcc/graphviz.h
+++ b/gcc/graphviz.h
@@ -23,10 +23,356 @@ along with GCC; see the file COPYING3. If not see
#include "pretty-print.h" /* for ATTRIBUTE_GCC_PPDIAG. */
+namespace xml { class node; }
+
+namespace dot {
+
+/* A class for writing .dot output to a pretty_printer with
+ indentation to show nesting. */
+
+class writer {
+public:
+ writer (pretty_printer &pp);
+
+ void indent () { m_indent++; }
+ void outdent () { m_indent--; }
+
+ void write_indent ();
+
+ void write_character (char ch)
+ {
+ pp_character (&m_pp, ch);
+ }
+ void write_string (const char *str)
+ {
+ pp_string (&m_pp, str);
+ }
+ void write_newline ()
+ {
+ pp_newline (&m_pp);
+ }
+
+ pretty_printer *get_pp () const { return &m_pp; }
+
+ private:
+ pretty_printer &m_pp;
+ int m_indent;
+};
+
+// An AST for the dot language
+// See https://graphviz.org/doc/info/lang.html
+
+// Forward decls
+
+struct id;
+struct node_id;
+struct port;
+struct kv_pair;
+struct graph;
+struct attr_list;
+struct stmt_list;
+struct stmt;
+ struct node_stmt;
+ struct attr_stmt;
+ struct kv_stmt;
+ struct edge_stmt;
+ struct subgraph;
+
+// Decls
+
+struct ast_node
+{
+ virtual ~ast_node () {}
+ virtual void print (writer &w) const = 0;
+
+ void dump () const;
+};
+
+struct id : public ast_node
+{
+ enum class kind
+ {
+ identifier,
+ quoted,
+ html
+ };
+
+ id (std::string str);
+
+ /* For HTML labels: see https://graphviz.org/doc/info/shapes.html#html */
+ id (const xml::node &n);
+
+ void print (writer &w) const final override;
+
+ static bool is_identifier_p (const char *);
+
+ std::string m_str;
+ enum kind m_kind;
+};
+
+/* ID '=' ID */
+
+struct kv_pair : ast_node
+{
+ kv_pair (id key, id value)
+ : m_key (std::move (key)),
+ m_value (std::move (value))
+ {
+ }
+
+ void print (writer &w) const final override;
+
+ id m_key;
+ id m_value;
+};
+
+/* attr_list: '[' [ a_list ] ']' [ attr_list ] */
+
+struct attr_list : public ast_node
+{
+ void print (writer &w) const;
+ void add (id key, id value)
+ {
+ m_kvs.push_back ({std::move (key), std::move (value)});
+ }
+
+ std::vector<kv_pair> m_kvs;
+};
+
+/* stmt_list : [ stmt [ ';' ] stmt_list ] */
+
+struct stmt_list : public ast_node
+{
+ void print (writer &w) const final override;
+ void add_stmt (std::unique_ptr<stmt> s)
+ {
+ m_stmts.push_back (std::move (s));
+ }
+ void add_edge (node_id src_id, node_id dst_id);
+ void add_attr (id key, id value);
+
+ std::vector<std::unique_ptr<stmt>> m_stmts;
+};
+
+/* graph : [ strict ] (graph | digraph) [ ID ] '{' stmt_list '}' */
+
+struct graph : public ast_node
+{
+ graph ()
+ : m_id (nullptr)
+ {
+ }
+
+ graph (id id_)
+ : m_id (std::make_unique<id> (std::move (id_)))
+ {
+ }
+
+ void print (writer &w) const final override;
+
+ void add_stmt (std::unique_ptr<stmt> s)
+ {
+ m_stmt_list.add_stmt (std::move (s));
+ }
+
+ std::unique_ptr<id> m_id; // optional
+ stmt_list m_stmt_list;
+};
+
+/* Abstract base class.
+ stmt : node_stmt
+ | edge_stmt
+ | attr_stmt
+ | ID '=' ID ("kv_stmt")
+ | subgraph */
+
+struct stmt
+{
+ virtual ~stmt () {}
+ virtual void print (writer &w) const = 0;
+};
+
+struct stmt_with_attr_list : public stmt
+{
+ void set_attr (id key, id value)
+ {
+ m_attrs.add (std::move (key), std::move (value));
+ }
+ void set_label (dot::id label);
+
+ attr_list m_attrs;
+};
+
+struct node_stmt : public stmt_with_attr_list
+{
+ node_stmt (id id_)
+ : m_id (id_)
+ {
+ }
+
+ void print (writer &w) const final override;
+
+ id m_id;
+};
+
+struct attr_stmt : public stmt_with_attr_list
+{
+ enum class kind { graph, node, edge };
+
+ attr_stmt (enum kind kind_)
+ : m_kind (kind_)
+ {
+ }
+
+ void print (writer &w) const final override;
+
+ enum kind m_kind;
+};
+
+/* "ID '=' ID" as a stmt. */
+
+struct kv_stmt : public stmt
+{
+ kv_stmt (kv_pair kv)
+ : m_kv (std::move (kv))
+ {}
+
+ void print (writer &w) const final override;
+
+ kv_pair m_kv;
+};
+
+/* node_id : ID [ port ] */
+
+enum class compass_pt
+{
+ n, ne, e, se, s, sw, w, nw, c
+ /* "_" clashes with intl macro */
+};
+
+/* port : ':' ID [ ':' compass_pt ]
+ | ':' compass_pt
+*/
+
+struct port : public ast_node
+{
+ port (id id_)
+ : m_id (std::make_unique<id> (std::move (id_))),
+ m_compass_pt (nullptr)
+ {
+ }
+
+ port (enum compass_pt compass_pt_)
+ : m_id (nullptr),
+ m_compass_pt (std::make_unique<compass_pt> (compass_pt_))
+ {
+ }
+
+ port (id id_,
+ enum compass_pt compass_pt_)
+ : m_id (std::make_unique<id> (std::move (id_))),
+ m_compass_pt (std::make_unique<compass_pt> (compass_pt_))
+ {
+ }
+
+ port (const port &other)
+ : m_id (nullptr),
+ m_compass_pt (nullptr)
+ {
+ if (other.m_id)
+ m_id = std::make_unique<id> (*other.m_id);
+ if (other.m_compass_pt)
+ m_compass_pt = std::make_unique<enum compass_pt> (*other.m_compass_pt);
+ }
+
+ void print (writer &w) const final override;
+
+ std::unique_ptr<id> m_id; // would be std::optional
+ std::unique_ptr<enum compass_pt> m_compass_pt; // would be std::optional
+};
+
+struct node_id : public ast_node
+{
+ node_id (id id_)
+ : m_id (id_),
+ m_port (nullptr)
+ {
+ }
+ node_id (id id_, port port_)
+ : m_id (id_),
+ m_port (std::make_unique<port> (std::move (port_)))
+ {
+ }
+ node_id (const node_id &other)
+ : m_id (other.m_id),
+ m_port (nullptr)
+ {
+ if (other.m_port)
+ m_port = std::make_unique<port> (*other.m_port);
+ }
+
+ void print (writer &w) const final override;
+
+ id m_id;
+ std::unique_ptr<port> m_port; // would be std::optional
+};
+
+/* The full grammar for edge_stmt is:
+ edge_stmt : (node_id | subgraph) edgeRHS [ attr_list ]
+ edgeRHS : edgeop (node_id | subgraph) [ edgeRHS ]
+ This class support the subsets where all are "node_id", rather than
+ "subgraph", and doesn't yet support "port" giving effectively:
+ node_id (edgeop node_id)+ [ attr_list]
+ */
+
+struct edge_stmt : public stmt_with_attr_list
+{
+ edge_stmt (node_id src_id, node_id dst_id)
+ {
+ m_node_ids.push_back (std::move (src_id));
+ m_node_ids.push_back (std::move (dst_id));
+ }
+
+ void print (writer &w) const final override;
+
+ std::vector<node_id> m_node_ids; // should have 2 or more elements
+};
+
+/* [ subgraph [ ID ] ] '{' stmt_list '}' */
+
+struct subgraph : public stmt
+{
+ subgraph (id id_)
+ : m_id (id_)
+ {
+ }
+
+ void print (writer &w) const final override;
+
+ void add_stmt (std::unique_ptr<stmt> s)
+ {
+ m_stmt_list.add_stmt (std::move (s));
+ }
+ void add_attr (id key, id value)
+ {
+ m_stmt_list.add_stmt
+ (std::make_unique <kv_stmt> (kv_pair (std::move (key),
+ std::move (value))));
+ }
+
+ id m_id;
+ stmt_list m_stmt_list;
+};
+
+extern std::unique_ptr<xml::node>
+make_svg_from_graph (const graph &g);
+
+} // namespace dot
+
/* A class for writing .dot output to a pretty_printer with
indentation to show nesting. */
-class graphviz_out {
+class graphviz_out : public dot::writer {
public:
graphviz_out (pretty_printer *pp);
@@ -35,11 +381,6 @@ class graphviz_out {
void println (const char *fmt, ...)
ATTRIBUTE_GCC_PPDIAG(2,3);
- void indent () { m_indent++; }
- void outdent () { m_indent--; }
-
- void write_indent ();
-
void begin_tr ();
void end_tr ();
@@ -48,12 +389,6 @@ class graphviz_out {
void begin_trtd ();
void end_tdtr ();
-
- pretty_printer *get_pp () const { return m_pp; }
-
- private:
- pretty_printer *m_pp;
- int m_indent;
};
#endif /* GCC_GRAPHVIZ_H */