diff options
author | bd-912 <bdunahu@colostate.edu> | 2024-04-20 00:23:21 -0600 |
---|---|---|
committer | bd-912 <bdunahu@colostate.edu> | 2024-04-20 00:23:21 -0600 |
commit | 63551aff281f1d289605fe2c9975a15124dbe643 (patch) | |
tree | 5d016ed04908d8fcf492c3bcefedfcb43c312b2c | |
parent | 18da70342efb2114042c8ad5fae089cef6e69862 (diff) |
Fun with GraphViz
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | graphviz/GraphViz.java | 365 | ||||
-rw-r--r-- | graphviz/config.properties | 23 | ||||
-rw-r--r-- | typecheck/tests/Operator.java | 15 | ||||
-rw-r--r-- | vaporize/library/CFGSimp.java | 45 | ||||
-rw-r--r-- | vaporize/library/ControlFlowGraph.java | 13 |
6 files changed, 447 insertions, 16 deletions
@@ -5,3 +5,5 @@ /jtb.out.jj /jtb132.jar /minijava.jj +/*.svg +/*.dot diff --git a/graphviz/GraphViz.java b/graphviz/GraphViz.java new file mode 100644 index 0000000..f7f4e89 --- /dev/null +++ b/graphviz/GraphViz.java @@ -0,0 +1,365 @@ +package graphviz; +// GraphViz.java - a simple API to call dot from Java programs + +/*$Id$*/ +/* +****************************************************************************** +* * +* (c) Copyright Laszlo Szathmary * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or * +* (at your option) any later version. * +* * +* This program 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. See the GNU Lesser General Public * +* License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program; if not, write to the Free Software Foundation, * +* Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * +* * +****************************************************************************** +*/ + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.InputStreamReader; +import java.util.Properties; + +/** + * <dl> + * <dt>Purpose: GraphViz Java API + * <dd> + * + * <dt>Description: + * <dd> With this Java class you can simply call dot + * from your Java programs. + * <dt>Example usage: + * <dd> + * <pre> + * GraphViz gv = new GraphViz(); + * gv.addln(gv.start_graph()); + * gv.addln("A -> B;"); + * gv.addln("A -> C;"); + * gv.addln(gv.end_graph()); + * System.out.println(gv.getDotSource()); + * + * String type = "gif"; + * File out = new File("out." + type); // out.gif in this example + * gv.writeGraphToFile( gv.getGraph( gv.getDotSource(), type ), out ); + * </pre> + * </dd> + * + * </dl> + * + * @version v0.5.1, 2013/03/18 (March) -- Patch of Juan Hoyos (Mac support) + * @version v0.5, 2012/04/24 (April) -- Patch of Abdur Rahman (OS detection + start subgraph + + * read config file) + * @version v0.4, 2011/02/05 (February) -- Patch of Keheliya Gallaba is added. Now you + * can specify the type of the output file: gif, dot, fig, pdf, ps, svg, png, etc. + * @version v0.3, 2010/11/29 (November) -- Windows support + ability to read the graph from a text file + * @version v0.2, 2010/07/22 (July) -- bug fix + * @version v0.1, 2003/12/04 (December) -- first release + * @author Laszlo Szathmary (<a href="jabba.laci@gmail.com">jabba.laci@gmail.com</a>) + */ +public class GraphViz +{ + /** + * Detects the client's operating system. + */ + private final static String osName = System.getProperty("os.name").replaceAll("\\s",""); + + /** + * Load the config.properties file. + */ + private final static String cfgProp = "./graphviz/config.properties"; + private final static Properties configFile = new Properties() { + private final static long serialVersionUID = 1L; { + try { + load(new FileInputStream(cfgProp)); + } catch (Exception e) {} + } + }; + + /** + * The dir. where temporary files will be created. + */ + private static String TEMP_DIR = "./graphviz/"; + + /** + * Where is your dot program located? It will be called externally. + */ + private static String DOT = configFile.getProperty("dotFor" + osName); + + /** + * The image size in dpi. 96 dpi is normal size. Higher values are 10% higher each. + * Lower values 10% lower each. + * + * dpi patch by Peter Mueller + */ + private int[] dpiSizes = {46, 51, 57, 63, 70, 78, 86, 96, 106, 116, 128, 141, 155, 170, 187, 206, 226, 249}; + + /** + * Define the index in the image size array. + */ + private int currentDpiPos = 7; + + /** + * Increase the image size (dpi). + */ + public void increaseDpi() { + if ( this.currentDpiPos < (this.dpiSizes.length - 1) ) { + ++this.currentDpiPos; + } + } + + /** + * Decrease the image size (dpi). + */ + public void decreaseDpi() { + if (this.currentDpiPos > 0) { + --this.currentDpiPos; + } + } + + public int getImageDpi() { + return this.dpiSizes[this.currentDpiPos]; + } + + /** + * The source of the graph written in dot language. + */ + private StringBuilder graph = new StringBuilder(); + + /** + * Constructor: creates a new GraphViz object that will contain + * a graph. + */ + public GraphViz() { + } + + /** + * Returns the graph's source description in dot language. + * @return Source of the graph in dot language. + */ + public String getDotSource() { + return this.graph.toString(); + } + + /** + * Adds a string to the graph's source (without newline). + */ + public void add(String line) { + this.graph.append(line); + } + + /** + * Adds a string to the graph's source (with newline). + */ + public void addln(String line) { + this.graph.append(line + "\n"); + } + + /** + * Adds a newline to the graph's source. + */ + public void addln() { + this.graph.append('\n'); + } + + public void clearGraph(){ + this.graph = new StringBuilder(); + } + + /** + * Returns the graph as an image in binary format. + * @param dot_source Source of the graph to be drawn. + * @param type Type of the output image to be produced, e.g.: gif, dot, fig, pdf, ps, svg, png. + * @return A byte array containing the image of the graph. + */ + public byte[] getGraph(String dot_source, String type) + { + File dot; + byte[] img_stream = null; + + try { + dot = writeDotSourceToFile(dot_source); + if (dot != null) + { + img_stream = get_img_stream(dot, type); + if (dot.delete() == false) + System.err.println("Warning: " + dot.getAbsolutePath() + " could not be deleted!"); + return img_stream; + } + return null; + } catch (java.io.IOException ioe) { return null; } + } + + /** + * Writes the graph's image in a file. + * @param img A byte array containing the image of the graph. + * @param file Name of the file to where we want to write. + * @return Success: 1, Failure: -1 + */ + public int writeGraphToFile(byte[] img, String file) + { + File to = new File(file); + return writeGraphToFile(img, to); + } + + /** + * Writes the graph's image in a file. + * @param img A byte array containing the image of the graph. + * @param to A File object to where we want to write. + * @return Success: 1, Failure: -1 + */ + public int writeGraphToFile(byte[] img, File to) + { + try { + FileOutputStream fos = new FileOutputStream(to); + fos.write(img); + fos.close(); + } catch (java.io.IOException ioe) { return -1; } + return 1; + } + + /** + * It will call the external dot program, and return the image in + * binary format. + * @param dot Source of the graph (in dot language). + * @param type Type of the output image to be produced, e.g.: gif, dot, fig, pdf, ps, svg, png. + * @return The image of the graph in .gif format. + */ + private byte[] get_img_stream(File dot, String type) + { + File img; + byte[] img_stream = null; + + try { + img = File.createTempFile("graph_", "."+type, new File(GraphViz.TEMP_DIR)); + Runtime rt = Runtime.getRuntime(); + + // patch by Mike Chenault + String[] args = {DOT, "-T"+type, "-Gdpi="+dpiSizes[this.currentDpiPos], dot.getAbsolutePath(), "-o", img.getAbsolutePath()}; + Process p = rt.exec(args); + + p.waitFor(); + + FileInputStream in = new FileInputStream(img.getAbsolutePath()); + img_stream = new byte[in.available()]; + in.read(img_stream); + // Close it if we need to + if( in != null ) in.close(); + + if (img.delete() == false) + System.err.println("Warning: " + img.getAbsolutePath() + " could not be deleted!"); + } + catch (java.io.IOException ioe) { + System.err.println("Error: in I/O processing of tempfile in dir " + GraphViz.TEMP_DIR+"\n"); + System.err.println(" or in calling external command"); + ioe.printStackTrace(); + } + catch (java.lang.InterruptedException ie) { + System.err.println("Error: the execution of the external program was interrupted"); + ie.printStackTrace(); + } + + return img_stream; + } + + /** + * Writes the source of the graph in a file, and returns the written file + * as a File object. + * @param str Source of the graph (in dot language). + * @return The file (as a File object) that contains the source of the graph. + */ + private File writeDotSourceToFile(String str) throws java.io.IOException + { + File temp; + try { + temp = File.createTempFile("dorrr",".dot", new File(GraphViz.TEMP_DIR)); + FileWriter fout = new FileWriter(temp); + fout.write(str); + BufferedWriter br=new BufferedWriter(new FileWriter("dotsource.dot")); + br.write(str); + br.flush(); + br.close(); + fout.close(); + } + catch (Exception e) { + System.err.println("Error: I/O error while writing the dot source to temp file!"); + return null; + } + return temp; + } + + /** + * Returns a string that is used to start a graph. + * @return A string to open a graph. + */ + public String start_graph() { + return "digraph G {"; + } + + /** + * Returns a string that is used to end a graph. + * @return A string to close a graph. + */ + public String end_graph() { + return "}"; + } + + /** + * Takes the cluster or subgraph id as input parameter and returns a string + * that is used to start a subgraph. + * @return A string to open a subgraph. + */ + public String start_subgraph(int clusterid) { + return "subgraph cluster_" + clusterid + " {"; + } + + /** + * Returns a string that is used to end a graph. + * @return A string to close a graph. + */ + public String end_subgraph() { + return "}"; + } + + /** + * Read a DOT graph from a text file. + * + * @param input Input text file containing the DOT graph + * source. + */ + public void readSource(String input) + { + StringBuilder sb = new StringBuilder(); + + try + { + FileInputStream fis = new FileInputStream(input); + DataInputStream dis = new DataInputStream(fis); + BufferedReader br = new BufferedReader(new InputStreamReader(dis)); + String line; + while ((line = br.readLine()) != null) { + sb.append(line); + } + dis.close(); + } + catch (Exception e) { + System.err.println("Error: " + e.getMessage()); + } + + this.graph = sb; + } + +} // end of class GraphViz diff --git a/graphviz/config.properties b/graphviz/config.properties new file mode 100644 index 0000000..60901d5 --- /dev/null +++ b/graphviz/config.properties @@ -0,0 +1,23 @@ +############################################################## +# Linux Configurations # +############################################################## +# The dir. where temporary files will be created. +tempDirForLinux = /tmp +# Where is your dot program located? It will be called externally. +dotForLinux = /home/bdunahu/.guix-home/profile/bin/dot + +############################################################## +# Windows Configurations # +############################################################## +# The dir. where temporary files will be created. +tempDirForWindows = c:/temp +# Where is your dot program located? It will be called externally. +dotForWindows = "c:/Program Files (x86)/Graphviz 2.28/bin/dot.exe" + +############################################################## +# Mac Configurations # +############################################################## +# The dir. where temporary files will be created. +tempDirForMacOSX = /tmp +# Where is your dot program located? It will be called externally. +dotForMacOSX = /usr/local/bin/dot
\ No newline at end of file diff --git a/typecheck/tests/Operator.java b/typecheck/tests/Operator.java new file mode 100644 index 0000000..732c905 --- /dev/null +++ b/typecheck/tests/Operator.java @@ -0,0 +1,15 @@ +class test01{ + public static void main(String[] a){ + System.out.println(new Operator().compute()); + } +} + +class Operator{ + + boolean result; + + public int compute(){ + result = true && false; + return 0; + } +} diff --git a/vaporize/library/CFGSimp.java b/vaporize/library/CFGSimp.java index 9f2556d..f4d63cf 100644 --- a/vaporize/library/CFGSimp.java +++ b/vaporize/library/CFGSimp.java @@ -1,8 +1,10 @@ package vaporize.library; import cs132.vapor.ast.*; -import st.*; +import graphviz.*; import misc.*; + +import java.io.File; import java.util.*; public class CFGSimp extends VInstr.VisitorPR<ControlFlowGraph, String, RuntimeException> { @@ -11,6 +13,7 @@ public class CFGSimp extends VInstr.VisitorPR<ControlFlowGraph, String, RuntimeE private Kettle kettle; private ArrayList<ControlFlowGraph> cfgs; private CFGNode curr; + private String dot_format; // a list of edges to be processed by graphviz public CFGSimp(VaporProgram vp, ArrayList<String> vapor) { this.vp = vp; @@ -21,6 +24,7 @@ public class CFGSimp extends VInstr.VisitorPR<ControlFlowGraph, String, RuntimeE for (VFunction f : this.vp.functions) { ControlFlowGraph cfg = new ControlFlowGraph(); + this.dot_format = ""; curr = new CFGNode(f.body[0]); cfg.setStart(curr); @@ -46,6 +50,8 @@ public class CFGSimp extends VInstr.VisitorPR<ControlFlowGraph, String, RuntimeE for (VInstr s : f.body) s.accept(cfg, this); + this.createDotGraph(this.kettle.parseFuncName(f)); + this.cfgs.add(cfg); } } @@ -54,6 +60,21 @@ public class CFGSimp extends VInstr.VisitorPR<ControlFlowGraph, String, RuntimeE return this.cfgs; } + public void createDotGraph(String file_name) { + MinimalLogger.info(String.format("Outputting %s to %s", + this.dot_format, + file_name)); + GraphViz gv = new GraphViz(); + gv.addln(gv.start_graph()); + gv.add(this.dot_format); + gv.addln(gv.end_graph()); + String type = "svg"; + gv.decreaseDpi(); + gv.decreaseDpi(); + File out = new File(file_name+"."+ type); + gv.writeGraphToFile( gv.getGraph( gv.getDotSource(), type ), out ); + } + public String visit(ControlFlowGraph cfg, VMemRead n) throws RuntimeException { MinimalLogger.info(String.format("->%s (\"%s\":%s)", n.getClass().getSimpleName(), @@ -61,7 +82,7 @@ public class CFGSimp extends VInstr.VisitorPR<ControlFlowGraph, String, RuntimeE n.sourcePos.toString())); /////////////////////////////////////////////////////////////// CFGNode curr = cfg.getNode(n); - cfg.addEdge(this.curr, cfg.getNode(n)); + this.dot_format += cfg.addEdge(this.curr, cfg.getNode(n)); this.curr = curr; /////////////////////////////////////////////////////////////// MinimalLogger.info(String.format("<-%s (\"%s\":%s)", @@ -78,7 +99,7 @@ public class CFGSimp extends VInstr.VisitorPR<ControlFlowGraph, String, RuntimeE n.sourcePos.toString())); /////////////////////////////////////////////////////////////// CFGNode curr = cfg.getNode(n); - cfg.addEdge(this.curr, cfg.getNode(n)); + this.dot_format += cfg.addEdge(this.curr, cfg.getNode(n)); this.curr = curr; /////////////////////////////////////////////////////////////// MinimalLogger.info(String.format("<-%s (\"%s\":%s)", @@ -95,7 +116,7 @@ public class CFGSimp extends VInstr.VisitorPR<ControlFlowGraph, String, RuntimeE n.sourcePos.toString())); /////////////////////////////////////////////////////////////// CFGNode curr = cfg.getNode(n); - cfg.addEdge(this.curr, cfg.getNode(n)); + this.dot_format += cfg.addEdge(this.curr, cfg.getNode(n)); this.curr = curr; /////////////////////////////////////////////////////////////// MinimalLogger.info(String.format("<-%s (\"%s\":%s)", @@ -112,9 +133,9 @@ public class CFGSimp extends VInstr.VisitorPR<ControlFlowGraph, String, RuntimeE n.sourcePos.toString())); /////////////////////////////////////////////////////////////// CFGNode curr = cfg.getNode(n); - cfg.addEdge(this.curr, cfg.getNode(n)); - cfg.addEdge(this.curr, cfg.getNode(new Integer(this.kettle - .findLabelIndex(n.target.toString())))); + this.dot_format += cfg.addEdge(this.curr, cfg.getNode(n)); + this.dot_format += cfg.addEdge(this.curr, cfg.getNode(new Integer(this.kettle + .findLabelIndex(n.target.toString())))); this.curr = curr; /////////////////////////////////////////////////////////////// @@ -132,8 +153,8 @@ public class CFGSimp extends VInstr.VisitorPR<ControlFlowGraph, String, RuntimeE n.sourcePos.toString())); /////////////////////////////////////////////////////////////// CFGNode curr = cfg.getNode(n); - cfg.addEdge(this.curr, cfg.getNode(new Integer(this.kettle - .findLabelIndex(n.target.toString())))); + this.dot_format += cfg.addEdge(this.curr, cfg.getNode(new Integer(this.kettle + .findLabelIndex(n.target.toString())))); this.curr = curr; /////////////////////////////////////////////////////////////// @@ -151,7 +172,7 @@ public class CFGSimp extends VInstr.VisitorPR<ControlFlowGraph, String, RuntimeE n.sourcePos.toString())); /////////////////////////////////////////////////////////////// CFGNode curr = cfg.getNode(n); - cfg.addEdge(this.curr, cfg.getNode(n)); + this.dot_format += cfg.addEdge(this.curr, cfg.getNode(n)); this.curr = curr; /////////////////////////////////////////////////////////////// MinimalLogger.info(String.format("<-%s (\"%s\":%s)", @@ -168,7 +189,7 @@ public class CFGSimp extends VInstr.VisitorPR<ControlFlowGraph, String, RuntimeE n.sourcePos.toString())); /////////////////////////////////////////////////////////////// CFGNode curr = cfg.getNode(n); - cfg.addEdge(this.curr, cfg.getNode(n)); + this.dot_format += cfg.addEdge(this.curr, cfg.getNode(n)); this.curr = curr; /////////////////////////////////////////////////////////////// MinimalLogger.info(String.format("<-%s (\"%s\":%s)", @@ -185,7 +206,7 @@ public class CFGSimp extends VInstr.VisitorPR<ControlFlowGraph, String, RuntimeE n.sourcePos.toString())); /////////////////////////////////////////////////////////////// CFGNode curr = cfg.getNode(n); - cfg.addEdge(this.curr, cfg.getNode(n)); + this.dot_format += cfg.addEdge(this.curr, cfg.getNode(n)); this.curr = curr; /////////////////////////////////////////////////////////////// MinimalLogger.info(String.format("<-%s (\"%s\":%s)", diff --git a/vaporize/library/ControlFlowGraph.java b/vaporize/library/ControlFlowGraph.java index c0eff10..364cec1 100644 --- a/vaporize/library/ControlFlowGraph.java +++ b/vaporize/library/ControlFlowGraph.java @@ -37,12 +37,17 @@ public class ControlFlowGraph { this.nodes.add(node); } - protected void addEdge(CFGNode source, CFGNode dest) { - MinimalLogger.info(String.format("Edge %s -> %s", - source.getInstruction().sourcePos.line, - dest.getInstruction().sourcePos.line)); + protected String addEdge(CFGNode source, CFGNode dest) { + String ret = String.format("%d -> %d", + source.getInstruction().sourcePos.line, + dest.getInstruction().sourcePos.line); + MinimalLogger.info(String.format("Edge %s", + ret)); + source.addDest(dest); dest.addSource(source); + + return ret +";"; } protected void setStart(CFGNode start) { |