From d7abcb7b55e6f165de9fc41ac081e35bbfaf925e Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Wed, 3 Apr 2019 17:37:57 +0200 Subject: [PATCH] Boxed up control flow structures and preparation for edge labeling --- src/main/java/grafos/CFG.java | 141 +++++++++++++++++++++--- src/main/java/grafos/Transformador.java | 12 +- src/main/java/grafos/Visitador.java | 23 +++- 3 files changed, 148 insertions(+), 28 deletions(-) diff --git a/src/main/java/grafos/CFG.java b/src/main/java/grafos/CFG.java index 983b9a3..ac8297a 100644 --- a/src/main/java/grafos/CFG.java +++ b/src/main/java/grafos/CFG.java @@ -1,22 +1,49 @@ package grafos; import com.github.javaparser.ast.Node; -import com.github.javaparser.ast.stmt.EmptyStmt; +import com.github.javaparser.ast.expr.BooleanLiteralExpr; +import com.github.javaparser.ast.stmt.*; -import java.util.*; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Stack; public class CFG { - private final List nodes = new ArrayList<>(); - private final List> edges = new LinkedList<>(); + private final List nodes = new LinkedList<>(); + private final LinkedList blocks = new LinkedList<>(); + private Stack blockStack = new Stack<>(); + private final List edges = new LinkedList<>(); private Node beginNode, endNode; + private String nextLabel; public void addNode(Node stmt) { nodes.add(stmt); + if (!blockStack.isEmpty()) + blockStack.peek().add(stmt); System.out.println("NODO: " + node2str(stmt)); } + public void beginBlock(Node node) { + Block b = new Block(node, this); + if (blockStack.isEmpty()) + blocks.addFirst(b); + else + blockStack.peek().addSubBlock(b); + blockStack.push(b); + } + + public void endBlock() { + blockStack.pop(); + } + + public void setNextLabel(boolean b) { + nextLabel = String.valueOf(b); + } + public void connect(Node begin, Node end) { - edges.add(new HashMap.SimpleEntry<>(begin, end)); + edges.add(new Edge(this, begin, end, nextLabel)); + nextLabel = null; } public void connect(Collection begin, Node end) { @@ -38,18 +65,18 @@ public class CFG { return endNode; } - public List toStringList() { - List res = new LinkedList(); - for (Map.Entry e : edges) { - res.add(edge2str(e.getKey(), e.getValue())); + public List toStringList(GraphViz gv) { + List res = new LinkedList<>(); + res.add(gv.start_graph()); + for (Block b : blocks) + res.addAll(b.toStringList(gv)); + for (Edge e : edges) { + res.add(e.toString()); } + res.add(gv.end_graph()); return res; } - private String edge2str(Node a, Node b) { - return node2str(a) + "->" + node2str(b); - } - private String node2str(Node s) { if (s == beginNode) return "Start"; @@ -67,4 +94,92 @@ public class CFG { return "\"(" + (index + 1) + ", " + s.getRange().get().begin.line + ") " + s.toString().replace("\"", "\\\"") + "\""; } + + static class Block extends LinkedList { + private static int clusterId = 0; + + private final Node container; + private final CFG cfg; + private final List inners = new LinkedList<>(); + + Block(Node container, CFG cfg) { + this.container = container; + this.cfg = cfg; + } + + void addSubBlock(Block block) { + inners.add(block); + } + + List toStringList(GraphViz gv) { + List res = new LinkedList<>(); + res.add(gv.start_subgraph(clusterId++)); + res.add("label = \"" + getTitle() + "\""); + for (Block b : inners) { + res.addAll(b.toStringList(gv)); + } + for (Node n : this) { + res.add(cfg.node2str(n)); + } + res.add(gv.end_subgraph()); + return res; + } + + String getTitle() { + String template; + Object[] filler; + if (container instanceof IfStmt) { + template = "if (%s)"; + filler = new Object[]{((IfStmt) container).getCondition()}; + } else if (container instanceof WhileStmt) { + template = "while (%s)"; + filler = new Object[]{((WhileStmt) container).getCondition()}; + } else if (container instanceof DoStmt) { + template = "do-while (%s)"; + filler = new Object[]{((DoStmt) container).getCondition()}; + } else if (container instanceof ForStmt) { + template = "for (%s; %s; %s)"; + filler = new Object[]{ + ((ForStmt) container).getInitialization(), + ((ForStmt) container).getCompare().orElse(new BooleanLiteralExpr(true)), + ((ForStmt) container).getUpdate()}; + } else if (container instanceof ForeachStmt) { + template = "for (%s : %s)"; + filler = new Object[]{ + ((ForeachStmt) container).getVariable(), + ((ForeachStmt) container).getIterable()}; + } else if (container instanceof BlockStmt) { + template = ""; + filler = new Object[0]; + } else if (container instanceof SwitchStmt) { + template = "switch (%s)"; + filler = new Object[]{((SwitchStmt) container).getSelector()}; + } else { + throw new RuntimeException("Unimplemented!!!"); + // TODO: remove + } + return String.format(template, filler); + } + } + + static class Edge { + private final CFG cfg; + private final Node origin, destination; + private final String label; + + Edge(CFG cfg, Node origin, Node destination, String label) { + this.cfg = cfg; + this.origin = origin; + this.destination = destination; + this.label = label; + } + + public String toString() { + String s = cfg.node2str(origin) + " -> " + cfg.node2str(destination); + if (label != null) { + s += " [ label = \"" + label + "\" ]"; + } + return s; + } + } } diff --git a/src/main/java/grafos/Transformador.java b/src/main/java/grafos/Transformador.java index 9a018af..6afbf22 100644 --- a/src/main/java/grafos/Transformador.java +++ b/src/main/java/grafos/Transformador.java @@ -47,20 +47,12 @@ public class Transformador { visitador.visit(cu, graph); // Imprimimos el CFG del program - StringBuilder builder = new StringBuilder(); - for (String s : graph.toStringList()) { - builder.append(s); - builder.append(";"); - System.out.println("ARCO: " + s); - } - String dotInfo = builder.toString(); + GraphViz gv = new GraphViz(); + String dotInfo = String.join("\n", graph.toStringList(gv)); // Generamos un PDF con el CFG del programa System.out.print("\nGenerando PDF..."); - GraphViz gv = new GraphViz(); - gv.addln(gv.start_graph()); gv.add(dotInfo); - gv.addln(gv.end_graph()); String type = "pdf"; // String type = "gif"; // gv.increaseDpi(); gv.decreaseDpi(); diff --git a/src/main/java/grafos/Visitador.java b/src/main/java/grafos/Visitador.java index 86a4969..1e1e8d0 100755 --- a/src/main/java/grafos/Visitador.java +++ b/src/main/java/grafos/Visitador.java @@ -52,6 +52,7 @@ public class Visitador extends VoidVisitorAdapter { @Override public void visit(IfStmt n, CFG graph) { + graph.beginBlock(n); Node ifStart = n.getCondition(); graph.addNode(ifStart); graph.connect(prevNode, ifStart); @@ -75,10 +76,12 @@ public class Visitador extends VoidVisitorAdapter { newPrev.add(ifStart); } prevNode = newPrev; + graph.endBlock(); } @Override public void visit(WhileStmt n, CFG graph) { + graph.beginBlock(n); Node whileStart = n.getCondition(); graph.addNode(whileStart); graph.connect(prevNode, whileStart); @@ -89,20 +92,25 @@ public class Visitador extends VoidVisitorAdapter { n.getBody().accept(this, graph); graph.connect(prevNode, whileStart); prevNode = Collections.singletonList(whileStart); + graph.endBlock(); } @Override public void visit(DoStmt n, CFG graph) { + graph.beginBlock(n); + Node condition = n.getCondition(); prevNode = new LinkedList<>(prevNode); - prevNode.add(n.getCondition()); + prevNode.add(condition); n.getBody().accept(this, graph); - graph.addNode(n.getCondition()); - graph.connect(prevNode, n.getCondition()); - prevNode = Collections.singletonList(n.getCondition()); + graph.addNode(condition); + graph.connect(prevNode, condition); + prevNode = Collections.singletonList(condition); + graph.endBlock(); } @Override public void visit(ForStmt n, CFG graph) { + graph.beginBlock(n); // Initialization expressions if (n.getInitialization() != null) { for (Expression e : n.getInitialization()) { @@ -139,10 +147,12 @@ public class Visitador extends VoidVisitorAdapter { prevNode = Collections.singletonList(n.getCompare().get()); else // There is no comparison, can't exit the loop TODO implement break and continue as way to exit prevNode = Collections.emptyList(); + graph.endBlock(); } @Override public void visit(ForeachStmt n, CFG graph) { + graph.beginBlock(n); ForeachStmt copy = new ForeachStmt(n.getTokenRange().orElse(null), n.getVariable(), n.getIterable(), new EmptyStmt()); graph.addNode(copy); graph.connect(prevNode, copy); @@ -150,6 +160,7 @@ public class Visitador extends VoidVisitorAdapter { n.getBody().accept(this, graph); graph.connect(prevNode, copy); prevNode = Collections.singletonList(copy); + graph.endBlock(); } @Override @@ -165,8 +176,9 @@ public class Visitador extends VoidVisitorAdapter { @Override public void visit(SwitchStmt n, CFG graph) { + graph.beginBlock(n); // Link previous statement to the switch's selector - Node selectorNode = new SwitchStmt(n.getTokenRange().orElse(null), n.getSelector(), new NodeList<>()); + Node selectorNode = n.getSelector(); graph.addNode(selectorNode); graph.connect(prevNode, selectorNode); // Analyze switch's cases @@ -191,6 +203,7 @@ public class Visitador extends VoidVisitorAdapter { prevNode.addAll(brokenStmts); // 1 if (n.getEntries().get(n.getEntries().size() - 1).getLabel().isPresent()) prevNode.add(selectorNode); // 2 + graph.endBlock(); } @Override