Tests, Structure, More #10
@ -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:
|
||||
i22005 marked this conversation as resolved
Outdated
|
||||
@ -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 {
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
i22011 marked this conversation as resolved
Outdated
i22005
commented
Können wir die ganze Ausgabe in ne extra Klasse auzslagern? Des macht die Main Klasse bissle arg unübersichtlich. Außerdem gehört des nacher nicht in den Endgültigen Compiler. Können wir die ganze Ausgabe in ne extra Klasse auzslagern? Des macht die Main Klasse bissle arg unübersichtlich. Außerdem gehört des nacher nicht in den Endgültigen Compiler.
|
||||
* <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();
|
||||
|
||||
/* ------------------------- Scanner -> tokens ------------------------- */
|
||||
// Use the SimpleJavaLexer to tokenize the input CharStream
|
||||
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();
|
||||
// Log the tokens
|
||||
MyLogger.logScanner(tokenStream);
|
||||
i22011 marked this conversation as resolved
Outdated
i22005
commented
Same Here Same Here
|
||||
|
||||
/*------------------------- 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
|
||||
|
||||
// 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();
|
||||
// Log the ParseTree
|
||||
MyLogger.logParser(parseTree, parser);
|
||||
|
||||
/*------------------------- AST builder -> AST -------------------------*/
|
||||
// Use the ASTBuilder to visit the ParseTree and generate an Abstract Syntax Tree (AST)
|
||||
i22011 marked this conversation as resolved
Outdated
i22005
commented
Same Here Same Here
|
||||
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();
|
||||
// Log the AST
|
||||
MyLogger.logAST(abstractSyntaxTree);
|
||||
|
||||
/*------------------------- Semantic Analyzer -> typed AST -------------------------*/
|
||||
// Use the SemanticAnalyzer to generate a typed AST
|
||||
ProgramNode typedAst = (ProgramNode) SemanticAnalyzer.generateTast(abstractSyntaxTree);
|
||||
i22011 marked this conversation as resolved
Outdated
i22005
commented
Same Here Same Here
|
||||
|
||||
// Printing the typed AST
|
||||
System.out.println("-------------------- Semantic Analyzer -> typed AST --------------------");
|
||||
printAST(typedAst, 0);
|
||||
System.out.println();
|
||||
// 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);
|
||||
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);
|
||||
|
||||
// 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());
|
||||
}
|
||||
|
||||
// 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);
|
||||
// Log the bytecode generation
|
||||
MyLogger.logBytecodeGenerator();
|
||||
}
|
||||
}
|
||||
|
||||
// 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());
|
||||
|
||||
// for (ASTNode child : node.) {
|
||||
// printAST(child, indent + 1);
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
178
src/main/java/MyLogger.java
Normal file
178
src/main/java/MyLogger.java
Normal 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);
|
||||
// }
|
||||
}
|
||||
}
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user
Warum muss der compiler mit einem Makefile gestartet werden? Es reicht doch wenn wir die jar mit
Java compiler fileIn fileOut ausführt.