64 lines
2.3 KiB
Java
64 lines
2.3 KiB
Java
package ch.usi.inf.sp.cfg;
|
|
|
|
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.StreamSupport;
|
|
|
|
public class ControlFlowGraphRenderer {
|
|
private static final String INDENTATION = " ";
|
|
private final StringBuilder code = new StringBuilder();
|
|
private int indentationLevel = 0;
|
|
|
|
private static String nodeIdentifier(final BasicBlock bb, final String graphId) {
|
|
// as the basic block ID is negative for the entry and exit node, and negative numbers contain
|
|
// a dash symbol, we need to quote the identifier to make a syntactically correct DOT file
|
|
return String.format("\"%sbb%d\"", graphId, bb.getId());
|
|
}
|
|
|
|
private static String nodeStyle(final BasicBlock bb, final String label) {
|
|
if (bb.getInEdges().isEmpty()) {
|
|
return "[shape=circle,label=\"e\",xlabel=\"" + label + "\"]";
|
|
} else if (bb.getOutEdges().isEmpty()) {
|
|
return "[shape=circle,label=\"x\"]";
|
|
} else {
|
|
return "[label=\"" + bb.getId() + "|{" +
|
|
StreamSupport.stream(bb.getInstructions().spliterator(), false)
|
|
.collect(Collectors.joining("|"))
|
|
+ "}\"]";
|
|
}
|
|
}
|
|
|
|
public static String renderControlFlowGraph(final String label, final ControlFlowGraph cfg) {
|
|
return new ControlFlowGraphRenderer().render(label, cfg);
|
|
}
|
|
|
|
private void line(String line) {
|
|
code.append(INDENTATION.repeat(indentationLevel)).append(line).append('\n');
|
|
}
|
|
|
|
private String render(final String desiredLabel, final ControlFlowGraph graph) {
|
|
final String label = desiredLabel.replaceAll("\\W+", "");
|
|
|
|
line("digraph " + label + " {");
|
|
code.append('\n');
|
|
indentationLevel++;
|
|
|
|
line("node [shape=record]");
|
|
for (final BasicBlock bb : graph.getNodes()) {
|
|
line(nodeIdentifier(bb, label) + " " + nodeStyle(bb, label));
|
|
}
|
|
code.append('\n');
|
|
|
|
for (var e : graph.getEdges()) {
|
|
final String l = e.getLabel();
|
|
final String suffix = l == null || l.isBlank() ? "" : (" [label=\"" + e.getLabel() + "\"]");
|
|
|
|
line(nodeIdentifier(e.getFrom(), label) + " -> " + nodeIdentifier(e.getTo(), label) + suffix);
|
|
}
|
|
indentationLevel--;
|
|
line("}");
|
|
|
|
return code.toString();
|
|
}
|
|
}
|