3:- module(dot_dcg, [dot/3]). 4
5:- use_module(library(dcg/basics)). 6
9
17
21dot(digraph(Name, StmtList)) -->
22 w_spc_opt, "digraph", w_spc,
23 id(Name),
24 w_spc,
25 "{", w_spc_opt, stmt_list(StmtList), w_spc_opt, "}",
26 w_spc_opt.
27
29stmt_list([]) --> [].
30stmt_list([Stmt]) --> stmt(Stmt).
31stmt_list([Stmt]) --> stmt(Stmt), w_spc_opt, ";".
32stmt_list([Stmt|Rest]) --> stmt(Stmt), w_spc_opt, ";", w_spc_opt, stmt_list(Rest).
34
35
38 39stmt(EdgeStmt) --> edge_stmt(EdgeStmt).
41stmt(NodeStmt) --> node_stmt(NodeStmt).
43stmt(SubGraph) --> subgraph(SubGraph).
45
48
50attr_list(AList) -->
51 "[", w_spc_opt, a_list(AList), w_spc_opt, "]",
52 !.
53attr_list(Merged) -->
54 "[", w_spc_opt,
55 { merge(AList, Rest, Merged) },
56 a_list(AList),
57 w_spc_opt, "]",
58 w_spc_opt,
59 attr_list(Rest).
60
61
63a_list([]) --> [].
64a_list([Attr]) -->
65 attr(Attr), !.
66a_list([Attr|Rest]) -->
67 attr(Attr),
68 w_spc_opt,
69 ("," ; ";"),
70 w_spc_opt,
71 a_list(Rest), !.
72
73
74attr(attr(Name, Value)) --> id(Name), w_spc_opt, "=", w_spc_opt, id(Value), !.
75attr(attr(Name)) --> id(Name).
76
79edge_stmt(edge_stmt(Nodes)) --> edge(Nodes).
80edge_stmt(edge_stmt(Nodes, AttrList)) --> edge(Nodes), w_spc_opt, attr_list(AttrList), !.
81
82
83edge([First|Rest]) --> node_id(First), w_spc_opt, edge_rhs(Rest).
84
87 88
89edge_rhs([Node]) -->
90 edge_op,
91 w_spc_opt,
92 node_id(Node).
93edge_rhs([Node|Rest]) -->
94 edge_op,
95 w_spc_opt,
96 node_id(Node),
97 w_spc_opt,
98 edge_rhs(Rest).
100
101
103node_stmt(node_stmt(NodeId, AttrList)) --> node_id(NodeId), w_spc, attr_list(AttrList).
104node_stmt(node_stmt(NodeId)) --> node_id(NodeId).
105
106
109node_id(NodeId) --> id(NodeId).
110
113subgraph(subgraph(SubGraphId, StmtList)) -->
114 id(SubGraphId),
115 w_spc,
116 "{", stmt_list(StmtList), "}".
117
120
121id_elem(C) -->
122 [C],
123 {code_type(C, alnum)
124 ;
125 atom_codes('_', [C])
126 }.
127
130 131 133
134id(Number) -->
135 {number(Number)},
136 !,
137 number(Number).
138id(AId) -->
139 140 {atomic(AId), atom_codes(AId, Id)},
141 !,
142 id(Id).
143
144id([C|Cs]) -->
145 id_elem(C),
146 {\+ digit(C, [C], [])},
147 id_(Cs).
148
149id(Cs) -->
150 quoted_string_body(Cs, false, false).
151
152
153
154id_([C]) --> id_elem(C).
155id_([C|Cs]) --> id_elem(C), id_(Cs).
156
157
158
159
161
164
165
166
168quoted_string(AString) -->
169 { atom(AString), atom_codes(AString, String) },
170 quoted_string_body(String, false, false).
171
172quoted_string_body([34|String], false, false, [34|Codes], Rest):-
173 174 quoted_string_body(String, true, false, Codes, Rest).
175
176quoted_string_body([92|String], true, false, [92|Codes], Rest):-
177 178 quoted_string_body(String, true, true, Codes, Rest).
179
180quoted_string_body([C|String], true, true, [C|Codes], Rest):-
181 182 quoted_string_body(String, true, false, Codes, Rest).
183
184quoted_string_body([C|String], true, false, [C|Codes], Rest):-
185 186 C \= 34,
187 quoted_string_body(String, true, false, Codes, Rest).
188
189quoted_string_body([34], true, false, [34|Codes], Rest) :-
190 191 Rest = Codes, !.
192
195edge_op --> "-", ">".
196
198w_spc --> w_spc_char.
199w_spc --> w_spc_char, w_spc.
200
201w_spc_char --> [32]; [10]; [11]; [12]; [13].
202
204w_spc_opt --> [].
205w_spc_opt --> w_spc.
206
208merge([], Ys, Ys).
209merge([X|Xs], Ys, [X|Zs]) :- merge(Xs, Ys, Zs)