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 &paramStrict,
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 &paramType,
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 &paramType)
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