bufixes with goto-successors, empty block removal
This commit is contained in:
@ -29,8 +29,12 @@ public class FlowBasicBlock {
|
||||
this("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Ermittelt ob ein BasicBlock ohne weiteres entfernbar ist.
|
||||
* Der Block darf kein Label haben, damit keine Sprünge ins Leere passieren.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return this.label.isBlank() && this.instructions.isEmpty();
|
||||
return this.instructions.isEmpty() && this.label.isBlank();
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
|
@ -1,19 +1,23 @@
|
||||
package codegen.flowgraph;
|
||||
|
||||
import util.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class FlowGraph {
|
||||
|
||||
private final FlowGraphHead head;
|
||||
private final List<FlowBasicBlock> blocks;
|
||||
private final List<FlowBasicBlock> basicBlocks;
|
||||
private final FlowGraphTail tail;
|
||||
|
||||
// If a new block has this label, the value in this map is a predecessor
|
||||
@ -21,7 +25,7 @@ public class FlowGraph {
|
||||
|
||||
public FlowGraph(String bytecodeVersion, String source, String clazz, int stackSize, int localCount) {
|
||||
this.head = new FlowGraphHead(bytecodeVersion, source, clazz, stackSize, localCount);
|
||||
this.blocks = new ArrayList<>();
|
||||
this.basicBlocks = new ArrayList<>();
|
||||
this.tail = new FlowGraphTail();
|
||||
this.predecessorMap = new HashMap<>();
|
||||
}
|
||||
@ -35,46 +39,24 @@ public class FlowGraph {
|
||||
if (this.predecessorMap.containsKey(label)) {
|
||||
this.predecessorMap.get(label).addSuccessor(newBlock);
|
||||
newBlock.addPredecessor(this.predecessorMap.get(label));
|
||||
|
||||
// this.predecessorMap.remove(label); // Problematic if multiple gotos to same label
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: Hier ist ein Bug, welcher im Datenflussgraph zu gotos mit 2 successors führt
|
||||
if (this.getCurrentBlock().isEmpty()) {
|
||||
// Replace empty blocks, we don't need them
|
||||
newBlock.addPredecessor(this.getCurrentBlock()); // Obvious predecessor of new block
|
||||
this.getCurrentBlock().addSuccessor(newBlock); // Obvious successor of current block
|
||||
|
||||
if (this.blocks.size() >= 2) {
|
||||
// This empty blocks successors become the previous blocks successors after replacment
|
||||
|
||||
this.blocks.get(this.blocks.size() - 2).addSuccessors(this.getCurrentBlock().getSuccessorSet());
|
||||
}
|
||||
|
||||
// Previous blocks predecessors are also the new blocks predecessors
|
||||
newBlock.addPredecessors(this.getCurrentBlock().getPredecessorSet());
|
||||
|
||||
this.blocks.set(this.blocks.size() - 1, newBlock); // Replace
|
||||
} else {
|
||||
*/
|
||||
// Append block if last one isn't empty
|
||||
|
||||
newBlock.addPredecessor(this.getCurrentBlock()); // Obvious predecessor of new block
|
||||
this.getCurrentBlock().addSuccessor(newBlock); // Obvious successor of current block
|
||||
|
||||
this.blocks.add(newBlock);
|
||||
// }
|
||||
this.basicBlocks.add(newBlock);
|
||||
}
|
||||
|
||||
// Jump means end of block
|
||||
public void addJump(String jumpInstruction, String label) {
|
||||
this.addInst(jumpInstruction, label);
|
||||
this.addInstruction(jumpInstruction, label);
|
||||
|
||||
final FlowBasicBlock newBlock = new FlowBasicBlock();
|
||||
newBlock.addPredecessor(this.getCurrentBlock()); // Obvious predecessor of new block
|
||||
|
||||
if (!"goto".equals(jumpInstruction)) {
|
||||
// Goto always jumps
|
||||
|
||||
newBlock.addPredecessor(this.getCurrentBlock()); // Obvious predecessor of new block
|
||||
this.getCurrentBlock().addSuccessor(newBlock); // Obvious successor of current block
|
||||
}
|
||||
|
||||
@ -91,22 +73,80 @@ public class FlowGraph {
|
||||
this.predecessorMap.put(label, this.getCurrentBlock()); // Current node is predecessor of label-block
|
||||
}
|
||||
|
||||
this.blocks.add(newBlock);
|
||||
this.basicBlocks.add(newBlock);
|
||||
}
|
||||
|
||||
public void addInst(String instruction, String... args) {
|
||||
if (this.blocks.isEmpty()) {
|
||||
this.blocks.add(new FlowBasicBlock()); // First block doesn't exist
|
||||
public void addInstruction(String instruction, String... args) {
|
||||
if (this.basicBlocks.isEmpty()) {
|
||||
this.basicBlocks.add(new FlowBasicBlock("START")); // First block doesn't exist
|
||||
}
|
||||
|
||||
this.getCurrentBlock().addInstruction(instruction, args); // Add to last block
|
||||
}
|
||||
|
||||
/**
|
||||
* Entfernt leere Blöcke.
|
||||
*/
|
||||
public void purgeEmptyBlocks() {
|
||||
Logger.log("\nPurging empty blocks: ");
|
||||
|
||||
final Set<FlowBasicBlock> toRemove = new HashSet<>();
|
||||
|
||||
// Collect removable blocks
|
||||
for (FlowBasicBlock block : this.basicBlocks) {
|
||||
if (block.isEmpty()) {
|
||||
Logger.log("Marking Block " + this.basicBlocks.indexOf(block) + " as removable.");
|
||||
toRemove.add(block);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove blocks + reroute predecessors/successors
|
||||
for (FlowBasicBlock block : toRemove) {
|
||||
|
||||
for (FlowBasicBlock pred : block.getPredecessorSet()) {
|
||||
|
||||
for (FlowBasicBlock succ : block.getSuccessorSet()) {
|
||||
|
||||
Logger.log("Rerouting Block " + this.basicBlocks.indexOf(pred) + " to Block " + this.basicBlocks.indexOf(succ));
|
||||
pred.addSuccessor(succ);
|
||||
succ.addPredecessor(pred);
|
||||
}
|
||||
|
||||
pred.getSuccessorSet().remove(block);
|
||||
}
|
||||
|
||||
for (FlowBasicBlock succ : block.getSuccessorSet()) {
|
||||
succ.getPredecessorSet().remove(block);
|
||||
}
|
||||
}
|
||||
|
||||
this.basicBlocks.removeAll(toRemove);
|
||||
}
|
||||
|
||||
// Getters, Setters
|
||||
|
||||
private FlowBasicBlock getBlockByLabel(String label) {
|
||||
return this.basicBlocks.stream()
|
||||
.filter(block -> block.getLabel().equals(label))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private FlowBasicBlock getCurrentBlock() {
|
||||
return this.basicBlocks.get(this.basicBlocks.size() - 1);
|
||||
}
|
||||
|
||||
public List<FlowBasicBlock> getBasicBlocks() {
|
||||
return this.basicBlocks;
|
||||
}
|
||||
|
||||
// Print + Overrides
|
||||
|
||||
public String print() {
|
||||
final String blocksString = this.blocks.stream()
|
||||
.map(FlowBasicBlock::toString)
|
||||
.map(string -> string + "-".repeat(50) + "\n")
|
||||
.collect(Collectors.joining());
|
||||
final String blocksString = this.basicBlocks.stream()
|
||||
.map(FlowBasicBlock::toString)
|
||||
.map(string -> string + "-".repeat(50) + "\n")
|
||||
.collect(Collectors.joining());
|
||||
|
||||
return this.head + "-".repeat(100) + "\n"
|
||||
+ "-".repeat(50) + "\n" + blocksString + "-".repeat(100) + "\n"
|
||||
@ -119,10 +159,10 @@ public class FlowGraph {
|
||||
dot.append("digraph dfd {\n")
|
||||
.append("node[shape=Mrecord]\n");
|
||||
|
||||
for (FlowBasicBlock block : this.blocks) {
|
||||
for (FlowBasicBlock block : this.basicBlocks) {
|
||||
dot.append(block.getId())
|
||||
.append(" [label=\"{<f0> ")
|
||||
.append(this.blocks.indexOf(block))
|
||||
.append(this.basicBlocks.indexOf(block))
|
||||
.append(": ")
|
||||
.append(block.getLabel())
|
||||
.append("|<f1> ")
|
||||
@ -133,13 +173,23 @@ public class FlowGraph {
|
||||
dot.append("START[label=\"START\"];\n")
|
||||
.append("END[label=\"END\"];\n");
|
||||
|
||||
dot.append("START -> ").append(this.blocks.get(0).getId()).append(";\n");
|
||||
dot.append("START -> ").append(this.basicBlocks.get(0).getId()).append(";\n");
|
||||
dot.append(this.getCurrentBlock().getId()).append(" -> END;\n");
|
||||
|
||||
for (FlowBasicBlock block : this.blocks) {
|
||||
for (FlowBasicBlock block : this.basicBlocks) {
|
||||
// Successors
|
||||
for (FlowBasicBlock succ : block.getSuccessorSet()) {
|
||||
dot.append(block.getId()).append(" -> ").append(succ.getId()).append(";\n");
|
||||
}
|
||||
|
||||
// Predecessors
|
||||
for (FlowBasicBlock pred : block.getPredecessorSet()) {
|
||||
if (!dot.toString().contains(pred.getId() + " -> " + block.getId())) {
|
||||
// No duplicate arrows
|
||||
|
||||
dot.append(pred.getId()).append(" -> ").append(block.getId()).append(";\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dot.append("}");
|
||||
@ -165,34 +215,13 @@ public class FlowGraph {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final String blocksString = this.blocks.stream()
|
||||
.map(FlowBasicBlock::toString)
|
||||
.collect(Collectors.joining());
|
||||
final String blocksString = this.basicBlocks.stream()
|
||||
.map(FlowBasicBlock::toString)
|
||||
.collect(Collectors.joining());
|
||||
|
||||
return this.head
|
||||
+ blocksString
|
||||
+ this.tail;
|
||||
}
|
||||
|
||||
private FlowBasicBlock getBlockByLabel(String label) {
|
||||
return this.blocks.stream()
|
||||
.filter(block -> block.getLabel().equals(label))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private FlowBasicBlock getCurrentBlock() {
|
||||
return this.blocks.get(this.blocks.size() - 1);
|
||||
}
|
||||
|
||||
public List<FlowBasicBlock> getBlocks() {
|
||||
return this.blocks;
|
||||
}
|
||||
|
||||
public FlowBasicBlock getBlockById(String id) {
|
||||
return this.blocks.stream()
|
||||
.filter(block -> block.getId().equals(id))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
|
@ -17,11 +17,15 @@ import java.util.Map;
|
||||
import static java.util.Map.entry;
|
||||
import static util.Logger.log;
|
||||
|
||||
/**
|
||||
* Erzeugt den SourceCode in FlussGraph-Darstellung.
|
||||
*/
|
||||
public final class FlowGraphGenerator {
|
||||
|
||||
private static final Map<String, Method> methodMap;
|
||||
|
||||
static {
|
||||
// Init the method mappings: ASTNode.getName() -> FlowGraphGenerator.method
|
||||
Map<String, Method> map;
|
||||
try {
|
||||
final Class<?> gen = FlowGraphGenerator.class;
|
||||
@ -76,7 +80,7 @@ public final class FlowGraphGenerator {
|
||||
private static Map<String, Integer> initVarMap(AST tree) {
|
||||
final Map<String, Integer> varMap = new HashMap<>();
|
||||
|
||||
// Assign variables to map
|
||||
// Assign variables to map: Symbol -> jasminLocalVarNr.
|
||||
int varCount = 0;
|
||||
final Deque<ASTNode> stack = new ArrayDeque<>();
|
||||
stack.push(tree.getRoot());
|
||||
@ -97,14 +101,17 @@ public final class FlowGraphGenerator {
|
||||
return Collections.unmodifiableMap(varMap);
|
||||
}
|
||||
|
||||
public Map<String, Integer> getVarMap() {
|
||||
return this.varMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erzeugt den Flussgraphen für den gespeicherten AST.
|
||||
* Der Flussgraph ist dabei die Graphenform des generierten SourceCodes:
|
||||
* Die Instruktionen sind unterteilt in BasicBlocks, welche über Kanten verbunden sind.
|
||||
*/
|
||||
public FlowGraph generateGraph() {
|
||||
System.out.println(" - Generating Source Graph...");
|
||||
|
||||
// Skip the first 2 identifiers: ClassName, MainArgs
|
||||
this.generateNode(this.tree.getRoot().getChildren().get(3).getChildren().get(11));
|
||||
this.graph.purgeEmptyBlocks();
|
||||
Logger.call(this.graph::printToImage);
|
||||
|
||||
log("\n\nSourceGraph print:\n" + "-".repeat(100) + "\n" + this.graph.print() + "-".repeat(100));
|
||||
@ -113,137 +120,168 @@ public final class FlowGraphGenerator {
|
||||
return this.graph;
|
||||
}
|
||||
|
||||
private void generateNode(ASTNode node) {
|
||||
if (methodMap.containsKey(node.getName())) {
|
||||
/**
|
||||
* Erzeugt den FlussGraphen für die angegebene Wurzel.
|
||||
* Der Wurzelname wird über die methodMap einer Methode zugewiesen.
|
||||
* Diese wird aufgerufen und erzeugt den entsprechenden Teilbaum.
|
||||
*/
|
||||
private void generateNode(ASTNode root) {
|
||||
if (methodMap.containsKey(root.getName())) {
|
||||
try {
|
||||
methodMap.get(node.getName()).invoke(this, node);
|
||||
methodMap.get(root.getName()).invoke(this, root);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
node.getChildren().forEach(this::generateNode);
|
||||
root.getChildren().forEach(this::generateNode);
|
||||
}
|
||||
}
|
||||
|
||||
// ifeq - if value is 0
|
||||
// ifne - if value is not 0
|
||||
private void condNode(ASTNode node) {
|
||||
|
||||
/**
|
||||
* Erzeugt den Teilbaum für einen If-Knoten.
|
||||
*/
|
||||
private void condNode(ASTNode root) {
|
||||
final int currentLabel = this.labelCounter;
|
||||
this.labelCounter++;
|
||||
|
||||
// Condition
|
||||
this.generateNode(node.getChildren().get(0));
|
||||
// Condition If ( ... ) {
|
||||
this.generateNode(root.getChildren().get(0));
|
||||
|
||||
// Jump
|
||||
// Jump if condition false
|
||||
this.graph.addJump("ifeq", "IFfalse" + currentLabel);
|
||||
|
||||
// IFtrue branch
|
||||
this.generateNode(node.getChildren().get(1));
|
||||
this.graph.addJump("goto", "IFend" + currentLabel);
|
||||
// IFtrue branch (gets executed without jump)
|
||||
this.generateNode(root.getChildren().get(1));
|
||||
this.graph.addJump("goto", "IFend" + currentLabel); // Skip IFfalse branch
|
||||
|
||||
// IFfalse branch
|
||||
// IFfalse branch (gets executed after jump)
|
||||
this.graph.addLabel("IFfalse" + currentLabel);
|
||||
if (node.getChildren().size() == 3) {
|
||||
if (root.getChildren().size() == 3) {
|
||||
// Else exists
|
||||
|
||||
this.generateNode(node.getChildren().get(2));
|
||||
this.generateNode(root.getChildren().get(2));
|
||||
}
|
||||
|
||||
// IFend branch
|
||||
this.graph.addLabel("IFend" + currentLabel);
|
||||
}
|
||||
|
||||
private void loopNode(ASTNode node) {
|
||||
/**
|
||||
* Erzeugt den Teilbaum für einen While-Knoten.
|
||||
*/
|
||||
private void loopNode(ASTNode root) {
|
||||
final int currentLabel = this.labelCounter;
|
||||
this.labelCounter++;
|
||||
|
||||
// LOOPstart label for loop repetition
|
||||
this.graph.addLabel("LOOPstart" + currentLabel);
|
||||
|
||||
// Condition
|
||||
this.generateNode(node.getChildren().get(0).getChildren().get(1));
|
||||
// Condition while ( ... ) {
|
||||
this.generateNode(root.getChildren().get(0).getChildren().get(1));
|
||||
|
||||
// Jump
|
||||
// Jump out of loop if condition is false
|
||||
this.graph.addJump("ifeq", "LOOPend" + currentLabel);
|
||||
|
||||
// Loop body
|
||||
this.generateNode(node.getChildren().get(1));
|
||||
this.graph.addJump("goto", "LOOPstart" + currentLabel);
|
||||
// Loop body (gets executed without jump)
|
||||
this.generateNode(root.getChildren().get(1));
|
||||
this.graph.addJump("goto", "LOOPstart" + currentLabel); // Repeat loop
|
||||
|
||||
// Loop end
|
||||
this.graph.addLabel("LOOPend" + currentLabel);
|
||||
}
|
||||
|
||||
private void assignNode(ASTNode node) { //! Stack - 1
|
||||
this.generateNode(node.getChildren().get(0));
|
||||
/**
|
||||
* Erzeugt den Teilbaum für Assignment-Knoten.
|
||||
* Die JVM-Stacksize wird dabei um 1 verringert, da istore/astore 1 Argument konsumieren.
|
||||
*/
|
||||
private void assignNode(ASTNode root) { //! Stack - 1
|
||||
this.generateNode(root.getChildren().get(0));
|
||||
|
||||
final String type = this.nodeTypeMap.get(node.getChildren().get(0));
|
||||
final String type = this.nodeTypeMap.get(root.getChildren().get(0));
|
||||
final String inst = switch (type) {
|
||||
case "INTEGER_TYPE", "BOOLEAN_TYPE" -> "istore";
|
||||
case "STRING_TYPE" -> "astore";
|
||||
default -> throw new IllegalStateException("Unexpected value: " + type);
|
||||
};
|
||||
|
||||
log("assign(): " + node.getName() + ": " + node.getValue() + " => " + inst);
|
||||
log("assign(): " + root.getName() + ": " + root.getValue() + " => " + inst);
|
||||
|
||||
this.graph.addInst(inst, this.varMap.get(node.getValue()).toString());
|
||||
this.graph.addInstruction(inst, this.varMap.get(root.getValue()).toString());
|
||||
}
|
||||
|
||||
private void exprNode(ASTNode node) {
|
||||
if ("INTEGER_TYPE".equals(this.nodeTypeMap.get(node))) {
|
||||
this.intExpr(node);
|
||||
} else if ("BOOLEAN_TYPE".equals(this.nodeTypeMap.get(node))) {
|
||||
this.boolExpr(node);
|
||||
/**
|
||||
* Wählt die entsprechende Methode für mathematische oder logische Ausdrücke.
|
||||
*/
|
||||
private void exprNode(ASTNode root) {
|
||||
if ("INTEGER_TYPE".equals(this.nodeTypeMap.get(root))) {
|
||||
this.intExpr(root);
|
||||
} else if ("BOOLEAN_TYPE".equals(this.nodeTypeMap.get(root))) {
|
||||
this.boolExpr(root);
|
||||
}
|
||||
}
|
||||
|
||||
private void intExpr(ASTNode node) {
|
||||
/**
|
||||
* Erzeugt den Teilbaum für mathematische Ausdrücke.
|
||||
* Bei unären Operatoren bleibt die Stackgröße konstant (1 konsumiert, 1 Ergebnis),
|
||||
* bei binären Operatoren sinkt die Stackgröße um 1 (2 konsumiert, 1 Ergebnis).
|
||||
*/
|
||||
private void intExpr(ASTNode root) {
|
||||
String inst = "";
|
||||
|
||||
if (node.getChildren().size() == 1) { //! Stack + 0
|
||||
if (root.getChildren().size() == 1) { //! Stack + 0
|
||||
// Unary operator
|
||||
|
||||
this.generateNode(node.getChildren().get(0));
|
||||
this.generateNode(root.getChildren().get(0));
|
||||
|
||||
inst = switch (node.getValue()) {
|
||||
inst = switch (root.getValue()) {
|
||||
case "ADD" -> "";
|
||||
case "SUB" -> "ineg";
|
||||
default -> throw new IllegalStateException("Unexpected value: " + node.getValue());
|
||||
default -> throw new IllegalStateException("Unexpected value: " + root.getValue());
|
||||
};
|
||||
} else if (node.getChildren().size() == 2) { //! Stack - 1
|
||||
} else if (root.getChildren().size() == 2) { //! Stack - 1
|
||||
// Binary operator
|
||||
|
||||
this.generateNode(node.getChildren().get(0));
|
||||
this.generateNode(node.getChildren().get(1));
|
||||
this.generateNode(root.getChildren().get(0));
|
||||
this.generateNode(root.getChildren().get(1));
|
||||
|
||||
inst = switch (node.getValue()) {
|
||||
inst = switch (root.getValue()) {
|
||||
case "ADD" -> "iadd"; // Integer
|
||||
case "SUB" -> "isub";
|
||||
case "MUL" -> "imul";
|
||||
case "DIV" -> "idiv";
|
||||
case "MOD" -> "irem"; // Remainder operator
|
||||
default -> throw new IllegalStateException("Unexpected value: " + node.getValue());
|
||||
default -> throw new IllegalStateException("Unexpected value: " + root.getValue());
|
||||
};
|
||||
}
|
||||
|
||||
log("intExpr(): " + node.getName() + ": " + node.getValue() + " => " + inst);
|
||||
log("intExpr(): " + root.getName() + ": " + root.getValue() + " => " + inst);
|
||||
|
||||
this.graph.addInst(inst);
|
||||
this.graph.addInstruction(inst);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erzeugt den Teilbaum für logische Ausdrücke.
|
||||
* Bei unären Operatoren wächst der Stack temporär um 1 (NOT pusht eine 1 für xor),
|
||||
* bei binären Operatoren sinkt die Stackgröße um 1 (2 konsumiert, 1 Ergebnis).
|
||||
*/
|
||||
private void boolExpr(ASTNode node) {
|
||||
if (node.getChildren().size() == 1) { //! Stack + 1
|
||||
// Unary operator
|
||||
|
||||
if (!"NOT".equals(node.getValue())) {
|
||||
// Diese Möglichkeit gibts eigentlich nicht
|
||||
// Possibility doesn't exist, would be frontend-error
|
||||
|
||||
throw new IllegalStateException("Unexpected value: " + node.getValue());
|
||||
}
|
||||
|
||||
this.generateNode(node.getChildren().get(0));
|
||||
|
||||
// 0 ^1 = 1, 1 ^1 = 0
|
||||
this.graph.addInst("ldc", "1");
|
||||
this.graph.addInst("ixor");
|
||||
// 0 xor 1 = 1, 1 xor 1 = 0 => not
|
||||
this.graph.addInstruction("ldc", "1");
|
||||
this.graph.addInstruction("ixor");
|
||||
|
||||
} else if (node.getChildren().size() == 2) { //! Stack - 1
|
||||
// Binary operator
|
||||
@ -266,9 +304,10 @@ public final class FlowGraphGenerator {
|
||||
default -> throw new IllegalStateException("Unexpected value: " + type);
|
||||
};
|
||||
|
||||
// The comparison operations need to jump
|
||||
switch (node.getValue()) {
|
||||
case "AND" -> this.graph.addInst("iand"); // Boolean
|
||||
case "OR" -> this.graph.addInst("ior");
|
||||
case "AND" -> this.graph.addInstruction("iand"); // Boolean
|
||||
case "OR" -> this.graph.addInstruction("ior");
|
||||
case "EQUAL" -> this.genComparisonInst(cmpeq, "EQ", currentLabel);
|
||||
case "NOT_EQUAL" -> this.genComparisonInst(cmpne, "NE", currentLabel);
|
||||
case "LESS" -> this.genComparisonInst("if_icmplt", "LT", currentLabel);
|
||||
@ -280,12 +319,19 @@ public final class FlowGraphGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Erzeugt die Instruktionen für eine Vergleichsoperation.
|
||||
*
|
||||
* @param cmpInst Die Vergleichsanweisung
|
||||
* @param labelPre Das Labelpräfix, abhängig von der Art des Vergleichs
|
||||
* @param currentLabel Der aktuelle Labelcounter
|
||||
*/
|
||||
private void genComparisonInst(String cmpInst, String labelPre, int currentLabel) {
|
||||
this.graph.addJump(cmpInst, labelPre + "true" + currentLabel); // If not equal jump to NEtrue
|
||||
this.graph.addInst("ldc", "0"); // If false load 0
|
||||
this.graph.addInstruction("ldc", "0"); // If false load 0
|
||||
this.graph.addJump("goto", labelPre + "end" + currentLabel); // If false skip to true
|
||||
this.graph.addLabel(labelPre + "true" + currentLabel);
|
||||
this.graph.addInst("ldc", "1"); // If true load 1
|
||||
this.graph.addInstruction("ldc", "1"); // If true load 1
|
||||
this.graph.addLabel(labelPre + "end" + currentLabel);
|
||||
}
|
||||
|
||||
@ -295,7 +341,7 @@ public final class FlowGraphGenerator {
|
||||
log("intStringLiteral(): " + node.getName() + ": " + node.getValue() + " => ldc");
|
||||
|
||||
// bipush only pushes 1 byte as int
|
||||
this.graph.addInst("ldc", node.getValue());
|
||||
this.graph.addInstruction("ldc", node.getValue());
|
||||
}
|
||||
|
||||
private void boolLiteralNode(ASTNode node) { //! Stack + 1
|
||||
@ -303,7 +349,7 @@ public final class FlowGraphGenerator {
|
||||
|
||||
final String val = "true".equals(node.getValue()) ? "1" : "0";
|
||||
|
||||
this.graph.addInst("ldc", val);
|
||||
this.graph.addInstruction("ldc", val);
|
||||
}
|
||||
|
||||
private void identifierNode(ASTNode node) { //! Stack + 1
|
||||
@ -316,11 +362,11 @@ public final class FlowGraphGenerator {
|
||||
|
||||
log("identifier(): " + node.getName() + ": " + node.getValue() + " => " + inst);
|
||||
|
||||
this.graph.addInst(inst, this.varMap.get(node.getValue()).toString());
|
||||
this.graph.addInstruction(inst, this.varMap.get(node.getValue()).toString());
|
||||
}
|
||||
|
||||
private void printlnNode(ASTNode node) { //! Stack + 1
|
||||
this.graph.addInst("getstatic", "java/lang/System/out", "Ljava/io/PrintStream;");
|
||||
this.graph.addInstruction("getstatic", "java/lang/System/out", "Ljava/io/PrintStream;");
|
||||
|
||||
final ASTNode expr = node.getChildren().get(1).getChildren().get(1);
|
||||
final String type = switch (this.nodeTypeMap.get(expr)) {
|
||||
@ -334,6 +380,12 @@ public final class FlowGraphGenerator {
|
||||
|
||||
log("println(): " + expr.getName() + ": " + expr.getValue() + " => " + type);
|
||||
|
||||
this.graph.addInst("invokevirtual", "java/io/PrintStream/println(" + type + ")V");
|
||||
this.graph.addInstruction("invokevirtual", "java/io/PrintStream/println(" + type + ")V");
|
||||
}
|
||||
|
||||
// Getters, Setters
|
||||
|
||||
public Map<String, Integer> getVarMap() {
|
||||
return this.varMap;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user