ocamldot/0040755000076400010010000000000007261155512013222 5ustar administratorNoneocamldot/LICENSE0100444000076400010010000000015407257665565014245 0ustar administratorNoneOcamldot was written by Trevor Jim. It is in the public domain; use it however you like, at your own risk. ocamldot/Makefile0100444000076400010010000000066207145037644014667 0ustar administratorNone# Try to automatically guess whether we are running under Windows. # Set WIN32=true manually if this doesn't work. # ifeq (${OSTYPE},cygwin32) # Cygwin Beta 19 WIN32=true else ifeq (${OSTYPE},cygwin) # Cygwin Beta 20 WIN32=true endif endif ifdef WIN32 EXE=.exe else # UNIX EXE= endif ocamldot$(EXE): ocamldot.mll ocamllex ocamldot.mll ocamlc -o $@ ocamldot.ml clean: $(RM) ocamldot$(EXE) ocamldot.ml *.cmi *.cmo *.o *.obj ocamldot/ocamldot.10100444000076400010010000000245707261155523015113 0ustar administratorNone.TH OCAMLDOT 1 .SH NAME ocamldot \- generate dependency graphs of ocaml programs .SH SYNOPSIS .B ocamldot .I .RI "[options] " .SH "DESCRIPTION" This manual page documents briefly the .BR ocamldot command. .PP .B ocamldot generates program dependency graphs for ocaml programs. The dependency graph output by ocamldot can be rendered by a separate program, \fIdot\fR. .P Ocamldot is designed to process the output of ocamldep. A typical use would be .P ocamldep *.ml | ocamldot > dep.dot .P or .P ocamldep *.ml > .depend .br ocamldot .depend > dep.dot .SH OPTIONS .TP .B \-fullgraph Draw the full graph (default is to draw only the kernel) .TP .B \-landscape Output in landscape format (default is portrait) .TP .B \-lr Draw graph from left to right (default is top to bottom) .TP .B \-r Use \fI\fR as a root in the graph; nodes reachable from \fI\fR will be shown. .P The transitive kernel of a dag is the smallest subset of the dag whose transitive closure is the same as the transitive closure of the dag. For example, the kernel of A->B, A->C, B->C is just the two edges A->B, B->C. .SH SEE ALSO .BR ocamldep (1), .BR dot(1) .P \fIhttp://www.research.att.com/~trevor/ocamldot\fR. .SH AUTHOR Trevor Jim ocamldot/ocamldot.mll0100444000076400010010000002643607145037645015547 0ustar administratorNone(* ocamldot.mll, July 1999, Trevor Jim *) { module StringSet = Set.Make(struct type t = string let compare = compare end) let dependencies = ref [] let currentSource = ref "" let addDepend t = let s = !currentSource in if s<>t then dependencies := (s,t)::(!dependencies) } rule processSource = parse ['.' '-' '/' 'A'-'Z' 'a'-'z' '_' '\192'-'\214' '\216'-'\246' '\248'-'\255' '\'' '0'-'9' ]+ '.' ['A'-'Z' 'a'-'z']+ [' ' '\009']* ':' { let s = Lexing.lexeme lexbuf in let i = String.rindex s '.' in let s = String.sub s 0 i in let s = Filename.basename s in let s = String.capitalize s in currentSource := s; processTargets lexbuf } | eof { () } | _ { processSource lexbuf } and processTargets = parse [' ' '\009']+ { processTargets lexbuf } | '\\' [' ' '\009']* ['\010' '\013']+ [' ' '\009']+ { processTargets lexbuf } | ['.' '/' 'A'-'Z' 'a'-'z' '_' '\192'-'\214' '\216'-'\246' '\248'-'\255' '\'' '0'-'9' ]+ '.' ['A'-'Z' 'a'-'z']+ { let t = Lexing.lexeme lexbuf in let i = String.rindex t '.' in let t = String.sub t 0 i in let t = Filename.basename t in let t = String.capitalize t in addDepend t; processTargets lexbuf } | eof { () } | _ { processSource lexbuf } { (********************************) (* Utility functions for graphs *) (********************************) (**********************************************************************) (* A graph is represented by a (string * StringSet) list, *) (* that is, a list of (source,targets) pairs. *) (**********************************************************************) let emptyGraph = [] (**********************************************************************) (* divideGraph graph source = (sourceTargets, graphWithoutSource) *) (* *) (* Return the targets of a source in a graph and the graph with the *) (* source substracted from the sources. GraphWithoutSources may *) (* still contain source as a target. *) (**********************************************************************) let divideGraph graph source = let rec aux l = match l with [] -> (StringSet.empty,[]) | (s,ts)::tl -> if s=source then (ts,tl) else let (sourceTargets,tlWithoutSource) = aux tl in (sourceTargets,(s,ts)::tlWithoutSource) in aux graph (*********************************************) (* Add the edge (source,target) to the graph *) (*********************************************) let addEdge graph source target = let (sourceTargets,graphWithoutSource) = divideGraph graph source in (source,StringSet.add target sourceTargets)::graphWithoutSource (************************************************************) (* Add the edges { (source,t) | t in targets } to the graph *) (************************************************************) let addEdges graph source targets = let (sourceTargets,graphWithoutSource) = divideGraph graph source in (source,StringSet.union targets sourceTargets)::graphWithoutSource (**************************************************) (* Remove the edge (source,target) from the graph *) (**************************************************) let removeEdge graph source target = let rec loop l = match l with [] -> [] | (s,ts)::tl -> if s=source then (s,StringSet.remove target ts)::tl else (s,ts)::(loop tl) in loop graph (*****************************************************************) (* Remove the edges { (source,t) | t in targets } from the graph *) (*****************************************************************) let removeEdges graph source targets = let rec loop l = match l with [] -> [] | (s,ts)::tl -> if s=source then (s,StringSet.diff ts targets)::tl else (s,ts)::(loop tl) in loop graph (**********************************************************************) (* Convert between an edge-list representation of graphs and our *) (* representation. *) (**********************************************************************) let edgesOfGraph graph = List.concat (List.map (fun (s,ts) -> List.map (fun t -> (s,t)) (StringSet.elements ts)) graph) let graphOfEdges edges = List.fold_left (fun g (s,t) -> addEdge g s t) emptyGraph edges (****************************) (* Is an edge in the graph? *) (****************************) let isEdge graph source target = try let sourceTargets = List.assoc source graph in StringSet.mem target sourceTargets with Not_found -> false (*****************) (* Print a graph *) (*****************) let printGraph graph = let printEdges(source,targets) = StringSet.iter (fun t -> Printf.printf " \"%s\" -> \"%s\" ;\n" source t) targets in List.iter printEdges graph (********************************) (* Targets of a node in a graph *) (********************************) let targetsOf graph node = (* A set of nodes *) try List.assoc node graph with Not_found -> StringSet.empty (*****************************************) (* Sources that target a node in a graph *) (*****************************************) let sourcesOf graph node = (* A list of nodes *) let rec aux l = match l with [] -> [] | (s,ts)::tl -> if StringSet.mem node ts then s::(aux tl) else aux tl in aux graph (******************************************************************) (* Add an edge to a transitively closed graph, and return the new *) (* transitive closure. *) (******************************************************************) let addEdgeTc graph source target = let targetTargets = targetsOf graph target in let (sourceTargets,graphWithoutSource) = divideGraph graph source in let sourceSources = sourcesOf graphWithoutSource source in let newSourceTargets = StringSet.add target (StringSet.union sourceTargets targetTargets) in (source,newSourceTargets):: (List.fold_right (fun s g -> addEdges g s newSourceTargets) sourceSources graphWithoutSource) (**********************************************************) (* Compute the transitive closure of a graph from scratch *) (**********************************************************) let tc graph = let loop graph (source,targets) = let reachableFromSource = List.fold_left (fun r (s,ts) -> if StringSet.mem s r then StringSet.union r ts else r) targets graph in (source,reachableFromSource):: (List.map (fun (s,ts) -> if StringSet.mem source ts then (s,StringSet.union ts reachableFromSource) else (s,ts)) graph) in List.fold_left loop [] graph (************************************************************************) (* The transitive kernel (tk) of a dag is a subset of the dag whose *) (* transitive closure is the same as the transitive closure of the dag. *) (* *) (* IF THE GRAPH IS NOT A DAG, THIS CODE WON'T WORK PROPERLY!!! *) (************************************************************************) (************************************************************************) (* Add an edge to a kernel dag and return the new kernel and transitive *) (* closure of the new kernel. Requires the transitive closure of the *) (* old kernel. *) (************************************************************************) let addEdgeTk kernel tcKernel source target = if isEdge tcKernel source target then (kernel,tcKernel) else if source=target then (addEdge kernel source target,tcKernel) else begin let (sourceTargets,kernelWithoutSource) = divideGraph kernel source in let targetTargets = StringSet.add target (targetsOf tcKernel target) in let sourceSources = sourcesOf tcKernel source in let kernelWithoutSource = List.fold_left (fun kws s -> removeEdges kws s targetTargets) kernelWithoutSource sourceSources in ((source, StringSet.add target (StringSet.diff sourceTargets targetTargets)) ::kernelWithoutSource, addEdgeTc tcKernel source target) end (**********************************) (* The transitive kernel of a dag *) (**********************************) let tk dag = let edges = edgesOfGraph dag in let (kernel,tcKernel) = List.fold_left (fun (k,tck) (s,t) -> addEdgeTk k tck s t) (emptyGraph,emptyGraph) edges in kernel (**************************) (* Print the dependencies *) (**************************) let doKernel = ref true let printDepend graph = if (!doKernel) then printGraph (tk graph) else printGraph graph let calledOnFile = ref false let getDependFromFile file = calledOnFile := true; try let ic = open_in file in let lexbuf = Lexing.from_channel ic in processSource lexbuf; close_in ic with Sys_error msg -> () | Exit -> () let getDependFromStdin () = try let lexbuf = Lexing.from_channel stdin in processSource lexbuf with Sys_error msg -> () | Exit -> () (***************) (* Entry point *) (***************) let usage = "Usage: ocamldot [options] " let leftToRight = ref false let landscape = ref false let roots = ref [] ;; Arg.parse [ ("-fullgraph", Arg.Clear doKernel, " draw the full graph (default is to draw only the kernel)"); ("-landscape", Arg.Set landscape, " output in landscape format (default is portrait)"); ("-lr", Arg.Set leftToRight, " draw graph from left to right (default is top to bottom)"); ("-r", Arg.String(fun s -> roots := s::!roots), " use as a root in the graph; nodes reachable from \n will be shown") ] getDependFromFile usage; if not(!calledOnFile) then getDependFromStdin(); print_string "digraph G {\n"; if !landscape then print_string " size=\"10,7.5\" ;\n rotate=90 ;\n" else print_string " size=\"7.5,10\" ;\n"; if (!leftToRight) then print_string " rankdir = LR ;\n" else print_string " rankdir = TB ;\n"; let graph = graphOfEdges(!dependencies) in begin match !roots with [] -> printDepend graph | roots -> (* Set up the graph so that the roots are printed at the same level *) print_string " { rank=same ;\n"; List.iter (fun r -> print_string " "; print_string r; print_string " ;\n") roots; print_string " };\n"; (* Find the graph reachable from the roots *) let tcGraph = tc graph in let reachable node = (List.exists (fun r -> r=node) roots) or (List.exists (fun r -> isEdge tcGraph r node) roots) in let reachableFromRoots = List.concat (List.map (fun (source,targets) -> if reachable source then [(source,targets)] else []) graph) in printDepend reachableFromRoots end; print_string "}\n"; exit 0 ;; } ocamldot/README0100444000076400010010000000213407145037644014103 0ustar administratorNoneOcamldot generates program dependency graphs for ocaml programs. The dependency graph output by ocamldot can be rendered by a separate program, dot. Dot is freely available from http://www.research.att.com/sw/tools/graphviz/ Ocamldot is designed to process the output of ocamldep. A typical use would be ocamldep *.ml | ocamldot > dep.dot or ocamldep *.ml > .depend ocamldot .depend > dep.dot This will output a dot graph into the file dep.dot. You can then use the program dotty to view, edit, and print the graph. Ocamldot has the following options: -fullgraph draw the full graph (default is to draw only the kernel) -landscape output in landscape format (default is portrait) -lr draw graph from left to right (default is top to bottom) -r use as a root in the graph; nodes reachable from will be shown (The transitive kernel of a dag is the smallest subset of the dag whose transitive closure is the same as the transitive closure of the dag. For example, the kernel of A->B, A->C, B->C is just the two edges A->B, B->C.) -Trevor Jim