overhaul logging
This commit is contained in:
@ -39,13 +39,13 @@ public final class StupsCompiler {
|
||||
}
|
||||
|
||||
private static void compile(String filename) {
|
||||
System.out.println("Beginning compilation.");
|
||||
final long begin = System.nanoTime();
|
||||
System.out.println("Kompiliere " + filename);
|
||||
// final long begin = System.nanoTime();
|
||||
|
||||
final FlowGraphGenerator gen = getFlowGraphGen(filename);
|
||||
final FlowGraph graph = gen.generateGraph();
|
||||
|
||||
Logger.call(graph::printToImage);
|
||||
Logger.logInfoSupplier(graph::printToImage, StupsCompiler.class);
|
||||
|
||||
// Codegeneration + Output
|
||||
final String fileExtension = filename.substring(filename.lastIndexOf('.') + 1);
|
||||
@ -68,8 +68,9 @@ public final class StupsCompiler {
|
||||
return;
|
||||
}
|
||||
|
||||
final long end = System.nanoTime();
|
||||
System.out.printf("%nCompilation completed in %dms.%n", (end - begin) / 1_000_000);
|
||||
System.out.println("Kompilieren abgeschlossen.");
|
||||
// final long end = System.nanoTime();
|
||||
// System.out.printf("%nCompilation completed in %dms.%n", (end - begin) / 1_000_000);
|
||||
}
|
||||
|
||||
private static void liveness(String filename) {
|
||||
@ -78,14 +79,17 @@ public final class StupsCompiler {
|
||||
final FlowGraphGenerator gen = getFlowGraphGen(filename);
|
||||
final FlowGraph graph = gen.generateGraph();
|
||||
|
||||
Logger.call(graph::printToImage);
|
||||
Logger.logInfoSupplier(graph::printToImage, StupsCompiler.class);
|
||||
|
||||
final DataFlowGraph dataFlowGraph = DataFlowGraph.fromFlowGraph(graph);
|
||||
|
||||
Logger.call(dataFlowGraph::printToImage);
|
||||
Logger.logInfoSupplier(dataFlowGraph::printToImage, StupsCompiler.class);
|
||||
|
||||
final LivenessAnalysis liveness = LivenessAnalysis.fromDataFlowGraph(dataFlowGraph, gen.getVarMap());
|
||||
liveness.doLivenessAnalysis();
|
||||
final int registers = liveness.doLivenessAnalysis();
|
||||
|
||||
System.out.println("Liveness-Analyse abgeschlossen.");
|
||||
System.out.println("Registers: " + registers);
|
||||
}
|
||||
|
||||
private static FlowGraphGenerator getFlowGraphGen(String filename) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package codegen.analysis;
|
||||
|
||||
import parser.ast.SyntaxTreeNode;
|
||||
import util.Logger;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
@ -37,6 +38,7 @@ public class StackModel {
|
||||
private void updateMax() {
|
||||
if (this.stack.size() > this.max) {
|
||||
this.max = this.stack.size();
|
||||
Logger.logInfo(" :: New maximum: " + this.max, StackModel.class);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,11 +2,10 @@ package codegen.analysis;
|
||||
|
||||
import parser.ast.SyntaxTree;
|
||||
import parser.ast.SyntaxTreeNode;
|
||||
import util.Logger;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static util.Logger.log;
|
||||
|
||||
/**
|
||||
* Ermittelt die maximal benötigte Stacktiefe für ein Programm.
|
||||
* Das Programm wird übergeben als {@link SyntaxTree}.
|
||||
@ -24,12 +23,13 @@ public final class StackSizeAnalyzer {
|
||||
private StackSizeAnalyzer() {}
|
||||
|
||||
public static int runStackModel(SyntaxTree tree) {
|
||||
log("\nDetermining required stack depth:");
|
||||
Logger.logDebug("Determining minimal stack-depth", StackSizeAnalyzer.class);
|
||||
|
||||
final StackModel stack = new StackModel();
|
||||
|
||||
runStackModel(tree.getRoot().getChildren().get(3).getChildren().get(11), stack);
|
||||
|
||||
Logger.logDebug("Found required stack-depth", StackSizeAnalyzer.class);
|
||||
return stack.getMax();
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import codegen.flowgraph.FlowBasicBlock;
|
||||
import codegen.flowgraph.FlowGraph;
|
||||
import codegen.flowgraph.FlowInstruction;
|
||||
import util.GraphvizCaller;
|
||||
import util.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -25,6 +26,8 @@ public final class DataFlowGraph implements Iterable<DataFlowNode> {
|
||||
}
|
||||
|
||||
public static DataFlowGraph fromFlowGraph(FlowGraph flowGraph) {
|
||||
Logger.logDebug("Beginning data-flow-graph generation", DataFlowGraph.class);
|
||||
|
||||
final List<DataFlowNode> dataFlowNodes = new ArrayList<>();
|
||||
|
||||
// Initialize all DataFlowNodes
|
||||
@ -37,6 +40,8 @@ public final class DataFlowGraph implements Iterable<DataFlowNode> {
|
||||
final DataFlowGraph dataFlowGraph = new DataFlowGraph(dataFlowNodes);
|
||||
initNodePosition(flowGraph, dataFlowGraph);
|
||||
|
||||
Logger.logDebug("Successfully generated data-flow-graph", DataFlowGraph.class);
|
||||
|
||||
return dataFlowGraph;
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,8 @@ public final class InterferenceGraph implements Iterable<InterferenceNode> {
|
||||
}
|
||||
|
||||
public static InterferenceGraph fromDataFlowGraph(DataFlowGraph dataFlowGraph, Map<String, Integer> varMap) {
|
||||
Logger.logDebug("Generating interference-graph", InterferenceGraph.class);
|
||||
|
||||
final List<InterferenceNode> interferenceNodes = new ArrayList<>();
|
||||
|
||||
// Init graph
|
||||
@ -41,13 +43,15 @@ public final class InterferenceGraph implements Iterable<InterferenceNode> {
|
||||
|
||||
if (leftNode.isPresent() && rightNode.isPresent()) {
|
||||
final boolean change = leftNode.get().addNeighbour(rightNode.get());
|
||||
Logger.logIfTrue(change, "Added interference neighbour: " + left + " -> " + right);
|
||||
Logger.logInfoIfTrue(change, "Added interference neighbour: " + left + " -> " + right, InterferenceGraph.class);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger.logDebug("Successfully generated interference-graph", InterferenceGraph.class);
|
||||
|
||||
return interferenceGraph;
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,8 @@ public final class LivenessAnalysis {
|
||||
}
|
||||
|
||||
private static void calculateLivenessInOut(DataFlowGraph dataFlowGraph) {
|
||||
Logger.logDebug("Calculating in/out-sets", LivenessAnalysis.class);
|
||||
|
||||
boolean change;
|
||||
|
||||
do {
|
||||
@ -45,6 +47,8 @@ public final class LivenessAnalysis {
|
||||
change = change || calculateLivenessInOutNode(node);
|
||||
}
|
||||
} while (change);
|
||||
|
||||
Logger.logDebug("Successfully calculated in/out-sets", LivenessAnalysis.class);
|
||||
}
|
||||
|
||||
private static boolean calculateLivenessInOutNode(DataFlowNode dataFlowNode) {
|
||||
@ -70,15 +74,11 @@ public final class LivenessAnalysis {
|
||||
* Die Registeranzahl wird durch naive Färbung des InterferenzGraphen ermittelt.
|
||||
*/
|
||||
public int doLivenessAnalysis() {
|
||||
final int registers = this.colorInterferenceGraph();
|
||||
|
||||
System.out.println("\nRegisters: " + registers);
|
||||
|
||||
return registers;
|
||||
return this.colorInterferenceGraph();
|
||||
}
|
||||
|
||||
private int colorInterferenceGraph() {
|
||||
Logger.log("Coloring Interference Graph\n");
|
||||
Logger.logDebug("Coloring interference-graph", LivenessAnalysis.class);
|
||||
|
||||
int colors = 0;
|
||||
int currentColor;
|
||||
@ -103,9 +103,11 @@ public final class LivenessAnalysis {
|
||||
if (currentColor > colors) {
|
||||
colors = currentColor;
|
||||
}
|
||||
|
||||
Logger.logDebug("Successfully colored interference-graph", LivenessAnalysis.class);
|
||||
}
|
||||
|
||||
Logger.call(this.interferenceGraph::printToImage);
|
||||
Logger.logInfoSupplier(this.interferenceGraph::printToImage, LivenessAnalysis.class);
|
||||
|
||||
return colors;
|
||||
}
|
||||
|
@ -48,10 +48,14 @@ public class FlowGraph implements Iterable<FlowBasicBlock> {
|
||||
* und zu Blöcken aus der {@link #predecessorMap} hergestellt.
|
||||
*/
|
||||
public void addLabel(String label) {
|
||||
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);
|
||||
|
||||
this.predecessorMap.get(label).addSuccessorBlock(newBlock);
|
||||
newBlock.addPredecessorBlock(this.predecessorMap.get(label));
|
||||
}
|
||||
@ -75,6 +79,8 @@ public class FlowGraph implements Iterable<FlowBasicBlock> {
|
||||
* @param jumpInstruction Der verwendete Sprungbefehl.
|
||||
*/
|
||||
public void addJump(String jumpInstruction, String label) {
|
||||
Logger.logInfo("Adding Jump to Label: " + label, FlowGraph.class);
|
||||
|
||||
this.addInstruction(jumpInstruction, label);
|
||||
|
||||
final FlowBasicBlock newBlock = new FlowBasicBlock();
|
||||
@ -105,6 +111,7 @@ public class FlowGraph implements Iterable<FlowBasicBlock> {
|
||||
// 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 -> this.predecessorMap.put(label, flowBasicBlock));
|
||||
}
|
||||
|
||||
@ -112,6 +119,8 @@ public class FlowGraph implements Iterable<FlowBasicBlock> {
|
||||
}
|
||||
|
||||
public void addInstruction(String instruction, String... args) {
|
||||
Logger.logInfo("Adding Instruction: " + instruction, FlowGraph.class);
|
||||
|
||||
if (this.basicBlocks.isEmpty()) {
|
||||
this.basicBlocks.add(new FlowBasicBlock("START")); // First block doesn't exist
|
||||
}
|
||||
@ -127,14 +136,14 @@ public class FlowGraph implements Iterable<FlowBasicBlock> {
|
||||
* Ein Block ist "leer", wenn er kein Label und keine Instructions hat.
|
||||
*/
|
||||
public void purgeEmptyBlocks() {
|
||||
Logger.log("\nPurging empty blocks: ");
|
||||
Logger.logDebug("Purging empty blocks", FlowGraph.class);
|
||||
|
||||
final Collection<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.");
|
||||
Logger.logInfo("Marking Block " + this.basicBlocks.indexOf(block) + " as removable.", FlowGraph.class);
|
||||
toRemove.add(block);
|
||||
}
|
||||
}
|
||||
@ -146,8 +155,8 @@ public class FlowGraph implements Iterable<FlowBasicBlock> {
|
||||
for (FlowBasicBlock predecessor : block.getBlockPredecessorSet()) {
|
||||
for (FlowBasicBlock successor : block.getBlockSuccessorSet()) {
|
||||
|
||||
Logger.log("Rerouting Block " + this.basicBlocks.indexOf(predecessor)
|
||||
+ " to Block " + this.basicBlocks.indexOf(successor));
|
||||
Logger.logInfo("Rerouting Block " + this.basicBlocks.indexOf(predecessor)
|
||||
+ " to Block " + this.basicBlocks.indexOf(successor), FlowGraph.class);
|
||||
predecessor.addSuccessorBlock(successor);
|
||||
successor.addPredecessorBlock(predecessor);
|
||||
}
|
||||
@ -164,6 +173,8 @@ public class FlowGraph implements Iterable<FlowBasicBlock> {
|
||||
}
|
||||
|
||||
this.basicBlocks.removeAll(toRemove);
|
||||
|
||||
Logger.logDebug("Successfully removed all empty blocks and rerouted graph", FlowGraph.class);
|
||||
}
|
||||
|
||||
private Optional<FlowBasicBlock> getBlockByLabel(String label) {
|
||||
@ -198,8 +209,6 @@ public class FlowGraph implements Iterable<FlowBasicBlock> {
|
||||
.append("node[shape=Mrecord]\n");
|
||||
|
||||
for (FlowBasicBlock block : this.basicBlocks) {
|
||||
System.out.println(block);
|
||||
System.out.println("-".repeat(100));
|
||||
dot.append(block.getId())
|
||||
.append(" [label=\"{<f0> ")
|
||||
.append(this.basicBlocks.indexOf(block))
|
||||
|
@ -5,6 +5,7 @@ import codegen.analysis.StackSizeAnalyzer;
|
||||
import parser.ast.SyntaxTree;
|
||||
import parser.ast.SyntaxTreeNode;
|
||||
import typechecker.TypeChecker;
|
||||
import util.Logger;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collections;
|
||||
@ -12,8 +13,6 @@ import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static util.Logger.log;
|
||||
|
||||
/**
|
||||
* Erzeugt den SourceCode in FlussGraph-Darstellung.
|
||||
*/
|
||||
@ -58,6 +57,8 @@ public final class FlowGraphGenerator {
|
||||
}
|
||||
|
||||
private static Map<String, Integer> initVarMap(SyntaxTree tree) {
|
||||
Logger.logDebug("Initializing variable-map", FlowGraphGenerator.class);
|
||||
|
||||
final Map<String, Integer> varMap = new HashMap<>();
|
||||
|
||||
final Deque<SyntaxTreeNode> stack = new ArrayDeque<>();
|
||||
@ -74,14 +75,16 @@ public final class FlowGraphGenerator {
|
||||
|
||||
currentVarNumber++;
|
||||
varMap.put(current.getChildren().get(0).getValue(), currentVarNumber);
|
||||
log("New local " + current.getValue() + " variable "
|
||||
+ current.getChildren().get(0).getValue()
|
||||
+ " assigned to slot " + currentVarNumber + ".");
|
||||
Logger.logInfo("New local " + current.getValue() + " variable "
|
||||
+ current.getChildren().get(0).getValue()
|
||||
+ " assigned to slot " + currentVarNumber + ".", FlowGraphGenerator.class);
|
||||
}
|
||||
|
||||
current.getChildren().forEach(stack::push);
|
||||
}
|
||||
|
||||
Logger.logDebug("Successfully initialized variable-map", FlowGraphGenerator.class);
|
||||
|
||||
return Collections.unmodifiableMap(varMap);
|
||||
}
|
||||
|
||||
@ -100,14 +103,14 @@ public final class FlowGraphGenerator {
|
||||
* Die Instruktionen sind unterteilt in BasicBlocks, welche über Kanten verbunden sind.
|
||||
*/
|
||||
public FlowGraph generateGraph() {
|
||||
System.out.println(" - Generating Source Graph...");
|
||||
Logger.logDebug("Beginning generation of source-graph", FlowGraphGenerator.class);
|
||||
|
||||
// Skip the first 2 identifiers: ClassName, MainArgs
|
||||
this.generateNode(this.tree.getRoot().getChildren().get(3).getChildren().get(11));
|
||||
this.graph.purgeEmptyBlocks();
|
||||
|
||||
log("\n\nSourceGraph print:\n" + "-".repeat(100) + "\n" + this.graph + "-".repeat(100));
|
||||
System.out.println("Graph-generation successful.");
|
||||
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;
|
||||
}
|
||||
@ -135,6 +138,8 @@ public final class FlowGraphGenerator {
|
||||
* Erzeugt den Teilbaum für einen If-Knoten.
|
||||
*/
|
||||
private void condNode(SyntaxTreeNode root) {
|
||||
Logger.logInfo("Generating Conditional Node", FlowGraphGenerator.class);
|
||||
|
||||
final int currentLabel = this.labelCounter;
|
||||
this.labelCounter++;
|
||||
|
||||
@ -164,6 +169,8 @@ public final class FlowGraphGenerator {
|
||||
* Erzeugt den Teilbaum für einen While-Knoten.
|
||||
*/
|
||||
private void loopNode(SyntaxTreeNode root) {
|
||||
Logger.logInfo("Generating Loop Node", FlowGraphGenerator.class);
|
||||
|
||||
final int currentLabel = this.labelCounter;
|
||||
this.labelCounter++;
|
||||
|
||||
@ -189,6 +196,8 @@ 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);
|
||||
|
||||
this.generateNode(root.getChildren().get(0));
|
||||
|
||||
final String type = this.nodeTypeMap.get(root.getChildren().get(0));
|
||||
@ -198,7 +207,7 @@ public final class FlowGraphGenerator {
|
||||
default -> throw new IllegalStateException("Unexpected value: " + type);
|
||||
};
|
||||
|
||||
log("assign(): " + root.getName() + ": " + root.getValue() + " => " + inst);
|
||||
Logger.logInfo("assign(): " + root.getName() + ": " + root.getValue() + " => " + inst, FlowGraphGenerator.class);
|
||||
|
||||
this.graph.addInstruction(inst, this.varMap.get(root.getValue()).toString());
|
||||
}
|
||||
@ -220,6 +229,8 @@ 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);
|
||||
|
||||
String inst = "";
|
||||
|
||||
if (root.getChildren().size() == 1) { //! Stack + 0
|
||||
@ -248,7 +259,7 @@ public final class FlowGraphGenerator {
|
||||
};
|
||||
}
|
||||
|
||||
log("intExpr(): " + root.getName() + ": " + root.getValue() + " => " + inst);
|
||||
Logger.logInfo("intExpr(): " + root.getName() + ": " + root.getValue() + " => " + inst, FlowGraphGenerator.class);
|
||||
|
||||
this.graph.addInstruction(inst);
|
||||
}
|
||||
@ -259,6 +270,8 @@ 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);
|
||||
|
||||
if (node.getChildren().size() == 1) { //! Stack + 1
|
||||
// Unary operator
|
||||
|
||||
@ -329,14 +342,14 @@ public final class FlowGraphGenerator {
|
||||
// Leafs
|
||||
|
||||
private void intStringLiteralNode(SyntaxTreeNode node) { //! Stack + 1
|
||||
log("intStringLiteral(): " + node.getName() + ": " + node.getValue() + " => ldc");
|
||||
Logger.logInfo("intStringLiteral(): " + 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
|
||||
log("booleanLiteral(): " + node.getName() + ": " + node.getValue() + " => ldc");
|
||||
Logger.logInfo("booleanLiteral(): " + node.getName() + ": " + node.getValue() + " => ldc", FlowGraphGenerator.class);
|
||||
|
||||
final String val = "true".equals(node.getValue()) ? "1" : "0";
|
||||
|
||||
@ -351,7 +364,7 @@ public final class FlowGraphGenerator {
|
||||
default -> throw new IllegalStateException("Unexpected value: " + type);
|
||||
};
|
||||
|
||||
log("identifier(): " + node.getName() + ": " + node.getValue() + " => " + inst);
|
||||
Logger.logInfo("identifier(): " + node.getName() + ": " + node.getValue() + " => " + inst, FlowGraphGenerator.class);
|
||||
|
||||
this.graph.addInstruction(inst, this.varMap.get(node.getValue()).toString());
|
||||
}
|
||||
@ -369,7 +382,7 @@ public final class FlowGraphGenerator {
|
||||
|
||||
this.generateNode(expr);
|
||||
|
||||
log("println(): " + expr.getName() + ": " + expr.getValue() + " => " + type);
|
||||
Logger.logInfo("println(): " + expr.getName() + ": " + expr.getValue() + " => " + type, FlowGraphGenerator.class);
|
||||
|
||||
this.graph.addInstruction("invokevirtual", "java/io/PrintStream/println(" + type + ")V");
|
||||
}
|
||||
|
@ -1,14 +1,13 @@
|
||||
package parser;
|
||||
|
||||
import parser.ast.SyntaxTree;
|
||||
|
||||
import static util.Logger.log;
|
||||
import util.Logger;
|
||||
|
||||
public class ParseException extends RuntimeException {
|
||||
|
||||
public ParseException(String message, SyntaxTree syntaxTree) {
|
||||
super("\n" + message);
|
||||
|
||||
log("\nAST at last state:\n" + syntaxTree);
|
||||
Logger.logException("\nAST at last state:\n" + syntaxTree, ParseException.class);
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import parser.ast.SyntaxTree;
|
||||
import parser.ast.SyntaxTreeNode;
|
||||
import parser.grammar.Grammar;
|
||||
import parser.grammar.GrammarAnalyzer;
|
||||
import util.Logger;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collection;
|
||||
@ -13,8 +14,9 @@ import java.util.Deque;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static util.Logger.log;
|
||||
|
||||
/**
|
||||
* Leitet eine Liste von Token nach einer Grammatik mit Hilfe einer {@link ParsingTable} ab.
|
||||
*/
|
||||
public class StupsParser {
|
||||
|
||||
private final ParsingTable parsetable;
|
||||
@ -28,17 +30,18 @@ public class StupsParser {
|
||||
return new StupsParser(analyzer.getTable());
|
||||
}
|
||||
|
||||
private static void printSourceLine(int line, Collection<? extends Token> token) {
|
||||
private static String printSourceLine(int line, Collection<? extends Token> token) {
|
||||
final Optional<String> srcLine = token.stream()
|
||||
.filter(tok -> tok.getLine() == line)
|
||||
.map(Token::getText)
|
||||
.reduce((s1, s2) -> s1 + " " + s2);
|
||||
|
||||
srcLine.ifPresent(s -> System.out.println(" :: " + s));
|
||||
return " :: " + srcLine.orElse("");
|
||||
}
|
||||
|
||||
public SyntaxTree parse(List<? extends Token> token, Vocabulary voc) {
|
||||
System.out.println(" - Parsing program...");
|
||||
Logger.logDebug("Beginning program-parsing", StupsParser.class);
|
||||
|
||||
final SyntaxTreeNode root = new SyntaxTreeNode(Grammar.START_SYMBOL, 0);
|
||||
final SyntaxTree tree = new SyntaxTree(root);
|
||||
final Deque<SyntaxTreeNode> stack = new ArrayDeque<>();
|
||||
@ -46,13 +49,14 @@ public class StupsParser {
|
||||
|
||||
int inputPosition = 0;
|
||||
|
||||
log("\nParsing:");
|
||||
log("Input: " + token + "\n");
|
||||
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);
|
||||
|
||||
final String currentTokenSym;
|
||||
int currentLine = 0;
|
||||
if (inputPosition >= token.size()) {
|
||||
@ -81,22 +85,23 @@ public class StupsParser {
|
||||
} else if (this.parsetable.getTerminals().contains(top)) {
|
||||
// Wenn das Terminal auf dem Stack nicht mit der aktuellen Eingabe übereinstimmt
|
||||
|
||||
System.out.println("\nLine " + currentLine + " Syntaxerror: Expected " + top + " but found " + currentTokenSym);
|
||||
StupsParser.printSourceLine(currentLine, token);
|
||||
Logger.logError("\nLine " + currentLine + " Syntaxerror: Expected " + top + " but found "
|
||||
+ currentTokenSym, StupsParser.class);
|
||||
Logger.logError(StupsParser.printSourceLine(currentLine, token), StupsParser.class);
|
||||
|
||||
throw new ParseException("Invalid terminal on stack: " + top, tree);
|
||||
} else if (prod == null) {
|
||||
// Wenn es für das aktuelle Terminal und das Nichtterminal auf dem Stack keine Regel gibt
|
||||
|
||||
System.out.println("\nLine " + currentLine + " Syntaxerror: Didn't expect " + currentTokenSym);
|
||||
StupsParser.printSourceLine(currentLine, token);
|
||||
Logger.logError("\nLine " + 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);
|
||||
} else {
|
||||
// Wenn das Nichtterminal auf dem Stack durch (s)eine Produktion ersetzt werden kann
|
||||
// Hier wird auch der AST aufgebaut
|
||||
|
||||
log("Used: " + top + " -> " + prod);
|
||||
Logger.logInfo("Used: " + top + " -> " + prod, StupsParser.class);
|
||||
final SyntaxTreeNode pop = stack.pop();
|
||||
|
||||
final String[] split = prod.split(" ");
|
||||
@ -120,10 +125,8 @@ public class StupsParser {
|
||||
}
|
||||
}
|
||||
|
||||
log("\nParsed AST:\n" + tree);
|
||||
log("-".repeat(100) + "\n");
|
||||
|
||||
System.out.println("Parsing successful.");
|
||||
Logger.logDebug("Successfully parsed the program and built the parse-tree", StupsParser.class);
|
||||
Logger.logInfo("\nParsed AST:\n" + tree, StupsParser.class);
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
@ -1,12 +1,11 @@
|
||||
package parser.ast;
|
||||
|
||||
import parser.grammar.Grammar;
|
||||
import util.Logger;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
import static util.Logger.log;
|
||||
|
||||
/**
|
||||
* Wendet in der Grammatik definierte Regeln auf einen Parsebaum an.
|
||||
* Dies ist der erste Schritt zum Abstrakten Syntaxbaum.
|
||||
@ -24,6 +23,8 @@ public final class ParseTreeCleaner {
|
||||
private ParseTreeCleaner() {}
|
||||
|
||||
public static void clean(SyntaxTree parseTree, Grammar grammar) {
|
||||
Logger.logDebug("Beginning cleaning of parse-tree", ParseTreeCleaner.class);
|
||||
|
||||
deleteChildren(parseTree, grammar);
|
||||
deleteIfEmpty(parseTree, grammar);
|
||||
promote(parseTree, grammar);
|
||||
@ -32,17 +33,17 @@ public final class ParseTreeCleaner {
|
||||
nameToValue(parseTree, grammar);
|
||||
valueToValue(parseTree, grammar);
|
||||
|
||||
log("\nCleaned Tree:\n" + parseTree);
|
||||
log("-".repeat(100));
|
||||
System.out.println(" - Compressing syntax-tree...");
|
||||
Logger.logDebug("Successfully cleaned the parse-tree", ParseTreeCleaner.class);
|
||||
Logger.logInfo("\nCleaned Tree:\n" + parseTree, ParseTreeCleaner.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Es werden Werte nach oben gereicht von [promote]-able Nodes.
|
||||
*/
|
||||
public static void promote(SyntaxTree parseTree, Grammar grammar) {
|
||||
log("\nPromoting nodes:");
|
||||
Logger.logDebug(" :: Beginning up-propagation of nodes", ParseTreeCleaner.class);
|
||||
promote(parseTree.getRoot(), grammar);
|
||||
Logger.logDebug(" :: Promoted nodes", ParseTreeCleaner.class);
|
||||
}
|
||||
|
||||
private static void promote(SyntaxTreeNode root, Grammar grammar) {
|
||||
@ -56,8 +57,8 @@ public final class ParseTreeCleaner {
|
||||
continue;
|
||||
}
|
||||
|
||||
log("Promoting " + child.getName() + " -> " + root.getName());
|
||||
log(root.toString());
|
||||
Logger.logInfo("Promoting " + child.getName() + " -> " + root.getName(), ParseTreeCleaner.class);
|
||||
Logger.logInfo(root.toString(), ParseTreeCleaner.class);
|
||||
|
||||
root.setName(child.getName());
|
||||
root.setValue(child.getValue());
|
||||
@ -74,8 +75,9 @@ public final class ParseTreeCleaner {
|
||||
* Löscht leere Knoten mit [delIfEmpty].
|
||||
*/
|
||||
public static void deleteIfEmpty(SyntaxTree parseTree, Grammar grammar) {
|
||||
log("\nDeleting empty nodes:");
|
||||
Logger.logDebug(" :: Beginning removal of empty nodes", ParseTreeCleaner.class);
|
||||
deleteIfEmpty(parseTree.getRoot(), grammar);
|
||||
Logger.logDebug(" :: Removed all empty nodes", ParseTreeCleaner.class);
|
||||
}
|
||||
|
||||
private static void deleteIfEmpty(SyntaxTreeNode root, Grammar grammar) {
|
||||
@ -88,7 +90,7 @@ public final class ParseTreeCleaner {
|
||||
continue;
|
||||
}
|
||||
|
||||
log("Removing " + child.getName());
|
||||
Logger.logInfo("Removing " + child.getName(), ParseTreeCleaner.class);
|
||||
|
||||
child.setValue("REMOVE"); // If both childs have the same identity both are removed, so change one
|
||||
toRemove.add(child);
|
||||
@ -101,8 +103,9 @@ public final class ParseTreeCleaner {
|
||||
* Löscht redundante Informationen in [delChildren]-Nodes (z.b. IF-child von COND) und Epsilon-Nodes.
|
||||
*/
|
||||
public static void deleteChildren(SyntaxTree parseTree, Grammar grammar) {
|
||||
log("Removing redundant children:");
|
||||
Logger.logDebug(" :: Beginning removal of redundant children", ParseTreeCleaner.class);
|
||||
deleteChildren(parseTree.getRoot(), grammar);
|
||||
Logger.logDebug(" :: Redundant children were removed", ParseTreeCleaner.class);
|
||||
}
|
||||
|
||||
private static void deleteChildren(SyntaxTreeNode root, Grammar grammar) {
|
||||
@ -115,7 +118,7 @@ public final class ParseTreeCleaner {
|
||||
continue;
|
||||
}
|
||||
|
||||
log("Removing " + root.getName() + " -> " + child.getName());
|
||||
Logger.logInfo("Removing " + root.getName() + " -> " + child.getName(), ParseTreeCleaner.class);
|
||||
|
||||
child.setValue("REMOVE"); // If both childs have the same identity both are removed, so change one
|
||||
toRemove.add(child);
|
||||
@ -128,8 +131,9 @@ public final class ParseTreeCleaner {
|
||||
* Führt Umbenennungen durch.
|
||||
*/
|
||||
private static void renameTo(SyntaxTree parseTree, Grammar grammar) {
|
||||
log("\nRenaming nodes:");
|
||||
Logger.logDebug(" :: Beginning renaming of nodes", ParseTreeCleaner.class);
|
||||
renameTo(parseTree.getRoot(), grammar);
|
||||
Logger.logDebug(" :: Renamed nodes", ParseTreeCleaner.class);
|
||||
}
|
||||
|
||||
private static void renameTo(SyntaxTreeNode root, Grammar grammar) {
|
||||
@ -140,7 +144,7 @@ public final class ParseTreeCleaner {
|
||||
continue;
|
||||
}
|
||||
|
||||
log("Rename " + root.getName() + " to " + grammar.getNewName(root) + ".");
|
||||
Logger.logInfo("Rename " + root.getName() + " to " + grammar.getNewName(root) + ".", ParseTreeCleaner.class);
|
||||
|
||||
root.setName(grammar.getNewName(root));
|
||||
}
|
||||
@ -150,8 +154,9 @@ public final class ParseTreeCleaner {
|
||||
* Verschiebt Knotennamen von [nametoval]-Nodes in Parent-Values und löscht das Child.
|
||||
*/
|
||||
public static void nameToValue(SyntaxTree parseTree, Grammar grammar) {
|
||||
log("\nMoving names to values:");
|
||||
Logger.logDebug(" :: Beginning up-propagation of node-names", ParseTreeCleaner.class);
|
||||
nameToValue(parseTree.getRoot(), grammar);
|
||||
Logger.logDebug(" :: Moved node-names to parent-values", ParseTreeCleaner.class);
|
||||
}
|
||||
|
||||
private static void nameToValue(SyntaxTreeNode root, Grammar grammar) {
|
||||
@ -164,8 +169,8 @@ public final class ParseTreeCleaner {
|
||||
continue;
|
||||
}
|
||||
|
||||
log("Moving " + child.getName() + " to value of " + root.getName());
|
||||
log(root.toString());
|
||||
Logger.logInfo("Moving " + child.getName() + " to value of " + root.getName(), ParseTreeCleaner.class);
|
||||
Logger.logInfo(root.toString(), ParseTreeCleaner.class);
|
||||
|
||||
root.setValue(child.getName());
|
||||
|
||||
@ -182,8 +187,9 @@ public final class ParseTreeCleaner {
|
||||
* Variablennamen als Wert anstatt als Child-Node.
|
||||
*/
|
||||
public static void valueToValue(SyntaxTree parseTree, Grammar grammar) {
|
||||
log("\nMoving values to values:");
|
||||
Logger.logDebug(" :: Beginning up-propagation of node-values", ParseTreeCleaner.class);
|
||||
valueToValue(parseTree.getRoot(), grammar);
|
||||
Logger.logDebug(" :: Moved node-values to parent-values", ParseTreeCleaner.class);
|
||||
}
|
||||
|
||||
private static void valueToValue(SyntaxTreeNode root, Grammar grammar) {
|
||||
@ -200,8 +206,8 @@ 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
|
||||
|
||||
log("Moving " + root.getChildren().get(1).getValue() + " to value of " + root.getName());
|
||||
log(root.toString());
|
||||
Logger.logInfo("Moving " + root.getChildren().get(1).getValue() + " to value of " + root.getName(), ParseTreeCleaner.class);
|
||||
Logger.logInfo(root.toString(), ParseTreeCleaner.class);
|
||||
|
||||
root.setValue(root.getChildren().get(1).getValue());
|
||||
|
||||
@ -211,8 +217,8 @@ public final class ParseTreeCleaner {
|
||||
} else {
|
||||
// Usual case where an expression is assigned
|
||||
|
||||
log("Moving " + child.getValue() + " to value of " + root.getName());
|
||||
log(root.toString());
|
||||
Logger.logInfo("Moving " + child.getValue() + " to value of " + root.getName(), ParseTreeCleaner.class);
|
||||
Logger.logInfo(root.toString(), ParseTreeCleaner.class);
|
||||
|
||||
root.setValue(child.getValue());
|
||||
toRemove.add(child);
|
||||
|
@ -25,7 +25,6 @@ public class SyntaxTree {
|
||||
|
||||
ParseTreeCleaner.clean(abstractSyntaxTree, grammar);
|
||||
SyntaxTreeRebalancer.rebalance(abstractSyntaxTree);
|
||||
System.out.println("Tree processing successful.");
|
||||
|
||||
return abstractSyntaxTree;
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
package parser.ast;
|
||||
|
||||
import util.Logger;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static util.Logger.log;
|
||||
|
||||
/**
|
||||
* Ein SyntaxTree wird an bestimmten Stellen rotiert, sodass bestimmte Eigenschaften
|
||||
* korrekt repräsentiert werden (Operatorpräzedenz, Linkassoziativität etc.).
|
||||
@ -62,23 +62,24 @@ public final class SyntaxTreeRebalancer {
|
||||
* </ul>
|
||||
*/
|
||||
public static void rebalance(SyntaxTree abstractSyntaxTree) {
|
||||
Logger.logDebug("Beginning rebalancing of syntax-tree", SyntaxTreeRebalancer.class);
|
||||
|
||||
flip(abstractSyntaxTree);
|
||||
leftPrecedence(abstractSyntaxTree);
|
||||
operatorPrecedence(abstractSyntaxTree);
|
||||
flipCommutativeExpr(abstractSyntaxTree);
|
||||
|
||||
log(abstractSyntaxTree.toString());
|
||||
log("-".repeat(100));
|
||||
|
||||
System.out.println(" - Balancing syntax-tree...");
|
||||
Logger.logDebug("Successfully rebalanced syntax-tree", SyntaxTreeRebalancer.class);
|
||||
Logger.logInfo("AST after rebalancing:" + abstractSyntaxTree, SyntaxTreeRebalancer.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Baum spiegeln, damit höhere Ebenen links sind und EXPR vorwärts laufen.
|
||||
*/
|
||||
public static void flip(SyntaxTree abstractSyntaxTree) {
|
||||
log("Flipping tree for ltr evaluation");
|
||||
Logger.logDebug(" :: Flipping tree for ltr evaluation", SyntaxTreeRebalancer.class);
|
||||
flip(abstractSyntaxTree.getRoot());
|
||||
Logger.logDebug(" :: Successfully flipped tree", SyntaxTreeRebalancer.class);
|
||||
}
|
||||
|
||||
private static void flip(SyntaxTreeNode root) {
|
||||
@ -93,8 +94,9 @@ public final class SyntaxTreeRebalancer {
|
||||
* Kommutative Ausdrücke werden gespiegelt, damit die tiefen Teilexpressions zuerst berechnet werden.
|
||||
*/
|
||||
public static void flipCommutativeExpr(SyntaxTree abstractSyntaxTree) {
|
||||
log("Flipping commutative expressions for stack efficiency");
|
||||
Logger.logDebug(" :: Flipping commutative expressions for stack efficiency", SyntaxTreeRebalancer.class);
|
||||
flipCommutativeExpr(abstractSyntaxTree.getRoot());
|
||||
Logger.logDebug(" :: Succesfully optimized stack efficiency", SyntaxTreeRebalancer.class);
|
||||
}
|
||||
|
||||
private static void flipCommutativeExpr(SyntaxTreeNode root) {
|
||||
@ -108,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
|
||||
|
||||
log("Flipping " + root.getName() + ": " + root.getValue() + " for stack efficiency.");
|
||||
log(root.toString());
|
||||
Logger.logInfo("Flipping " + root.getName() + ": " + root.getValue() + " for stack efficiency.", SyntaxTreeRebalancer.class);
|
||||
Logger.logInfo(root.toString(), SyntaxTreeRebalancer.class);
|
||||
|
||||
Collections.reverse(root.getChildren());
|
||||
}
|
||||
@ -121,8 +123,9 @@ public final class SyntaxTreeRebalancer {
|
||||
* Es werden EXPR-Nodes (2 Childs, 1 davon EXPR, Kein Wert) solange wie möglich linksrotiert.
|
||||
*/
|
||||
public static void leftPrecedence(SyntaxTree abstractSyntaxTree) {
|
||||
log("Left-rotating expressions for left-precedence");
|
||||
Logger.logDebug(" :: Left-rotating expressions for left-precedence", SyntaxTreeRebalancer.class);
|
||||
leftPrecedence(abstractSyntaxTree.getRoot());
|
||||
Logger.logDebug(" :: Successfully rotated expressions for left-precedence", SyntaxTreeRebalancer.class);
|
||||
}
|
||||
|
||||
private static void leftPrecedence(SyntaxTreeNode root) {
|
||||
@ -150,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) {
|
||||
log("Special-Left-Rotation around " + root.getName());
|
||||
log(root.toString());
|
||||
Logger.logInfo("Special-Left-Rotation around " + root.getName(), SyntaxTreeRebalancer.class);
|
||||
Logger.logInfo(root.toString(), SyntaxTreeRebalancer.class);
|
||||
|
||||
final SyntaxTreeNode left = root.getChildren().get(0);
|
||||
final SyntaxTreeNode right = root.getChildren().get(1);
|
||||
@ -195,13 +198,15 @@ public final class SyntaxTreeRebalancer {
|
||||
* als die Operatoren mit niedriger Priorität.
|
||||
*/
|
||||
public static void operatorPrecedence(SyntaxTree abstractSyntaxTree) {
|
||||
log("Right-rotating expressions for operator-precedence");
|
||||
Logger.logDebug(" :: Right-rotating expressions for operator-precedence", SyntaxTreeRebalancer.class);
|
||||
|
||||
boolean changed;
|
||||
|
||||
do {
|
||||
changed = operatorPrecedence(abstractSyntaxTree.getRoot());
|
||||
} while (changed);
|
||||
|
||||
Logger.logDebug(" :: Rotated expressions for operator-precedence", SyntaxTreeRebalancer.class);
|
||||
}
|
||||
|
||||
public static boolean operatorPrecedence(SyntaxTreeNode root) {
|
||||
@ -240,8 +245,8 @@ public final class SyntaxTreeRebalancer {
|
||||
}
|
||||
|
||||
private static void simpleRightRotate(SyntaxTreeNode root) {
|
||||
log("Right-Rotation around " + root.getName() + ": " + root.getValue());
|
||||
log(root.toString());
|
||||
Logger.logInfo("Right-Rotation around " + root.getName() + ": " + root.getValue(), SyntaxTreeRebalancer.class);
|
||||
Logger.logInfo(root.toString(), SyntaxTreeRebalancer.class);
|
||||
|
||||
final SyntaxTreeNode left = root.getChildren().get(0);
|
||||
final SyntaxTreeNode right = root.getChildren().get(1);
|
||||
|
@ -1,6 +1,7 @@
|
||||
package parser.grammar;
|
||||
|
||||
import parser.ast.SyntaxTreeNode;
|
||||
import util.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
@ -22,7 +23,6 @@ import static parser.grammar.GrammarAction.NAMETOVAL;
|
||||
import static parser.grammar.GrammarAction.PROMOTE;
|
||||
import static parser.grammar.GrammarAction.RENAMETO;
|
||||
import static parser.grammar.GrammarAction.VALTOVAL;
|
||||
import static util.Logger.log;
|
||||
|
||||
/**
|
||||
* Repräsentiert die Parse-Grammatik und die Kontextaktionen.
|
||||
@ -90,7 +90,6 @@ public class Grammar {
|
||||
}
|
||||
|
||||
public static Grammar fromFile(Path path) throws IOException {
|
||||
System.out.println(" - Reading parser-grammar...");
|
||||
List<String> lines = Files.readAllLines(path);
|
||||
|
||||
// Remove Whitespace + Comments
|
||||
@ -116,10 +115,10 @@ public class Grammar {
|
||||
actionMap.put(action, new HashSet<>());
|
||||
}
|
||||
|
||||
log("Parsing Grammar from File:");
|
||||
Logger.logDebug("Beginning grammar parsing", Grammar.class);
|
||||
for (String currentLine : lines) {
|
||||
|
||||
log("Parsed: " + currentLine);
|
||||
Logger.logInfo("Parsed: " + currentLine, Grammar.class);
|
||||
|
||||
// Parse Keywords
|
||||
if (currentLine.startsWith("TERM:")) {
|
||||
@ -137,9 +136,8 @@ public class Grammar {
|
||||
}
|
||||
}
|
||||
|
||||
log("\n" + actionMap);
|
||||
log("-".repeat(100));
|
||||
System.out.println("Grammar parsed successfully.");
|
||||
Logger.logInfo("Registered actions: " + actionMap, Grammar.class);
|
||||
Logger.logDebug("Grammar parsed successfully", Grammar.class);
|
||||
|
||||
return new Grammar(terminals, nonterminals,
|
||||
actionMap, renameMappings, nameToValMappings,
|
||||
@ -172,6 +170,8 @@ public class Grammar {
|
||||
|
||||
final Set<String> actionSet = parseActionSet(leftside, open, close);
|
||||
|
||||
Logger.logInfo("Current Line " + currentLine + " has Actions: " + actionSet, Grammar.class);
|
||||
|
||||
// Validate Actions
|
||||
throwOnInvalidActionSet(actionSet);
|
||||
|
||||
@ -214,7 +214,7 @@ public class Grammar {
|
||||
final String[] flagSplit = flag.split("=");
|
||||
final GrammarAction action = GrammarAction.valueOf(flagSplit[0].toUpperCase());
|
||||
|
||||
registerRegularAction(action, leftside, flag, actions);
|
||||
registerAction(action, leftside, flag, actions);
|
||||
|
||||
if (flagSplit.length > 1) {
|
||||
|
||||
@ -226,11 +226,11 @@ public class Grammar {
|
||||
/**
|
||||
* Es wird ein Eintrag in der action-Map mit der entsprechenden leftside hinzugefügt.
|
||||
*/
|
||||
private static void registerRegularAction(GrammarAction action, String leftside, String flag,
|
||||
Map<GrammarAction, Set<String>> actions) {
|
||||
private static void registerAction(GrammarAction action, String leftside, String flag,
|
||||
Map<GrammarAction, Set<String>> actions) {
|
||||
|
||||
actions.get(action).add(leftside.trim());
|
||||
log("Registered " + flag + ": " + leftside.trim());
|
||||
Logger.logInfo("Registered " + flag + ": " + leftside.trim(), Grammar.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -246,6 +246,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);
|
||||
|
||||
switch (action) {
|
||||
case DELCHILD -> delChildMappings.put(leftside, Arrays.asList(argSplit));
|
||||
case VALTOVAL -> valToValMappings.put(leftside, Arrays.asList(argSplit));
|
||||
@ -267,6 +269,8 @@ public class Grammar {
|
||||
for (String prod : prods) {
|
||||
final GrammarRule rule = new GrammarRule(leftside, prod.split(" "));
|
||||
rules.add(rule);
|
||||
|
||||
Logger.logInfo("Registered production " + rule, Grammar.class);
|
||||
}
|
||||
}
|
||||
|
||||
@ -277,6 +281,8 @@ public class Grammar {
|
||||
|
||||
for (String flag : flagSet) {
|
||||
if (!actionSet.contains(flag.split("=")[0].toUpperCase())) {
|
||||
|
||||
Logger.logError("Action " + flag.split("=")[0] + " is invalid.", Grammar.class);
|
||||
throw new GrammarParseException("Invalid Action: " + flag);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package parser.grammar;
|
||||
|
||||
import parser.ParsingTable;
|
||||
import util.Logger;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Arrays;
|
||||
@ -12,10 +13,6 @@ import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static util.Logger.log;
|
||||
import static util.Logger.logIfTrue;
|
||||
import static util.Logger.logNullable;
|
||||
|
||||
public final class GrammarAnalyzer {
|
||||
|
||||
private final Grammar grammar;
|
||||
@ -37,17 +34,14 @@ public final class GrammarAnalyzer {
|
||||
private GrammarAnalyzer(Grammar grammar) {
|
||||
this.grammar = grammar;
|
||||
|
||||
log("Analyzing Grammar:\n");
|
||||
Logger.logDebug("Beginning grammar analysis", GrammarAnalyzer.class);
|
||||
|
||||
// Es muss zwingend in der Reihenfolge [Nullable < First < Follow < Table] initialisiert werden
|
||||
System.out.println(" - Initializing first-set...");
|
||||
// Es muss zwingend in der Reihenfolge [First < Follow < Table] initialisiert werden
|
||||
this.first = this.initFirst();
|
||||
System.out.println(" - Initializing follow-set...");
|
||||
this.follow = this.initFollow();
|
||||
System.out.println(" - Initializing parse-table...");
|
||||
this.table = this.initParseTable();
|
||||
|
||||
System.out.println("Grammar analysis successful.");
|
||||
Logger.logDebug("Grammar analysis successful", GrammarAnalyzer.class);
|
||||
}
|
||||
|
||||
public static GrammarAnalyzer fromGrammar(Grammar grammar) {
|
||||
@ -55,6 +49,8 @@ public final class GrammarAnalyzer {
|
||||
}
|
||||
|
||||
private Map<String, Set<String>> initFirst() {
|
||||
Logger.logDebug(" :: Initializing first-set", GrammarAnalyzer.class);
|
||||
|
||||
final Map<String, Set<String>> firstOut = new HashMap<>();
|
||||
|
||||
// Die Methode funktioniert erst, nachdem first initialisiert ist.
|
||||
@ -65,8 +61,6 @@ public final class GrammarAnalyzer {
|
||||
final Predicate<String[]> allNullable = split -> split.length == 0
|
||||
|| Arrays.stream(split).allMatch(nullable);
|
||||
|
||||
log("First Initialisieren:");
|
||||
|
||||
// Initialisieren
|
||||
for (String nterm : this.grammar.getNonterminals()) {
|
||||
firstOut.put(nterm, new HashSet<>());
|
||||
@ -113,7 +107,8 @@ public final class GrammarAnalyzer {
|
||||
final boolean changeNow = firstOut.get(leftside).addAll(firstYiNoEps);
|
||||
change = change || changeNow;
|
||||
|
||||
logIfTrue(changeNow, "First: Added " + firstYiNoEps + " to " + leftside + " (All before are nullable)");
|
||||
Logger.logInfoIfTrue(changeNow, "First: Added " + firstYiNoEps + " to "
|
||||
+ leftside + " (All before are nullable)", GrammarAnalyzer.class);
|
||||
}
|
||||
|
||||
if (i == split.length - 1 && allNullable.test(split)) {
|
||||
@ -122,7 +117,8 @@ public final class GrammarAnalyzer {
|
||||
final boolean changeNow = firstOut.get(leftside).add(Grammar.EPSILON_SYMBOL);
|
||||
change = change || changeNow;
|
||||
|
||||
logIfTrue(changeNow, "First: Added " + Grammar.EPSILON_SYMBOL + " to " + leftside + " (All are nullable)");
|
||||
Logger.logInfoIfTrue(changeNow, "First: Added " + Grammar.EPSILON_SYMBOL + " to "
|
||||
+ leftside + " (All are nullable)", GrammarAnalyzer.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -133,22 +129,23 @@ public final class GrammarAnalyzer {
|
||||
final boolean changeNow = firstOut.get(leftside).add(Grammar.EPSILON_SYMBOL);
|
||||
change = change || changeNow;
|
||||
|
||||
logIfTrue(changeNow, "First: Added " + Grammar.EPSILON_SYMBOL + " to " + leftside + " (X -> EPS exists)");
|
||||
Logger.logInfoIfTrue(changeNow, "First: Added " + Grammar.EPSILON_SYMBOL + " to "
|
||||
+ leftside + " (X -> EPS exists)", GrammarAnalyzer.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (change);
|
||||
|
||||
log("\n" + firstOut);
|
||||
log("-".repeat(100) + "\n");
|
||||
Logger.logDebug(" :: First-set initialized successfully", GrammarAnalyzer.class);
|
||||
Logger.logInfo("First Set: " + firstOut, GrammarAnalyzer.class);
|
||||
|
||||
return firstOut;
|
||||
}
|
||||
|
||||
private Map<String, Set<String>> initFollow() {
|
||||
final Map<String, Set<String>> followOut = new HashMap<>();
|
||||
Logger.logDebug(" :: Initializing follow-set", GrammarAnalyzer.class);
|
||||
|
||||
log("Follow Initialisieren:");
|
||||
final Map<String, Set<String>> followOut = new HashMap<>();
|
||||
|
||||
// Initialisieren
|
||||
for (String nterm : this.grammar.getNonterminals()) {
|
||||
@ -195,7 +192,8 @@ public final class GrammarAnalyzer {
|
||||
final boolean changeNow = followOut.get(split[i - 1]).addAll(firstXkNoEps);
|
||||
change = change || changeNow;
|
||||
|
||||
logIfTrue(changeNow, "Follow: Added " + firstXkNoEps + " to " + split[i - 1] + " (Dazwischen nullable)");
|
||||
Logger.logInfoIfTrue(changeNow, "Follow: Added " + firstXkNoEps + " to "
|
||||
+ split[i - 1] + " (Dazwischen nullable)", GrammarAnalyzer.class);
|
||||
}
|
||||
}
|
||||
|
||||
@ -208,7 +206,8 @@ public final class GrammarAnalyzer {
|
||||
final boolean changeNow = followOut.get(split[i - 1]).addAll(followOut.get(leftside));
|
||||
change = change || changeNow;
|
||||
|
||||
logIfTrue(changeNow, "Follow: Added " + leftside + " to " + split[i - 1] + " (Dahinter nullable)");
|
||||
Logger.logInfoIfTrue(changeNow, "Follow: Added " + leftside + " to "
|
||||
+ split[i - 1] + " (Dahinter nullable)", GrammarAnalyzer.class);
|
||||
}
|
||||
}
|
||||
|
||||
@ -218,23 +217,24 @@ public final class GrammarAnalyzer {
|
||||
final boolean changeNow = followOut.get(split[split.length - 1]).addAll(followOut.get(leftside));
|
||||
change = change || changeNow;
|
||||
|
||||
logIfTrue(changeNow, "Follow: Added " + followOut.get(leftside) + " to " + split[split.length - 1] + " (Ende der Regel)");
|
||||
Logger.logInfoIfTrue(changeNow, "Follow: Added " + followOut.get(leftside) + " to "
|
||||
+ split[split.length - 1] + " (Ende der Regel)", GrammarAnalyzer.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} while (change);
|
||||
|
||||
log("\n" + followOut);
|
||||
log("-".repeat(100) + "\n");
|
||||
Logger.logDebug(" :: Follow-set initialized successfully", GrammarAnalyzer.class);
|
||||
Logger.logInfo("Follow Set: " + followOut, GrammarAnalyzer.class);
|
||||
|
||||
return followOut;
|
||||
}
|
||||
|
||||
private ParsingTable initParseTable() {
|
||||
final Map<Map.Entry<String, String>, String> tableOut = new HashMap<>();
|
||||
Logger.logDebug(" :: Initializing parse-table", GrammarAnalyzer.class);
|
||||
|
||||
log("Parsetable Aufstellen:");
|
||||
final Map<Map.Entry<String, String>, String> tableOut = new HashMap<>();
|
||||
|
||||
for (String leftside : this.grammar.getLeftSides()) {
|
||||
|
||||
@ -248,8 +248,9 @@ public final class GrammarAnalyzer {
|
||||
|
||||
final String prev = tableOut.put(new AbstractMap.SimpleEntry<>(leftside, sym), rightside);
|
||||
|
||||
log("Add " + rightside + " to cell (" + leftside + ", " + sym + ") (" + sym + " in first of " + rightside + ")");
|
||||
logNullable("Overwritten " + prev + "!\n", prev);
|
||||
Logger.logInfo("Add " + rightside + " to cell (" + leftside + ", " + sym + ") (" + sym
|
||||
+ " in first of " + rightside + ")", GrammarAnalyzer.class);
|
||||
Logger.logInfoNullable(prev, "Overwritten " + prev + "!\n", GrammarAnalyzer.class);
|
||||
}
|
||||
|
||||
final Set<String> followLeftside = this.follow(leftside);
|
||||
@ -262,8 +263,9 @@ public final class GrammarAnalyzer {
|
||||
|
||||
final String prev = tableOut.put(new AbstractMap.SimpleEntry<>(leftside, sym), rightside);
|
||||
|
||||
log("Add " + rightside + " to cell (" + leftside + ", " + sym + ") (" + sym + " in follow of " + leftside + ")");
|
||||
logNullable("Overwritten " + prev + "!\n", prev);
|
||||
Logger.logInfo("Add " + rightside + " to cell (" + leftside + ", " + sym + ") (" + sym
|
||||
+ " in follow of " + leftside + ")", GrammarAnalyzer.class);
|
||||
Logger.logInfoNullable(prev, "Overwritten " + prev + "!\n", GrammarAnalyzer.class);
|
||||
}
|
||||
|
||||
if (followLeftside.contains("$")) {
|
||||
@ -271,19 +273,21 @@ public final class GrammarAnalyzer {
|
||||
|
||||
final String prev = tableOut.put(new AbstractMap.SimpleEntry<>(leftside, "$"), rightside);
|
||||
|
||||
log("Add " + rightside + " to cell (" + leftside + ", $) (epsilon in first of " + rightside + " and $ in follow of " + leftside + ")");
|
||||
logNullable("Overwritten " + prev + "!\n", prev);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final ParsingTable table = new ParsingTable(this.grammar, tableOut);
|
||||
final ParsingTable parsingTable = new ParsingTable(this.grammar, tableOut);
|
||||
|
||||
log("\n" + table);
|
||||
log("-".repeat(100) + "\n");
|
||||
Logger.logDebug(" :: Parse-table initialized successfully", GrammarAnalyzer.class);
|
||||
Logger.logInfo("ParsingTable: " + parsingTable, GrammarAnalyzer.class);
|
||||
|
||||
return table;
|
||||
return parsingTable;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,8 +1,12 @@
|
||||
package parser.grammar;
|
||||
|
||||
import util.Logger;
|
||||
|
||||
public class GrammarParseException extends RuntimeException {
|
||||
|
||||
public GrammarParseException(String message) {
|
||||
super(message);
|
||||
|
||||
Logger.logException(message, GrammarParseException.class);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package typechecker;
|
||||
|
||||
import parser.ast.SyntaxTree;
|
||||
import parser.ast.SyntaxTreeNode;
|
||||
import util.Logger;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@ -9,8 +10,6 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static util.Logger.log;
|
||||
|
||||
public final class TypeChecker {
|
||||
|
||||
private static final Collection<String> lit = Arrays.asList("INTEGER_LIT", "STRING_LIT", "BOOLEAN_LIT");
|
||||
@ -19,18 +18,17 @@ public final class TypeChecker {
|
||||
private TypeChecker() {}
|
||||
|
||||
// TODO: merge nodeTable into typetable?
|
||||
// Wirft exception bei typeerror, return nodeTable?
|
||||
// Wirft exception bei typeerror
|
||||
public static Map<SyntaxTreeNode, String> validate(SyntaxTree tree) {
|
||||
final TypeTable table = TypeTable.fromAST(tree);
|
||||
final Map<SyntaxTreeNode, String> nodeTable = new HashMap<>();
|
||||
|
||||
System.out.println(" - Validating syntax-tree...");
|
||||
Logger.logDebug("Beginning typevalidation of abstract-syntax-tree", TypeChecker.class);
|
||||
|
||||
log("Typevalidation:");
|
||||
validate(tree.getRoot(), table, nodeTable);
|
||||
log("-".repeat(100));
|
||||
|
||||
System.out.println("Typechecking successful.");
|
||||
Logger.logDebug("Successfully typevalidated the abstract-syntax-tree", TypeChecker.class);
|
||||
|
||||
return nodeTable;
|
||||
}
|
||||
|
||||
@ -44,6 +42,8 @@ public final class TypeChecker {
|
||||
|
||||
final String literalType = getLiteralType(root.getName());
|
||||
|
||||
Logger.logInfo("Type " + literalType + " for Node:\n" + root, TypeChecker.class);
|
||||
|
||||
nodeTable.put(root, literalType);
|
||||
return;
|
||||
} else if ("expr".equals(root.getName())) {
|
||||
@ -51,6 +51,8 @@ public final class TypeChecker {
|
||||
|
||||
final String exprType = table.getMethodReturnType(root.getValue());
|
||||
|
||||
Logger.logInfo("Type " + exprType + " for Node:\n" + root, TypeChecker.class);
|
||||
|
||||
nodeTable.put(root, exprType);
|
||||
} else if ("par_expr".equals(root.getName())) {
|
||||
// Nodetable Eintrag für Klammern
|
||||
@ -63,6 +65,8 @@ public final class TypeChecker {
|
||||
|
||||
final String identifierType = table.getSymbolType(root.getValue());
|
||||
|
||||
Logger.logInfo("Type " + identifierType + " for Node:\n" + root, TypeChecker.class);
|
||||
|
||||
nodeTable.put(root, identifierType);
|
||||
}
|
||||
|
||||
@ -79,10 +83,11 @@ public final class TypeChecker {
|
||||
final SyntaxTreeNode literalNode = root.getChildren().get(0);
|
||||
final String literalType = nodeTable.get(literalNode);
|
||||
|
||||
log("Validating Assignment: " + identifierType + ": " + identifier + " = " + literalType);
|
||||
Logger.logInfo("Validating Assignment: " + identifierType + ": " + identifier + " = " + literalType, TypeChecker.class);
|
||||
|
||||
if (!literalType.equals(identifierType)) {
|
||||
System.out.println("Line " + root.getLine() + " Typeerror: Can't assign [" + literalNode.getValue() + "] to [" + identifier + "]: " + identifierType);
|
||||
Logger.logError("Line " + root.getLine() + " Typeerror: Can't assign [" + literalNode.getValue()
|
||||
+ "] to [" + identifier + "]: " + identifierType, TypeChecker.class);
|
||||
|
||||
throw new AssignmentTypeMismatchException("Trying to assign " + literalType + " to a " + identifierType + " variable.");
|
||||
}
|
||||
@ -91,25 +96,25 @@ public final class TypeChecker {
|
||||
private static void validateExpression(SyntaxTreeNode root, TypeTable table, Map<SyntaxTreeNode, String> nodeTable) {
|
||||
final String op = root.getValue();
|
||||
|
||||
log("Validating Expression: " + root.getValue());
|
||||
Logger.logInfo("Validating Expression: " + root.getValue(), TypeChecker.class);
|
||||
|
||||
if (root.isEmpty()) {
|
||||
// Keine Kinder
|
||||
|
||||
System.out.println("Line " + root.getLine() + " Operatorerror: Can't use [" + op + "] without arguments");
|
||||
Logger.logError("Line " + root.getLine() + " Operatorerror: Can't use [" + op + "] without arguments", TypeChecker.class);
|
||||
|
||||
throw new OperatorUsageException("Versuche Operator " + op + " ohne Argumente aufzurufen.");
|
||||
} else if (root.getChildren().size() != 1 && "NOT".equals(op)) {
|
||||
// Unärer Operator mit != 1 Child
|
||||
// SUB, ADD müssen nicht geprüft werden, da diese doppelt belegt sind mit ihrem binären Gegenstück
|
||||
|
||||
System.out.println("Line " + root.getLine() + " Operatorerror: Can't use [" + op + "] with more than 1 argument");
|
||||
Logger.logError("Line " + root.getLine() + " Operatorerror: Can't use [" + op + "] with more than 1 argument", TypeChecker.class);
|
||||
|
||||
throw new OperatorUsageException("Versuche unären Operator " + op + " mit mehreren Argument aufzurufen.");
|
||||
} else if (root.getChildren().size() == 1 && !unary.contains(op)) {
|
||||
// Binärer Operator mit 1 Child
|
||||
|
||||
System.out.println("Line " + root.getLine() + " Operatorerror: Can't use [" + op + "] with only 1 argument");
|
||||
Logger.logError("Line " + root.getLine() + " Operatorerror: Can't use [" + op + "] with only 1 argument", TypeChecker.class);
|
||||
|
||||
throw new OperatorUsageException("Versuche binären Operator " + op + " mit einem Argument aufzurufen.");
|
||||
}
|
||||
@ -121,7 +126,7 @@ public final class TypeChecker {
|
||||
final String childReturnType = nodeTable.get(child);
|
||||
|
||||
if (childReturnType == null) {
|
||||
System.out.println("Variable " + child.getValue() + " wurde nicht deklariert.");
|
||||
Logger.logError("Variable " + child.getValue() + " wurde nicht deklariert.", TypeChecker.class);
|
||||
|
||||
throw new SymbolNotDefinedException("Zugriff auf nicht deklarierte Variable " + child.getValue());
|
||||
}
|
||||
@ -130,7 +135,8 @@ public final class TypeChecker {
|
||||
// Child returned Typ, welcher nicht im SymbolTable als Argumenttyp steht
|
||||
// Der NodeTable enthält auch Literale, diese müssen also nicht einzeln behandelt werden
|
||||
|
||||
System.out.println("Line " + root.getLine() + " Typeerror: Can't use [" + op + "] with argument of type [" + nodeTable.get(child) + "]");
|
||||
Logger.logError("Line " + root.getLine() + " Typeerror: Can't use [" + op
|
||||
+ "] with argument of type [" + nodeTable.get(child) + "]", TypeChecker.class);
|
||||
|
||||
throw new OperatorTypeMismatchException("Versuche Operator " + op + " mit Argument vom Typ " + nodeTable.get(child) + " aufzurufen.");
|
||||
}
|
||||
@ -141,7 +147,9 @@ public final class TypeChecker {
|
||||
final SyntaxTreeNode right = root.getChildren().get(1);
|
||||
|
||||
if (!nodeTable.get(left).equals(nodeTable.get(right))) {
|
||||
System.out.println("Line " + root.getLine() + " Typeerror: Can't use [" + op + "] with arguments of type [" + nodeTable.get(left) + "] and [" + nodeTable.get(right) + "]");
|
||||
Logger.logError("Line " + root.getLine() + " Typeerror: Can't use [" + op
|
||||
+ "] with arguments of type [" + nodeTable.get(left) + "] and [" + nodeTable.get(right)
|
||||
+ "]", TypeChecker.class);
|
||||
|
||||
throw new OperatorTypeMismatchException("Versuche Operator" + op + " mit Argumenten ungleichen Types zu verwenden.");
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package typechecker;
|
||||
|
||||
import parser.ast.SyntaxTree;
|
||||
import parser.ast.SyntaxTreeNode;
|
||||
import util.Logger;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@ -9,8 +10,6 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static util.Logger.log;
|
||||
|
||||
/**
|
||||
* Speichert die Datentypen von Symbolen und Funktionen in einem Programm.
|
||||
*/
|
||||
@ -68,12 +67,13 @@ public final class TypeTable {
|
||||
}
|
||||
|
||||
public static TypeTable fromAST(SyntaxTree tree) {
|
||||
System.out.println(" - Building TypeTable...");
|
||||
Logger.logDebug("Building typetable", TypeTable.class);
|
||||
|
||||
final Map<String, String> symbolTable = new HashMap<>();
|
||||
|
||||
log("Creating TypeTable");
|
||||
initSymbolTable(tree.getRoot(), symbolTable);
|
||||
log("-".repeat(100));
|
||||
|
||||
Logger.logDebug("Successfully built typetable", TypeTable.class);
|
||||
|
||||
return new TypeTable(symbolTable);
|
||||
}
|
||||
@ -86,11 +86,11 @@ public final class TypeTable {
|
||||
if ("declaration".equals(root.getName())) {
|
||||
final SyntaxTreeNode child = root.getChildren().get(0);
|
||||
|
||||
log("Adding Entry " + child.getValue() + " -> " + root.getValue());
|
||||
Logger.logInfo("Adding Entry " + child.getValue() + " -> " + root.getValue(), TypeTable.class);
|
||||
final String oldEntry = table.put(child.getValue(), root.getValue());
|
||||
|
||||
if (oldEntry != null) {
|
||||
System.out.println("Line " + root.getLine() + " Symbolerror: [" + child.getValue() + "] already defined");
|
||||
Logger.logError("Line " + root.getLine() + " Symbolerror: [" + child.getValue() + "] already defined", TypeTable.class);
|
||||
throw new SymbolAlreadyDefinedException("Das Symbol " + child.getValue() + " wurde bereits deklariert.");
|
||||
}
|
||||
}
|
||||
|
@ -1,35 +1,117 @@
|
||||
package util;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
// Maximal professioneller Logger
|
||||
public final class Logger {
|
||||
|
||||
private static final boolean enabled = false;
|
||||
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 Map<String, Boolean> packages;
|
||||
|
||||
static {
|
||||
packages = Map.ofEntries(Map.entry("parser.grammar", true),
|
||||
Map.entry("parser", true),
|
||||
Map.entry("parser.ast", true),
|
||||
Map.entry("typechecker", true),
|
||||
Map.entry("codegen.flowgraph", true),
|
||||
Map.entry("codegen.analysis", true),
|
||||
Map.entry("codegen.analysis.dataflow", true),
|
||||
Map.entry("codegen.analysis.liveness", true),
|
||||
Map.entry("codegen", false));
|
||||
}
|
||||
|
||||
private Logger() {}
|
||||
|
||||
public static void log(String message) {
|
||||
if (enabled) {
|
||||
System.out.println(message);
|
||||
private static void log(String message, Class clazz) {
|
||||
if (LOG_ENABLED
|
||||
&& packages.containsKey(clazz.getPackageName()) && packages.get(clazz.getPackageName()).equals(true)) {
|
||||
System.out.printf("%-75s\t(%s)%n", message, clazz.getName());
|
||||
|
||||
} else if (LOG_ENABLED && !packages.containsKey(clazz.getPackageName())) {
|
||||
System.out.println("Failed Logging attempt from " + clazz.getName() + ": " + clazz.getPackageName());
|
||||
}
|
||||
}
|
||||
|
||||
public static void logNullable(String message, String nullable) {
|
||||
if (nullable != null && !nullable.isBlank() && !nullable.isEmpty() && !"null".equals(nullable)) {
|
||||
log(message);
|
||||
public static void logException(String message, Class clazz) {
|
||||
if (LOG_EXCEPTIONS) {
|
||||
log("EXCEP - " + message, clazz);
|
||||
}
|
||||
}
|
||||
|
||||
public static void logIfTrue(boolean pred, String message) {
|
||||
public static void logError(String message, Class clazz) {
|
||||
if (LOG_LEVEL >= 0) {
|
||||
log("ERROR - " + message, clazz);
|
||||
}
|
||||
}
|
||||
|
||||
public static void logDebug(String message, Class clazz) {
|
||||
if (LOG_LEVEL >= 1) {
|
||||
log("DEBUG - " + message, clazz);
|
||||
}
|
||||
}
|
||||
|
||||
public static void logInfo(String message, Class clazz) {
|
||||
if (LOG_LEVEL >= 2) {
|
||||
log("INFO - " + message, clazz);
|
||||
}
|
||||
}
|
||||
|
||||
public static void logErrorSupplier(Supplier<String> call, Class clazz) {
|
||||
if (LOG_ENABLED && LOG_LEVEL >= 0) {
|
||||
logError(call.get(), clazz);
|
||||
}
|
||||
}
|
||||
|
||||
public static void logDebugSupplier(Supplier<String> call, Class clazz) {
|
||||
if (LOG_ENABLED && LOG_LEVEL >= 1) {
|
||||
logDebug(call.get(), clazz);
|
||||
}
|
||||
}
|
||||
|
||||
public static void logInfoSupplier(Supplier<String> call, Class clazz) {
|
||||
if (LOG_ENABLED && LOG_LEVEL >= 2) {
|
||||
logInfo(call.get(), clazz);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Flipped nullble and message
|
||||
public static void logErrorNullable(String nullable, String message, Class clazz) {
|
||||
if (nullable != null && !nullable.isEmpty() && !"null".equals(nullable)) {
|
||||
logError(message, clazz);
|
||||
}
|
||||
}
|
||||
|
||||
public static void logDebugNullable(String nullable, String message, Class clazz) {
|
||||
if (nullable != null && !nullable.isEmpty() && !"null".equals(nullable)) {
|
||||
logDebug(message, clazz);
|
||||
}
|
||||
}
|
||||
|
||||
public static void logInfoNullable(String nullable, String message, Class clazz) {
|
||||
if (nullable != null && !nullable.isEmpty() && !"null".equals(nullable)) {
|
||||
logInfo(message, clazz);
|
||||
}
|
||||
}
|
||||
|
||||
public static void logErrorIfTrue(boolean pred, String message, Class clazz) {
|
||||
if (pred) {
|
||||
log(message);
|
||||
logError(message, clazz);
|
||||
}
|
||||
}
|
||||
|
||||
public static void call(Supplier<String> call) {
|
||||
if (enabled) {
|
||||
call.get();
|
||||
public static void logDebugIfTrue(boolean pred, String message, Class clazz) {
|
||||
if (pred) {
|
||||
logDebug(message, clazz);
|
||||
}
|
||||
}
|
||||
|
||||
public static void logInfoIfTrue(boolean pred, String message, Class clazz) {
|
||||
if (pred) {
|
||||
logInfo(message, clazz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user