package cfg; import cs132.vapor.ast.*; import misc.*; import java.util.ArrayList; import java.util.Arrays; public class ControlFlowGraph { private VFunction f; // the function represented by this CFG private ArrayList nodes; public ControlFlowGraph(VFunction f) { this.f = f; this.nodes = new ArrayList<>(); } public String getFunction() { return this.f.ident; } public CFGNode getNode(Object a) { CFGNode ret = null; for (CFGNode n : this.nodes) { if (n.equals(a)) { ret = n; break; } } if (ret == null) { String str = (a instanceof Node) ? ((Node) a).sourcePos.toString() : a.toString(); MinimalLogger.severe(String.format("Could not find a node matching %s", str)); } return ret; } public CFGNode getNextNode(CFGNode a) { CFGNode ret = null; // we return null if the passed node is the last in the list for (int i = 0; i < this.nodes.size()-1; ++i) { if (this.nodes.get(i).equals(a)) { ret = this.nodes.get(i+1); break; } } if (ret == null) MinimalLogger.severe(String.format("Could not find the next node for %s", a.toString())); return ret; } public void addNode(CFGNode n) { MinimalLogger.info(String.format("Node + %s", n.toString())); this.nodes.add(n); } public String addEdge(CFGNode source, CFGNode dest) { /** * Iff the CFGNodes are different, construct an edge between them. * All variables reaching the parent also reach the children. * * Returns a string capable of being manipulated by graphviz. */ String ret = ""; if (!source.equals(dest)) { ret = String.format("%s -> %s", source.toString(), dest.toString()); MinimalLogger.info(String.format("Edge %s", ret)); source.addDest(dest); dest.addSource(source); ret += ";"; } else { MinimalLogger.info(String.format("Skipping duplicate edge for %s", source.toString())); } return ret; } public void addReaching(CFGNode n, String s) { MinimalLogger.info(String.format("Def \"%s\" at %s", s, n.toString())); n.reaching.add(s); } public void addLiveness(CFGNode n, String s) { if (this.isKnownVar(s)) { MinimalLogger.info(String.format("Use \"%s\" at %s", s, n.toString())); n.liveness.add(s); } else MinimalLogger.info(String.format("Use \"%s\" not a known variable!", s)); } public ArrayList getNodes() { return this.nodes; } protected boolean isKnownVar(String str) { /** * Returns true if the variable belongs to the current function. * Required when matching liveness in certain instructions. * * Helper for addLivenessi */ return Arrays.asList(f.vars).contains(str) || Arrays.asList(f.params).contains(str); } }