From e77fe8f772ac5bb880153bb055a0021cbfdc30c8 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Thu, 4 Apr 2019 00:03:12 +0200 Subject: [PATCH] Complete API change --- src/main/java/grafos/CFG.java | 99 +++++++++++++------ src/main/java/grafos/Visitador.java | 147 +++++++++------------------- 2 files changed, 115 insertions(+), 131 deletions(-) diff --git a/src/main/java/grafos/CFG.java b/src/main/java/grafos/CFG.java index add3188..92d59c1 100644 --- a/src/main/java/grafos/CFG.java +++ b/src/main/java/grafos/CFG.java @@ -4,34 +4,90 @@ import com.github.javaparser.ast.Node; import com.github.javaparser.ast.expr.BooleanLiteralExpr; import com.github.javaparser.ast.stmt.*; -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; -import java.util.Stack; +import java.util.*; public class CFG { private final List nodes = new LinkedList<>(); private final LinkedList blocks = new LinkedList<>(); - private Stack blockStack = new Stack<>(); + private final Stack blockStack = new Stack<>(); private final List edges = new LinkedList<>(); - private Node beginNode, endNode; + private final Node beginNode = new EmptyStmt(), endNode = new EmptyStmt(); + private final List nodeList = new LinkedList<>(); + private String nextLabel; - public void addNode(Node stmt) { + private void registerNode(Node stmt) { nodes.add(stmt); if (!blockStack.isEmpty()) blockStack.peek().add(stmt); System.out.println("NODO: " + node2str(stmt)); } - public void beginBlock(Node node, Node condition) { - beginBlock(node, condition, true); + public void setNode(Node node) { + clearNode(); + appendNode(node); } - public void beginBlock(Node node, Node condition, boolean addNow) { + public void clearNode() { + nodeList.clear(); + } + + public void connectTo(Node node) { + connectTo(node, true); + } + + public void connectTo(Node node, boolean overwrite) { + if (!nodesContains(node)) + registerNode(node); + for (Node begin : nodeList) + connect(begin, node); + if (overwrite) + setNode(node); + } + + private boolean nodesContains(Object object) { + for (Node n : nodes) + if (n == object) + return true; + return false; + } + + public void removeNode(Node node) { + nodeList.remove(node); + } + + public void appendNode(Node node) { + nodeList.add(node); + } + + public void appendNodes(Collection nodes) { + nodeList.addAll(nodes); + } + + public List getNodeList() { + return Collections.unmodifiableList(nodeList); + } + + public void setNodeList(List nodes) { + nodeList.clear(); + nodeList.addAll(nodes); + } + + public void beginMethod() { + nodeList.clear(); + nodeList.add(beginNode); + } + + public void finishMethod() { + for (Node begin : nodeList) + if (begin != endNode) + connect(begin, endNode); + } + + public void beginBlock(Node node, Node condition) { Block b = new Block(node, condition); - if (condition != null && addNow) - addNode(condition); + if (condition != null) + registerNode(condition); if (blockStack.isEmpty()) blocks.addFirst(b); else @@ -47,27 +103,12 @@ public class CFG { nextLabel = String.valueOf(b); } - public void connect(Node begin, Node end) { + private void connect(Node begin, Node end) { edges.add(new Edge(begin, end, nextLabel)); nextLabel = null; } - public void connect(Collection begin, Node end) { - for (Node n : begin) - connect(n, end); - } - - public Node beginNode() { - if (beginNode == null) { - beginNode = new EmptyStmt(); - } - return beginNode; - } - - public Node endNode() { - if (endNode == null) { - endNode = new EmptyStmt(); - } + public Node getEndNode() { return endNode; } diff --git a/src/main/java/grafos/Visitador.java b/src/main/java/grafos/Visitador.java index 1012461..e633c75 100755 --- a/src/main/java/grafos/Visitador.java +++ b/src/main/java/grafos/Visitador.java @@ -7,76 +7,51 @@ import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.stmt.*; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Stack; public class Visitador extends VoidVisitorAdapter { - //********************************************************/ - //********************** Atributos ***********************/ - //********************************************************/ - private List prevNode; private Stack switchStack = new Stack<>(); private List brokenStmts = new LinkedList<>(); - //********************************************************/ - //*********************** Metodos ************************/ - //********************************************************/ - - // Visitador de métodos - // Este visitador añade el nodo final al CFG @Override public void visit(MethodDeclaration methodDeclaration, CFG graph) { - prevNode = Collections.singletonList(graph.beginNode()); - - // Visitamos el método + graph.beginMethod(); super.visit(methodDeclaration, graph); - - // Añadimos el nodo final al CFG - Node end = graph.endNode(); - for (Node n : prevNode) - if (n != end) - graph.connect(n, end); + graph.finishMethod(); } @Override public void visit(ReturnStmt n, CFG arg) { - arg.addNode(n); - arg.connect(prevNode, n); - super.visit(n, arg); - arg.connect(n, arg.endNode()); - prevNode = Collections.emptyList(); + arg.connectTo(n); + arg.connectTo(arg.getEndNode()); + arg.clearNode(); } @Override public void visit(IfStmt n, CFG graph) { + // Connect to the condition Node ifStart = n.getCondition(); graph.beginBlock(n, ifStart); - graph.connect(prevNode, ifStart); - - // TODO: shortcut conditions (||, &&) - - prevNode = Collections.singletonList(ifStart); + graph.connectTo(ifStart); + // Connect condition to then block graph.setNextLabel(true); - List prevNodeBegin = prevNode; n.getThenStmt().accept(this, graph); - List newPrev = new LinkedList<>(); - if (prevNode == prevNodeBegin) - newPrev.add(ifStart); - else newPrev.addAll(prevNode); - prevNode = Collections.singletonList(ifStart); + // Save end of then block + List newPrev = new LinkedList<>(graph.getNodeList()); + // Connect condition to else block + graph.setNode(ifStart); graph.setNextLabel(false); if (n.getElseStmt().isPresent()) { n.getElseStmt().get().accept(this, graph); - if (prevNode == prevNodeBegin) - newPrev.add(ifStart); - else newPrev.addAll(prevNode); + newPrev.addAll(graph.getNodeList()); } else { newPrev.add(ifStart); } - prevNode = newPrev; + // Set ends of then/else as the new list + graph.setNodeList(newPrev); graph.endBlock(); } @@ -84,15 +59,10 @@ public class Visitador extends VoidVisitorAdapter { public void visit(WhileStmt n, CFG graph) { Node whileStart = n.getCondition(); graph.beginBlock(n, whileStart); - graph.connect(prevNode, whileStart); - - // TODO: shortcut conditions (||, &&) - - prevNode = Collections.singletonList(whileStart); + graph.connectTo(whileStart); graph.setNextLabel(true); n.getBody().accept(this, graph); - graph.connect(prevNode, whileStart); - prevNode = Collections.singletonList(whileStart); + graph.connectTo(whileStart); graph.setNextLabel(false); graph.endBlock(); } @@ -100,13 +70,10 @@ public class Visitador extends VoidVisitorAdapter { @Override public void visit(DoStmt n, CFG graph) { Node condition = n.getCondition(); - graph.beginBlock(n, condition, false); - prevNode = new LinkedList<>(prevNode); - prevNode.add(condition); + graph.beginBlock(n, condition); + graph.appendNode(condition); n.getBody().accept(this, graph); - graph.addNode(condition); - graph.connect(prevNode, condition); - prevNode = Collections.singletonList(condition); + graph.connectTo(condition); graph.setNextLabel(false); graph.endBlock(); } @@ -117,41 +84,31 @@ public class Visitador extends VoidVisitorAdapter { // Initialization expressions if (n.getInitialization() != null) { for (Expression e : n.getInitialization()) { - graph.addNode(e); - graph.connect(prevNode, e); - prevNode = Collections.singletonList(e); + graph.connectTo(e); } } // Comparison expression // TODO: shortcut conditions (||, &&) if (n.getCompare().isPresent()) { - graph.addNode(n.getCompare().get()); - graph.connect(prevNode, n.getCompare().get()); - prevNode = Collections.singletonList(n.getCompare().get()); + graph.connectTo(n.getCompare().get()); graph.setNextLabel(true); } // Loop body n.getBody().accept(this, graph); // Update expressions - if (n.getUpdate() != null) { - for (Expression e : n.getUpdate()) { - graph.addNode(e); - graph.connect(prevNode, e); - prevNode = Collections.singletonList(e); - } - } + if (n.getUpdate() != null) + for (Expression e : n.getUpdate()) + graph.connectTo(e); // Connect to comparison expression - if (n.getCompare().isPresent()) - graph.connect(prevNode, n.getCompare().get()); - else { - // TODO: connect last update / end of loop with first element of loop body - } // Set comparison as last possible statement if (n.getCompare().isPresent()) { - prevNode = Collections.singletonList(n.getCompare().get()); + graph.connectTo(n.getCompare().get()); graph.setNextLabel(false); - } else // There is no comparison, can't exit the loop TODO implement break and continue as way to exit - prevNode = Collections.emptyList(); + } else { + // TODO: connect last update / end of loop with first element of loop body + // There is no comparison, can't exit the loop TODO implement break and continue as way to exit + graph.clearNode(); + } graph.endBlock(); } @@ -159,11 +116,11 @@ public class Visitador extends VoidVisitorAdapter { public void visit(ForeachStmt n, CFG graph) { ForeachStmt copy = new ForeachStmt(n.getTokenRange().orElse(null), n.getVariable(), n.getIterable(), new EmptyStmt()); graph.beginBlock(n, copy); - graph.connect(prevNode, copy); - prevNode = Collections.singletonList(copy); + graph.connectTo(copy); + graph.setNextLabel(true); n.getBody().accept(this, graph); - graph.connect(prevNode, copy); - prevNode = Collections.singletonList(copy); + graph.connectTo(copy); + graph.setNextLabel(false); graph.endBlock(); } @@ -171,9 +128,7 @@ public class Visitador extends VoidVisitorAdapter { public void visit(SwitchEntryStmt n, CFG graph) { // Case header Node caseNode = new SwitchEntryStmt(n.getTokenRange().orElse(null), n.getLabel().orElse(null), new NodeList<>()); - graph.addNode(caseNode); - graph.connect(prevNode, caseNode); - prevNode = Collections.singletonList(caseNode); + graph.connectTo(caseNode); // Case body n.getStatements().accept(this, graph); } @@ -183,39 +138,32 @@ public class Visitador extends VoidVisitorAdapter { // Link previous statement to the switch's selector Node selectorNode = n.getSelector(); graph.beginBlock(n, selectorNode); - graph.connect(prevNode, selectorNode); + graph.connectTo(selectorNode); // Analyze switch's cases - prevNode = Collections.singletonList(selectorNode); switchStack.push(n); for (SwitchEntryStmt entry : n.getEntries()) { entry.accept(this, graph); - if (prevNode.isEmpty()) { - prevNode = Collections.singletonList(selectorNode); - } else { - prevNode = new LinkedList<>(prevNode); - prevNode.add(selectorNode); - } + graph.appendNode(selectorNode); } switchStack.pop(); // The next statement will be linked to: // 1. All break statements that broke from the switch // 2. If the switch doesn't have a default statement, the switch's selector // 3. If the last entry doesn't break, to the last statement - prevNode = new LinkedList<>(prevNode); // 3 - prevNode.remove(selectorNode); - prevNode.addAll(brokenStmts); // 1 + graph.removeNode(selectorNode); + graph.appendNodes(brokenStmts); // 1 + brokenStmts.clear(); if (n.getEntries().get(n.getEntries().size() - 1).getLabel().isPresent()) - prevNode.add(selectorNode); // 2 + graph.appendNode(selectorNode); // 2 graph.endBlock(); } @Override public void visit(BreakStmt n, CFG graph) { if (!switchStack.isEmpty() && !n.getLabel().isPresent()) { - graph.addNode(n); - graph.connect(prevNode, n); + graph.connectTo(n, false); brokenStmts.add(n); - prevNode = Collections.emptyList(); + graph.clearNode(); return; } super.visit(n, graph); @@ -223,11 +171,6 @@ public class Visitador extends VoidVisitorAdapter { @Override public void visit(ExpressionStmt es, CFG graph) { - graph.addNode(es); - graph.connect(prevNode, es); - prevNode = Collections.singletonList(es); - - // Seguimos visitando... - super.visit(es, graph); + graph.connectTo(es); } }