Tests, Structure, More #10
4
.gitignore
vendored
4
.gitignore
vendored
@ -76,4 +76,6 @@ fabric.properties
|
|||||||
# Android studio 3.1+ serialized cache file
|
# Android studio 3.1+ serialized cache file
|
||||||
.idea/caches/build_file_checksums.ser
|
.idea/caches/build_file_checksums.ser
|
||||||
|
|
||||||
/target
|
/target
|
||||||
|
src/main/resources/logs/RaupenLog.log
|
||||||
|
src/main/resources/output/CompilerInput.class
|
||||||
|
22
pom.xml
22
pom.xml
@ -45,6 +45,28 @@
|
|||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<version>3.0.0-M5</version> <!-- Change the version as needed -->
|
<version>3.0.0-M5</version> <!-- Change the version as needed -->
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>make-assembly</id> <!-- this is used for inheritance merges -->
|
||||||
|
<phase>package</phase> <!-- bind to the packaging phase -->
|
||||||
|
<goals>
|
||||||
|
<goal>single</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>main.Main</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
<descriptorRefs>
|
||||||
|
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||||
|
</descriptorRefs>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
@ -1,102 +0,0 @@
|
|||||||
import ast.ASTNode;
|
|
||||||
import ast.ProgramNode;
|
|
||||||
import parser.ASTBuilder;
|
|
||||||
import parser.generated.SimpleJavaLexer;
|
|
||||||
import parser.generated.SimpleJavaParser;
|
|
||||||
import semantic.SemanticAnalyzer;
|
|
||||||
import bytecode.ByteCodeGenerator;
|
|
||||||
|
|
||||||
import org.antlr.v4.runtime.*;
|
|
||||||
import org.antlr.v4.runtime.tree.ParseTree;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start Raupenpiler with the following commands:
|
|
||||||
* <p> <code> cd .\src\test\ </code>
|
|
||||||
* <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
|
|
||||||
// args[1] is the output directory path
|
|
||||||
String inputFilePath = args[0];
|
|
||||||
String outputDirectoryPath = args[1];
|
|
||||||
System.out.println("Compiling file: " + inputFilePath);
|
|
||||||
try {
|
|
||||||
CharStream inputCharStream = CharStreams.fromPath(Paths.get(inputFilePath));
|
|
||||||
compileFile(inputCharStream, outputDirectoryPath);
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.err.println("Error reading the file: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* !!! Else Branch ist nicht zur Verwendung vorgesehen, alles über make starten !!!
|
|
||||||
else {
|
|
||||||
try {
|
|
||||||
CharStream codeCharStream = CharStreams.fromPath(Paths.get("src/main/resources/input/CompilerInput.java"));
|
|
||||||
compileFile(codeCharStream);
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.err.println("Error reading the file: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 RaupenLogger();
|
|
||||||
|
|
||||||
/* ------------------------- 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
|
|
||||||
RaupenLogger.logScanner(tokenStream);
|
|
||||||
|
|
||||||
/*------------------------- Parser -> Parsetree -------------------------*/
|
|
||||||
// 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
|
|
||||||
RaupenLogger.logParser(parseTree, parser);
|
|
||||||
|
|
||||||
/*------------------------- AST builder -> AST -------------------------*/
|
|
||||||
// Use the ASTBuilder to visit the ParseTree and generate an Abstract Syntax Tree (AST)
|
|
||||||
ASTBuilder astBuilder = new ASTBuilder();
|
|
||||||
ASTNode abstractSyntaxTree = astBuilder.visit(parseTree);
|
|
||||||
// Log the AST
|
|
||||||
RaupenLogger.logAST(abstractSyntaxTree);
|
|
||||||
|
|
||||||
/*------------------------- Semantic Analyzer -> typed AST -------------------------*/
|
|
||||||
// Use the SemanticAnalyzer to generate a typed AST
|
|
||||||
ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree);
|
|
||||||
// Log the typed AST
|
|
||||||
RaupenLogger.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((ProgramNode) typedAst);
|
|
||||||
// Log the bytecode generation
|
|
||||||
RaupenLogger.logBytecodeGenerator();
|
|
||||||
}
|
|
||||||
}
|
|
108
src/main/java/main/Main.java
Normal file
108
src/main/java/main/Main.java
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
package main;
|
||||||
|
|
||||||
|
import ast.ASTNode;
|
||||||
|
import ast.ProgramNode;
|
||||||
|
import parser.ASTBuilder;
|
||||||
|
import parser.generated.SimpleJavaLexer;
|
||||||
|
import parser.generated.SimpleJavaParser;
|
||||||
|
import semantic.SemanticAnalyzer;
|
||||||
|
import bytecode.ByteCodeGenerator;
|
||||||
|
|
||||||
|
import org.antlr.v4.runtime.*;
|
||||||
|
import org.antlr.v4.runtime.tree.ParseTree;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start Raupenpiler using make:
|
||||||
|
* <p> <code> cd .\src\test\ </code>
|
||||||
|
* <p> <code> make clean compile-raupenpiler </code>
|
||||||
|
* <p> Start Raupenpiler using jar:
|
||||||
|
* <p> <code> java.exe -jar .\target\JavaCompiler-1.0-SNAPSHOT-jar-with-dependencies.jar 'path_to_input_file.java' 'path_to_output_directory' </code>
|
||||||
|
* <p> Example:
|
||||||
|
* <code> java.exe -jar .\target\JavaCompiler-1.0-SNAPSHOT-jar-with-dependencies.jar 'src/main/resources/input/CompilerInput.java' 'src/main/resources/output' </code>
|
||||||
|
*/
|
||||||
|
public class Main {
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
if (args.length > 0) {
|
||||||
|
// args[0] is the input file path
|
||||||
|
// args[1] is the output directory path
|
||||||
|
String inputFilePath = args[0];
|
||||||
|
String outputDirectoryPath = args[1];
|
||||||
|
System.out.println("Compiling file: " + inputFilePath);
|
||||||
|
try {
|
||||||
|
CharStream inputCharStream = CharStreams.fromPath(Paths.get(inputFilePath));
|
||||||
|
compileFile(inputCharStream, outputDirectoryPath);
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("Error reading the file: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* !!! Else Branch ist nicht zur Verwendung vorgesehen, immer mit args starten !!!
|
||||||
|
else {
|
||||||
|
try {
|
||||||
|
CharStream codeCharStream = CharStreams.fromPath(Paths.get("src/main/resources/input/CompilerInput.java"));
|
||||||
|
compileFile(codeCharStream);
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("Error reading the file: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 RaupenLogger();
|
||||||
|
|
||||||
|
/* ------------------------- 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
|
||||||
|
RaupenLogger.logScanner(tokenStream);
|
||||||
|
|
||||||
|
/*------------------------- Parser -> Parsetree -------------------------*/
|
||||||
|
// 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
|
||||||
|
RaupenLogger.logParser(parseTree, parser);
|
||||||
|
|
||||||
|
/*------------------------- AST builder -> AST -------------------------*/
|
||||||
|
// Use the ASTBuilder to visit the ParseTree and generate an Abstract Syntax Tree (AST)
|
||||||
|
ASTBuilder astBuilder = new ASTBuilder();
|
||||||
|
ASTNode abstractSyntaxTree = astBuilder.visit(parseTree);
|
||||||
|
// Log the AST
|
||||||
|
RaupenLogger.logAST(abstractSyntaxTree);
|
||||||
|
|
||||||
|
/*------------------------- Semantic Analyzer -> typed AST -------------------------*/
|
||||||
|
// Use the SemanticAnalyzer to generate a typed AST
|
||||||
|
ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree);
|
||||||
|
// Log the typed AST
|
||||||
|
RaupenLogger.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((ProgramNode) typedAst);
|
||||||
|
// Log the bytecode generation
|
||||||
|
RaupenLogger.logBytecodeGenerator();
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
package main;
|
||||||
|
|
||||||
import ast.ASTNode;
|
import ast.ASTNode;
|
||||||
import org.antlr.v4.runtime.CommonTokenStream;
|
import org.antlr.v4.runtime.CommonTokenStream;
|
||||||
import org.antlr.v4.runtime.Parser;
|
import org.antlr.v4.runtime.Parser;
|
@ -8,8 +8,8 @@ compile-javac:
|
|||||||
javac -d .\resources\output\javac .\resources\input\CompilerInput.java
|
javac -d .\resources\output\javac .\resources\input\CompilerInput.java
|
||||||
|
|
||||||
compile-raupenpiler:
|
compile-raupenpiler:
|
||||||
cd ../.. ; mvn -DskipTests package
|
cd ../.. ; mvn -DskipTests install
|
||||||
cd ../.. ; mvn exec:java -Dexec.mainClass="Main" -Dexec.args="'src/main/resources/input/CompilerInput.java' 'src/main/resources/output' "
|
cd ../.. ; mvn exec:java -Dexec.mainClass="main.Main" -Dexec.args="'src/main/resources/input/CompilerInput.java' 'src/main/resources/output' "
|
||||||
|
|
||||||
test: test-javac test-raupenpiler
|
test: test-javac test-raupenpiler
|
||||||
|
|
||||||
|
@ -78,8 +78,8 @@ Compiled Classfile
|
|||||||
|
|
||||||
wenn beides erfolgreich
|
wenn beides erfolgreich
|
||||||
|
|
||||||
- Ergebnis vom eigenen Compiler mithilfe von TestCompilerOutput ausführen
|
- Ergebnis vom eigenen Compiler mithilfe von main.TestCompilerOutput ausführen
|
||||||
- (Ergebnis von javac mithilfe von TestCompilerOutput ausführen)
|
- (Ergebnis von javac mithilfe von main.TestCompilerOutput ausführen)
|
||||||
|
|
||||||
### Andis Tipps:
|
### Andis Tipps:
|
||||||
|
|
||||||
@ -89,4 +89,4 @@ wenn beides erfolgreich
|
|||||||
- mvn package
|
- mvn package
|
||||||
- javac tester // tester compilen
|
- javac tester // tester compilen
|
||||||
- java tester // tester ausführen
|
- java tester // tester ausführen
|
||||||
- -> tester ist in unserem Fall TestCompilerOutput.java
|
- -> tester ist in unserem Fall main.TestCompilerOutput.java
|
@ -1,3 +1,5 @@
|
|||||||
|
package main;
|
||||||
|
|
||||||
public class EmptyClassExample {
|
public class EmptyClassExample {
|
||||||
private class Inner {
|
private class Inner {
|
||||||
}
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
package main;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
@ -62,7 +64,7 @@ public class FailureTest {
|
|||||||
void typedASTTest() throws IOException {
|
void typedASTTest() throws IOException {
|
||||||
CharStream codeCharStream = null;
|
CharStream codeCharStream = null;
|
||||||
try {
|
try {
|
||||||
codeCharStream = CharStreams.fromPath(Paths.get("src/main/test/resources/EmptyClassExample.java"));
|
codeCharStream = CharStreams.fromPath(Paths.get("src/main/test/resources/main/EmptyClassExample.java"));
|
||||||
Main.compileFile(codeCharStream, "src/main/test/resources/output");
|
Main.compileFile(codeCharStream, "src/main/test/resources/output");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.err.println("Error reading the file: " + e.getMessage());
|
System.err.println("Error reading the file: " + e.getMessage());
|
@ -1,3 +1,5 @@
|
|||||||
|
package main;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.antlr.v4.runtime.CharStream;
|
import org.antlr.v4.runtime.CharStream;
|
||||||
import org.antlr.v4.runtime.CharStreams;
|
import org.antlr.v4.runtime.CharStreams;
|
@ -1,11 +1,13 @@
|
|||||||
|
package main;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is used to test the output of the compiler.
|
* This class is used to test the output of the compiler.
|
||||||
*
|
*
|
||||||
* <p>Im gleichen Ordner wie diese Datei (TestCompilerOutput.java) muss die selbst kompilierte CompilerInput.class Datei sein.
|
* <p>Im gleichen Ordner wie diese Datei (main.TestCompilerOutput.java) muss die selbst kompilierte CompilerInput.class Datei sein.
|
||||||
* <br><strong>Hinweis:</strong> Diese muss man also vom Ordner <code> main/resources/output </code> in diesen Ordner hier (test/java) rein kopieren. (bis es eine bessere Lösung gibt)</p>
|
* <br><strong>Hinweis:</strong> Diese muss man also vom Ordner <code> main/resources/output </code> in diesen Ordner hier (test/java) rein kopieren. (bis es eine bessere Lösung gibt)</p>
|
||||||
*
|
*
|
||||||
* <p>Die selbst kompilierte .class Datei wird dann hier drin geladen und eine Instanz von ihr erstellt, es können auch Methoden aufgerufen werden.
|
* <p>Die selbst kompilierte .class Datei wird dann hier drin geladen und eine Instanz von ihr erstellt, es können auch Methoden aufgerufen werden.
|
||||||
* <p>Diese TestCompilerOutput.java Datei wird dann in <code> \src\test\java> </code> mit <code>javac .\TestCompilerOutput.java</code> kompiliert und mit <code>java TestCompilerOutput</code> ausgeführt.
|
* <p>Diese main.TestCompilerOutput.java Datei wird dann in <code> \src\test\java> </code> mit <code>javac .\main.TestCompilerOutput.java</code> kompiliert und mit <code>java main.TestCompilerOutput</code> ausgeführt.
|
||||||
* Wenn unser Compiler funktioniert, sollten keine Errors kommen (sondern nur die Ausgaben, die wir in der CompilerInput.java Datei gemacht haben,
|
* Wenn unser Compiler funktioniert, sollten keine Errors kommen (sondern nur die Ausgaben, die wir in der CompilerInput.java Datei gemacht haben,
|
||||||
* oder Methoden, die wir hier aufrufen).</p>
|
* oder Methoden, die wir hier aufrufen).</p>
|
||||||
*
|
*
|
Loading…
Reference in New Issue
Block a user