diff --git a/src/main/java/Main.java b/src/main/java/Main.java index 6f6517f..7174d66 100644 --- a/src/main/java/Main.java +++ b/src/main/java/Main.java @@ -13,23 +13,41 @@ import java.io.IOException; import java.nio.file.Paths; import java.util.List; +/** + * Start Raupenpiler with the following commands: + *

cd .\src\test\ + *

make clean compile-raupenpiler + */ public class Main { public static void main(String[] args) throws Exception { if (args.length > 0) { - System.out.println("Main file has args: " + args[0]); - } else { + // 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 codeCharStream = CharStreams.fromPath(Paths.get("src/main/resources/input/CompilerInput.java")); - parseFile(codeCharStream); + 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()); + } + } + */ } - static void parseFile(CharStream codeCharStream) { + static void compileFile(CharStream inputCharStream, String outputDirectoryPath) { /* ------------------------- Scanner -> tokens ------------------------- */ - SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream); + SimpleJavaLexer lexer = new SimpleJavaLexer(inputCharStream); CommonTokenStream tokenStream = new CommonTokenStream(lexer); // Printing the tokens @@ -51,20 +69,20 @@ public class Main { ParseTree parseTree = parser.program(); // parse the input // Printing the parse tree - System.out.println("-------------------- Parser -> Parsetree --------------------"); - System.out.println(parseTree.toStringTree(parser)); - printTree(parseTree, parser, 0); - System.out.println(); + System.out.println("-------------------- Parser -> Parsetree --------------------"); + System.out.println(parseTree.toStringTree(parser)); + 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(); + 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); @@ -75,11 +93,12 @@ public class Main { System.out.println(); /*------------------------- Bytecode Generator -> Bytecode -------------------------*/ - ByteCodeGenerator byteCodeGenerator = new ByteCodeGenerator(); + 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. @@ -114,6 +133,7 @@ public class Main { } } + // TODO: Fix this method public static void printAST(ASTNode node, int indent) { if (node == null) { System.out.println("null"); diff --git a/src/main/java/bytecode/ByteCodeGenerator.java b/src/main/java/bytecode/ByteCodeGenerator.java index 5494255..99cf5c1 100644 --- a/src/main/java/bytecode/ByteCodeGenerator.java +++ b/src/main/java/bytecode/ByteCodeGenerator.java @@ -6,10 +6,16 @@ import bytecode.visitor.ProgramVisitor; public class ByteCodeGenerator implements ProgramVisitor { + private final String outputDirectoryPath; + + public ByteCodeGenerator(String outputDirectoryPath) { + this.outputDirectoryPath = outputDirectoryPath; + } + @Override public void visit(ProgramNode programNode) { for (ClassNode classDeclarationNode : programNode.classes) { - ClassCodeGen classCodeGen = new ClassCodeGen(); + ClassCodeGen classCodeGen = new ClassCodeGen(outputDirectoryPath); classDeclarationNode.accept(classCodeGen); } } diff --git a/src/main/java/bytecode/ClassCodeGen.java b/src/main/java/bytecode/ClassCodeGen.java index d91b17b..d8cdaaa 100644 --- a/src/main/java/bytecode/ClassCodeGen.java +++ b/src/main/java/bytecode/ClassCodeGen.java @@ -6,7 +6,9 @@ import ast.member.MemberNode; import ast.member.MethodNode; import ast.type.BaseTypeNode; import bytecode.visitor.ClassVisitor; + import java.io.File; + import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; @@ -17,8 +19,10 @@ import java.io.IOException; public class ClassCodeGen implements ClassVisitor { private Mapper mapper; private ClassWriter classWriter; + private final String outputDirectoryPath; - public ClassCodeGen() { + public ClassCodeGen(String outputDirectoryPath) { + this.outputDirectoryPath = outputDirectoryPath; mapper = new Mapper(); } @@ -45,20 +49,21 @@ public class ClassCodeGen implements ClassVisitor { @Override public void visit(FieldNode fieldNode) { - if(fieldNode.type instanceof BaseTypeNode baseTypeNode){ - classWriter.visitField(mapper.mapAccessTypeToOpcode(fieldNode.accessTypeNode), fieldNode.identifier, mapper.getTypeChar(baseTypeNode.enumType), null, null ); + if (fieldNode.type instanceof BaseTypeNode baseTypeNode) { + classWriter.visitField(mapper.mapAccessTypeToOpcode(fieldNode.accessTypeNode), fieldNode.identifier, mapper.getTypeChar(baseTypeNode.enumType), null, null); } classWriter.visitEnd(); } private void printIntoClassFile(byte[] byteCode, String name) { - String directoryPath = "src/main/resources/output"; - File directory = new File(directoryPath); + // String outputDirectoryPath = "src/main/resources/output"; + System.out.println("Output directory path: " + outputDirectoryPath); + File directory = new File(outputDirectoryPath); if (!directory.exists()) { directory.mkdirs(); } - String filePath = directoryPath + "/" + name + ".class"; + String filePath = outputDirectoryPath + "/" + name + ".class"; try { FileOutputStream fileOutputStream = new FileOutputStream(filePath); fileOutputStream.write(byteCode); diff --git a/src/main/java/bytecode/visitor/ClassVisitor.java b/src/main/java/bytecode/visitor/ClassVisitor.java index 98ef25c..725b075 100644 --- a/src/main/java/bytecode/visitor/ClassVisitor.java +++ b/src/main/java/bytecode/visitor/ClassVisitor.java @@ -5,6 +5,7 @@ import ast.member.FieldNode; import org.objectweb.asm.ClassWriter; public interface ClassVisitor { - void visit(ClassNode classNode); - void visit(FieldNode fieldNode); + void visit(ClassNode classNode); + + void visit(FieldNode fieldNode); } diff --git a/src/test/Makefile b/src/test/Makefile index e14b5d4..1329f1d 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -9,8 +9,16 @@ compile-javac: compile-raupenpiler: cd ../.. ; mvn -DskipTests package - cd ../.. ; mvn exec:java -Dexec.mainClass="Main" # -Dexec.args="arg0 arg1 arg2" + cd ../.. ; mvn exec:java -Dexec.mainClass="Main" -Dexec.args="'src/main/resources/input/CompilerInput.java' 'src/main/resources/output' " +test: test-javac test-raupenpiler + +test-javac: + compile-javac + java -cp .\resources\output\javac CompilerInput + +test-raupenpiler: + java -cp .\resources\output\raupenpiler CompilerInput clean: rm -f ./resources/output/javac/*.class diff --git a/src/test/java/FailureTest.java b/src/test/java/FailureTest.java index 366ce56..028c5d1 100644 --- a/src/test/java/FailureTest.java +++ b/src/test/java/FailureTest.java @@ -63,7 +63,7 @@ public class FailureTest { CharStream codeCharStream = null; try { codeCharStream = CharStreams.fromPath(Paths.get("src/main/test/resources/EmptyClassExample.java")); - Main.parseFile(codeCharStream); + Main.compileFile(codeCharStream, "src/main/test/resources/output"); } catch (IOException e) { System.err.println("Error reading the file: " + e.getMessage()); } diff --git a/src/test/java/MainTest.java b/src/test/java/MainTest.java index a8c3a93..eec63b0 100644 --- a/src/test/java/MainTest.java +++ b/src/test/java/MainTest.java @@ -16,7 +16,7 @@ public class MainTest { CharStream codeCharStream = null; try { codeCharStream = CharStreams.fromPath(Paths.get("src/main/test/resources/CompilerInput.java")); - Main.parseFile(codeCharStream); + Main.compileFile(codeCharStream, "src/main/test/resources/output"); } catch (IOException e) { System.err.println("Error reading the file: " + e.getMessage()); } diff --git a/src/test/java/TestCompilerOutput.java b/src/test/java/TestCompilerOutput.java index 567ebde..6a7c031 100644 --- a/src/test/java/TestCompilerOutput.java +++ b/src/test/java/TestCompilerOutput.java @@ -1,10 +1,10 @@ /** * This class is used to test the output of the compiler. * - *

Im gleichen Ordner wie diese Datei (TestCompilerOutput.java) muss die selbstkompilierte CompilerInput.java Datei sein. - *
Hinweis: Diese muss man also vom Ordner classFileOutput in diesen Ordner hier (test/java) rein kopieren. (bis es eine bessere Lösung gibt)

+ *

Im gleichen Ordner wie diese Datei (TestCompilerOutput.java) muss die selbst kompilierte CompilerInput.class Datei sein. + *
Hinweis: Diese muss man also vom Ordner main/resources/output in diesen Ordner hier (test/java) rein kopieren. (bis es eine bessere Lösung gibt)

* - *

Die selbstkompilierte .class Datei wird dann hier drin geladen und eine Instanz von ihr erstellt, es können auch Methoden aufgerufen werden. + *

Die selbst kompilierte .class Datei wird dann hier drin geladen und eine Instanz von ihr erstellt, es können auch Methoden aufgerufen werden. *

Diese TestCompilerOutput.java Datei wird dann in \src\test\java> mit javac .\TestCompilerOutput.java kompiliert und mit java TestCompilerOutput ausgeführt. * 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).

diff --git a/src/test/java/parser/ParserTest.java b/src/test/java/parser/ParserTest.java new file mode 100644 index 0000000..834f988 --- /dev/null +++ b/src/test/java/parser/ParserTest.java @@ -0,0 +1,4 @@ +package parser; + +public class ParserTest { +}