From 5c27fe4cb656567338be32528c8727e1dd769b31 Mon Sep 17 00:00:00 2001 From: ChUrl Date: Thu, 4 Feb 2021 19:59:00 +0100 Subject: [PATCH] overhaul logging + printing ast to image --- src/main/java/StupsCompiler.java | 9 ++- .../analysis/dataflow/DataFlowGraph.java | 4 +- .../analysis/liveness/InterferenceGraph.java | 4 +- .../analysis/liveness/LivenessAnalysis.java | 2 +- .../java/codegen/flowgraph/FlowGraph.java | 25 ++++---- .../codegen/flowgraph/FlowGraphGenerator.java | 28 ++++----- src/main/java/parser/StupsParser.java | 15 ++--- .../java/parser/ast/ParseTreeCleaner.java | 26 ++++---- src/main/java/parser/ast/SyntaxTree.java | 49 +++++++++++++++ src/main/java/parser/ast/SyntaxTreeNode.java | 14 +++++ .../java/parser/ast/SyntaxTreeRebalancer.java | 14 ++--- src/main/java/parser/grammar/Grammar.java | 24 +++++--- .../java/parser/grammar/GrammarAnalyzer.java | 60 +++++++++++-------- src/main/java/typechecker/TypeChecker.java | 13 ++-- src/main/java/typechecker/TypeTable.java | 2 +- src/main/java/util/Logger.java | 7 ++- 16 files changed, 196 insertions(+), 100 deletions(-) diff --git a/src/main/java/StupsCompiler.java b/src/main/java/StupsCompiler.java index b69ea2e..19b958b 100644 --- a/src/main/java/StupsCompiler.java +++ b/src/main/java/StupsCompiler.java @@ -45,7 +45,7 @@ public final class StupsCompiler { final FlowGraphGenerator gen = getFlowGraphGen(filename); final FlowGraph graph = gen.generateGraph(); - Logger.logInfoSupplier(graph::printToImage, StupsCompiler.class); + Logger.logDebugSupplier(graph::printToImage, StupsCompiler.class); // Codegeneration + Output final String fileExtension = filename.substring(filename.lastIndexOf('.') + 1); @@ -79,11 +79,11 @@ public final class StupsCompiler { final FlowGraphGenerator gen = getFlowGraphGen(filename); final FlowGraph graph = gen.generateGraph(); - Logger.logInfoSupplier(graph::printToImage, StupsCompiler.class); + Logger.logDebugSupplier(graph::printToImage, StupsCompiler.class); final DataFlowGraph dataFlowGraph = DataFlowGraph.fromFlowGraph(graph); - Logger.logInfoSupplier(dataFlowGraph::printToImage, StupsCompiler.class); + Logger.logDebugSupplier(dataFlowGraph::printToImage, StupsCompiler.class); final LivenessAnalysis liveness = LivenessAnalysis.fromDataFlowGraph(dataFlowGraph, gen.getVarMap()); final int registers = liveness.doLivenessAnalysis(); @@ -129,7 +129,10 @@ public final class StupsCompiler { // Parsing + Typechecking of program final SyntaxTree parseTree = stupsParser.parse(lexer.getAllTokens(), lexer.getVocabulary()); + Logger.logDebugSupplier(() -> parseTree.printToImage("ParseTree"), StupsCompiler.class); + final SyntaxTree abstractSyntaxTree = SyntaxTree.toAbstractSyntaxTree(parseTree, grammar); + final Map nodeTable = TypeChecker.validate(abstractSyntaxTree); return FlowGraphGenerator.fromAST(abstractSyntaxTree, nodeTable, filename); diff --git a/src/main/java/codegen/analysis/dataflow/DataFlowGraph.java b/src/main/java/codegen/analysis/dataflow/DataFlowGraph.java index 3845fda..f1aa55f 100644 --- a/src/main/java/codegen/analysis/dataflow/DataFlowGraph.java +++ b/src/main/java/codegen/analysis/dataflow/DataFlowGraph.java @@ -98,7 +98,7 @@ public final class DataFlowGraph implements Iterable { public String printToImage() { if (this.dataFlowNodes.isEmpty()) { - return "Empty Graph"; + return "Can't export empty graph: DataFLowGraph.svg"; } final StringBuilder dot = new StringBuilder(); @@ -132,7 +132,7 @@ public final class DataFlowGraph implements Iterable { GraphvizCaller.callGraphviz(dot, "DataFlowGraph"); - return "Finished."; + return "Successfully exported as image: DataFlowGraph.svg"; } // Overrides diff --git a/src/main/java/codegen/analysis/liveness/InterferenceGraph.java b/src/main/java/codegen/analysis/liveness/InterferenceGraph.java index 3460adc..8004e79 100644 --- a/src/main/java/codegen/analysis/liveness/InterferenceGraph.java +++ b/src/main/java/codegen/analysis/liveness/InterferenceGraph.java @@ -69,7 +69,7 @@ public final class InterferenceGraph implements Iterable { public String printToImage() { if (this.interferenceNodes.isEmpty()) { - return "Empty Graph"; + return "Can't export empty graph: Interference.svg"; } final StringBuilder dot = new StringBuilder(); @@ -100,7 +100,7 @@ public final class InterferenceGraph implements Iterable { GraphvizCaller.callGraphviz(dot, "InterferenceGraph"); - return "Finished."; + return "Successfully exported as Image: InterferenceGraph.svg"; } // Overrides diff --git a/src/main/java/codegen/analysis/liveness/LivenessAnalysis.java b/src/main/java/codegen/analysis/liveness/LivenessAnalysis.java index 5beaf2f..61a770e 100644 --- a/src/main/java/codegen/analysis/liveness/LivenessAnalysis.java +++ b/src/main/java/codegen/analysis/liveness/LivenessAnalysis.java @@ -107,7 +107,7 @@ public final class LivenessAnalysis { Logger.logDebug("Successfully colored interference-graph", LivenessAnalysis.class); } - Logger.logInfoSupplier(this.interferenceGraph::printToImage, LivenessAnalysis.class); + Logger.logDebugSupplier(this.interferenceGraph::printToImage, LivenessAnalysis.class); return colors; } diff --git a/src/main/java/codegen/flowgraph/FlowGraph.java b/src/main/java/codegen/flowgraph/FlowGraph.java index 54c7fb6..31ce2b9 100644 --- a/src/main/java/codegen/flowgraph/FlowGraph.java +++ b/src/main/java/codegen/flowgraph/FlowGraph.java @@ -48,13 +48,16 @@ public class FlowGraph implements Iterable { * und zu Blöcken aus der {@link #predecessorMap} hergestellt. */ public void addLabel(String label) { - Logger.logInfo("Adding Label: " + label, FlowGraph.class); + Logger.logInfo(" :: Adding label: \"" + label + "\"", FlowGraph.class); final FlowBasicBlock newBlock = new FlowBasicBlock(label); // Resolve missing successors/predecessors from jumps if (this.predecessorMap.containsKey(label)) { - Logger.logInfo("Handling PredecessorMap Entry: " + this.predecessorMap.get(label), FlowGraph.class); + Logger.logInfo(" :: Handling predecessor-map entry:\n\t\t\t" + + this.predecessorMap.get(label).getLabel() + + "\n\t\t\t[...]\n\t\t\t" + + this.predecessorMap.get(label).getLastInstruction(), FlowGraph.class); this.predecessorMap.get(label).addSuccessorBlock(newBlock); newBlock.addPredecessorBlock(this.predecessorMap.get(label)); @@ -79,7 +82,7 @@ public class FlowGraph implements Iterable { * @param jumpInstruction Der verwendete Sprungbefehl. */ public void addJump(String jumpInstruction, String label) { - Logger.logInfo("Adding Jump to Label: " + label, FlowGraph.class); + Logger.logInfo(" :: Adding jump to label \"" + label + "\"", FlowGraph.class); this.addInstruction(jumpInstruction, label); @@ -111,7 +114,9 @@ public class FlowGraph implements Iterable { // Successor doesn't exist, so wait until it does // Current node is predecessor of label-block - Logger.logInfo("Adding Entry to PredecessorMap: " + currentBlock, FlowGraph.class); + currentBlock.ifPresent(flowBasicBlock -> Logger.logInfo(" :: Adding entry to predecessor-map: \n\t\t\t" + + flowBasicBlock.getLabel() + "\n\t\t\t[...]\n\t\t\t" + + flowBasicBlock.getLastInstruction(), FlowGraph.class)); currentBlock.ifPresent(flowBasicBlock -> this.predecessorMap.put(label, flowBasicBlock)); } @@ -119,7 +124,7 @@ public class FlowGraph implements Iterable { } public void addInstruction(String instruction, String... args) { - Logger.logInfo("Adding Instruction: " + instruction, FlowGraph.class); + Logger.logInfo(" :: Adding instruction \"" + instruction + "\"", FlowGraph.class); if (this.basicBlocks.isEmpty()) { this.basicBlocks.add(new FlowBasicBlock("START")); // First block doesn't exist @@ -143,7 +148,7 @@ public class FlowGraph implements Iterable { // Collect removable blocks for (FlowBasicBlock block : this.basicBlocks) { if (block.isEmpty()) { - Logger.logInfo("Marking Block " + this.basicBlocks.indexOf(block) + " as removable.", FlowGraph.class); + Logger.logInfo(" :: Marking block nr. " + this.basicBlocks.indexOf(block) + " as removable.", FlowGraph.class); toRemove.add(block); } } @@ -155,8 +160,8 @@ public class FlowGraph implements Iterable { for (FlowBasicBlock predecessor : block.getBlockPredecessorSet()) { for (FlowBasicBlock successor : block.getBlockSuccessorSet()) { - Logger.logInfo("Rerouting Block " + this.basicBlocks.indexOf(predecessor) - + " to Block " + this.basicBlocks.indexOf(successor), FlowGraph.class); + Logger.logInfo(" :: Rerouting block nr. " + this.basicBlocks.indexOf(predecessor) + + " to block nr. " + this.basicBlocks.indexOf(successor), FlowGraph.class); predecessor.addSuccessorBlock(successor); successor.addPredecessorBlock(predecessor); } @@ -200,7 +205,7 @@ public class FlowGraph implements Iterable { final Optional currentBlock = this.getCurrentBlock(); if (this.basicBlocks.isEmpty() || currentBlock.isEmpty()) { - return "Empty Graph"; + return "Can't export empty graph: FlowGraph.svg"; } final StringBuilder dot = new StringBuilder(); @@ -237,7 +242,7 @@ public class FlowGraph implements Iterable { GraphvizCaller.callGraphviz(dot, "FlowGraph"); - return "Finished."; + return "Successfully exported the graph as Image: FlowGraph.svg"; } // Overrides diff --git a/src/main/java/codegen/flowgraph/FlowGraphGenerator.java b/src/main/java/codegen/flowgraph/FlowGraphGenerator.java index fed0bfd..3888f45 100644 --- a/src/main/java/codegen/flowgraph/FlowGraphGenerator.java +++ b/src/main/java/codegen/flowgraph/FlowGraphGenerator.java @@ -75,9 +75,8 @@ public final class FlowGraphGenerator { currentVarNumber++; varMap.put(current.getChildren().get(0).getValue(), currentVarNumber); - Logger.logInfo("New local " + current.getValue() + " variable " - + current.getChildren().get(0).getValue() - + " assigned to slot " + currentVarNumber + ".", FlowGraphGenerator.class); + Logger.logInfo("Assign local variable \"" + current.getChildren().get(0).getValue() + "\" -> \"" + + current.getValue() + "\" to slot " + currentVarNumber, FlowGraphGenerator.class); } current.getChildren().forEach(stack::push); @@ -110,7 +109,6 @@ public final class FlowGraphGenerator { this.graph.purgeEmptyBlocks(); Logger.logDebug("Source-graph generation complete", FlowGraphGenerator.class); - Logger.logInfo("\n\nSourceGraph print:\n" + "-".repeat(100) + "\n" + this.graph + "-".repeat(100), FlowGraphGenerator.class); return this.graph; } @@ -138,7 +136,7 @@ public final class FlowGraphGenerator { * Erzeugt den Teilbaum für einen If-Knoten. */ private void condNode(SyntaxTreeNode root) { - Logger.logInfo("Generating Conditional Node", FlowGraphGenerator.class); + Logger.logInfo("Generating conditional node", FlowGraphGenerator.class); final int currentLabel = this.labelCounter; this.labelCounter++; @@ -169,7 +167,7 @@ public final class FlowGraphGenerator { * Erzeugt den Teilbaum für einen While-Knoten. */ private void loopNode(SyntaxTreeNode root) { - Logger.logInfo("Generating Loop Node", FlowGraphGenerator.class); + Logger.logInfo("Generating loop node", FlowGraphGenerator.class); final int currentLabel = this.labelCounter; this.labelCounter++; @@ -196,7 +194,7 @@ public final class FlowGraphGenerator { * Die JVM-Stacksize wird dabei um 1 verringert, da istore/astore 1 Argument konsumieren. */ private void assignNode(SyntaxTreeNode root) { //! Stack - 1 - Logger.logInfo("Generating Assignment Node", FlowGraphGenerator.class); + Logger.logInfo("Generating assignment node", FlowGraphGenerator.class); this.generateNode(root.getChildren().get(0)); @@ -207,7 +205,7 @@ public final class FlowGraphGenerator { default -> throw new IllegalStateException("Unexpected value: " + type); }; - Logger.logInfo("assign(): " + root.getName() + ": " + root.getValue() + " => " + inst, FlowGraphGenerator.class); + Logger.logInfo("assign(): Node \"" + root.getName() + ": " + root.getValue() + "\" => " + inst, FlowGraphGenerator.class); this.graph.addInstruction(inst, this.varMap.get(root.getValue()).toString()); } @@ -229,7 +227,7 @@ public final class FlowGraphGenerator { * bei binären Operatoren sinkt die Stackgröße um 1 (2 konsumiert, 1 Ergebnis). */ private void intExpr(SyntaxTreeNode root) { - Logger.logInfo("Generating Integer Expression Node", FlowGraphGenerator.class); + Logger.logInfo("Generating integer expression node: \"" + root.getName() + ": " + root.getValue() + "\"", FlowGraphGenerator.class); String inst = ""; @@ -259,7 +257,7 @@ public final class FlowGraphGenerator { }; } - Logger.logInfo("intExpr(): " + root.getName() + ": " + root.getValue() + " => " + inst, FlowGraphGenerator.class); + Logger.logInfo("intExpr(): Node \"" + root.getName() + ": " + root.getValue() + "\" => " + inst, FlowGraphGenerator.class); this.graph.addInstruction(inst); } @@ -270,7 +268,7 @@ public final class FlowGraphGenerator { * bei binären Operatoren sinkt die Stackgröße um 1 (2 konsumiert, 1 Ergebnis). */ private void boolExpr(SyntaxTreeNode node) { - Logger.logInfo("Generating Boolean Expression", FlowGraphGenerator.class); + Logger.logInfo("Generating boolean expression", FlowGraphGenerator.class); if (node.getChildren().size() == 1) { //! Stack + 1 // Unary operator @@ -342,14 +340,14 @@ public final class FlowGraphGenerator { // Leafs private void intStringLiteralNode(SyntaxTreeNode node) { //! Stack + 1 - Logger.logInfo("intStringLiteral(): " + node.getName() + ": " + node.getValue() + " => ldc", FlowGraphGenerator.class); + Logger.logInfo("intStringLiteral(): Node \"" + node.getName() + ": " + node.getValue() + "\" => ldc", FlowGraphGenerator.class); // bipush only pushes 1 byte as int this.graph.addInstruction("ldc", node.getValue()); } private void boolLiteralNode(SyntaxTreeNode node) { //! Stack + 1 - Logger.logInfo("booleanLiteral(): " + node.getName() + ": " + node.getValue() + " => ldc", FlowGraphGenerator.class); + Logger.logInfo("booleanLiteral(): Node \"" + node.getName() + ": " + node.getValue() + "\" => ldc", FlowGraphGenerator.class); final String val = "true".equals(node.getValue()) ? "1" : "0"; @@ -364,7 +362,7 @@ public final class FlowGraphGenerator { default -> throw new IllegalStateException("Unexpected value: " + type); }; - Logger.logInfo("identifier(): " + node.getName() + ": " + node.getValue() + " => " + inst, FlowGraphGenerator.class); + Logger.logInfo("identifier(): Node \"" + node.getName() + ": " + node.getValue() + "\" => " + inst, FlowGraphGenerator.class); this.graph.addInstruction(inst, this.varMap.get(node.getValue()).toString()); } @@ -382,7 +380,7 @@ public final class FlowGraphGenerator { this.generateNode(expr); - Logger.logInfo("println(): " + expr.getName() + ": " + expr.getValue() + " => " + type, FlowGraphGenerator.class); + Logger.logInfo("println(): Node \"" + expr.getName() + ": " + expr.getValue() + "\" => " + type, FlowGraphGenerator.class); this.graph.addInstruction("invokevirtual", "java/io/PrintStream/println(" + type + ")V"); } diff --git a/src/main/java/parser/StupsParser.java b/src/main/java/parser/StupsParser.java index fa7bb13..98425b4 100644 --- a/src/main/java/parser/StupsParser.java +++ b/src/main/java/parser/StupsParser.java @@ -49,13 +49,11 @@ public class StupsParser { int inputPosition = 0; - Logger.logInfo("Input: " + token + "\n", StupsParser.class); - // Parsing while (!stack.isEmpty()) { final String top = stack.peek().getName(); - Logger.logInfo("Parsing Top Symbol: " + top, StupsParser.class); + Logger.logInfo("Parsing Top Symbol: \"" + top + "\"", StupsParser.class); final String currentTokenSym; int currentLine = 0; @@ -76,16 +74,20 @@ public class StupsParser { if (top.equals(Grammar.EPSILON_SYMBOL)) { // Wenn auf dem Stack das Epsilonsymbol liegt +// Logger.logInfo(" :: Skip epsilon", StupsParser.class); + stack.pop(); } else if (top.equals(currentTokenSym)) { // Wenn auf dem Stack ein Terminal liegt (dieses muss mit der Eingabe übereinstimmen) +// Logger.logInfo(" :: Skip terminal-symbol (Matches input)", StupsParser.class); + stack.pop(); inputPosition++; } else if (this.parsetable.getTerminals().contains(top)) { // Wenn das Terminal auf dem Stack nicht mit der aktuellen Eingabe übereinstimmt - Logger.logError("\nLine " + currentLine + " Syntaxerror: Expected " + top + " but found " + Logger.logError("Line " + currentLine + " Syntaxerror: Expected " + top + " but found " + currentTokenSym, StupsParser.class); Logger.logError(StupsParser.printSourceLine(currentLine, token), StupsParser.class); @@ -93,7 +95,7 @@ public class StupsParser { } else if (prod == null) { // Wenn es für das aktuelle Terminal und das Nichtterminal auf dem Stack keine Regel gibt - Logger.logError("\nLine " + currentLine + " Syntaxerror: Didn't expect " + currentTokenSym, StupsParser.class); + Logger.logError("Line " + currentLine + " Syntaxerror: Didn't expect " + currentTokenSym, StupsParser.class); Logger.logError(StupsParser.printSourceLine(currentLine, token), StupsParser.class); throw new ParseException("No prod. for nonterminal " + top + ", terminal " + currentTokenSym, tree); @@ -101,7 +103,7 @@ public class StupsParser { // Wenn das Nichtterminal auf dem Stack durch (s)eine Produktion ersetzt werden kann // Hier wird auch der AST aufgebaut - Logger.logInfo("Used: " + top + " -> " + prod, StupsParser.class); + Logger.logInfo(" :: Used rule: \"" + top + " -> " + prod + "\"", StupsParser.class); final SyntaxTreeNode pop = stack.pop(); final String[] split = prod.split(" "); @@ -126,7 +128,6 @@ public class StupsParser { } Logger.logDebug("Successfully parsed the program and built the parse-tree", StupsParser.class); - Logger.logInfo("\nParsed AST:\n" + tree, StupsParser.class); return tree; } diff --git a/src/main/java/parser/ast/ParseTreeCleaner.java b/src/main/java/parser/ast/ParseTreeCleaner.java index 9ffc064..30bbe4c 100644 --- a/src/main/java/parser/ast/ParseTreeCleaner.java +++ b/src/main/java/parser/ast/ParseTreeCleaner.java @@ -34,7 +34,7 @@ public final class ParseTreeCleaner { valueToValue(parseTree, grammar); Logger.logDebug("Successfully cleaned the parse-tree", ParseTreeCleaner.class); - Logger.logInfo("\nCleaned Tree:\n" + parseTree, ParseTreeCleaner.class); + Logger.logDebugSupplier(() -> parseTree.printToImage("ParseTreeCleaned"), ParseTreeCleaner.class); } /** @@ -57,8 +57,8 @@ public final class ParseTreeCleaner { continue; } - Logger.logInfo("Promoting " + child.getName() + " -> " + root.getName(), ParseTreeCleaner.class); - Logger.logInfo(root.toString(), ParseTreeCleaner.class); + Logger.logInfo("Promoting child \"" + child.getName() + "\" to root \"" + root.getName() + "\"\n" + + root.nodePrint("\t\t"), ParseTreeCleaner.class); root.setName(child.getName()); root.setValue(child.getValue()); @@ -90,7 +90,7 @@ public final class ParseTreeCleaner { continue; } - Logger.logInfo("Removing " + child.getName(), ParseTreeCleaner.class); + Logger.logInfo("Removing node \"" + child.getName() + "\"", ParseTreeCleaner.class); child.setValue("REMOVE"); // If both childs have the same identity both are removed, so change one toRemove.add(child); @@ -118,7 +118,8 @@ public final class ParseTreeCleaner { continue; } - Logger.logInfo("Removing " + root.getName() + " -> " + child.getName(), ParseTreeCleaner.class); + Logger.logInfo("Removing child \"" + child.getName() + "\" from root \"" + root.getName() + "\"\n" + + root.nodePrint("\t\t"), ParseTreeCleaner.class); child.setValue("REMOVE"); // If both childs have the same identity both are removed, so change one toRemove.add(child); @@ -144,7 +145,7 @@ public final class ParseTreeCleaner { continue; } - Logger.logInfo("Rename " + root.getName() + " to " + grammar.getNewName(root) + ".", ParseTreeCleaner.class); + Logger.logInfo("Renaming node \"" + root.getName() + "\" to \"" + grammar.getNewName(root) + "\"", ParseTreeCleaner.class); root.setName(grammar.getNewName(root)); } @@ -169,8 +170,8 @@ public final class ParseTreeCleaner { continue; } - Logger.logInfo("Moving " + child.getName() + " to value of " + root.getName(), ParseTreeCleaner.class); - Logger.logInfo(root.toString(), ParseTreeCleaner.class); + Logger.logInfo("Moving child-name \"" + child.getName() + "\" to parent-value of node \"" + root.getName() + "\"\n" + + root.nodePrint("\t\t"), ParseTreeCleaner.class); root.setValue(child.getName()); @@ -206,8 +207,9 @@ public final class ParseTreeCleaner { && root.getChildren().get(0).getName().equals(root.getChildren().get(1).getName())) { // Case where variable is assigned another variable with the same name - Logger.logInfo("Moving " + root.getChildren().get(1).getValue() + " to value of " + root.getName(), ParseTreeCleaner.class); - Logger.logInfo(root.toString(), ParseTreeCleaner.class); + Logger.logInfo("Moving child-value \"" + root.getChildren().get(1).getValue() + + "\" to parent-value of node \"" + root.getName() + "\"\n" + + root.nodePrint("\t\t"), ParseTreeCleaner.class); root.setValue(root.getChildren().get(1).getValue()); @@ -217,8 +219,8 @@ public final class ParseTreeCleaner { } else { // Usual case where an expression is assigned - Logger.logInfo("Moving " + child.getValue() + " to value of " + root.getName(), ParseTreeCleaner.class); - Logger.logInfo(root.toString(), ParseTreeCleaner.class); + Logger.logInfo("Moving child value \"" + child.getValue() + "\" to parent-value of node \"" + + root.getName() + "\"\n" + root.nodePrint("\t\t"), ParseTreeCleaner.class); root.setValue(child.getValue()); toRemove.add(child); diff --git a/src/main/java/parser/ast/SyntaxTree.java b/src/main/java/parser/ast/SyntaxTree.java index 7293218..e53560d 100644 --- a/src/main/java/parser/ast/SyntaxTree.java +++ b/src/main/java/parser/ast/SyntaxTree.java @@ -1,7 +1,10 @@ package parser.ast; import parser.grammar.Grammar; +import util.GraphvizCaller; +import java.util.ArrayDeque; +import java.util.Deque; import java.util.Objects; /** @@ -47,6 +50,52 @@ public class SyntaxTree { return this.root.isEmpty(); } + public String printToImage(String filename) { + if (this.isEmpty()) { + return "Empty tree can't be exported to image: " + filename + ".svg"; + } + + final Deque stack = new ArrayDeque<>(); + final StringBuilder dot = new StringBuilder(); + + dot.append("digraph tree {\n") + .append("node[shape=Mrecord]\n"); + + stack.push(this.root); + while (!stack.isEmpty()) { + final SyntaxTreeNode current = stack.pop(); + + dot.append("\"").append(current.getId()).append("\"") + .append(" [label=\"{ ") + .append(current.getName()) + .append("| ") + .append(current.getValue()) + .append("}\"];\n"); + + current.getChildren().forEach(stack::push); + } + + stack.push(this.root); + while (!stack.isEmpty()) { + final SyntaxTreeNode current = stack.pop(); + + for (SyntaxTreeNode child : current.getChildren()) { + dot.append("\"").append(current.getId()).append("\"") + .append(" -> ") + .append("\"").append(child.getId()).append("\"") + .append("\n"); + } + + current.getChildren().forEach(stack::push); + } + + dot.append("}"); + + GraphvizCaller.callGraphviz(dot, filename); + + return "Successfully generated image of syntax-tree: " + filename + ".svg"; + } + // Overrides @Override diff --git a/src/main/java/parser/ast/SyntaxTreeNode.java b/src/main/java/parser/ast/SyntaxTreeNode.java index 5453086..ad63e2f 100644 --- a/src/main/java/parser/ast/SyntaxTreeNode.java +++ b/src/main/java/parser/ast/SyntaxTreeNode.java @@ -5,6 +5,7 @@ import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Objects; +import java.util.UUID; import java.util.stream.Collectors; /** @@ -13,12 +14,14 @@ import java.util.stream.Collectors; */ public class SyntaxTreeNode { + private final UUID id; private final int line; private String name; private String value; private List children = new ArrayList<>(); public SyntaxTreeNode(String name, int line) { + this.id = UUID.randomUUID(); this.name = name; this.line = line; this.value = ""; @@ -82,6 +85,10 @@ public class SyntaxTreeNode { this.name = name; } + public UUID getId() { + return this.id; + } + // Printing // toString() und treePrint() von hier: https://stackoverflow.com/a/8948691 @@ -104,6 +111,13 @@ public class SyntaxTreeNode { } } + public String nodePrint(String prefix) { + return prefix + this.name + ": " + this.value + "\n" + + prefix + this.children.stream() + .map(child -> prefix + "└── " + child.name + ": " + child.value + "\n") + .collect(Collectors.joining()).trim(); + } + // Overrides @Override diff --git a/src/main/java/parser/ast/SyntaxTreeRebalancer.java b/src/main/java/parser/ast/SyntaxTreeRebalancer.java index 0908ff0..b47b689 100644 --- a/src/main/java/parser/ast/SyntaxTreeRebalancer.java +++ b/src/main/java/parser/ast/SyntaxTreeRebalancer.java @@ -70,7 +70,7 @@ public final class SyntaxTreeRebalancer { flipCommutativeExpr(abstractSyntaxTree); Logger.logDebug("Successfully rebalanced syntax-tree", SyntaxTreeRebalancer.class); - Logger.logInfo("AST after rebalancing:" + abstractSyntaxTree, SyntaxTreeRebalancer.class); + Logger.logDebugSupplier(() -> abstractSyntaxTree.printToImage("AbstractSyntaxTree"), SyntaxTreeRebalancer.class); } /** @@ -110,8 +110,8 @@ public final class SyntaxTreeRebalancer { if (root.getChildren().size() == 2 && root.getChildren().get(0).size() < root.getChildren().get(1).size()) { // Make the bigger subtree the left one - Logger.logInfo("Flipping " + root.getName() + ": " + root.getValue() + " for stack efficiency.", SyntaxTreeRebalancer.class); - Logger.logInfo(root.toString(), SyntaxTreeRebalancer.class); + Logger.logInfo("Flipping node \"" + root.getName() + ": " + root.getValue() + "\"\n" + + root.nodePrint("\t\t"), SyntaxTreeRebalancer.class); Collections.reverse(root.getChildren()); } @@ -153,8 +153,8 @@ public final class SyntaxTreeRebalancer { * @return Es wird false zurückgegeben, sobald keine weitere Rotation mehr möglich ist. */ private static boolean specialLeftRotate(SyntaxTreeNode root) { - Logger.logInfo("Special-Left-Rotation around " + root.getName(), SyntaxTreeRebalancer.class); - Logger.logInfo(root.toString(), SyntaxTreeRebalancer.class); + Logger.logInfo("Special-left-rotation around node \"" + root.getName() + ": " + root.getValue() + "\"\n" + + root.nodePrint("\t\t"), SyntaxTreeRebalancer.class); final SyntaxTreeNode left = root.getChildren().get(0); final SyntaxTreeNode right = root.getChildren().get(1); @@ -245,8 +245,8 @@ public final class SyntaxTreeRebalancer { } private static void simpleRightRotate(SyntaxTreeNode root) { - Logger.logInfo("Right-Rotation around " + root.getName() + ": " + root.getValue(), SyntaxTreeRebalancer.class); - Logger.logInfo(root.toString(), SyntaxTreeRebalancer.class); + Logger.logInfo("Simple right-rotation around node \"" + root.getName() + ": " + root.getValue() + "\"\n" + + root.nodePrint("\t\t"), SyntaxTreeRebalancer.class); final SyntaxTreeNode left = root.getChildren().get(0); final SyntaxTreeNode right = root.getChildren().get(1); diff --git a/src/main/java/parser/grammar/Grammar.java b/src/main/java/parser/grammar/Grammar.java index e2823b8..a1f8593 100644 --- a/src/main/java/parser/grammar/Grammar.java +++ b/src/main/java/parser/grammar/Grammar.java @@ -118,15 +118,23 @@ public class Grammar { Logger.logDebug("Beginning grammar parsing", Grammar.class); for (String currentLine : lines) { - Logger.logInfo("Parsed: " + currentLine, Grammar.class); + Logger.logInfo("Parsing: \"" + currentLine + "\"", Grammar.class); // Parse Keywords if (currentLine.startsWith("TERM:")) { terminals.addAll(Arrays.stream(currentLine.split(" ")).skip(1).collect(Collectors.toSet())); + + Arrays.stream(currentLine.split(" ")) + .skip(1) + .forEach(term -> Logger.logInfo(" :: Registered terminal symbol \"" + term + "\"", Grammar.class)); } else if (currentLine.startsWith("NTERM:")) { nonterminals.addAll(Arrays.stream(currentLine.split(" ")).skip(1).collect(Collectors.toSet())); + + Arrays.stream(currentLine.split(" ")) + .skip(1) + .forEach(nterm -> Logger.logInfo(" :: Registered nonterminal symbol \"" + nterm + "\"", Grammar.class)); } else { // Parse regular lines @@ -136,7 +144,10 @@ public class Grammar { } } - Logger.logInfo("Registered actions: " + actionMap, Grammar.class); + Logger.logInfo("Grammar terminals: " + terminals, Grammar.class); + Logger.logInfo("Grammar nonterminals: " + nonterminals, Grammar.class); + Logger.logInfo("Grammar productions: " + rules, Grammar.class); + Logger.logInfo("Grammar actions: " + actionMap, Grammar.class); Logger.logDebug("Grammar parsed successfully", Grammar.class); return new Grammar(terminals, nonterminals, @@ -170,8 +181,6 @@ public class Grammar { final Set actionSet = parseActionSet(leftside, open, close); - Logger.logInfo("Current Line " + currentLine + " has Actions: " + actionSet, Grammar.class); - // Validate Actions throwOnInvalidActionSet(actionSet); @@ -230,7 +239,7 @@ public class Grammar { Map> actions) { actions.get(action).add(leftside.trim()); - Logger.logInfo("Registered " + flag + ": " + leftside.trim(), Grammar.class); + Logger.logInfo(" :: Registered action [" + flag + "] for \"" + leftside.trim() + "\"", Grammar.class); } /** @@ -246,7 +255,8 @@ public class Grammar { final int argStart = flag.indexOf('='); final String[] argSplit = flag.substring(argStart + 1).split(","); - Logger.logInfo("Registered " + flag + " args: " + argSplit, Grammar.class); + Arrays.stream(argSplit) + .forEach(arg -> Logger.logInfo(" :: Action has arg " + arg, Grammar.class)); switch (action) { case DELCHILD -> delChildMappings.put(leftside, Arrays.asList(argSplit)); @@ -270,7 +280,7 @@ public class Grammar { final GrammarRule rule = new GrammarRule(leftside, prod.split(" ")); rules.add(rule); - Logger.logInfo("Registered production " + rule, Grammar.class); + Logger.logInfo(" :: Registered production \"" + rule + "\"", Grammar.class); } } diff --git a/src/main/java/parser/grammar/GrammarAnalyzer.java b/src/main/java/parser/grammar/GrammarAnalyzer.java index 9d0fc52..a124445 100644 --- a/src/main/java/parser/grammar/GrammarAnalyzer.java +++ b/src/main/java/parser/grammar/GrammarAnalyzer.java @@ -83,6 +83,7 @@ public final class GrammarAnalyzer { for (String rightside : this.grammar.getRightsides(leftside)) { // ...and X -> Y1 Y2 ... Yk is a production... + if (!rightside.equals(Grammar.EPSILON_SYMBOL)) { // ...for some k >= 1... @@ -107,8 +108,9 @@ public final class GrammarAnalyzer { final boolean changeNow = firstOut.get(leftside).addAll(firstYiNoEps); change = change || changeNow; - Logger.logInfoIfTrue(changeNow, "First: Added " + firstYiNoEps + " to " - + leftside + " (All before are nullable)", GrammarAnalyzer.class); + Logger.logInfoIfTrue(changeNow, "Rule: \"" + leftside + " -> " + rightside + "\"", GrammarAnalyzer.class); + Logger.logInfoIfTrue(changeNow, " :: Added " + firstYiNoEps + " to \"first(" + + leftside + ")\" (All before are nullable)", GrammarAnalyzer.class); } if (i == split.length - 1 && allNullable.test(split)) { @@ -117,8 +119,9 @@ public final class GrammarAnalyzer { final boolean changeNow = firstOut.get(leftside).add(Grammar.EPSILON_SYMBOL); change = change || changeNow; - Logger.logInfoIfTrue(changeNow, "First: Added " + Grammar.EPSILON_SYMBOL + " to " - + leftside + " (All are nullable)", GrammarAnalyzer.class); + Logger.logInfoIfTrue(changeNow, "Rule: \"" + leftside + " -> " + rightside + "\"", GrammarAnalyzer.class); + Logger.logInfoIfTrue(changeNow, " :: Added [" + Grammar.EPSILON_SYMBOL + "] to \"first(" + + leftside + ")\" (All are nullable)", GrammarAnalyzer.class); } } } @@ -129,15 +132,16 @@ public final class GrammarAnalyzer { final boolean changeNow = firstOut.get(leftside).add(Grammar.EPSILON_SYMBOL); change = change || changeNow; - Logger.logInfoIfTrue(changeNow, "First: Added " + Grammar.EPSILON_SYMBOL + " to " - + leftside + " (X -> EPS exists)", GrammarAnalyzer.class); + Logger.logInfoIfTrue(changeNow, "Rule: \"" + leftside + " -> " + rightside + "\"", GrammarAnalyzer.class); + Logger.logInfoIfTrue(changeNow, " :: Added [" + Grammar.EPSILON_SYMBOL + "] to \"first(" + + leftside + ")\" (X -> EPS exists)", GrammarAnalyzer.class); } } } } while (change); - Logger.logDebug(" :: First-set initialized successfully", GrammarAnalyzer.class); Logger.logInfo("First Set: " + firstOut, GrammarAnalyzer.class); + Logger.logDebug(" :: First-set initialized successfully", GrammarAnalyzer.class); return firstOut; } @@ -192,8 +196,9 @@ public final class GrammarAnalyzer { final boolean changeNow = followOut.get(split[i - 1]).addAll(firstXkNoEps); change = change || changeNow; - Logger.logInfoIfTrue(changeNow, "Follow: Added " + firstXkNoEps + " to " - + split[i - 1] + " (Dazwischen nullable)", GrammarAnalyzer.class); + Logger.logInfoIfTrue(changeNow, "Rule: \"" + leftside + " -> " + rightside + "\"", GrammarAnalyzer.class); + Logger.logInfoIfTrue(changeNow, " :: Added " + firstXkNoEps + " to \"follow(" + + split[i - 1] + ")\" (All nullable inbetween)", GrammarAnalyzer.class); } } @@ -206,8 +211,9 @@ public final class GrammarAnalyzer { final boolean changeNow = followOut.get(split[i - 1]).addAll(followOut.get(leftside)); change = change || changeNow; - Logger.logInfoIfTrue(changeNow, "Follow: Added " + leftside + " to " - + split[i - 1] + " (Dahinter nullable)", GrammarAnalyzer.class); + Logger.logInfoIfTrue(changeNow, "Rule: \"" + leftside + " -> " + rightside + "\"", GrammarAnalyzer.class); + Logger.logInfoIfTrue(changeNow, " :: Added " + leftside + " to \"follow(" + + split[i - 1] + ")\" (All following are nullable)", GrammarAnalyzer.class); } } @@ -217,16 +223,17 @@ public final class GrammarAnalyzer { final boolean changeNow = followOut.get(split[split.length - 1]).addAll(followOut.get(leftside)); change = change || changeNow; - Logger.logInfoIfTrue(changeNow, "Follow: Added " + followOut.get(leftside) + " to " - + split[split.length - 1] + " (Ende der Regel)", GrammarAnalyzer.class); + Logger.logInfoIfTrue(changeNow, "Rule: \"" + leftside + " -> " + rightside + "\"", GrammarAnalyzer.class); + Logger.logInfoIfTrue(changeNow, " :: Added " + followOut.get(leftside) + " to \"follow(" + + split[split.length - 1] + ")\" (Last item in production)", GrammarAnalyzer.class); } } } } while (change); - Logger.logDebug(" :: Follow-set initialized successfully", GrammarAnalyzer.class); Logger.logInfo("Follow Set: " + followOut, GrammarAnalyzer.class); + Logger.logDebug(" :: Follow-set initialized successfully", GrammarAnalyzer.class); return followOut; } @@ -248,9 +255,10 @@ public final class GrammarAnalyzer { final String prev = tableOut.put(new AbstractMap.SimpleEntry<>(leftside, sym), rightside); - Logger.logInfo("Add " + rightside + " to cell (" + leftside + ", " + sym + ") (" + sym - + " in first of " + rightside + ")", GrammarAnalyzer.class); - Logger.logInfoNullable(prev, "Overwritten " + prev + "!\n", GrammarAnalyzer.class); + Logger.logInfo("Rule: \"" + leftside + " -> " + rightside + "\"", GrammarAnalyzer.class); + Logger.logInfo(" :: Add " + rightside + " to cell (" + leftside + ", " + sym + ") (" + sym + + " in \"first(" + rightside + ")\")", GrammarAnalyzer.class); + Logger.logInfoNullable(prev, " :: Overwritten " + prev + "!", GrammarAnalyzer.class); } final Set followLeftside = this.follow(leftside); @@ -263,9 +271,10 @@ public final class GrammarAnalyzer { final String prev = tableOut.put(new AbstractMap.SimpleEntry<>(leftside, sym), rightside); - Logger.logInfo("Add " + rightside + " to cell (" + leftside + ", " + sym + ") (" + sym - + " in follow of " + leftside + ")", GrammarAnalyzer.class); - Logger.logInfoNullable(prev, "Overwritten " + prev + "!\n", GrammarAnalyzer.class); + Logger.logInfo("Rule: \"" + leftside + " -> " + rightside + "\"", GrammarAnalyzer.class); + Logger.logInfo(" :: Add " + rightside + " to cell (" + leftside + ", " + sym + ") (" + sym + + " in \"follow(" + leftside + ")\")", GrammarAnalyzer.class); + Logger.logInfoNullable(prev, " :: Overwritten " + prev + "!", GrammarAnalyzer.class); } if (followLeftside.contains("$")) { @@ -273,10 +282,11 @@ public final class GrammarAnalyzer { final String prev = tableOut.put(new AbstractMap.SimpleEntry<>(leftside, "$"), rightside); - Logger.logInfo("Add " + rightside + " to cell (" + leftside - + ", $) (epsilon in first of " + rightside + " and $ in follow of " - + leftside + ")", GrammarAnalyzer.class); - Logger.logInfoNullable(prev, "Overwritten " + prev + "!\n", GrammarAnalyzer.class); + Logger.logInfo("Rule: \"" + leftside + " -> " + rightside + "\"", GrammarAnalyzer.class); + Logger.logInfo(" :: Add " + rightside + " to cell (" + leftside + + ", $) (epsilon in \"first(" + rightside + ")\" and $ in \"follow(" + + leftside + ")\")", GrammarAnalyzer.class); + Logger.logInfoNullable(prev, " :: Overwritten " + prev + "!", GrammarAnalyzer.class); } } } @@ -284,8 +294,8 @@ public final class GrammarAnalyzer { final ParsingTable parsingTable = new ParsingTable(this.grammar, tableOut); + Logger.logInfo("ParsingTable:\n" + parsingTable, GrammarAnalyzer.class); Logger.logDebug(" :: Parse-table initialized successfully", GrammarAnalyzer.class); - Logger.logInfo("ParsingTable: " + parsingTable, GrammarAnalyzer.class); return parsingTable; } diff --git a/src/main/java/typechecker/TypeChecker.java b/src/main/java/typechecker/TypeChecker.java index e4d892a..73ec4cc 100644 --- a/src/main/java/typechecker/TypeChecker.java +++ b/src/main/java/typechecker/TypeChecker.java @@ -42,7 +42,8 @@ public final class TypeChecker { final String literalType = getLiteralType(root.getName()); - Logger.logInfo("Type " + literalType + " for Node:\n" + root, TypeChecker.class); + Logger.logInfo("Register type \"" + literalType + "\" for node \"" + root.getName() + ": " + + root.getValue() + "\"", TypeChecker.class); nodeTable.put(root, literalType); return; @@ -51,7 +52,8 @@ public final class TypeChecker { final String exprType = table.getMethodReturnType(root.getValue()); - Logger.logInfo("Type " + exprType + " for Node:\n" + root, TypeChecker.class); + Logger.logInfo("Register type \"" + exprType + "\" for node \"" + root.getName() + "\"\n" + + root.nodePrint("\t\t"), TypeChecker.class); nodeTable.put(root, exprType); } else if ("par_expr".equals(root.getName())) { @@ -65,7 +67,8 @@ public final class TypeChecker { final String identifierType = table.getSymbolType(root.getValue()); - Logger.logInfo("Type " + identifierType + " for Node:\n" + root, TypeChecker.class); + Logger.logInfo("Register type \"" + identifierType + "\" for node \"" + root.getName() + ": " + + root.getValue() + "\"", TypeChecker.class); nodeTable.put(root, identifierType); } @@ -83,7 +86,7 @@ public final class TypeChecker { final SyntaxTreeNode literalNode = root.getChildren().get(0); final String literalType = nodeTable.get(literalNode); - Logger.logInfo("Validating Assignment: " + identifierType + ": " + identifier + " = " + literalType, TypeChecker.class); + Logger.logInfo("Validating assignment: \"" + identifier + "\" -> \"" + identifierType + "\" = \"" + literalType + "\"", TypeChecker.class); if (!literalType.equals(identifierType)) { Logger.logError("Line " + root.getLine() + " Typeerror: Can't assign [" + literalNode.getValue() @@ -96,7 +99,7 @@ public final class TypeChecker { private static void validateExpression(SyntaxTreeNode root, TypeTable table, Map nodeTable) { final String op = root.getValue(); - Logger.logInfo("Validating Expression: " + root.getValue(), TypeChecker.class); + Logger.logInfo("Validating expression: \"" + root.getValue() + "\"\n" + root.nodePrint("\t\t"), TypeChecker.class); if (root.isEmpty()) { // Keine Kinder diff --git a/src/main/java/typechecker/TypeTable.java b/src/main/java/typechecker/TypeTable.java index 25cd215..90f57d5 100644 --- a/src/main/java/typechecker/TypeTable.java +++ b/src/main/java/typechecker/TypeTable.java @@ -86,7 +86,7 @@ public final class TypeTable { if ("declaration".equals(root.getName())) { final SyntaxTreeNode child = root.getChildren().get(0); - Logger.logInfo("Adding Entry " + child.getValue() + " -> " + root.getValue(), TypeTable.class); + Logger.logInfo("Adding Entry: \"" + child.getValue() + "\" -> \"" + root.getValue() + "\"", TypeTable.class); final String oldEntry = table.put(child.getValue(), root.getValue()); if (oldEntry != null) { diff --git a/src/main/java/util/Logger.java b/src/main/java/util/Logger.java index da088c5..c21807c 100644 --- a/src/main/java/util/Logger.java +++ b/src/main/java/util/Logger.java @@ -8,7 +8,7 @@ public final class Logger { private static final boolean LOG_ENABLED = true; private static final boolean LOG_EXCEPTIONS = false; - private static final int LOG_LEVEL = 1; // 0 = ERROR, 1 = DEBUG, 2 = INFO + private static final int LOG_LEVEL = 2; // 0 = ERROR, 1 = DEBUG, 2 = INFO private static final Map packages; @@ -21,14 +21,15 @@ public final class Logger { Map.entry("codegen.analysis", true), Map.entry("codegen.analysis.dataflow", true), Map.entry("codegen.analysis.liveness", true), - Map.entry("codegen", false)); + Map.entry("codegen", true)); } private Logger() {} private static void log(String message, Class clazz) { if (LOG_ENABLED - && packages.containsKey(clazz.getPackageName()) && packages.get(clazz.getPackageName()).equals(true)) { + && (packages.containsKey(clazz.getPackageName()) && packages.get(clazz.getPackageName()).equals(true)) + || "StupsCompiler".equals(clazz.getName())) { System.out.printf("%-75s\t(%s)%n", message, clazz.getName()); } else if (LOG_ENABLED && !packages.containsKey(clazz.getPackageName())) {