summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbd-912 <bdunahu@colostate.edu>2024-04-20 00:23:21 -0600
committerbd-912 <bdunahu@colostate.edu>2024-04-20 00:23:21 -0600
commit63551aff281f1d289605fe2c9975a15124dbe643 (patch)
tree5d016ed04908d8fcf492c3bcefedfcb43c312b2c
parent18da70342efb2114042c8ad5fae089cef6e69862 (diff)
Fun with GraphViz
-rw-r--r--.gitignore2
-rw-r--r--graphviz/GraphViz.java365
-rw-r--r--graphviz/config.properties23
-rw-r--r--typecheck/tests/Operator.java15
-rw-r--r--vaporize/library/CFGSimp.java45
-rw-r--r--vaporize/library/ControlFlowGraph.java13
6 files changed, 447 insertions, 16 deletions
diff --git a/.gitignore b/.gitignore
index aefa856..505b7ba 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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) {