From 87e863e7736f8c49b181ae4c5d9367cb9efd034e Mon Sep 17 00:00:00 2001 From: Jochen Seyfried Date: Sat, 22 Jun 2024 12:30:06 +0200 Subject: [PATCH 1/4] Implemented CodeGen for Constants and fixed an issue regarding the placements of local variables on the JVM stack. ( index JVM = index localVars + 1) --- src/main/java/Compiler.java | 2 +- .../Expression/BooleanConstantExpression.java | 7 ++++++- .../Expression/CharConstantExpression.java | 3 ++- .../Expression/IntConstantExpression.java | 4 +++- .../abstractSyntaxTree/Expression/LocalVarIdentifier.java | 4 ++-- .../java/abstractSyntaxTree/Statement/ReturnStatement.java | 1 - 6 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/main/java/Compiler.java b/src/main/java/Compiler.java index 0a0ff90..3f197ab 100644 --- a/src/main/java/Compiler.java +++ b/src/main/java/Compiler.java @@ -28,7 +28,7 @@ public class Compiler { public static void main(String[] args) throws Exception{ - Path filePath = Paths.get("src/main/java/Input.java"); + Path filePath = Paths.get("src/main/java/InputTest.java"); // todo remove this debug info diff --git a/src/main/java/abstractSyntaxTree/Expression/BooleanConstantExpression.java b/src/main/java/abstractSyntaxTree/Expression/BooleanConstantExpression.java index ffc7198..da0e925 100644 --- a/src/main/java/abstractSyntaxTree/Expression/BooleanConstantExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/BooleanConstantExpression.java @@ -5,6 +5,7 @@ import TypeCheck.TypeCheckException; import TypeCheck.TypeCheckResult; import abstractSyntaxTree.Parameter.ParameterList; import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; import java.util.HashMap; import java.util.LinkedHashMap; @@ -26,7 +27,11 @@ public class BooleanConstantExpression extends AbstractType implements IExpressi @Override public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext) throws Exception { - + if (value){ + mv.visitInsn(Opcodes.ICONST_1); + } else { + mv.visitInsn(Opcodes.ICONST_0); + } } @Override public TypeCheckResult getTypeCheckResult() { diff --git a/src/main/java/abstractSyntaxTree/Expression/CharConstantExpression.java b/src/main/java/abstractSyntaxTree/Expression/CharConstantExpression.java index ecc0b4f..1485cd5 100644 --- a/src/main/java/abstractSyntaxTree/Expression/CharConstantExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/CharConstantExpression.java @@ -4,6 +4,7 @@ import TypeCheck.AbstractType; import TypeCheck.TypeCheckResult; import abstractSyntaxTree.Parameter.ParameterList; import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; import java.util.HashMap; import java.util.LinkedHashMap; @@ -25,7 +26,7 @@ public class CharConstantExpression extends AbstractType implements IExpression{ @Override public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext) throws Exception { - + mv.visitIntInsn(Opcodes.BIPUSH, (int) value); } @Override diff --git a/src/main/java/abstractSyntaxTree/Expression/IntConstantExpression.java b/src/main/java/abstractSyntaxTree/Expression/IntConstantExpression.java index c10e36c..fd1fb24 100644 --- a/src/main/java/abstractSyntaxTree/Expression/IntConstantExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/IntConstantExpression.java @@ -4,6 +4,7 @@ import TypeCheck.AbstractType; import TypeCheck.TypeCheckResult; import abstractSyntaxTree.Parameter.ParameterList; import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; import java.util.HashMap; import java.util.LinkedHashMap; @@ -27,7 +28,8 @@ public class IntConstantExpression extends AbstractType implements IExpression{ @Override public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext) throws Exception { - + //TODO: When we are finished this can be done more efficiently + mv.visitLdcInsn(value); } @Override diff --git a/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java b/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java index 69c115f..7642d08 100644 --- a/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java +++ b/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java @@ -45,12 +45,12 @@ public class LocalVarIdentifier extends AbstractType implements IExpression{ throw new Exception("Variable " + identifier + " not declared"); } - // Load the variable onto the stack + // Find the index of the variable int index = -1; int counter = 0; for (String key : localVars.keySet()){ if (key.equals(identifier)){ - index = counter; + index = counter+1; // +1 because the first local variable is at index 1, 0 is used for "this" break; } counter++; diff --git a/src/main/java/abstractSyntaxTree/Statement/ReturnStatement.java b/src/main/java/abstractSyntaxTree/Statement/ReturnStatement.java index f6dfd8c..b9a64e4 100644 --- a/src/main/java/abstractSyntaxTree/Statement/ReturnStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/ReturnStatement.java @@ -50,7 +50,6 @@ public class ReturnStatement extends AbstractType implements IStatement{ mv.visitInsn(Opcodes.IRETURN); } else { mv.visitInsn(Opcodes.ARETURN); - } } else { mv.visitInsn(Opcodes.RETURN); From 9ff069827a845ec392e01bb8ee3fd6b19cbeba97 Mon Sep 17 00:00:00 2001 From: Jochen Seyfried Date: Sat, 22 Jun 2024 16:33:53 +0200 Subject: [PATCH 2/4] Fixed Bugs in bytecode generation --- src/main/java/TypeCheck/TypeCheckHelper.java | 2 +- src/main/java/abstractSyntaxTree/Class/MethodDecl.java | 5 +++-- .../java/abstractSyntaxTree/Statement/LocalVarDecl.java | 2 +- .../StatementExpression/AssignStatementExpression.java | 7 +++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/TypeCheck/TypeCheckHelper.java b/src/main/java/TypeCheck/TypeCheckHelper.java index 6e7542a..b9c9384 100644 --- a/src/main/java/TypeCheck/TypeCheckHelper.java +++ b/src/main/java/TypeCheck/TypeCheckHelper.java @@ -24,7 +24,7 @@ public class TypeCheckHelper { } public static boolean typeExists(String type, List customTypeslist) { - if(type.equals("int") || type.equals("bool") || type.equals("char")){ + if(type.equals("int") || type.equals("boolean") || type.equals("char")){ return true; } return customTypeslist.contains(type); diff --git a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java index 04c7525..b4cfcab 100644 --- a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java @@ -125,7 +125,7 @@ public class MethodDecl implements Node { for (Parameter param : parameters.parameterList) { switch (param.type) { case "int" -> descriptor.append("I"); - case "bool" -> descriptor.append("Z"); + case "boolean" -> descriptor.append("Z"); case "char" -> descriptor.append("C"); case "void" -> descriptor.append("V"); default -> { @@ -144,11 +144,12 @@ public class MethodDecl implements Node { } else { switch (returnType) { case "int" -> descriptor.append("I"); - case "bool" -> descriptor.append("Z"); + case "boolean" -> descriptor.append("Z"); case "char" -> descriptor.append("C"); case "void" -> descriptor.append("V"); default -> { // object + // methodContext (class, (returnType, (identifier, parameter))) HashMap> classMethods = methodContext.get(classThatContainsMethod); HashMap methodDetails = classMethods.get(name); diff --git a/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java b/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java index fd748c3..78b36c2 100644 --- a/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java +++ b/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java @@ -51,7 +51,7 @@ public class LocalVarDecl extends AbstractType implements IStatement{ mv.visitInsn(Opcodes.ICONST_0); mv.visitVarInsn(Opcodes.ISTORE, index); break; - case "bool": + case "boolean": mv.visitInsn(Opcodes.ICONST_0); mv.visitVarInsn(Opcodes.ISTORE, index); break; diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java index eb31a57..e80fb12 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java @@ -47,7 +47,7 @@ public class AssignStatementExpression extends AbstractType implements IExpressi String upperbound = helper.upperBound(leftType.type, rightType.type); if(Objects.equals(leftType.type, "boolean")) - leftType.type = "bool"; + leftType.type = "boolean"; if (!Objects.equals(upperbound, leftType.type)) { throw new TypeCheckException("The upper bound of assignment is not the left type."); } @@ -78,7 +78,7 @@ public class AssignStatementExpression extends AbstractType implements IExpressi int counter = 0; for (String key : localVars.keySet()) { if (key.equals(varName)) { - index = counter; + index = counter+1; break; } counter++; @@ -90,8 +90,7 @@ public class AssignStatementExpression extends AbstractType implements IExpressi String type = localVars.get(localVar.getIdentifier()); switch (type) { - case "int": - case "bool": + case "int", "char", "boolean": mv.visitVarInsn(Opcodes.ISTORE, index); break; default: From 90936affb947f533e89a452f1a3c58535b9a8770 Mon Sep 17 00:00:00 2001 From: Jochen Seyfried Date: Sat, 22 Jun 2024 16:39:29 +0200 Subject: [PATCH 3/4] Changed "bool" to "boolean" --- .../java/abstractSyntaxTree/Expression/LocalVarIdentifier.java | 2 +- .../StatementExpression/AssignStatementExpression.java | 2 +- .../StatementExpression/NewStatementExpression.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java b/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java index 7642d08..aa8345e 100644 --- a/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java +++ b/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java @@ -65,7 +65,7 @@ public class LocalVarIdentifier extends AbstractType implements IExpression{ case "int": mv.visitVarInsn(Opcodes.ILOAD, index); break; - case "bool": + case "boolean": mv.visitVarInsn(Opcodes.ILOAD, index); break; case "void": diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java index e80fb12..560d155 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/AssignStatementExpression.java @@ -116,7 +116,7 @@ public class AssignStatementExpression extends AbstractType implements IExpressi case "int": descriptor.append("I"); break; - case "bool": + case "boolean": descriptor.append("Z"); break; default: diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/NewStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/NewStatementExpression.java index a868c0e..23b7b71 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/NewStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/NewStatementExpression.java @@ -66,7 +66,7 @@ public class NewStatementExpression extends AbstractType implements IExpression, case "int": descriptor.append("I"); break; - case "bool": + case "boolean": descriptor.append("Z"); break; case "char": From 1dac9245f23113221dd1e9ca2713df4fb963381a Mon Sep 17 00:00:00 2001 From: Jochen Seyfried Date: Sun, 23 Jun 2024 16:42:27 +0200 Subject: [PATCH 4/4] Added other implementation for methodCallStatement --- .../Statement/LocalVarDecl.java | 3 +- .../MethodCallStatementExpression.java | 62 ++++++++++--------- .../NewStatementExpression.java | 3 + 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java b/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java index 78b36c2..44338f2 100644 --- a/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java +++ b/src/main/java/abstractSyntaxTree/Statement/LocalVarDecl.java @@ -43,9 +43,10 @@ public class LocalVarDecl extends AbstractType implements IStatement{ public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext) throws Exception { localVars.put(identifier, type); - // Set a default value for the variable --> less problems + int index = localVars.size()-1; + // Set a default value for the variable --> less problems switch (type){ case "int": mv.visitInsn(Opcodes.ICONST_0); diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java index bfbe742..92646c0 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/MethodCallStatementExpression.java @@ -65,41 +65,45 @@ public class MethodCallStatementExpression extends AbstractType implements IExpr @Override public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext) throws Exception { //Generate Bytecode for the receiver - if (classThatHasTheMethodIfNotThis != null) { - //TODO: classThatHasTheMethodIfNotThis must be an object --> instance of the class not the class itself - // This is not finished - // Need to call codeGen so it pushes the instance onto the stack, which will be popped of - //classThatHasTheMethodIfNotThis.codeGen(); - - String descriptor; - List methodDecls = thisClass.methodDecls; - for (MethodDecl methodDecl : methodDecls) { - if (methodDecl.name.equals(methodName)) { - //Get the method descriptor - // descriptor = methodDecl.getMethodDescriptor(methodContext); - } - } - // mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, classThatHasTheMethodIfNotThis.name, methodName, descriptor, false); - - } else { - // Load this onto the stack + if (receiver.thisExpression) { + // If the receiver is "this" then load "this" onto the stack mv.visitVarInsn(Opcodes.ALOAD, 0); + } else if (receiver.instVarExpression != null) { + receiver.instVarExpression.codeGen(mv, localVars, typeContext); - for (IExpression argument : arguments) { - argument.codeGen(mv, localVars, typeContext); - } + } else if (receiver.newStatementExpression != null) { + receiver.newStatementExpression.codeGen(mv, localVars, typeContext); - // Get the method descriptor - String descriptor; - List methodDecls = thisClass.methodDecls; - for (MethodDecl methodDecl : methodDecls) { - if (methodDecl.name.equals(methodName)) { - //Get the method descriptor - //descriptor = methodDecl.getMethodDescriptor(methodContext); + // Not sure about this part + } else if (receiver.identifier != null) { + // Load local variable onto the stack + for (String key : localVars.keySet()) { + if (key.equals(receiver.identifier)) { + String type = localVars.get(key); + int opcode = type.equals("int") ? Opcodes.ILOAD : Opcodes.ALOAD; + mv.visitVarInsn(opcode, Integer.parseInt(key)); + break; } } - // mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, thisClass.name, methodName, descriptor, false); } + + // Generate Bytecode for the arguments + for (IExpression argument : arguments) { + argument.codeGen(mv, localVars, typeContext); + } + + + String descriptor; + List methodDecls = thisClass.methodDecls; + for (MethodDecl methodDecl : methodDecls) { + if (methodDecl.name.equals(methodName)) { + //Get the method descriptor + //descriptor = methodDecl.getMethodDescriptor(methodContext); //methodContext is missing + } + } + // Invoke the method + String className = classThatHasTheMethodIfNotThis != null ? classThatHasTheMethodIfNotThis.name : thisClass.name; + //mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, className, methodName, descriptor, false); } @Override diff --git a/src/main/java/abstractSyntaxTree/StatementExpression/NewStatementExpression.java b/src/main/java/abstractSyntaxTree/StatementExpression/NewStatementExpression.java index 23b7b71..4188fbd 100644 --- a/src/main/java/abstractSyntaxTree/StatementExpression/NewStatementExpression.java +++ b/src/main/java/abstractSyntaxTree/StatementExpression/NewStatementExpression.java @@ -53,6 +53,9 @@ public class NewStatementExpression extends AbstractType implements IExpression, //Call the constructor mv.visitMethodInsn(Opcodes.INVOKESPECIAL, className, "", descriptor, false); + + // One instance of the class remains now on the stack + // Which will then be used in an assignment or method call } private String getConstructorDescriptor() {