Added logging
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run

This commit is contained in:
Lucas 2024-06-19 12:49:46 +02:00
parent f59d7e9918
commit 102961bccc
4 changed files with 229 additions and 101 deletions

View File

@ -1,4 +1,3 @@
import ast.ASTNode;
import ast.ProgramNode;
import parser.ASTBuilder;
import parser.generated.SimpleJavaLexer;
@ -11,7 +10,7 @@ import org.antlr.v4.runtime.tree.ParseTree;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.List;
/**
* Start Raupenpiler with the following commands:
@ -19,6 +18,8 @@ import java.util.List;
* <p> <code> make clean compile-raupenpiler </code>
*/
public class Main {
public static void main(String[] args) throws Exception {
if (args.length > 0) {
// args[0] is the input file path
@ -45,105 +46,56 @@ public class Main {
*/
}
static void compileFile(CharStream inputCharStream, String outputDirectoryPath) {
/* ------------------------- Scanner -> tokens ------------------------- */
SimpleJavaLexer lexer = new SimpleJavaLexer(inputCharStream);
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
tokenStream.fill();
// Printing the tokens
System.out.println("-------------------- Scanner -> Tokens --------------------");
List<Token> tokens = tokenStream.getTokens();
for (Token token : tokens) {
String tokenType =
SimpleJavaLexer.VOCABULARY.getSymbolicName(token.getType());
String tokenText = token.getText();
// System.out.println("Token Type: " + tokenType + ", Token Text: " + tokenText);
System.out.println(tokenType + " " + tokenText);
}
System.out.println();
/*------------------------- Parser -> Parsetree -------------------------*/
SimpleJavaParser parser = new SimpleJavaParser(tokenStream);
ParseTree parseTree = parser.program(); // parse the input
// Printing the parse tree
System.out.println("-------------------- Parser -> Parsetree --------------------");
System.out.println(parseTree.toStringTree(parser)); //one line representation
// printTree(parseTree, parser, 0);
System.out.println();
/*------------------------- AST builder -> AST -------------------------*/
ASTBuilder astBuilder = new ASTBuilder();
ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree);
// Printing the AST
System.out.println("-------------------- AST builder -> AST --------------------");
// System.out.println("AST: " + ast.toString());
printAST(abstractSyntaxTree, 0);
System.out.println();
/*------------------------- Semantic Analyzer -> typed AST -------------------------*/
ProgramNode typedAst = (ProgramNode) SemanticAnalyzer.generateTast(abstractSyntaxTree);
// Printing the typed AST
System.out.println("-------------------- Semantic Analyzer -> typed AST --------------------");
printAST(typedAst, 0);
System.out.println();
/*------------------------- Bytecode Generator -> Bytecode -------------------------*/
ByteCodeGenerator byteCodeGenerator = new ByteCodeGenerator(outputDirectoryPath);
byteCodeGenerator.visit(typedAst);
System.out.println("Bytecode generated");
}
/* ------------------------- Printing methods ------------------------- */
/**
* This method is used to print the parse tree in a structured format.
* It recursively traverses the tree and prints the rule names and text of the
* nodes.
*
* @param tree The parse tree to be printed.
* @param parser The parser used to parse the input. It's used to get the rule
* names.
* @param indent The current indentation level. It's used to format the output.
*/
public static void printTree(ParseTree tree, Parser parser, int indent) {
// Create an indentation string based on the current indentation level
String indentString = " ".repeat(indent * 2);
* This method is used to compile a file from a given CharStream and output the bytecode to a specified directory.
* It goes through the following steps:
* <p>1. Scanner: It uses the SimpleJavaLexer to tokenize the input CharStream.
* <p>2. Parser: It uses the SimpleJavaParser to parse the tokens and generate a ParseTree.
* <p>3. AST Builder: It uses the ASTBuilder to visit the ParseTree and generate an Abstract Syntax Tree (AST).
* <p>4. Semantic Analyzer: It uses the SemanticAnalyzer to generate a typed AST.
* <p>5. Bytecode Generator: It uses the ByteCodeGenerator to generate bytecode from the typed AST and output it to the specified directory.
*
* @param inputCharStream The CharStream representing the input file to be compiled.
* @param outputDirectoryPath The path of the directory where the output bytecode should be written.
*/
static void compileFile(CharStream inputCharStream, String outputDirectoryPath) {
// Initialize the logger
new MyLogger();
// If the tree node is an instance of RuleContext (i.e., it's an internal node),
// print the rule name
if (tree instanceof RuleContext) {
int ruleIndex = ((RuleContext) tree).getRuleIndex();
String ruleName = parser.getRuleNames()[ruleIndex];
System.out.println(indentString + ruleName);
} else {
// If the tree node is not an instance of RuleContext (i.e., it's a leaf node),
// print the text of the node
System.out.println(indentString + tree.getText());
}
/* ------------------------- Scanner -> tokens ------------------------- */
// Use the SimpleJavaLexer to tokenize the input CharStream
SimpleJavaLexer lexer = new SimpleJavaLexer(inputCharStream);
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
tokenStream.fill();
// Log the tokens
MyLogger.logScanner(tokenStream);
// Recursively print the children of the current node, increasing the
// indentation level
for (int i = 0; i < tree.getChildCount(); i++) {
printTree(tree.getChild(i), parser, indent + 1);
}
}
/*------------------------- Parser -> Parse tree -------------------------*/
// Use the SimpleJavaParser to parse the tokens and generate a ParseTree
SimpleJavaParser parser = new SimpleJavaParser(tokenStream);
ParseTree parseTree = parser.program(); // parse the input
// Log the ParseTree
MyLogger.logParser(parseTree, parser);
// TODO: Fix this method
public static void printAST(ASTNode node, int indent) {
if (node == null) {
System.out.println("null");
return;
}
String indentString = " ".repeat(indent * 2);
System.out.println(indentString + node.getClass().toString());
/*------------------------- AST builder -> AST -------------------------*/
// Use the ASTBuilder to visit the ParseTree and generate an Abstract Syntax Tree (AST)
ASTBuilder astBuilder = new ASTBuilder();
ProgramNode abstractSyntaxTree = (ProgramNode) astBuilder.visit(parseTree);
// Log the AST
MyLogger.logAST(abstractSyntaxTree);
// for (ASTNode child : node.) {
// printAST(child, indent + 1);
// }
}
/*------------------------- Semantic Analyzer -> typed AST -------------------------*/
// Use the SemanticAnalyzer to generate a typed AST
ProgramNode typedAst = (ProgramNode) SemanticAnalyzer.generateTast(abstractSyntaxTree);
// Log the typed AST
MyLogger.logSemanticAnalyzer(typedAst);
/*------------------------- Bytecode Generator -> Bytecode -------------------------*/
// Use the ByteCodeGenerator to generate bytecode from the typed AST and output it to the specified directory
ByteCodeGenerator byteCodeGenerator = new ByteCodeGenerator(outputDirectoryPath);
assert typedAst != null;
byteCodeGenerator.visit(typedAst);
// Log the bytecode generation
MyLogger.logBytecodeGenerator();
}
}

178
src/main/java/MyLogger.java Normal file
View File

@ -0,0 +1,178 @@
import ast.ASTNode;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.Parser;
import org.antlr.v4.runtime.RuleContext;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.tree.ParseTree;
import parser.generated.SimpleJavaLexer;
import parser.generated.SimpleJavaParser;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.logging.*;
/**
Beispiel für Logging-Arten:
<p><code>logger.severe("Schwerwiegender Fehler");</code>
<p><code>logger.warning("Warnung");</code>
<p><code>logger.info("Information");</code>
<p><code>logger.config("Konfigurationshinweis");</code>
<p><code>logger.fine("Fein");</code>
<p><code>logger.finer("Feiner");</code>
<p><code>logger.finest("Am feinsten");</code>
<p>You may toggle the logging level of the console and file handlers by
changing the level ALL/OFF/etc. in the constructor.
<code>consoleHandler.setLevel(Level.OFF);</code>
<code>fileHandler.setLevel(Level.ALL);</code>
*/
public class MyLogger {
static Logger logger = Logger.getLogger("RaupenLogs");
public MyLogger() {
// ------------------------- Logging -------------------------
logger.setLevel(Level.ALL);
logger.getParent().getHandlers()[0].setLevel(Level.ALL);
logger.setUseParentHandlers(false);
// Custom formatter class
class CustomFormatter extends Formatter {
private final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss dd-MM-yyyy");
@Override
public String format(LogRecord record) {
return formatMessage(record) + System.lineSeparator();
}
@Override
public String getHead(Handler h) {
Date now = new Date();
String dateTime = dateFormat.format(now);
return "Log Start Time: " + dateTime + "\n"
+ "Logger Name: " + h.getFormatter().getClass().getName() + "\n\n";
}
}
try {
// Configure console handler
Handler consoleHandler = new ConsoleHandler();
// Toggle console logging on/off
consoleHandler.setLevel(Level.OFF);
consoleHandler.setFormatter(new CustomFormatter());
logger.addHandler(consoleHandler);
// Configure file handler
Handler fileHandler = new FileHandler("src/main/resources/logs/RaupenLog.log");
// Toggle file logging on/off
fileHandler.setLevel(Level.ALL);
fileHandler.setFormatter(new CustomFormatter());
logger.addHandler(fileHandler);
} catch (SecurityException | IOException e) {
e.printStackTrace();
}
}
public static void logScanner(CommonTokenStream tokenStream) {
// Printing the tokens
logger.info("-------------------- Scanner -> Tokens --------------------");
List<Token> tokens = tokenStream.getTokens();
for (Token token : tokens) {
String tokenType =
SimpleJavaLexer.VOCABULARY.getSymbolicName(token.getType());
String tokenText = token.getText();
// logger.info("Token Type: " + tokenType + ", Token Text: " + tokenText);
logger.info(tokenType + " " + tokenText);
}
logger.info("\n");
}
public static void logParser(ParseTree parseTree, SimpleJavaParser parser) {
// Printing the parse tree
logger.info("-------------------- Parser -> Parsetree --------------------");
logger.info(parseTree.toStringTree(parser)); //one line representation
logTree(parseTree, parser, 0);
logger.info("\n");
}
public static void logAST(ASTNode node) {
// Printing the AST
logger.info("-------------------- AST builder -> AST --------------------");
// logger.info("AST: " + ast.toString());
logAST(node, 0);
logger.info("\n");
}
public static void logSemanticAnalyzer(ASTNode node) {
// Printing the typed AST
logger.info("-------------------- Semantic Analyzer -> typed AST --------------------");
logAST(node, 0);
logger.info("\n");
}
public static void logBytecodeGenerator() {
// Printing the bytecode
logger.info("-------------------- Bytecode Generator -> Bytecode --------------------");
logger.info("Bytecode generated");
logger.info("\n");
}
/* ------------------------- Printing methods ------------------------- */
/**
* This method is used to print the parse tree in a structured format.
* It recursively traverses the tree and prints the rule names and text of the
* nodes.
*
* @param tree The parse tree to be printed.
* @param parser The parser used to parse the input. It's used to get the rule
* names.
* @param indent The current indentation level. It's used to format the output.
*/
public static void logTree(ParseTree tree, Parser parser, int indent) {
// Create an indentation string based on the current indentation level
String indentString = " ".repeat(indent * 2);
// If the tree node is an instance of RuleContext (i.e., it's an internal node),
// print the rule name
if (tree instanceof RuleContext) {
int ruleIndex = ((RuleContext) tree).getRuleIndex();
String ruleName = parser.getRuleNames()[ruleIndex];
logger.info(indentString + ruleName);
} else {
// If the tree node is not an instance of RuleContext (i.e., it's a leaf node),
// print the text of the node
logger.info(indentString + tree.getText());
}
// Recursively print the children of the current node, increasing the
// indentation level
for (int i = 0; i < tree.getChildCount(); i++) {
logTree(tree.getChild(i), parser, indent + 1);
}
}
// TODO: Fix this method
public static void logAST(ASTNode node, int indent) {
if (node == null) {
System.out.println("null");
return;
}
String indentString = " ".repeat(indent * 2);
logger.info(indentString + node.getClass().toString());
// for (ASTNode child : node.) {
// printAST(child, indent + 1);
// }
}
}

View File

@ -1,6 +1,6 @@
# Makefile
### IntelliJs play buttons do not work. Run in "src/test" folder with "make" command to run all
### Or run only parts with "make compile-javac", "make delete" etc.
### Or run only parts with "make compile-javac", "make clean" etc.
all: compile-javac compile-raupenpiler
@ -25,4 +25,5 @@ clean:
rm -f ./resources/output/raupenpiler/*.class
rm -f ./java/*.class
rm -f ../main/resources/output/*.class
rm -f ../main/resources/logs/*.log

View File

@ -1,6 +1,5 @@
package parser;
import ast.ProgramNode;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.ParseTree;
import org.junit.jupiter.api.BeforeEach;
@ -10,9 +9,7 @@ import parser.generated.SimpleJavaParser;
import static org.junit.jupiter.api.Assertions.*;
import java.nio.file.Paths;
import java.util.*;
import java.util.function.BooleanSupplier;
public class ParserTest {
@BeforeEach