From 66c77227287b8c5a288c8cfa28cd711fa3c5fc36 Mon Sep 17 00:00:00 2001 From: Jochen Seyfried Date: Fri, 28 Jun 2024 18:23:19 +0200 Subject: [PATCH 1/8] After the realization that there was a mixup with the produced .class files we once again fix the codeGen In this commit the standard constructors, mainMethod and standard variable declations were fixed and validated --- .../abstractSyntaxTree/Class/MethodDecl.java | 1 - .../abstractSyntaxTree/Class/RefType.java | 16 +++++++++- src/main/java/abstractSyntaxTree/Program.java | 32 ++++--------------- .../Statement/LocalVarDecl.java | 10 +++++- 4 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java index c1143b8..0026c58 100644 --- a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java @@ -51,7 +51,6 @@ public class MethodDecl implements Node { } - //TODO: Es wird kein Bytecode für Standardkonstruktoren für die Klassen generiert //TODO: Stack computing schlägt fehl --> Reihenfolge aufruf? --> Sobald if-else / if / while drin sind? --> vllt auch schon bei MethodenDecl //Need to get the returnType of the method if it is an object // methodContext (class, (returnType, (identifier, parameter))) diff --git a/src/main/java/abstractSyntaxTree/Class/RefType.java b/src/main/java/abstractSyntaxTree/Class/RefType.java index 76cc208..4e72eda 100644 --- a/src/main/java/abstractSyntaxTree/Class/RefType.java +++ b/src/main/java/abstractSyntaxTree/Class/RefType.java @@ -6,6 +6,7 @@ import TypeCheck.TypeCheckResult; import abstractSyntaxTree.Expression.IExpression; import abstractSyntaxTree.Node; import abstractSyntaxTree.Parameter.ParameterList; +import abstractSyntaxTree.Statement.BlockStatement; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; @@ -79,7 +80,7 @@ public class RefType extends AbstractType implements Node { // Method for code generation which iterates over all the field declarations // and method declarations and calls their CodeGen methods - public void codeGen(ClassWriter cw, HashMap>> methodContext, HashMap> typeContext) throws Exception { + public void codeGen(ClassWriter cw, HashMap>> methodContext, HashMap> typeContext) throws Exception { cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, name, null, "java/lang/Object", null); @@ -88,6 +89,19 @@ public class RefType extends AbstractType implements Node { field.codeGen(cw); } + boolean hasCustomConstructor = false; + for (MethodDecl method : methodDecls) { + if (method.name.equals(name) && method.returnType == null) { + hasCustomConstructor = true; + break; + } + } + + if (!hasCustomConstructor) { + MethodDecl standardConstructor = new MethodDecl(name, null, name, new ParameterList(new ArrayList<>()), new BlockStatement(new ArrayList<>(), "void")); + standardConstructor.codeGen(cw, methodContext, typeContext); + } + for (MethodDecl method : methodDecls) { method.codeGen(cw, methodContext, typeContext); } diff --git a/src/main/java/abstractSyntaxTree/Program.java b/src/main/java/abstractSyntaxTree/Program.java index 2582f18..51ba338 100644 --- a/src/main/java/abstractSyntaxTree/Program.java +++ b/src/main/java/abstractSyntaxTree/Program.java @@ -52,8 +52,8 @@ public class Program implements Node { } methodContext.put(oneClass.name, identifierAndMethod); } - - + //TODO: uncomment this code + /* int mainCounter = 0; // check if main exists for(RefType oneClass : classes){ @@ -62,6 +62,7 @@ public class Program implements Node { } if(mainCounter != 1) throw new TypeCheckException("There is not 1 Main method."); + */ // typecheck each class TypeCheckResult result = new TypeCheckResult(); @@ -73,7 +74,7 @@ public class Program implements Node { } public void codeGen() throws Exception{ - try (JarOutputStream jos = new JarOutputStream(new FileOutputStream("output.jar"))) { + try { for (RefType oneClass : classes) { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, oneClass.name, null, "java/lang/Object", null); @@ -89,30 +90,9 @@ public class Program implements Node { e.printStackTrace(); } } + } catch (Exception e) { + throw new RuntimeException(e); } - - - /*// Write the bytecode to a .class file in the .jar file - JarEntry entry = new JarEntry(oneClass.name + ".class"); - jos.putNextEntry(entry); - jos.write(bytecode); - jos.closeEntry(); - } - } catch (IOException e) { - e.printStackTrace(); - }*/ - - /* - for(RefType oneClass : classes){ - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC,oneClass.name, null, - "java/lang/Object", null); - oneClass.codeGen(cw); - - cw.visitEnd(); - byte[] bytecode = cw.toByteArray(); - } - */ } @Override diff --git a/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java b/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java index 5413556..53e1dd8 100644 --- a/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java +++ b/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java @@ -50,7 +50,15 @@ public class LocalVarDecl extends AbstractType implements IStatement{ public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception { localVars.put(identifier, type); - int index = localVars.size() - 1; + int index = -1; + int counter = 0; + // Get the index of the local variable + for (String key : localVars.keySet()) { + counter++; + if (key.equals(identifier)) { + index = counter; + } + } if (expression != null) { expression.codeGen(mv, localVars, typeContext,methodContext); From c30dcdb77393cad3b8698b2197158ca1d6c3cd87 Mon Sep 17 00:00:00 2001 From: Jochen Seyfried Date: Fri, 28 Jun 2024 18:44:03 +0200 Subject: [PATCH 2/8] Updated switch statements in case of char --- .../Expression/LocalVarIdentifier.java | 5 +---- .../Statement/LocalVarDecl.java | 20 +++++++++---------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java b/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java index d098002..f38f767 100644 --- a/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java +++ b/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java @@ -69,10 +69,7 @@ public class LocalVarIdentifier extends AbstractType implements IExpression{ // Load the variable onto the stack switch (type){ - case "int": - mv.visitVarInsn(Opcodes.ILOAD, index); - break; - case "boolean": + case "int", "boolean", "char": mv.visitVarInsn(Opcodes.ILOAD, index); break; case "void": diff --git a/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java b/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java index 53e1dd8..cef38d3 100644 --- a/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java +++ b/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java @@ -52,12 +52,16 @@ public class LocalVarDecl extends AbstractType implements IStatement{ int index = -1; int counter = 0; - // Get the index of the local variable - for (String key : localVars.keySet()) { - counter++; - if (key.equals(identifier)) { - index = counter; + for (String key : localVars.keySet()){ + if (key.equals(identifier)){ + index = counter+1; // +1 because the first local variable is at index 1, 0 is used for "this" + break; } + counter++; + } + + if (index == -1){ + throw new Exception("Variable " + identifier + " not found"); } if (expression != null) { @@ -75,11 +79,7 @@ public class LocalVarDecl extends AbstractType implements IStatement{ // Set a default value for the variable --> less problems switch (type) { - case "int": - mv.visitInsn(Opcodes.ICONST_1); - mv.visitVarInsn(Opcodes.ISTORE, index); - break; - case "boolean": + case "int", "boolean", "char": mv.visitInsn(Opcodes.ICONST_0); mv.visitVarInsn(Opcodes.ISTORE, index); break; From 3b2a32818210b4deaebf34c8e506bc9be7340cb4 Mon Sep 17 00:00:00 2001 From: StefanZ3 Date: Fri, 28 Jun 2024 19:46:09 +0200 Subject: [PATCH 3/8] add expression to fieldecl --- src/main/java/abstractSyntaxTree/Class/FieldDecl.java | 7 +++++-- src/main/java/astGenerator/ASTGenerator.java | 8 ++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/java/abstractSyntaxTree/Class/FieldDecl.java b/src/main/java/abstractSyntaxTree/Class/FieldDecl.java index a79fe5d..a7c500f 100644 --- a/src/main/java/abstractSyntaxTree/Class/FieldDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/FieldDecl.java @@ -4,6 +4,7 @@ import TypeCheck.AbstractType; import TypeCheck.TypeCheckException; import TypeCheck.TypeCheckHelper; import TypeCheck.TypeCheckResult; +import abstractSyntaxTree.Expression.IExpression; import abstractSyntaxTree.Node; import abstractSyntaxTree.Program; import org.objectweb.asm.ClassWriter; @@ -18,11 +19,13 @@ import java.util.Objects; public class FieldDecl extends AbstractType implements Node { public String type; // from parser - public String identifier; // from parser + public String identifier;// from parser + public IExpression expression; - public FieldDecl(String type, String identifier){ + public FieldDecl(String type, String identifier, IExpression expression){ this.type = type; this.identifier = identifier; + this.expression = expression; } public TypeCheckResult typeCheck(HashMap> typeContext) throws TypeCheckException { diff --git a/src/main/java/astGenerator/ASTGenerator.java b/src/main/java/astGenerator/ASTGenerator.java index 0b23d52..2127a6e 100644 --- a/src/main/java/astGenerator/ASTGenerator.java +++ b/src/main/java/astGenerator/ASTGenerator.java @@ -56,7 +56,12 @@ public class ASTGenerator extends DecafBaseVisitor { } public Node generateFieldDecl(DecafParser.LocalVarDeclContext ctx) { - return new FieldDecl(ctx.type().getText(), ctx.Identifier().getText()); + if (ctx.expression() != null) { + IExpression expression = (IExpression) visit(ctx.expression()); + return new FieldDecl(ctx.type().getText(), ctx.Identifier().getText(), expression); + } else { + return new FieldDecl(ctx.type().getText(), ctx.Identifier().getText(), null); + } } @Override @@ -198,7 +203,6 @@ public class ASTGenerator extends DecafBaseVisitor { return new AssignStatementExpression(ctx.Assign().getText(),(IExpression) left, (IExpression) right); } - // @Override public Node visitMethodCall(DecafParser.MethodCallContext ctx) { String methodName = ctx.Identifier().getText(); From 27ca4a978f90629bdf298dfc932bd75ef6c27018 Mon Sep 17 00:00:00 2001 From: Jochen Seyfried Date: Fri, 28 Jun 2024 20:16:19 +0200 Subject: [PATCH 4/8] Updated the handling of fields --- .../abstractSyntaxTree/Class/FieldDecl.java | 2 +- .../abstractSyntaxTree/Class/MethodDecl.java | 45 +++++++++++++++++-- .../abstractSyntaxTree/Class/RefType.java | 4 +- .../Expression/LocalVarIdentifier.java | 11 ++++- 4 files changed, 54 insertions(+), 8 deletions(-) diff --git a/src/main/java/abstractSyntaxTree/Class/FieldDecl.java b/src/main/java/abstractSyntaxTree/Class/FieldDecl.java index a7c500f..d1bba33 100644 --- a/src/main/java/abstractSyntaxTree/Class/FieldDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/FieldDecl.java @@ -20,7 +20,7 @@ public class FieldDecl extends AbstractType implements Node { public String type; // from parser public String identifier;// from parser - public IExpression expression; + public IExpression expression; // value of the field public FieldDecl(String type, String identifier, IExpression expression){ this.type = type; diff --git a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java index 2a6373d..d991c86 100644 --- a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java @@ -57,7 +57,8 @@ public class MethodDecl implements Node { //TODO: Stack computing schlägt fehl --> Reihenfolge aufruf? --> Sobald if-else / if / while drin sind? --> vllt auch schon bei MethodenDecl //Need to get the returnType of the method if it is an object // methodContext (class, (returnType, (identifier, parameter))) - public void codeGen(ClassWriter cw, HashMap>> methodContext, HashMap> typeContext) throws Exception { + // typeContext (class, (type, identifier)) + public void codeGen(ClassWriter cw, HashMap>> methodContext, HashMap> typeContext, List fieldDecls) throws Exception { localVars.put("this", classThatContainsMethod); for (Parameter param : parameters.parameterList) { @@ -72,18 +73,41 @@ public class MethodDecl implements Node { //Call the superclass constructor mv.visitVarInsn(Opcodes.ALOAD, 0); + mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "", "()V", false); + + //TODO: Initialize the fields of the class + HashMap classFields = typeContext.get(classThatContainsMethod); + + for (Map.Entry entry : classFields.entrySet()) { + String fieldName = entry.getKey(); + for (FieldDecl field : fieldDecls) { + if (field.identifier.equals(fieldName)) { + mv.visitVarInsn(Opcodes.ALOAD, 0); + field.expression.codeGen(mv, localVars, typeContext, methodContext); + descriptor = getFieldDescriptor(field.type); + mv.visitFieldInsn(Opcodes.PUTFIELD, classThatContainsMethod, fieldName, descriptor); + } else { + throw new Exception("Field " + fieldName + " not found"); + } + } + } //Load the parameters onto the stack int localVarIndex = 1; for (Parameter param : parameters.parameterList) { String paramType = param.type; switch(paramType) { - case "int", "boolean", "char" -> mv.visitVarInsn(Opcodes.ILOAD, localVarIndex); - default -> mv.visitVarInsn(Opcodes.ALOAD, localVarIndex); + case "int", "boolean", "char" -> { + mv.visitVarInsn(Opcodes.ILOAD, localVarIndex); + mv.visitVarInsn(Opcodes.ISTORE, localVarIndex); + } + default -> { + mv.visitVarInsn(Opcodes.ALOAD, localVarIndex); + mv.visitVarInsn(Opcodes.ASTORE, localVarIndex); + } } localVarIndex++; } - mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "", descriptor, false); mv.visitCode(); codeBlock.codeGen(mv, localVars, typeContext, methodContext); @@ -170,6 +194,19 @@ public class MethodDecl implements Node { return descriptor.toString(); } + private String getFieldDescriptor(String type) { + switch (type) { + case "int": + return "I"; + case "boolean": + return "Z"; + case "char": + return "C"; + default: + return "L" + type + ";"; + } + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/src/main/java/abstractSyntaxTree/Class/RefType.java b/src/main/java/abstractSyntaxTree/Class/RefType.java index 4e72eda..580aca9 100644 --- a/src/main/java/abstractSyntaxTree/Class/RefType.java +++ b/src/main/java/abstractSyntaxTree/Class/RefType.java @@ -99,11 +99,11 @@ public class RefType extends AbstractType implements Node { if (!hasCustomConstructor) { MethodDecl standardConstructor = new MethodDecl(name, null, name, new ParameterList(new ArrayList<>()), new BlockStatement(new ArrayList<>(), "void")); - standardConstructor.codeGen(cw, methodContext, typeContext); + standardConstructor.codeGen(cw, methodContext, typeContext, fieldDecls); } for (MethodDecl method : methodDecls) { - method.codeGen(cw, methodContext, typeContext); + method.codeGen(cw, methodContext, typeContext, fieldDecls); } cw.visitEnd(); } diff --git a/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java b/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java index f38f767..a4ccd73 100644 --- a/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java +++ b/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java @@ -47,11 +47,20 @@ public class LocalVarIdentifier extends AbstractType implements IExpression{ @Override public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception { // Check if the variable is in the list of local variables - String type = localVars.get(identifier); + + String type = null; + if (localVars.containsKey(identifier)){ + type = localVars.get(identifier); + } else { + // check if instvar + type = typeContext.get(thisClass).get(identifier); + } if (type == null){ throw new Exception("Variable " + identifier + " not declared"); } + //TODO: What if field + // Find the index of the variable int index = -1; int counter = 0; From b787b333fb56b7fe670ba78335d84f48304303d0 Mon Sep 17 00:00:00 2001 From: Jochen Seyfried Date: Fri, 28 Jun 2024 20:29:58 +0200 Subject: [PATCH 5/8] Fixed usage of fields --- .../Expression/LocalVarIdentifier.java | 80 +++++++++++-------- 1 file changed, 47 insertions(+), 33 deletions(-) diff --git a/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java b/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java index a4ccd73..772eef6 100644 --- a/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java +++ b/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java @@ -46,46 +46,60 @@ public class LocalVarIdentifier extends AbstractType implements IExpression{ @Override public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception { - // Check if the variable is in the list of local variables - String type = null; - if (localVars.containsKey(identifier)){ + + // if it's a local variable + if (localVars.containsKey(identifier)) { type = localVars.get(identifier); - } else { - // check if instvar - type = typeContext.get(thisClass).get(identifier); - } - if (type == null){ - throw new Exception("Variable " + identifier + " not declared"); - } - - //TODO: What if field - - // Find the index of the variable - int index = -1; - int counter = 0; - for (String key : localVars.keySet()){ - if (key.equals(identifier)){ - index = counter+1; // +1 because the first local variable is at index 1, 0 is used for "this" - break; + // Find the index of the variable + int index = -1; + int counter = 0; + for (String key : localVars.keySet()) { + if (key.equals(identifier)) { + index = counter + 1; // +1 because the first local variable is at index 1, 0 is used for "this" + break; + } + counter++; } - counter++; - } - if (index == -1){ + if (index == -1) { + throw new Exception("Variable " + identifier + " not found"); + } + + // Load the variable onto the stack + switch (type) { + case "int", "boolean", "char": + mv.visitVarInsn(Opcodes.ILOAD, index); + break; + case "void": + break; + default: + mv.visitVarInsn(Opcodes.ALOAD, index); + break; + } + // If it's a field + } else if (typeContext.get(thisClass).get(identifier) != null){ + type = typeContext.get(thisClass).get(identifier); + + // Load "this" onto the stack + mv.visitVarInsn(Opcodes.ALOAD, 0); + // Get the field from "this" + mv.visitFieldInsn(Opcodes.GETFIELD, thisClass, identifier, getFieldDescriptor(type)); + } else throw new Exception("Variable " + identifier + " not found"); - } + } - // Load the variable onto the stack - switch (type){ - case "int", "boolean", "char": - mv.visitVarInsn(Opcodes.ILOAD, index); - break; - case "void": - break; + //TODO move this to a helper class and remove the doubled code in MethodDecl and in other places + private String getFieldDescriptor(String type) { + switch (type) { + case "int": + return "I"; + case "boolean": + return "Z"; + case "char": + return "C"; default: - mv.visitVarInsn(Opcodes.ALOAD, index); - break; + return "L" + type + ";"; } } From d1da1c6eee0ac8f3b8905521907d2f5663ba15ff Mon Sep 17 00:00:00 2001 From: Jochen Seyfried Date: Fri, 28 Jun 2024 20:31:21 +0200 Subject: [PATCH 6/8] Deleted TODOs which are done --- src/main/java/abstractSyntaxTree/Class/FieldDecl.java | 1 - src/main/java/abstractSyntaxTree/Class/MethodDecl.java | 1 - src/main/java/abstractSyntaxTree/Program.java | 4 +--- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/abstractSyntaxTree/Class/FieldDecl.java b/src/main/java/abstractSyntaxTree/Class/FieldDecl.java index d1bba33..14d4d39 100644 --- a/src/main/java/abstractSyntaxTree/Class/FieldDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/FieldDecl.java @@ -49,7 +49,6 @@ public class FieldDecl extends AbstractType implements Node { } public void codeGen(ClassWriter cw) { - //TODO: Do we have fields with initial values? --> No dont think so --> assign FieldVisitor fv = cw.visitField(Opcodes.ACC_PUBLIC, identifier, getFieldDescriptor(), null, null); fv.visitEnd(); } diff --git a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java index d991c86..224cb01 100644 --- a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java @@ -75,7 +75,6 @@ public class MethodDecl implements Node { mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "", "()V", false); - //TODO: Initialize the fields of the class HashMap classFields = typeContext.get(classThatContainsMethod); for (Map.Entry entry : classFields.entrySet()) { diff --git a/src/main/java/abstractSyntaxTree/Program.java b/src/main/java/abstractSyntaxTree/Program.java index 51ba338..3826a24 100644 --- a/src/main/java/abstractSyntaxTree/Program.java +++ b/src/main/java/abstractSyntaxTree/Program.java @@ -52,8 +52,7 @@ public class Program implements Node { } methodContext.put(oneClass.name, identifierAndMethod); } - //TODO: uncomment this code - /* + int mainCounter = 0; // check if main exists for(RefType oneClass : classes){ @@ -62,7 +61,6 @@ public class Program implements Node { } if(mainCounter != 1) throw new TypeCheckException("There is not 1 Main method."); - */ // typecheck each class TypeCheckResult result = new TypeCheckResult(); From 392fea7d23e81e66bf4f88280524193ce6bdf658 Mon Sep 17 00:00:00 2001 From: Jochen Seyfried Date: Sat, 29 Jun 2024 14:02:51 +0200 Subject: [PATCH 7/8] Fixed Bug concerning all BinaryOperators which are not booleanExpressions but produce a value. --- .../Expression/BinaryExpression.java | 164 +++++++++--------- .../Statement/IfElseStatement.java | 5 +- .../Statement/WhileStatement.java | 1 - 3 files changed, 81 insertions(+), 89 deletions(-) diff --git a/src/main/java/abstractSyntaxTree/Expression/BinaryExpression.java b/src/main/java/abstractSyntaxTree/Expression/BinaryExpression.java index 6b775f6..cbce259 100644 --- a/src/main/java/abstractSyntaxTree/Expression/BinaryExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/BinaryExpression.java @@ -76,105 +76,97 @@ public class BinaryExpression extends AbstractType implements IExpression{ Label expressionEnd = new Label(); //End of the whole expression // Bytecode for the binary operation - switch (operator) { - case "&&": - left.codeGen(mv, localVars, typeContext, methodContext); - mv.visitJumpInsn(Opcodes.IFEQ, operationFalse); // IFEQ --> "if equals to zero" (false) --> if left exp is false + if (operator.equals("+") || operator.equals("-") || operator.equals("*") || operator.equals("/")) { + switch (operator) { + case "+" -> { + left.codeGen(mv, localVars, typeContext, methodContext); + right.codeGen(mv, localVars, typeContext, methodContext); + mv.visitInsn(Opcodes.IADD); + } + case "-" -> { + left.codeGen(mv, localVars, typeContext, methodContext); + right.codeGen(mv, localVars, typeContext, methodContext); + mv.visitInsn(Opcodes.ISUB); + } + case "*" -> { + left.codeGen(mv, localVars, typeContext, methodContext); + right.codeGen(mv, localVars, typeContext, methodContext); + mv.visitInsn(Opcodes.IMUL); + } + case "/" -> { + left.codeGen(mv, localVars, typeContext, methodContext); + right.codeGen(mv, localVars, typeContext, methodContext); + mv.visitInsn(Opcodes.IDIV); + } + } + } else { + switch (operator) { + case "&&" -> { + left.codeGen(mv, localVars, typeContext, methodContext); + mv.visitJumpInsn(Opcodes.IFEQ, operationFalse); // IFEQ --> "if equals to zero" (false) --> if left exp is false - right.codeGen(mv, localVars, typeContext, methodContext); - mv.visitJumpInsn(Opcodes.IFEQ, operationFalse); // If right exp is false, jump to the end of the whole expression + right.codeGen(mv, localVars, typeContext, methodContext); + mv.visitJumpInsn(Opcodes.IFEQ, operationFalse); - mv.visitJumpInsn(Opcodes.GOTO, operationTrue); // If it reaches this point, the right exp is true - break; + mv.visitJumpInsn(Opcodes.GOTO, operationTrue); // If it reaches this point, the right exp is true + } + case "||" -> { + left.codeGen(mv, localVars, typeContext, methodContext); + mv.visitJumpInsn(Opcodes.IFNE, operationTrue); // IFNE --> "if not equals to zero" (true) --> if left exp is true - case "||": - left.codeGen(mv, localVars, typeContext, methodContext); - mv.visitJumpInsn(Opcodes.IFNE, operationTrue); // IFNE --> "if not equals to zero" (true) --> if left exp is true + right.codeGen(mv, localVars, typeContext, methodContext); + mv.visitJumpInsn(Opcodes.IFNE, operationTrue); + } + case "==" -> { + // Keep in mind that only primitive types are allowed in this case (at this time) - right.codeGen(mv, localVars, typeContext, methodContext); - mv.visitJumpInsn(Opcodes.IFNE, operationTrue); - break; + left.codeGen(mv, localVars, typeContext, methodContext); + right.codeGen(mv, localVars, typeContext, methodContext); - case "==": - // Keep in mind that only primitive types are allowed in this case (at this time) + mv.visitJumpInsn(Opcodes.IF_ICMPEQ, operationTrue); // If the two values are equal, jump to the end of the expression + } + case "<" -> { + left.codeGen(mv, localVars, typeContext, methodContext); + right.codeGen(mv, localVars, typeContext, methodContext); - left.codeGen(mv, localVars, typeContext, methodContext); - right.codeGen(mv, localVars, typeContext, methodContext); + mv.visitJumpInsn(Opcodes.IF_ICMPLT, operationTrue); // Checks only on less than, not equal + } + case ">" -> { + left.codeGen(mv, localVars, typeContext, methodContext); + right.codeGen(mv, localVars, typeContext, methodContext); - mv.visitJumpInsn(Opcodes.IF_ICMPEQ, operationTrue); // If the two values are equal, jump to the end of the expression - break; + mv.visitJumpInsn(Opcodes.IF_ICMPGT, operationTrue); // Checks only on greater than, not equal + } + case "<=" -> { + left.codeGen(mv, localVars, typeContext, methodContext); + right.codeGen(mv, localVars, typeContext, methodContext); - case "<": - left.codeGen(mv, localVars, typeContext, methodContext); - right.codeGen(mv, localVars, typeContext, methodContext); + mv.visitJumpInsn(Opcodes.IF_ICMPLE, operationTrue); // Checks on less than OR equal + } + case ">=" -> { + left.codeGen(mv, localVars, typeContext, methodContext); + right.codeGen(mv, localVars, typeContext, methodContext); - mv.visitJumpInsn(Opcodes.IF_ICMPLT, operationTrue); // Checks only on less than, not equal - break; + mv.visitJumpInsn(Opcodes.IF_ICMPGE, operationTrue); // Checks on greater than OR equal + } + case "!=" -> { + left.codeGen(mv, localVars, typeContext, methodContext); + right.codeGen(mv, localVars, typeContext, methodContext); - case ">": - left.codeGen(mv, localVars, typeContext, methodContext); - right.codeGen(mv, localVars, typeContext, methodContext); + mv.visitJumpInsn(Opcodes.IF_ICMPNE, operationTrue); // Checks on not equal + } + default -> throw new TypeCheckException("The operator " + operator + " is not known."); + } + //TODO: This is only viable for boolean expressions --> structure this file differently + mv.visitLabel(operationFalse); + mv.visitInsn(Opcodes.ICONST_0); // Push false on the stack + mv.visitJumpInsn(Opcodes.GOTO, expressionEnd); // Jump to the end of the expression (skip the true push) - mv.visitJumpInsn(Opcodes.IF_ICMPGT, operationTrue); // Checks only on greater than, not equal - break; + mv.visitLabel(operationTrue); + mv.visitInsn(Opcodes.ICONST_1); // Push true on the stack - case "<=": - left.codeGen(mv, localVars, typeContext, methodContext); - right.codeGen(mv, localVars, typeContext, methodContext); - - mv.visitJumpInsn(Opcodes.IF_ICMPLE, operationTrue); // Checks on less than OR equal - break; - - case ">=": - left.codeGen(mv, localVars, typeContext, methodContext); - right.codeGen(mv, localVars, typeContext, methodContext); - - mv.visitJumpInsn(Opcodes.IF_ICMPGE, operationTrue); // Checks on greater than OR equal - break; - - case "!=": - left.codeGen(mv, localVars, typeContext, methodContext); - right.codeGen(mv, localVars, typeContext, methodContext); - - mv.visitJumpInsn(Opcodes.IF_ICMPNE, operationTrue); // Checks on not equal - break; - - case "+": - left.codeGen(mv, localVars, typeContext, methodContext); - right.codeGen(mv, localVars, typeContext, methodContext); - mv.visitInsn(Opcodes.IADD); - break; - - case "-": - left.codeGen(mv, localVars, typeContext, methodContext); - right.codeGen(mv, localVars, typeContext, methodContext); - mv.visitInsn(Opcodes.ISUB); - break; - - case "*": - left.codeGen(mv, localVars, typeContext, methodContext); - right.codeGen(mv, localVars, typeContext, methodContext); - mv.visitInsn(Opcodes.IMUL); - break; - - case "/": - left.codeGen(mv, localVars, typeContext, methodContext); - right.codeGen(mv, localVars, typeContext, methodContext); - mv.visitInsn(Opcodes.IDIV); - break; - - default: - throw new TypeCheckException("The operator " + operator + " is not known."); + mv.visitLabel(expressionEnd); } - - mv.visitLabel(operationFalse); - mv.visitInsn(Opcodes.ICONST_0); // Push false on the stack - mv.visitJumpInsn(Opcodes.GOTO, expressionEnd); // Jump to the end of the expression (skip the true push) - - mv.visitLabel(operationTrue); - mv.visitInsn(Opcodes.ICONST_1); // Push true on the stack - - mv.visitLabel(expressionEnd); } @Override diff --git a/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java b/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java index d380fae..b290dcf 100644 --- a/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java @@ -54,7 +54,7 @@ public class IfElseStatement extends AbstractType implements IStatement{ } - + //TODO: There are 2 NOPs and one athrow on the stack between the if-Block and else-Block execution --> I have no idea why @Override public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception { @@ -67,7 +67,8 @@ public class IfElseStatement extends AbstractType implements IStatement{ mv.visitJumpInsn(Opcodes.IFEQ, conditionFalse); //Checks if the condition is false (0) ifStatement.codeGen(mv, blockLocalVars, typeContext, methodContext); //If the condition is true, execute the ifBlock - mv.visitJumpInsn(Opcodes.GOTO, statementEnd); //Jump to the end of the if-else statement + + mv.visitJumpInsn(Opcodes.GOTO, statementEnd); //Jump to the end of the else statement mv.visitLabel(conditionFalse); elseStatement.codeGen(mv, blockLocalVars, typeContext, methodContext); //If the condition is false, execute the elseBlock diff --git a/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java b/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java index 47255ea..a81de81 100644 --- a/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/WhileStatement.java @@ -55,7 +55,6 @@ public class WhileStatement extends AbstractType implements IStatement { mv.visitJumpInsn(Opcodes.IFEQ, conditionFalse); // Checks if the condition is false (0) statement.codeGen(mv, blockLocalVars, typeContext, methodContext); - //statement.codeGen(mv); //TODO: If the block ends with a return statement, we might have to pop it from the stack // So the next iteration starts with a clean stack mv.visitJumpInsn(Opcodes.GOTO, LoopStart); // Jump to the start of the while loop From 942597d5359101ec639f1c7f7ac4938295253b07 Mon Sep 17 00:00:00 2001 From: Jochen Seyfried Date: Sat, 29 Jun 2024 14:04:00 +0200 Subject: [PATCH 8/8] Removed TODOs --- src/main/java/abstractSyntaxTree/Class/MethodDecl.java | 2 -- .../java/abstractSyntaxTree/Expression/BinaryExpression.java | 1 - 2 files changed, 3 deletions(-) diff --git a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java index 224cb01..d836d61 100644 --- a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java @@ -53,8 +53,6 @@ public class MethodDecl implements Node { return result; } - - //TODO: Stack computing schlägt fehl --> Reihenfolge aufruf? --> Sobald if-else / if / while drin sind? --> vllt auch schon bei MethodenDecl //Need to get the returnType of the method if it is an object // methodContext (class, (returnType, (identifier, parameter))) // typeContext (class, (type, identifier)) diff --git a/src/main/java/abstractSyntaxTree/Expression/BinaryExpression.java b/src/main/java/abstractSyntaxTree/Expression/BinaryExpression.java index cbce259..68f58e5 100644 --- a/src/main/java/abstractSyntaxTree/Expression/BinaryExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/BinaryExpression.java @@ -157,7 +157,6 @@ public class BinaryExpression extends AbstractType implements IExpression{ } default -> throw new TypeCheckException("The operator " + operator + " is not known."); } - //TODO: This is only viable for boolean expressions --> structure this file differently mv.visitLabel(operationFalse); mv.visitInsn(Opcodes.ICONST_0); // Push false on the stack mv.visitJumpInsn(Opcodes.GOTO, expressionEnd); // Jump to the end of the expression (skip the true push)