123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215(**************************************************************************)(* *)(* Ocamlgraph: a generic graph library for OCaml *)(* Copyright (C) 2004-2010 *)(* Sylvain Conchon, Jean-Christophe Filliatre and Julien Signoles *)(* *)(* This software is free software; you can redistribute it and/or *)(* modify it under the terms of the GNU Library General Public *)(* License version 2.1, with the special exception on linking *)(* described in file LICENSE. *)(* *)(* This software is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *)(* *)(**************************************************************************)(** Parser for DOT file format *)openDot_astletparse_dot_ast_from_chanc=letlb=Lexing.from_channelcinletdot=tryDot_parser.fileDot_lexer.tokenlbwithParsing.Parse_error->letn=Lexing.lexeme_startlbinfailwith(Printf.sprintf"Dot.parse: parse error character %d"n)inclose_inc;dotletparse_dot_astf=letc=open_infinparse_dot_ast_from_chanctypeclusters_hash=(string,attrlist)Hashtbl.tletget_string=function|Strings->s|Idents->s|Numbers->s|Htmls->smoduleParse(B:Builder.S)(L:sigvalnode:node_id->attrlist->B.G.V.label(** how to build the node label out of the set of attributes *)valedge:attrlist->B.G.E.label(** how to build the edge label out of the set of attributes *)end)=structmoduleAttr=structmoduleM=Map.Make(structtypet=idletcompare:t->t->int=Stdlib.compareend)letempty=M.emptyletadd=List.fold_left(funa(x,v)->M.addxva)letaddl=List.fold_leftaddletlista=M.fold(funxvl->(x,v)::l)a[]endletcreate_graph_and_clustersdot=(* pass 1*)(* collect node attributes *)letdef_node_attr=refAttr.emptyinletnode_attr=Hashtbl.create97in(* collect cluster attributes *)letdef_clust_attr=refAttr.emptyinletclust_attr=Hashtbl.create97in(* collect clusters nodes *)letclust_nodes=Hashtbl.create97inletadd_node_attridal=letl=tryHashtbl.findnode_attridwithNot_found->!def_node_attrinHashtbl.replacenode_attrid(Attr.addllal)inletadd_clust_attrid_optal=matchid_optwith|Someid->lets=get_stringidinletl=tryHashtbl.findclust_attrswithNot_found->!def_clust_attrinHashtbl.replaceclust_attrs(Attr.addllal)|_->()inletadd_clust_nodeid_clusterid_node=letid_nodes=tryHashtbl.findclust_nodesid_clusterwithNot_found->[]inHashtbl.addclust_nodesid_cluster(id_node::id_nodes)inletreccollect_node_attrcluster_opstmts=List.iter(function|Node_stmt(id,al)->add_node_attridal;beginmatchcluster_opwith|Someid_cluster->add_clust_nodeid_clusterid|_->()end|Attr_nodeal->def_node_attr:=Attr.addl!def_node_attral|Edge_stmt(NodeIdid,nl,_)->add_node_attrid[];List.iter(function|NodeIdid->add_node_attrid[]|_->())nl|Subgraph(SubgraphDef(id,stmts))->collect_node_attr(Someid)stmts|Attr_graphal->beginmatchcluster_opwith|Someid->add_clust_attridal|None->()end|_->())stmtsincollect_node_attrNonedot.stmts;(* pass 2: build the graph and the clusters *)letdef_edge_attr=refAttr.emptyinletnodes=Hashtbl.create97inletnodegid_=tryg,Hashtbl.findnodesidwithNot_found->letl=tryHashtbl.findnode_attridwithNot_found->Attr.emptyinletn=B.G.V.create(L.nodeid[Attr.listl])inHashtbl.addnodesidn;B.add_vertexgn,ninletrecadd_stmtsgstmts=List.fold_left(fungs->matchswith|Node_stmt(id,al)->letg,_=nodegidaling|Edge_stmt(NodeIdid,nl,al)->letal=Attr.addl!def_edge_attralinletel=L.edge[Attr.listal]inletg,vn=nodegid[]infst(List.fold_left(fun(g,pvn)m->matchmwith|NodeIdidm->letg,vm=nodegidm[]inlete=B.G.E.createpvnelvmin((B.add_edge_ege),vm)|NodeSub_->(g,pvn))(g,vn)nl)|Attr_edgeal->def_edge_attr:=Attr.addl!def_edge_attral;g|Subgraph(SubgraphDef(_,stmts))->add_stmtsgstmts|_->g)gstmtsinletgraph=add_stmts(B.empty())dot.stmtsinletclusters_hash=leth=Hashtbl.create30inHashtbl.iter(funka->Hashtbl.addhk[Attr.lista])clust_attr;hingraph,clusters_hashletget_graph_bbstmts=letgraph_bb=refNoneinletread_attr=function|(Ident"bb",Some(Stringbb))->graph_bb:=Somebb|_->()inletread_stmt=function|Attr_graphattrs->List.iter(List.iterread_attr)attrs|_->()inList.iterread_stmtstmts;!graph_bbletparse_dot_from_chanc=letlb=Lexing.from_channelcinletdot=tryDot_parser.fileDot_lexer.tokenlbwithParsing.Parse_error->letn=Lexing.lexeme_startlbinfailwith(Printf.sprintf"Dot.parse: parse error character %d"n)inclose_inc;dotletparse_dotf=letc=open_infinparse_dot_from_chancletparsef=fst(create_graph_and_clusters(parse_dotf))letparse_bounding_box_and_clustersf=letdot=parse_dotfinletgraph,clusters=create_graph_and_clustersdotinmatchget_graph_bbdot.stmtswith|Somebounding_box->graph,bounding_box,clusters|None->failwith"Cannot read bounding box in xdot file"end