Boxed up control flow structures and preparation for edge labeling

This commit is contained in:
Carlos Galindo 2019-04-03 17:37:57 +02:00
parent 137d01938c
commit d7abcb7b55
Signed by untrusted user who does not match committer: kauron
GPG key ID: 83E68706DEE119A3
3 changed files with 148 additions and 28 deletions

View file

@ -1,22 +1,49 @@
package grafos; package grafos;
import com.github.javaparser.ast.Node; 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 { public class CFG {
private final List<Node> nodes = new ArrayList<>(); private final List<Node> nodes = new LinkedList<>();
private final List<Map.Entry<Node, Node>> edges = new LinkedList<>(); private final LinkedList<Block> blocks = new LinkedList<>();
private Stack<Block> blockStack = new Stack<>();
private final List<Edge> edges = new LinkedList<>();
private Node beginNode, endNode; private Node beginNode, endNode;
private String nextLabel;
public void addNode(Node stmt) { public void addNode(Node stmt) {
nodes.add(stmt); nodes.add(stmt);
if (!blockStack.isEmpty())
blockStack.peek().add(stmt);
System.out.println("NODO: " + node2str(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) { 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<Node> begin, Node end) { public void connect(Collection<Node> begin, Node end) {
@ -38,18 +65,18 @@ public class CFG {
return endNode; return endNode;
} }
public List<String> toStringList() { public List<String> toStringList(GraphViz gv) {
List<String> res = new LinkedList<String>(); List<String> res = new LinkedList<>();
for (Map.Entry<Node, Node> e : edges) { res.add(gv.start_graph());
res.add(edge2str(e.getKey(), e.getValue())); for (Block b : blocks)
res.addAll(b.toStringList(gv));
for (Edge e : edges) {
res.add(e.toString());
} }
res.add(gv.end_graph());
return res; return res;
} }
private String edge2str(Node a, Node b) {
return node2str(a) + "->" + node2str(b);
}
private String node2str(Node s) { private String node2str(Node s) {
if (s == beginNode) if (s == beginNode)
return "Start"; return "Start";
@ -67,4 +94,92 @@ public class CFG {
return "\"(" + (index + 1) + ", " + s.getRange().get().begin.line + ") " return "\"(" + (index + 1) + ", " + s.getRange().get().begin.line + ") "
+ s.toString().replace("\"", "\\\"") + "\""; + s.toString().replace("\"", "\\\"") + "\"";
} }
static class Block extends LinkedList<Node> {
private static int clusterId = 0;
private final Node container;
private final CFG cfg;
private final List<Block> inners = new LinkedList<>();
Block(Node container, CFG cfg) {
this.container = container;
this.cfg = cfg;
}
void addSubBlock(Block block) {
inners.add(block);
}
List<String> toStringList(GraphViz gv) {
List<String> 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;
}
}
} }

View file

@ -47,20 +47,12 @@ public class Transformador {
visitador.visit(cu, graph); visitador.visit(cu, graph);
// Imprimimos el CFG del program // Imprimimos el CFG del program
StringBuilder builder = new StringBuilder(); GraphViz gv = new GraphViz();
for (String s : graph.toStringList()) { String dotInfo = String.join("\n", graph.toStringList(gv));
builder.append(s);
builder.append(";");
System.out.println("ARCO: " + s);
}
String dotInfo = builder.toString();
// Generamos un PDF con el CFG del programa // Generamos un PDF con el CFG del programa
System.out.print("\nGenerando PDF..."); System.out.print("\nGenerando PDF...");
GraphViz gv = new GraphViz();
gv.addln(gv.start_graph());
gv.add(dotInfo); gv.add(dotInfo);
gv.addln(gv.end_graph());
String type = "pdf"; // String type = "gif"; String type = "pdf"; // String type = "gif";
// gv.increaseDpi(); // gv.increaseDpi();
gv.decreaseDpi(); gv.decreaseDpi();

View file

@ -52,6 +52,7 @@ public class Visitador extends VoidVisitorAdapter<CFG> {
@Override @Override
public void visit(IfStmt n, CFG graph) { public void visit(IfStmt n, CFG graph) {
graph.beginBlock(n);
Node ifStart = n.getCondition(); Node ifStart = n.getCondition();
graph.addNode(ifStart); graph.addNode(ifStart);
graph.connect(prevNode, ifStart); graph.connect(prevNode, ifStart);
@ -75,10 +76,12 @@ public class Visitador extends VoidVisitorAdapter<CFG> {
newPrev.add(ifStart); newPrev.add(ifStart);
} }
prevNode = newPrev; prevNode = newPrev;
graph.endBlock();
} }
@Override @Override
public void visit(WhileStmt n, CFG graph) { public void visit(WhileStmt n, CFG graph) {
graph.beginBlock(n);
Node whileStart = n.getCondition(); Node whileStart = n.getCondition();
graph.addNode(whileStart); graph.addNode(whileStart);
graph.connect(prevNode, whileStart); graph.connect(prevNode, whileStart);
@ -89,20 +92,25 @@ public class Visitador extends VoidVisitorAdapter<CFG> {
n.getBody().accept(this, graph); n.getBody().accept(this, graph);
graph.connect(prevNode, whileStart); graph.connect(prevNode, whileStart);
prevNode = Collections.singletonList(whileStart); prevNode = Collections.singletonList(whileStart);
graph.endBlock();
} }
@Override @Override
public void visit(DoStmt n, CFG graph) { public void visit(DoStmt n, CFG graph) {
graph.beginBlock(n);
Node condition = n.getCondition();
prevNode = new LinkedList<>(prevNode); prevNode = new LinkedList<>(prevNode);
prevNode.add(n.getCondition()); prevNode.add(condition);
n.getBody().accept(this, graph); n.getBody().accept(this, graph);
graph.addNode(n.getCondition()); graph.addNode(condition);
graph.connect(prevNode, n.getCondition()); graph.connect(prevNode, condition);
prevNode = Collections.singletonList(n.getCondition()); prevNode = Collections.singletonList(condition);
graph.endBlock();
} }
@Override @Override
public void visit(ForStmt n, CFG graph) { public void visit(ForStmt n, CFG graph) {
graph.beginBlock(n);
// Initialization expressions // Initialization expressions
if (n.getInitialization() != null) { if (n.getInitialization() != null) {
for (Expression e : n.getInitialization()) { for (Expression e : n.getInitialization()) {
@ -139,10 +147,12 @@ public class Visitador extends VoidVisitorAdapter<CFG> {
prevNode = Collections.singletonList(n.getCompare().get()); 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 else // There is no comparison, can't exit the loop TODO implement break and continue as way to exit
prevNode = Collections.emptyList(); prevNode = Collections.emptyList();
graph.endBlock();
} }
@Override @Override
public void visit(ForeachStmt n, CFG graph) { public void visit(ForeachStmt n, CFG graph) {
graph.beginBlock(n);
ForeachStmt copy = new ForeachStmt(n.getTokenRange().orElse(null), n.getVariable(), n.getIterable(), new EmptyStmt()); ForeachStmt copy = new ForeachStmt(n.getTokenRange().orElse(null), n.getVariable(), n.getIterable(), new EmptyStmt());
graph.addNode(copy); graph.addNode(copy);
graph.connect(prevNode, copy); graph.connect(prevNode, copy);
@ -150,6 +160,7 @@ public class Visitador extends VoidVisitorAdapter<CFG> {
n.getBody().accept(this, graph); n.getBody().accept(this, graph);
graph.connect(prevNode, copy); graph.connect(prevNode, copy);
prevNode = Collections.singletonList(copy); prevNode = Collections.singletonList(copy);
graph.endBlock();
} }
@Override @Override
@ -165,8 +176,9 @@ public class Visitador extends VoidVisitorAdapter<CFG> {
@Override @Override
public void visit(SwitchStmt n, CFG graph) { public void visit(SwitchStmt n, CFG graph) {
graph.beginBlock(n);
// Link previous statement to the switch's selector // 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.addNode(selectorNode);
graph.connect(prevNode, selectorNode); graph.connect(prevNode, selectorNode);
// Analyze switch's cases // Analyze switch's cases
@ -191,6 +203,7 @@ public class Visitador extends VoidVisitorAdapter<CFG> {
prevNode.addAll(brokenStmts); // 1 prevNode.addAll(brokenStmts); // 1
if (n.getEntries().get(n.getEntries().size() - 1).getLabel().isPresent()) if (n.getEntries().get(n.getEntries().size() - 1).getLabel().isPresent())
prevNode.add(selectorNode); // 2 prevNode.add(selectorNode); // 2
graph.endBlock();
} }
@Override @Override