package grafos; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.expr.BooleanLiteralExpr; import com.github.javaparser.ast.expr.SimpleName; import com.github.javaparser.ast.stmt.*; import java.util.*; public class CFG { private final List nodes = new LinkedList<>(); private final LinkedList blocks = new LinkedList<>(); private final Stack blockStack = new Stack<>(); private final List edges = new LinkedList<>(); private final Node beginNode = new EmptyStmt(), endNode = new EmptyStmt(); private final LinkedList nodeList = new LinkedList<>(); private final Map labelMap = new HashMap<>(); private final Map> breakMap = new HashMap<>(); private final Stack> breakStack = new Stack<>(); private void registerNode(Node stmt) { nodes.add(stmt); if (!blockStack.isEmpty()) blockStack.peek().add(stmt); System.out.println("NODO: " + node2str(stmt)); } public void setNode(Node node) { clearNode(); appendNode(node); } 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) registerNode(condition); if (blockStack.isEmpty()) blocks.addFirst(b); else blockStack.peek().addSubBlock(b); blockStack.push(b); } public void endBlock() { blockStack.pop(); } public void setNextLabel(boolean b) { labelMap.put(nodeList.getLast(), String.valueOf(b)); } private void connect(Node begin, Node end) { edges.add(new Edge(begin, end, labelMap.get(begin))); labelMap.remove(begin); } public Node getEndNode() { return endNode; } public void beginBreakSection(SimpleName name) { breakMap.put(name, new LinkedList<>()); } public void beginBreakSection() { breakStack.push(new LinkedList<>()); } public void registerBreak(BreakStmt stmt) { List list; if (stmt.getLabel().isPresent()) { list = breakMap.get(stmt.getLabel().get()); } else { list = breakStack.peek(); } list.add(stmt); } public void endBreakSection(SimpleName name) { nodeList.addAll(breakMap.remove(name)); } public void endBreakSection() { nodeList.addAll(breakStack.pop()); } 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 node2str(Node n) { if (n == beginNode) return "Start"; if (n == endNode) return "Stop"; return String.format("\"(%d, %d) %s\"", indexOfNode(n) + 1, n.getRange().get().begin.line, escape(n.toString())); } private int indexOfNode(Node n) { for (int i = 0; i < nodes.size(); i++) if (nodes.get(i) == n) return i; throw new RuntimeException("Internal error, can't find node in list"); } private String escape(String s) { return s.replace("\"", "\\\""); } private static int clusterId = 0; class Block extends LinkedList { private final Node container, condition; private final List inners = new LinkedList<>(); Block(Node container, Node condition) { this.container = container; this.condition = condition; } 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() + "\""); if (condition != null) { res.add("node [ shape = rectangle ]; " + node2str(condition)); res.add("node [ shape = ellipse ]"); } for (Block b : inners) { res.addAll(b.toStringList(gv)); } for (Node n : this) { res.add(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); } } class Edge { private final Node origin, destination; private final String label; Edge(Node origin, Node destination, String label) { this.origin = origin; this.destination = destination; this.label = label; } public String toString() { String s = node2str(origin) + " -> " + node2str(destination); if (label != null) { s += " [ label = \"" + label + "\" ]"; } return s; } } }