1 /** \file
2 * \brief Declarations for DOT Parser
3 *
4 * \author Łukasz Hanuszczak
5 *
6 * \par License:
7 * This file is part of the Open Graph Drawing Framework (OGDF).
8 *
9 * \par
10 * Copyright (C)<br>
11 * See README.md in the OGDF root directory for details.
12 *
13 * \par
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * Version 2 or 3 as published by the Free Software Foundation;
17 * see the file LICENSE.txt included in the packaging of this file
18 * for details.
19 *
20 * \par
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * \par
27 * You should have received a copy of the GNU General Public
28 * License along with this program; if not, see
29 * http://www.gnu.org/copyleft/gpl.html
30 */
31
32 #include <ogdf/fileformats/DotParser.h>
33 #include <ogdf/fileformats/Utils.h>
34 #include <ogdf/fileformats/GraphIO.h>
35
36
37 namespace ogdf {
38
39 namespace dot {
40
41 /**
42 * Frees a singly linked list without using recursion.
43 * Should be called from within list destructors.
44 *
45 * @tparam T list element type
46 * @param list A pointer to the list to be deleted.
47 */
48 template<typename T>
destroyList(T * list)49 static void destroyList(T *list) {
50 delete list->head;
51 for (T *next, *element = list->tail; element != nullptr; element = next) {
52 next = element->tail;
53 element->tail = nullptr; // don't recurse deeply on delete
54 delete element;
55 }
56 }
57
Graph(const bool & paramStrict,const bool & dir,std::string * idString,StmtList * statementList)58 Ast::Graph::Graph(
59 const bool ¶mStrict,
60 const bool &dir,
61 std::string *idString,
62 StmtList *statementList)
63 : strict(paramStrict), directed(dir), id(idString), statements(statementList)
64 {
65 }
66
67
~Graph()68 Ast::Graph::~Graph()
69 {
70 delete id;
71 delete statements;
72 }
73
74
StmtList(Stmt * headSTMT,StmtList * tailStatementList)75 Ast::StmtList::StmtList(
76 Stmt *headSTMT,
77 StmtList *tailStatementList)
78 : head(headSTMT), tail(tailStatementList)
79 {
80 }
81
82
~StmtList()83 Ast::StmtList::~StmtList()
84 {
85 destroyList(this);
86 }
87
88
~Stmt()89 Ast::Stmt::~Stmt()
90 {
91 }
92
93
NodeStmt(NodeId * nodeID,AttrList * attrList)94 Ast::NodeStmt::NodeStmt(
95 NodeId *nodeID,
96 AttrList *attrList)
97 : nodeId(nodeID), attrs(attrList)
98 {
99 }
100
101
~NodeStmt()102 Ast::NodeStmt::~NodeStmt()
103 {
104 delete nodeId;
105 delete attrs;
106 }
107
108
EdgeStmt(EdgeLhs * edgeLHS,EdgeRhs * edgeRHS,AttrList * attrList)109 Ast::EdgeStmt::EdgeStmt(
110 EdgeLhs *edgeLHS,
111 EdgeRhs *edgeRHS,
112 AttrList *attrList)
113 : lhs(edgeLHS), rhs(edgeRHS), attrs(attrList)
114 {
115 }
116
117
~EdgeStmt()118 Ast::EdgeStmt::~EdgeStmt()
119 {
120 delete lhs;
121 delete rhs;
122 delete attrs;
123 }
124
125
AsgnStmt(const std::string & lhsString,const std::string & rhsString)126 Ast::AsgnStmt::AsgnStmt(
127 const std::string &lhsString,
128 const std::string &rhsString)
129 : lhs(lhsString), rhs(rhsString)
130 {
131 }
132
133
~AsgnStmt()134 Ast::AsgnStmt::~AsgnStmt()
135 {
136 }
137
138
AttrStmt(const Type & paramType,AttrList * attrList)139 Ast::AttrStmt::AttrStmt(
140 const Type ¶mType,
141 AttrList *attrList)
142 : type(paramType), attrs(attrList)
143 {
144 }
145
146
~AttrStmt()147 Ast::AttrStmt::~AttrStmt()
148 {
149 delete attrs;
150 }
151
152
Subgraph(std::string * idString,StmtList * statementList)153 Ast::Subgraph::Subgraph(
154 std::string *idString,
155 StmtList *statementList)
156 : id(idString), statements(statementList)
157 {
158 }
159
160
~Subgraph()161 Ast::Subgraph::~Subgraph()
162 {
163 delete id;
164 delete statements;
165 }
166
167
~EdgeLhs()168 Ast::EdgeLhs::~EdgeLhs()
169 {
170 }
171
172
EdgeRhs(EdgeLhs * headEdgeLHS,EdgeRhs * tailEdgeRHS)173 Ast::EdgeRhs::EdgeRhs(
174 EdgeLhs *headEdgeLHS,
175 EdgeRhs *tailEdgeRHS)
176 : head(headEdgeLHS), tail(tailEdgeRHS)
177 {
178 }
179
180
~EdgeRhs()181 Ast::EdgeRhs::~EdgeRhs()
182 {
183 destroyList(this);
184 }
185
186
NodeId(const std::string & idString,Port * paramPort)187 Ast::NodeId::NodeId(
188 const std::string &idString,
189 Port *paramPort)
190 : id(idString), port(paramPort)
191 {
192 }
193
194
~NodeId()195 Ast::NodeId::~NodeId()
196 {
197 delete port;
198 }
199
200
Port(std::string * idString,CompassPt * compassPT)201 Ast::Port::Port(
202 std::string *idString,
203 CompassPt *compassPT)
204 : id(idString), compassPt(compassPT)
205 {
206 }
207
208
~Port()209 Ast::Port::~Port()
210 {
211 delete id;
212 delete compassPt;
213 }
214
215
CompassPt(const Type & paramType)216 Ast::CompassPt::CompassPt(
217 const Type ¶mType)
218 : type(paramType)
219 {
220 }
221
222
~CompassPt()223 Ast::CompassPt::~CompassPt()
224 {
225 }
226
227
AttrList(AList * headAList,AttrList * tailAttrList)228 Ast::AttrList::AttrList(
229 AList *headAList,
230 AttrList *tailAttrList)
231 : head(headAList), tail(tailAttrList)
232 {
233 }
234
235
~AttrList()236 Ast::AttrList::~AttrList()
237 {
238 destroyList(this);
239 }
240
241
AList(AsgnStmt * headAsgnStmt,AList * tailAList)242 Ast::AList::AList(
243 AsgnStmt *headAsgnStmt,
244 AList *tailAList)
245 : head(headAsgnStmt), tail(tailAList)
246 {
247 }
248
249
~AList()250 Ast::AList::~AList()
251 {
252 destroyList(this);
253 }
254
255
Ast(const Tokens & tokens)256 Ast::Ast(const Tokens &tokens)
257 : m_tokens(tokens), m_tend(m_tokens.end()), m_graph(nullptr)
258 {
259 }
260
261
~Ast()262 Ast::~Ast()
263 {
264 delete m_graph;
265 }
266
267
build()268 bool Ast::build()
269 {
270 Iterator it = m_tokens.begin();
271 delete m_graph;
272 m_graph = parseGraph(it, it);
273 return m_graph != nullptr;
274 }
275
276
root() const277 Ast::Graph *Ast::root() const
278 {
279 return m_graph;
280 }
281
282
parseEdgeStmt(Iterator curr,Iterator & rest)283 Ast::EdgeStmt *Ast::parseEdgeStmt(
284 Iterator curr, Iterator &rest)
285 {
286 EdgeLhs *lhs;
287 if(!((lhs = parseNodeId(curr, curr)) ||
288 (lhs = parseSubgraph(curr, curr)))) {
289 return nullptr;
290 }
291
292 EdgeRhs *rhs = parseEdgeRhs(curr, curr);
293 if(!rhs) {
294 delete lhs;
295 return nullptr;
296 }
297
298 AttrList *attrs = parseAttrList(curr, curr);
299
300 rest = curr;
301 return new EdgeStmt(lhs, rhs, attrs);
302 }
303
304
parseEdgeRhs(Iterator curr,Iterator & rest)305 Ast::EdgeRhs *Ast::parseEdgeRhs(
306 Iterator curr, Iterator &rest)
307 {
308 if(curr == m_tend || (curr->type != Token::Type::edgeOpDirected &&
309 curr->type != Token::Type::edgeOpUndirected)) {
310 return nullptr;
311 }
312 curr++;
313
314 EdgeLhs *head;
315 if(!((head = parseSubgraph(curr, curr)) ||
316 (head = parseNodeId(curr, curr)))) {
317 return nullptr;
318 }
319
320 EdgeRhs *tail = parseEdgeRhs(curr, curr);
321
322 rest = curr;
323 return new EdgeRhs(head, tail);
324 }
325
326
parseNodeStmt(Iterator curr,Iterator & rest)327 Ast::NodeStmt *Ast::parseNodeStmt(
328 Iterator curr, Iterator &rest)
329 {
330 NodeId *nodeId = parseNodeId(curr, curr);
331 if(!nodeId) {
332 return nullptr;
333 }
334
335 AttrList *attrs = parseAttrList(curr, curr);
336
337 rest = curr;
338 return new NodeStmt(nodeId, attrs);
339 }
340
341
parseNodeId(Iterator curr,Iterator & rest)342 Ast::NodeId *Ast::parseNodeId(
343 Iterator curr, Iterator &rest)
344 {
345 if(curr == m_tend || curr->type != Token::Type::identifier) {
346 return nullptr;
347 }
348 std::string id = *(curr->value);
349 curr++;
350
351 Port *port = parsePort(curr, curr);
352
353 rest = curr;
354 return new NodeId(id, port);
355 }
356
357
parseCompassPt(Iterator curr,Iterator & rest)358 Ast::CompassPt *Ast::parseCompassPt(
359 Iterator curr, Iterator &rest)
360 {
361 if(curr == m_tend || curr->type != Token::Type::identifier) {
362 return nullptr;
363 }
364 const std::string &str = *(curr->value);
365 curr++;
366 if(str == "n") {
367 rest = curr;
368 return new CompassPt(CompassPt::Type::n);
369 }
370 if(str == "ne") {
371 rest = curr;
372 return new CompassPt(CompassPt::Type::ne);
373 }
374 if(str == "e") {
375 rest = curr;
376 return new CompassPt(CompassPt::Type::e);
377 }
378 if(str == "se") {
379 rest = curr;
380 return new CompassPt(CompassPt::Type::se);
381 }
382 if(str == "s") {
383 rest = curr;
384 return new CompassPt(CompassPt::Type::s);
385 }
386 if(str == "sw") {
387 rest = curr;
388 return new CompassPt(CompassPt::Type::sw);
389 }
390 if(str == "w") {
391 rest = curr;
392 return new CompassPt(CompassPt::Type::w);
393 }
394 if(str == "nw") {
395 rest = curr;
396 return new CompassPt(CompassPt::Type::nw);
397 }
398 if(str == "c") {
399 rest = curr;
400 return new CompassPt(CompassPt::Type::c);
401 }
402 if(str == "_") {
403 rest = curr;
404 return new CompassPt(CompassPt::Type::wildcard);
405 }
406 return nullptr;
407 }
408
409
parsePort(Iterator curr,Iterator & rest)410 Ast::Port *Ast::parsePort(
411 Iterator curr, Iterator &rest)
412 {
413 if(curr == m_tend || curr->type != Token::Type::colon) {
414 return nullptr;
415 }
416 curr++;
417
418 CompassPt *compass = parseCompassPt(curr, curr);
419 if(compass) {
420 rest = curr;
421 return new Port(nullptr, compass);
422 }
423
424 std::string *id = curr->value;
425 curr++;
426
427 if(curr != m_tend && curr->type == Token::Type::colon) {
428 curr++;
429
430 compass = parseCompassPt(curr, curr);
431 if(compass) {
432 rest = curr;
433 return new Port(id, compass);
434 }
435
436 // Compass parsing not succeeded, "put back" the colon.
437 curr--;
438 }
439
440 rest = curr;
441 return new Port(id, nullptr);
442 }
443
444
parseAttrStmt(Iterator curr,Iterator & rest)445 Ast::AttrStmt *Ast::parseAttrStmt(
446 Iterator curr, Iterator &rest)
447 {
448 if(curr == m_tend) {
449 return nullptr;
450 }
451
452 AttrStmt::Type type;
453 switch(curr->type) {
454 case Token::Type::graph:
455 type = AttrStmt::Type::graph;
456 break;
457 case Token::Type::node:
458 type = AttrStmt::Type::node;
459 break;
460 case Token::Type::edge:
461 type = AttrStmt::Type::edge;
462 break;
463 default:
464 return nullptr;
465 }
466 curr++;
467
468 AttrList *attrs = parseAttrList(curr, curr);
469 if(!attrs) {
470 return nullptr;
471 }
472
473 rest = curr;
474 return new AttrStmt(type, attrs);
475 }
476
477
parseAsgnStmt(Iterator curr,Iterator & rest)478 Ast::AsgnStmt *Ast::parseAsgnStmt(
479 Iterator curr, Iterator &rest)
480 {
481 if(curr == m_tend || curr->type != Token::Type::identifier) {
482 return nullptr;
483 }
484 std::string lhs = *(curr->value);
485 curr++;
486
487 if(curr == m_tend || curr->type != Token::Type::assignment) {
488 return nullptr;
489 }
490 curr++;
491
492 if(curr == m_tend || curr->type != Token::Type::identifier) {
493 return nullptr;
494 }
495 std::string rhs = *(curr->value);
496 curr++;
497
498 rest = curr;
499 return new AsgnStmt(lhs, rhs);
500 }
501
502
parseSubgraph(Iterator curr,Iterator & rest)503 Ast::Subgraph *Ast::parseSubgraph(
504 Iterator curr, Iterator &rest)
505 {
506 if(curr == m_tend) {
507 return nullptr;
508 }
509
510 // Optional "subgraph" keyword and optional identifier.
511 std::string *id = nullptr;
512 if(curr->type == Token::Type::subgraph) {
513 curr++;
514 if(curr == m_tend) {
515 return nullptr;
516 }
517 if(curr->type == Token::Type::identifier) {
518 id = new std::string(*(curr->value));
519 curr++;
520 }
521 }
522
523 if(curr == m_tend || curr->type != Token::Type::leftBrace) {
524 delete id;
525 return nullptr;
526 }
527 curr++;
528
529 StmtList *stmts = parseStmtList(curr, curr);
530
531 if(curr == m_tend || curr->type != Token::Type::rightBrace) {
532 delete id;
533 delete stmts;
534 return nullptr;
535 }
536 curr++;
537
538 rest = curr;
539 return new Subgraph(id, stmts);
540 }
541
542
parseStmt(Iterator curr,Iterator & rest)543 Ast::Stmt *Ast::parseStmt(
544 Iterator curr, Iterator &rest)
545 {
546 Stmt *stmt;
547 if((stmt = parseEdgeStmt(curr, curr)) ||
548 (stmt = parseAttrStmt(curr, curr)) ||
549 (stmt = parseAsgnStmt(curr, curr)) ||
550 (stmt = parseNodeStmt(curr, curr)) ||
551 (stmt = parseSubgraph(curr, curr))) {
552 rest = curr;
553 return stmt;
554 }
555
556 return nullptr;
557 }
558
559
parseStmtList(Iterator curr,Iterator & rest)560 Ast::StmtList *Ast::parseStmtList(
561 Iterator curr, Iterator &rest)
562 {
563 if (curr == m_tend) {
564 return nullptr;
565 }
566
567 ArrayBuffer<Stmt*> stmts;
568 Stmt *head;
569
570 // Collect statements iteratively (a recursive implementation would cause
571 // stack overflows).
572 do {
573 head = parseStmt(curr, curr);
574
575 if (head != nullptr) {
576 stmts.push(head);
577
578 // Optional semicolon.
579 if (curr != m_tend && curr->type == Token::Type::semicolon) {
580 curr++;
581 }
582 }
583 } while (curr != m_tend && head != nullptr);
584
585 // Build StmtList from statements.
586 StmtList *stmtList = nullptr;
587 while (!stmts.empty()) {
588 stmtList = new StmtList(stmts.popRet(), stmtList);
589 }
590
591 rest = curr;
592 return stmtList;
593 }
594
595
parseGraph(Iterator curr,Iterator & rest)596 Ast::Graph *Ast::parseGraph(
597 Iterator curr, Iterator &rest)
598 {
599 if(curr == m_tend) {
600 return nullptr;
601 }
602
603 bool strict = false;
604 bool directed = false;
605 std::string *id = nullptr;
606
607 if(curr->type == dot::Token::Type::strict) {
608 strict = true;
609 curr++;
610 }
611
612 if(curr == m_tend) {
613 return nullptr;
614 }
615
616 switch(curr->type) {
617 case Token::Type::graph:
618 directed = false;
619 break;
620 case Token::Type::digraph:
621 directed = true;
622 break;
623 default:
624 GraphIO::logger.lout() << "Unexpected token \""
625 << Token::toString(curr->type)
626 << "\" at "
627 << curr->row << ", " << curr->column << "." << std::endl;
628 return nullptr;
629 }
630 curr++;
631
632 if(curr == m_tend) {
633 return nullptr;
634 }
635
636 if(curr->type == Token::Type::identifier) {
637 id = new std::string(*(curr->value));
638 curr++;
639 }
640
641 if(curr == m_tend || curr->type != Token::Type::leftBrace) {
642 #if 0
643 GraphIO::logger.lout() << "Expected \""
644 << Token::toString(Token::Type::leftBrace)
645 << ", found \"" << Token::toString(curr->type)
646 << "\" at " << curr->row << ", " << curr->column
647 << ".\n";
648 #endif
649 delete id;
650 return nullptr;
651 }
652 curr++;
653
654 StmtList *statements = parseStmtList(curr, curr);
655
656 if(curr == m_tend || curr->type != Token::Type::rightBrace) {
657 GraphIO::logger.lout() << "Expected \""
658 << Token::toString(Token::Type::rightBrace)
659 << ", found \""
660 << Token::toString(curr->type)
661 << "\" at "
662 << curr->row << ", " << curr->column << "." << std::endl;
663 delete id;
664 delete statements;
665 return nullptr;
666 }
667 curr++;
668
669 rest = curr;
670 return new Graph(strict, directed, id, statements);
671 }
672
673
parseAttrList(Iterator curr,Iterator & rest)674 Ast::AttrList *Ast::parseAttrList(
675 Iterator curr, Iterator &rest)
676 {
677
678 ArrayBuffer<AList*> subLists;
679 bool doContinue = false;
680
681 do {
682 doContinue = curr != m_tend && curr->type == Token::Type::leftBracket;
683 AList *head = nullptr;
684
685 if(doContinue) {
686 curr++;
687 head = parseAList(curr, curr);
688
689 doContinue = curr != m_tend && curr->type == Token::Type::rightBracket;
690 }
691
692 if(doContinue) {
693 curr++;
694 subLists.push(head);
695 rest = curr;
696 } else {
697 delete head;
698 }
699 } while(doContinue);
700
701 AttrList *result = nullptr;
702
703 while(!subLists.empty()) {
704 result = new AttrList(subLists.popRet(), result);
705 }
706
707 return result;
708 }
709
710
parseAList(Iterator curr,Iterator & rest)711 Ast::AList *Ast::parseAList(
712 Iterator curr, Iterator &rest)
713 {
714 ArrayBuffer<AsgnStmt*> statements;
715 AsgnStmt *head = nullptr;
716
717 do {
718 head = parseAsgnStmt(curr, curr);
719
720 if(head != nullptr) {
721 // Optional comma.
722 if(curr != m_tend && curr->type == Token::Type::comma) {
723 curr++;
724 }
725
726 statements.push(head);
727 rest = curr;
728 }
729 } while(head != nullptr);
730
731 AList *result = nullptr;
732
733 while(!statements.empty()) {
734 result = new AList(statements.popRet(), result);
735 }
736
737 return result;
738 }
739
740
readBends(const std::string & str,DPolyline & polyline)741 static bool readBends(
742 const std::string &str,
743 DPolyline &polyline)
744 {
745 // First, just trim every unnecessary charater - we don't treat DOT's
746 // spline as spline but just set of bending points. One can always
747 // implement B-splines and then generate bending points.
748 std::string fixed(str);
749 for(auto &elem : fixed) {
750 if(elem == ',' || elem == ';' ||
751 elem == 'e' || elem == 'p')
752 {
753 elem = ' ';
754 }
755 }
756
757 std::istringstream is(fixed);
758
759 double x, y;
760 polyline.clear();
761 while(is >> x && is >> y) {
762 polyline.pushBack(DPoint(x, y));
763 }
764
765 return true;
766 }
767
768
readAttribute(GraphAttributes & GA,const node & v,const Ast::AsgnStmt & stmt)769 static bool readAttribute(
770 GraphAttributes &GA, const node &v,
771 const Ast::AsgnStmt &stmt)
772 {
773 const long flags = GA.attributes();
774
775 std::istringstream ss(stmt.rhs);
776 switch(toAttribute(stmt.lhs)) {
777 case Attribute::Id:
778 if(flags & GraphAttributes::nodeId) {
779 ss >> GA.idNode(v);
780 }
781 break;
782 case Attribute::Label:
783 if(flags & GraphAttributes::nodeLabel) {
784 GA.label(v) = stmt.rhs;
785 }
786 break;
787 case Attribute::Template:
788 if(flags & GraphAttributes::nodeTemplate) {
789 GA.templateNode(v) = stmt.rhs;
790 }
791 break;
792 case Attribute::Width:
793 if(flags & GraphAttributes::nodeGraphics) {
794 // sscanf(stmt.rhs.c_str(), "%lf", &GA.width(v));
795 ss >> GA.width(v);
796 }
797 break;
798 case Attribute::Height:
799 if(flags & GraphAttributes::nodeGraphics) {
800 // sscanf(stmt.rhs.c_str(), "%lf", &GA.height(v));
801 ss >> GA.height(v);
802 }
803 break;
804 case Attribute::Weight:
805 if (flags & GraphAttributes::nodeWeight) {
806 ss >> GA.weight(v);
807 }
808 break;
809 case Attribute::Shape:
810 if(flags & GraphAttributes::nodeGraphics) {
811 GA.shape(v) = toShape(stmt.rhs);
812 }
813 break;
814 case Attribute::Position:
815 if(flags & GraphAttributes::nodeGraphics) {
816 // sscanf(stmt.rhs.c_str(), "%lf,%lf", &GA.x(v), &GA.y(v));
817 ss >> GA.x(v) >> TokenIgnorer(',') >> GA.y(v);
818 if(flags & GraphAttributes::threeD) {
819 ss >> TokenIgnorer(',') >> GA.z(v);
820 }
821 }
822 break;
823 case Attribute::LabelPosition:
824 if(flags & GraphAttributes::nodeLabelPosition) {
825 ss >> GA.xLabel(v) >> TokenIgnorer(',') >> GA.yLabel(v);
826 if(flags & GraphAttributes::threeD) {
827 ss >> TokenIgnorer(',') >> GA.zLabel(v);
828 }
829 }
830 break;
831 case Attribute::Stroke:
832 if(flags & GraphAttributes::nodeStyle) {
833 GA.strokeColor(v) = stmt.rhs;
834 // TODO: color literals.
835 }
836 break;
837 case Attribute::StrokeWidth:
838 if(flags & GraphAttributes::nodeStyle) {
839 ss >> GA.strokeWidth(v);
840 }
841 break;
842 case Attribute::FillBackground:
843 if(flags & GraphAttributes::nodeStyle) {
844 GA.fillBgColor(v) = stmt.rhs;
845 }
846 break;
847 case Attribute::FillPattern:
848 if(flags & GraphAttributes::nodeStyle) {
849 string help;
850 ss >> help;
851 GA.fillPattern(v) = fromString<FillPattern>(help);
852 }
853 break;
854 case Attribute::Type:
855 if(flags & GraphAttributes::nodeType) {
856 int help;
857 ss >> help;
858 GA.type(v) = Graph::NodeType(help);
859 }
860 break;
861 case Attribute::StrokeType:
862 if(flags & GraphAttributes::nodeStyle) {
863 string help;
864 ss >> help;
865 GA.strokeType(v) = fromString<StrokeType>(help);
866 }
867 break;
868 case Attribute::Fill:
869 if(flags & GraphAttributes::nodeStyle) {
870 GA.fillColor(v) = stmt.rhs;
871 // TODO: color literals.
872 }
873 break;
874 default:
875 GraphIO::logger.lout(Logger::Level::Minor) << "Attribute \"" << stmt.lhs
876 << "\" is not supported by node or incorrect. Ignoring." << std::endl;
877 }
878
879 return true;
880 }
881
882
readAttribute(GraphAttributes & GA,const edge & e,const Ast::AsgnStmt & stmt)883 static bool readAttribute(
884 GraphAttributes &GA, const edge &e,
885 const Ast::AsgnStmt &stmt)
886 {
887 const long flags = GA.attributes();
888
889 std::istringstream ss(stmt.rhs);
890 switch(toAttribute(stmt.lhs)) {
891 case Attribute::Label:
892 if(flags & GraphAttributes::edgeLabel) {
893 GA.label(e) = stmt.rhs;
894 }
895 break;
896 case Attribute::Weight:
897 if(flags & GraphAttributes::edgeDoubleWeight) {
898 ss >> GA.doubleWeight(e);
899 } else if (flags & GraphAttributes::edgeIntWeight) {
900 ss >> GA.intWeight(e);
901 }
902 break;
903 case Attribute::Position:
904 if(flags & GraphAttributes::edgeGraphics) {
905 readBends(stmt.rhs, GA.bends(e));
906 }
907 break;
908 case Attribute::Stroke:
909 if(flags & GraphAttributes::edgeStyle) {
910 GA.strokeColor(e) = stmt.rhs;
911 // TODO: color literals.
912 }
913 break;
914 case Attribute::StrokeWidth:
915 if(flags & GraphAttributes::edgeStyle) {
916 ss >> GA.strokeWidth(e);
917 }
918 break;
919 case Attribute::StrokeType:
920 if(flags & GraphAttributes::edgeStyle) {
921 string help;
922 ss >> help;
923 GA.strokeType(e) = fromString<StrokeType>(help);
924 }
925 break;
926 case Attribute::Type:
927 if(flags & GraphAttributes::edgeType) {
928 string help;
929 ss >> help;
930 GA.type(e) = dot::toEdgeType(help);
931 }
932 break;
933 case Attribute::Arrow:
934 if(flags & GraphAttributes::edgeArrow) {
935 int help;
936 ss >> help;
937 GA.arrowType(e) = EdgeArrow(help);
938 }
939 break;
940 case Attribute::Dir:
941 if (flags & GraphAttributes::edgeArrow) {
942 GA.arrowType(e) = dot::toArrow(stmt.rhs);
943 }
944 break;
945 case Attribute::SubGraphs:
946 if (flags & GraphAttributes::edgeSubGraphs) {
947 int sg;
948 while(ss >> sg) {
949 GA.addSubGraph(e, sg);
950 }
951 }
952 break;
953 default:
954 GraphIO::logger.lout(Logger::Level::Minor) << "Attribute \"" << stmt.lhs << "\" is not supported by edge or incorrect. Ignoring." << std::endl;
955 }
956
957 return true;
958 }
959
960
readAttribute(ClusterGraphAttributes & CA,const cluster & c,const Ast::AsgnStmt & stmt)961 static bool readAttribute(
962 ClusterGraphAttributes &CA, const cluster &c,
963 const Ast::AsgnStmt &stmt)
964 {
965 const long flags = CA.attributes();
966
967 std::istringstream ss(stmt.rhs);
968 switch(toAttribute(stmt.lhs)) {
969 case Attribute::Label:
970 if (flags & ClusterGraphAttributes::clusterLabel) {
971 CA.label(c) = stmt.rhs;
972 }
973 break;
974 case Attribute::Template:
975 if (flags & ClusterGraphAttributes::clusterTemplate) {
976 CA.templateCluster(c) = stmt.rhs;
977 }
978 break;
979 case Attribute::Position:
980 if (flags & ClusterGraphAttributes::clusterGraphics) {
981 ss >> CA.x(c) >> TokenIgnorer(',') >> CA.y(c);
982 }
983 break;
984 case Attribute::Width:
985 if (flags & ClusterGraphAttributes::clusterGraphics) {
986 ss >> CA.width(c);
987 }
988 break;
989 case Attribute::Height:
990 if (flags & ClusterGraphAttributes::clusterGraphics) {
991 ss >> CA.height(c);
992 }
993 break;
994 case Attribute::StrokeType:
995 if (flags & ClusterGraphAttributes::clusterStyle) {
996 string help;
997 ss >> help;
998 CA.strokeType(c) = fromString<StrokeType>(help);
999 }
1000 break;
1001 case Attribute::Fill:
1002 if (flags & ClusterGraphAttributes::clusterStyle) {
1003 CA.fillColor(c) = stmt.rhs;
1004 }
1005 break;
1006 case Attribute::Stroke:
1007 if (flags & ClusterGraphAttributes::clusterStyle) {
1008 CA.strokeColor(c) = stmt.rhs;
1009 }
1010 break;
1011 case Attribute::StrokeWidth:
1012 if (flags & ClusterGraphAttributes::clusterStyle) {
1013 ss >> CA.strokeWidth(c);
1014 }
1015 break;
1016 case Attribute::FillPattern:
1017 if (flags & ClusterGraphAttributes::clusterStyle) {
1018 string help;
1019 ss >> help;
1020 CA.fillPattern(c) = fromString<FillPattern>(help);
1021 }
1022 break;
1023 case Attribute::FillBackground:
1024 if (flags & ClusterGraphAttributes::clusterStyle) {
1025 CA.fillBgColor(c) = stmt.rhs;
1026 }
1027 break;
1028 default:
1029 GraphIO::logger.lout(Logger::Level::Minor) << "Attribute \"" << stmt.lhs
1030 << "\" is not supported by cluster or incorrect. Ignoring." << std::endl;
1031 }
1032 return true;
1033 }
1034
1035
1036 template <typename G, typename T>
readAttributes(G & GA,T elem,Ast::AttrList * attrs)1037 static inline bool readAttributes(
1038 G &GA, T elem,
1039 Ast::AttrList *attrs)
1040 {
1041 for(; attrs; attrs = attrs->tail) {
1042 for(Ast::AList *alist = attrs->head; alist; alist = alist->tail) {
1043 if(!readAttribute(GA, elem, *(alist->head))) {
1044 return false;
1045 }
1046 }
1047 }
1048
1049 return true;
1050 }
1051
1052
1053 template <typename G, typename T>
readAttributes(G & GA,T elem,const std::vector<Ast::AttrList * > & defaults)1054 static inline bool readAttributes(
1055 G &GA, T elem,
1056 const std::vector<Ast::AttrList *> &defaults)
1057 {
1058 for(Ast::AttrList *p : defaults)
1059 {
1060 if(!readAttributes(GA, elem, p)) {
1061 return false;
1062 }
1063 }
1064
1065 return true;
1066 }
1067
1068
readStatements(Parser & P,Graph & G,GraphAttributes * GA,ClusterGraph * C,ClusterGraphAttributes * CA,const SubgraphData & data,Ast::StmtList * stmts)1069 static inline bool readStatements(
1070 Parser &P,
1071 Graph &G, GraphAttributes *GA,
1072 ClusterGraph *C, ClusterGraphAttributes *CA,
1073 const SubgraphData &data,
1074 Ast::StmtList *stmts)
1075 {
1076 for(; stmts; stmts = stmts->tail) {
1077 if(!stmts->head->read(P, G, GA, C, CA, data)) {
1078 return false;
1079 }
1080 }
1081
1082 return true;
1083 }
1084
1085
read(Parser & P,ogdf::Graph & G,GraphAttributes * GA,ClusterGraph * C,ClusterGraphAttributes * CA)1086 bool Ast::Graph::read(
1087 Parser &P,
1088 ogdf::Graph &G, GraphAttributes *GA,
1089 ClusterGraph *C, ClusterGraphAttributes *CA)
1090 {
1091 if(GA) {
1092 GA->directed() = directed;
1093 }
1094
1095 std::set<node> subgraphNodes;
1096 std::vector<AttrList *> nodeDefaults, edgeDefaults;
1097 return readStatements(
1098 P, G, GA, C, CA,
1099 SubgraphData(
1100 // Root cluster.
1101 C ? C->rootCluster() : nullptr,
1102 nodeDefaults, edgeDefaults, subgraphNodes),
1103 statements);
1104 }
1105
1106
read(Parser & P,ogdf::Graph & G,GraphAttributes * GA,ClusterGraph * C,ClusterGraphAttributes *,const SubgraphData & data)1107 bool Ast::NodeStmt::read(
1108 Parser &P,
1109 ogdf::Graph &G, GraphAttributes *GA,
1110 ClusterGraph *C, ClusterGraphAttributes* /*unused parameter*/,
1111 const SubgraphData &data)
1112 {
1113 const node v = P.requestNode(G, GA, C, data, nodeId->id);
1114 data.nodes.insert(v);
1115 return GA ? readAttributes(*GA, v, attrs) : true;
1116 }
1117
1118
cross(ogdf::Graph & G,GraphAttributes * GA,ClusterGraph *,ClusterGraphAttributes *,const std::vector<Ast::AttrList * > & defaults,Ast::AttrList * attrs,const std::set<ogdf::node> & lnodes,const std::set<ogdf::node> & rnodes)1119 static inline bool cross(
1120 ogdf::Graph &G, GraphAttributes *GA,
1121 ClusterGraph* /*unused parameter*/, ClusterGraphAttributes* /*unused parameter*/,
1122 const std::vector<Ast::AttrList *> &defaults, Ast::AttrList *attrs,
1123 const std::set<ogdf::node> &lnodes, const std::set<ogdf::node> &rnodes)
1124 {
1125 for(node vl : lnodes)
1126 {
1127 for(node vr : rnodes)
1128 {
1129 const edge e = G.newEdge(vl, vr);
1130 if(GA && !(readAttributes(*GA, e, defaults) &&
1131 readAttributes(*GA, e, attrs))) {
1132 return false;
1133 }
1134 }
1135 }
1136
1137 return true;
1138 }
1139
read(Parser & P,ogdf::Graph & G,GraphAttributes * GA,ClusterGraph * C,ClusterGraphAttributes * CA,const SubgraphData & data)1140 bool Ast::EdgeStmt::read(
1141 Parser &P,
1142 ogdf::Graph &G, GraphAttributes *GA,
1143 ClusterGraph *C, ClusterGraphAttributes *CA,
1144 const SubgraphData &data)
1145 {
1146 Ast::EdgeLhs *edgeLhs = this->lhs;
1147
1148 std::set<node> lnodes;
1149 edgeLhs->read(P, G, GA, C, CA, data.withNodes(lnodes));
1150
1151 for(Ast::EdgeRhs *edgeRhs = this->rhs; edgeRhs; edgeRhs = edgeRhs->tail) {
1152 std::set<node> rnodes;
1153 edgeRhs->head->read(P, G, GA, C, CA, data.withNodes(rnodes));
1154
1155 if(!cross(G, GA, C, CA, data.edgeDefaults, attrs, lnodes, rnodes)) {
1156 return false;
1157 }
1158
1159 // Append left side nodes to the result and make right node left ones.
1160 data.nodes.insert(lnodes.begin(), lnodes.end());
1161 std::swap(lnodes, rnodes);
1162 edgeLhs = edgeRhs->head;
1163 }
1164
1165 return true;
1166 }
1167
1168
read(Parser & P,ogdf::Graph & G,GraphAttributes *,ClusterGraph *,ClusterGraphAttributes * CA,const SubgraphData & data)1169 bool Ast::AsgnStmt::read(
1170 Parser &P,
1171 ogdf::Graph &G, GraphAttributes* /*unused parameter*/,
1172 ClusterGraph* /*unused parameter*/, ClusterGraphAttributes *CA,
1173 const SubgraphData &data)
1174 {
1175 return CA ? readAttribute(*CA, data.rootCluster, *this) : true;
1176 }
1177
1178
read(Parser & P,ogdf::Graph & G,GraphAttributes *,ClusterGraph *,ClusterGraphAttributes * CA,const SubgraphData & data)1179 bool Ast::AttrStmt::read(
1180 Parser &P,
1181 ogdf::Graph &G, GraphAttributes* /*unused parameter*/,
1182 ClusterGraph* /*unused parameter*/, ClusterGraphAttributes *CA,
1183 const SubgraphData &data)
1184 {
1185 switch(type) {
1186 case Type::graph:
1187 return CA ? readAttributes(*CA, data.rootCluster, attrs) : true;
1188 case Type::node:
1189 data.nodeDefaults.push_back(attrs);
1190 return true;
1191 case Type::edge:
1192 data.edgeDefaults.push_back(attrs);
1193 return true;
1194 default:
1195 return false;
1196 }
1197 }
1198
1199
read(Parser & P,ogdf::Graph & G,GraphAttributes * GA,ClusterGraph * C,ClusterGraphAttributes * CA,const SubgraphData & data)1200 bool Ast::Subgraph::read(
1201 Parser &P,
1202 ogdf::Graph &G, GraphAttributes *GA,
1203 ClusterGraph *C, ClusterGraphAttributes *CA,
1204 const SubgraphData &data)
1205 {
1206 // We pass a copy of defaults to subgraph because those parameters should
1207 // be local for given subgraph.
1208 std::vector<AttrList *> nodeDefaults(data.nodeDefaults);
1209 std::vector<AttrList *> edgeDefaults(data.edgeDefaults);
1210 SubgraphData newData = data.withDefaults(nodeDefaults, edgeDefaults);
1211
1212 // Create new cluster if subgraph identifier is given and it starts with
1213 // pattern "cluster". Otherwise, subgraph is not considered as a cluster
1214 // (as stated in DOT manual).
1215 const std::string patt = "cluster";
1216 if(C && id && id->compare(0, patt.length(), patt) == 0) {
1217 return readStatements(
1218 P, G, GA, C, CA,
1219 newData.withCluster(C->newCluster(newData.rootCluster)),
1220 statements);
1221 }
1222
1223 return readStatements(P, G, GA, C, CA, newData, statements);
1224 }
1225
1226
read(Parser & P,ogdf::Graph & G,GraphAttributes * GA,ClusterGraph * C,ClusterGraphAttributes *,const SubgraphData & data)1227 bool Ast::NodeId::read(
1228 Parser &P,
1229 ogdf::Graph &G, GraphAttributes *GA,
1230 ClusterGraph *C, ClusterGraphAttributes* /*unused parameter*/,
1231 const SubgraphData &data)
1232 {
1233 data.nodes.insert(P.requestNode(G, GA, C, data, id));
1234 return true;
1235 }
1236
1237
Parser(std::istream & in)1238 Parser::Parser(std::istream &in) : m_in(in), m_nodeId(nullptr)
1239 {
1240 }
1241
1242
requestNode(Graph & G,GraphAttributes * GA,ClusterGraph * C,const SubgraphData & data,const std::string & id)1243 node Parser::requestNode(
1244 Graph &G, GraphAttributes *GA, ClusterGraph *C,
1245 const SubgraphData &data,
1246 const std::string &id)
1247 {
1248 node v;
1249 // Ugly and slow, fix it somehow in the future.
1250 if(!m_nodeId[id]) {
1251 v = m_nodeId[id] = G.newNode();
1252 if(C) {
1253 C->reassignNode(v, data.rootCluster);
1254 }
1255
1256 // We also set default attributes when a node is requested for the
1257 // first time. This may sound strange but Graphviz's DOT tool behaves
1258 // exactly the same so I guess this is a right place to use these.
1259 if(GA) {
1260 if(GA->has(GraphAttributes::nodeLabel)) {
1261 GA->label(v) = id;
1262 }
1263 readAttributes(*GA, v, data.nodeDefaults);
1264 }
1265 } else {
1266 v = m_nodeId[id];
1267 }
1268
1269 // So, the question is: where to put a node if it can be declared with
1270 // edge statement and edge statements with common node may appear in
1271 // various clusters? Accoring to my own tests (using Graphviz's DOT tool)
1272 // it is simple: put it in the deepest possible cluster in which it shows
1273 // up. And this is achieved by the line below - if a node is requested on
1274 // a level that is deeper than currently assigned one, then we reassign
1275 // cluster.
1276 if(C && data.rootCluster->depth() > C->clusterOf(v)->depth()) {
1277 C->reassignNode(v, data.rootCluster);
1278 }
1279
1280 return v;
1281 }
1282
1283
readGraph(Graph & G,GraphAttributes * GA,ClusterGraph * C,ClusterGraphAttributes * CA)1284 bool Parser::readGraph(
1285 Graph &G, GraphAttributes *GA,
1286 ClusterGraph *C, ClusterGraphAttributes *CA)
1287 {
1288 m_nodeId.clear();
1289 G.clear();
1290 if(C) {
1291 C->clear();
1292 }
1293
1294 Lexer lexer(m_in);
1295 if(!lexer.tokenize()) {
1296 return false;
1297 }
1298
1299 Ast ast(lexer.tokens());
1300 return ast.build() && ast.root()->read(*this, G, GA, C, CA);
1301 }
1302
1303
read(Graph & G)1304 bool Parser::read(Graph &G)
1305 {
1306 return readGraph(G, nullptr, nullptr, nullptr);
1307 }
1308
1309
read(Graph & G,GraphAttributes & GA)1310 bool Parser::read(Graph &G, GraphAttributes &GA)
1311 {
1312 return readGraph(G, &GA, nullptr, nullptr);
1313 }
1314
1315
read(Graph & G,ClusterGraph & C)1316 bool Parser::read(Graph &G, ClusterGraph &C)
1317 {
1318 return readGraph(G, nullptr, &C, nullptr);
1319 }
1320
1321
read(Graph & G,ClusterGraph & C,ClusterGraphAttributes & CA)1322 bool Parser::read(Graph &G, ClusterGraph &C, ClusterGraphAttributes &CA)
1323 {
1324 return readGraph(G, &CA, &C, &CA);
1325 }
1326
1327
SubgraphData(cluster root,std::vector<Ast::AttrList * > & nodeDefaultsVector,std::vector<Ast::AttrList * > & edgeDefaultsVector,std::set<node> & nodeSet)1328 SubgraphData::SubgraphData(
1329 cluster root,
1330 std::vector<Ast::AttrList *> &nodeDefaultsVector,
1331 std::vector<Ast::AttrList *> &edgeDefaultsVector,
1332 std::set<node> &nodeSet)
1333 :
1334 rootCluster(root),
1335 nodeDefaults(nodeDefaultsVector),
1336 edgeDefaults(edgeDefaultsVector),
1337 nodes(nodeSet)
1338 {
1339 }
1340
1341
withCluster(cluster newRootCluster) const1342 SubgraphData SubgraphData::withCluster(
1343 cluster newRootCluster) const
1344 {
1345 return SubgraphData(newRootCluster, nodeDefaults, edgeDefaults, nodes);
1346 }
1347
1348
withDefaults(std::vector<Ast::AttrList * > & newNodeDefaults,std::vector<Ast::AttrList * > & newEdgeDefaults) const1349 SubgraphData SubgraphData::withDefaults(
1350 std::vector<Ast::AttrList *> &newNodeDefaults,
1351 std::vector<Ast::AttrList *> &newEdgeDefaults) const
1352 {
1353
1354 return SubgraphData(rootCluster, newNodeDefaults, newEdgeDefaults, nodes);
1355 }
1356
1357
withNodes(std::set<node> & newNodes) const1358 SubgraphData SubgraphData::withNodes(
1359 std::set<node> &newNodes) const
1360 {
1361 return SubgraphData(rootCluster, nodeDefaults, edgeDefaults, newNodes);
1362 }
1363
1364 }
1365
1366 }
1367