Implemented CodeGen for Assign and MethodCall. But MethodCall is not working at the moment

This commit is contained in:
Jochen Seyfried 2024-05-22 12:49:59 +02:00
parent 108b8f63ea
commit b91174eeee
11 changed files with 217 additions and 83 deletions

View File

@ -36,10 +36,6 @@ public class FieldDecl extends AbstractType implements Node {
//write field table //write field table
} }
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, List<MethodDecl> fieldsOrMethods) throws Exception {
return null;
}
public void codeGen(ClassWriter cw) { public void codeGen(ClassWriter cw) {
//TODO: Do we have fields with initial values? --> No dont think so --> assign //TODO: Do we have fields with initial values? --> No dont think so --> assign
FieldVisitor fv = cw.visitField(Opcodes.ACC_PUBLIC, identifier, getFieldDescriptor(), null, null); FieldVisitor fv = cw.visitField(Opcodes.ACC_PUBLIC, identifier, getFieldDescriptor(), null, null);
@ -47,11 +43,10 @@ public class FieldDecl extends AbstractType implements Node {
} }
private String getFieldDescriptor() { private String getFieldDescriptor() {
//TODO: Maybe we have to check for arrays?
switch (type) { switch (type) {
case "int": case "int":
return "I"; return "I";
case "bool": case "boolean":
return "Z"; return "Z";
case "char": case "char":
return "C"; return "C";

View File

@ -22,7 +22,8 @@ public class MethodDecl implements Node {
public String returnType; public String returnType;
public BlockStatement codeBlock; public BlockStatement codeBlock;
public HashMap<String, String> localVars; //TODO: Can this be a linked hash map? --> need it to be to get the index of local variables
public LinkedHashMap<String, String> localVars;
public MethodDecl(String classThatContainsMethod, String returnType, String name, ParameterList parameters, BlockStatement codeBlock){ public MethodDecl(String classThatContainsMethod, String returnType, String name, ParameterList parameters, BlockStatement codeBlock){
this.classThatContainsMethod = classThatContainsMethod; this.classThatContainsMethod = classThatContainsMethod;
@ -30,7 +31,7 @@ public class MethodDecl implements Node {
this.name = name; this.name = name;
this.parameters = parameters; this.parameters = parameters;
this.codeBlock = codeBlock; this.codeBlock = codeBlock;
this.localVars = new HashMap<>(); this.localVars = new LinkedHashMap<>();
} }
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext) throws Exception { public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext) throws Exception {

View File

@ -8,6 +8,7 @@ import org.objectweb.asm.*;
import java.beans.Expression; import java.beans.Expression;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Objects; import java.util.Objects;
public class BinaryExpression extends AbstractType implements IExpression{ public class BinaryExpression extends AbstractType implements IExpression{
@ -66,7 +67,7 @@ public class BinaryExpression extends AbstractType implements IExpression{
} }
@Override @Override
public void codeGen(MethodVisitor mv) throws Exception { public void codeGen(MethodVisitor mv, HashMap<String, HashMap<String, String>> typeContext, LinkedHashMap<String, String> localVars) throws Exception {
// Label for the jump instruction // Label for the jump instruction
Label operationFalse = new Label(); //Operation is false Label operationFalse = new Label(); //Operation is false
Label operationTrue = new Label(); //Operation is true Label operationTrue = new Label(); //Operation is true
@ -76,88 +77,88 @@ public class BinaryExpression extends AbstractType implements IExpression{
// Bytecode for the binary operation // Bytecode for the binary operation
switch (operator) { switch (operator) {
case "&&": case "&&":
left.codeGen(mv); left.codeGen(mv, typeContext, localVars);
mv.visitJumpInsn(Opcodes.IFEQ, operationFalse); // IFEQ --> "if equals to zero" (false) --> if left exp is false mv.visitJumpInsn(Opcodes.IFEQ, operationFalse); // IFEQ --> "if equals to zero" (false) --> if left exp is false
right.codeGen(mv); right.codeGen(mv, typeContext, localVars);
mv.visitJumpInsn(Opcodes.IFEQ, operationFalse); // If right exp is false, jump to the end of the whole expression mv.visitJumpInsn(Opcodes.IFEQ, operationFalse); // If right exp is false, jump to the end of the whole expression
mv.visitJumpInsn(Opcodes.GOTO, operationTrue); // If it reaches this point, the right exp is true mv.visitJumpInsn(Opcodes.GOTO, operationTrue); // If it reaches this point, the right exp is true
break; break;
case "||": case "||":
left.codeGen(mv); left.codeGen(mv, typeContext, localVars);
mv.visitJumpInsn(Opcodes.IFNE, operationTrue); // IFNE --> "if not equals to zero" (true) --> if left exp is true mv.visitJumpInsn(Opcodes.IFNE, operationTrue); // IFNE --> "if not equals to zero" (true) --> if left exp is true
right.codeGen(mv); right.codeGen(mv, typeContext, localVars);
mv.visitJumpInsn(Opcodes.IFNE, operationTrue); mv.visitJumpInsn(Opcodes.IFNE, operationTrue);
break; break;
case "==": case "==":
// Keep in mind that only primitive types are allowed in this case (at this time) // Keep in mind that only primitive types are allowed in this case (at this time)
left.codeGen(mv); left.codeGen(mv, typeContext, localVars);
right.codeGen(mv); right.codeGen(mv, typeContext, localVars);
mv.visitJumpInsn(Opcodes.IF_ICMPEQ, operationTrue); // If the two values are equal, jump to the end of the expression mv.visitJumpInsn(Opcodes.IF_ICMPEQ, operationTrue); // If the two values are equal, jump to the end of the expression
break; break;
case "<": case "<":
left.codeGen(mv); left.codeGen(mv, typeContext, localVars);
right.codeGen(mv); right.codeGen(mv, typeContext, localVars);
mv.visitJumpInsn(Opcodes.IF_ICMPLT, operationTrue); // Checks only on less than, not equal mv.visitJumpInsn(Opcodes.IF_ICMPLT, operationTrue); // Checks only on less than, not equal
break; break;
case ">": case ">":
left.codeGen(mv); left.codeGen(mv, typeContext, localVars);
right.codeGen(mv); right.codeGen(mv, typeContext, localVars);
mv.visitJumpInsn(Opcodes.IF_ICMPGT, operationTrue); // Checks only on greater than, not equal mv.visitJumpInsn(Opcodes.IF_ICMPGT, operationTrue); // Checks only on greater than, not equal
break; break;
case "<=": case "<=":
left.codeGen(mv); left.codeGen(mv, typeContext, localVars);
right.codeGen(mv); right.codeGen(mv, typeContext, localVars);
mv.visitJumpInsn(Opcodes.IF_ICMPLE, operationTrue); // Checks on less than OR equal mv.visitJumpInsn(Opcodes.IF_ICMPLE, operationTrue); // Checks on less than OR equal
break; break;
case ">=": case ">=":
left.codeGen(mv); left.codeGen(mv, typeContext, localVars);
right.codeGen(mv); right.codeGen(mv, typeContext, localVars);
mv.visitJumpInsn(Opcodes.IF_ICMPGE, operationTrue); // Checks on greater than OR equal mv.visitJumpInsn(Opcodes.IF_ICMPGE, operationTrue); // Checks on greater than OR equal
break; break;
case "!=": case "!=":
left.codeGen(mv); left.codeGen(mv, typeContext, localVars);
right.codeGen(mv); right.codeGen(mv, typeContext, localVars);
mv.visitJumpInsn(Opcodes.IF_ICMPNE, operationTrue); // Checks on not equal mv.visitJumpInsn(Opcodes.IF_ICMPNE, operationTrue); // Checks on not equal
break; break;
case "+": case "+":
left.codeGen(mv); left.codeGen(mv, typeContext, localVars);
right.codeGen(mv); right.codeGen(mv, typeContext, localVars);
mv.visitInsn(Opcodes.IADD); mv.visitInsn(Opcodes.IADD);
break; break;
case "-": case "-":
left.codeGen(mv); left.codeGen(mv, typeContext, localVars);
right.codeGen(mv); right.codeGen(mv, typeContext, localVars);
mv.visitInsn(Opcodes.ISUB); mv.visitInsn(Opcodes.ISUB);
break; break;
case "*": case "*":
left.codeGen(mv); left.codeGen(mv, typeContext, localVars);
right.codeGen(mv); right.codeGen(mv, typeContext, localVars);
mv.visitInsn(Opcodes.IMUL); mv.visitInsn(Opcodes.IMUL);
break; break;
case "/": case "/":
left.codeGen(mv); left.codeGen(mv, typeContext, localVars);
right.codeGen(mv); right.codeGen(mv, typeContext, localVars);
mv.visitInsn(Opcodes.IDIV); mv.visitInsn(Opcodes.IDIV);
break; break;

View File

@ -5,6 +5,7 @@ import abstractSyntaxTree.Parameter.ParameterList;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap;
public interface IExpression { public interface IExpression {
// typeCheck method // typeCheck method
@ -12,5 +13,5 @@ public interface IExpression {
TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception; TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception;
// visit method for code generation // visit method for code generation
void codeGen(MethodVisitor mv) throws Exception; void codeGen(MethodVisitor mv, HashMap<String, HashMap<String, String>> typeContext, LinkedHashMap<String, String> localVars) throws Exception;
} }

View File

@ -5,15 +5,17 @@ import abstractSyntaxTree.Class.RefType;
import abstractSyntaxTree.Parameter.ParameterList; import abstractSyntaxTree.Parameter.ParameterList;
import jdk.jshell.spi.ExecutionControl; import jdk.jshell.spi.ExecutionControl;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap;
public class InstVarExpression implements IExpression{ public class InstVarExpression implements IExpression{
//TODO: We have to decide upon more parameters and where they come from, for //TODO: We have to decide upon more parameters and where they come from, for
// example here we need the index of the field, the class reference and the field name // example here we need the index of the field, the class reference and the field name
private RefType classRef; public RefType classRef;
private String fieldName; public String fieldName;
public InstVarExpression(RefType classRef, String fieldName){ public InstVarExpression(RefType classRef, String fieldName){
this.classRef = classRef; this.classRef = classRef;
@ -29,11 +31,33 @@ public class InstVarExpression implements IExpression{
} }
@Override @Override
public void codeGen(MethodVisitor mv) throws Exception { // typeContext: (ClassName, (FieldName, FieldType))
throw new ExecutionControl.NotImplementedException("CodeGen not implemented for InstVarExpression"); public void codeGen(MethodVisitor mv, HashMap<String, HashMap<String, String>> typeContext, LinkedHashMap<String, String> localVars) throws Exception {
// Load "this" onto the stack
mv.visitVarInsn(Opcodes.ALOAD, 0);
//ALOAD the index of the var //Get the field information
//GETFIELD the field String fieldType = typeContext.get(classRef.name).get(fieldName);
//visitFieldInsn(Opcodes.GETFIELD, "class reference", "field name", type);
String fieldDescriptor;
switch (fieldType) {
case "int":
fieldDescriptor = "I";
break;
case "boolean":
fieldDescriptor = "Z";
break;
case "char":
fieldDescriptor = "C";
break;
default:
//TODO: We need the fully qualified name of the class here in field type
fieldDescriptor = "L" + fieldType + ";";
break;
}
// Load the variable onto the stack
mv.visitFieldInsn(Opcodes.GETFIELD, classRef.name, fieldName, fieldDescriptor);
} }
} }

View File

@ -2,7 +2,10 @@ package abstractSyntaxTree.Expression;
import TypeCheck.TypeCheckHelper; import TypeCheck.TypeCheckHelper;
import TypeCheck.TypeCheckResult; import TypeCheck.TypeCheckResult;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.*;
import java.util.HashMap;
import java.util.LinkedHashMap;
public class LocalVarIdentifier implements IExpression{ public class LocalVarIdentifier implements IExpression{
@ -21,7 +24,41 @@ public class LocalVarIdentifier implements IExpression{
} }
@Override @Override
public void codeGen(MethodVisitor mv) throws Exception { public void codeGen(MethodVisitor mv, HashMap<String, HashMap<String, String>> typeContext, LinkedHashMap<String, String> localVars) throws Exception {
// Check if the variable is in the list of local variables
String type = localVars.get(identifier);
if (type == null){
throw new Exception("Variable " + identifier + " not declared");
}
// Load the variable onto the stack
int index = -1;
int counter = 0;
for (String key : localVars.keySet()){
if (key.equals(identifier)){
index = counter;
break;
}
counter++;
}
if (index == -1){
throw new Exception("Variable " + identifier + " not found");
}
// Load the variable onto the stack
switch (type){
case "int":
mv.visitVarInsn(Opcodes.ILOAD, index);
break;
case "bool":
mv.visitVarInsn(Opcodes.ILOAD, index);
break;
case "void":
break;
default:
mv.visitVarInsn(Opcodes.ALOAD, index);
break;
}
} }
} }

View File

@ -7,6 +7,8 @@ import abstractSyntaxTree.Datatype.IDatatype;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Objects; import java.util.Objects;
public class UnaryExpression extends AbstractType implements IExpression{ public class UnaryExpression extends AbstractType implements IExpression{
@ -47,7 +49,7 @@ public class UnaryExpression extends AbstractType implements IExpression{
} }
@Override @Override
public void codeGen(MethodVisitor mv) throws Exception { public void codeGen(MethodVisitor mv, HashMap<String, HashMap<String, String>> typeContext, LinkedHashMap<String, String> localVars) throws Exception {
operand.codeGen(mv); operand.codeGen(mv);

View File

@ -6,11 +6,14 @@ import abstractSyntaxTree.Parameter.ParameterList;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
public interface IStatement extends Node { public interface IStatement extends Node {
TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception; TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, String> localVars) throws Exception;
void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception; void codeGen(MethodVisitor mv, LinkedHashMap<String, String> localVars) throws Exception;
void codeGen(MethodVisitor mv, LinkedHashMap<String, String> localVars, HashMap<String, HashMap<String, String>> typeContext) throws Exception;
} }

View File

@ -32,5 +32,24 @@ public class LocalVarDecl implements IStatement{
@Override @Override
public void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception { public void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception {
localVars.put(identifier, type); localVars.put(identifier, type);
// Set a default value for the variable --> less problems
int index = localVars.size()-1;
switch (type){
case "int":
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ISTORE, index);
break;
case "bool":
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ISTORE, index);
break;
case "void":
break;
default:
mv.visitInsn(Opcodes.ACONST_NULL);
mv.visitVarInsn(Opcodes.ASTORE, index);
}
} }
} }

View File

@ -8,16 +8,16 @@ import abstractSyntaxTree.Expression.InstVarExpression;
import abstractSyntaxTree.Expression.LocalVarIdentifier; import abstractSyntaxTree.Expression.LocalVarIdentifier;
import abstractSyntaxTree.Parameter.ParameterList; import abstractSyntaxTree.Parameter.ParameterList;
import abstractSyntaxTree.Statement.IStatement; import abstractSyntaxTree.Statement.IStatement;
import abstractSyntaxTree.Statement.LocalVarDecl;
import org.objectweb.asm.*; import org.objectweb.asm.*;
import java.util.HashMap; import java.util.HashMap;
import java.util.Objects; import java.util.LinkedHashMap;
public class AssignStatementExpression extends AbstractType implements IExpression, IStatement { public class AssignStatementExpression extends AbstractType implements IExpression, IStatement {
public String operator; public String operator;
public IExpression left; public IExpression left;
public IExpression right; public IExpression right;
private InstVarExpression instVar;
public AssignStatementExpression(String operator, IExpression leftExpression, IExpression rightExpression){ public AssignStatementExpression(String operator, IExpression leftExpression, IExpression rightExpression){
this.operator = operator; this.operator = operator;
@ -50,37 +50,70 @@ public class AssignStatementExpression extends AbstractType implements IExpressi
return result; return result;
} }
@Override
public void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception {
if (left instanceof LocalVarIdentifier) {
LocalVarIdentifier localVar = (LocalVarIdentifier) left;
String varName = localVar.getIdentifier();
//Get the index of the local variable
int varIndex = localVars.get(varName)
}
}
public TypeCheckResult typeCheck() throws Exception { public TypeCheckResult typeCheck() throws Exception {
return null; return null;
} }
@Override @Override
public void codeGen(MethodVisitor mv) throws Exception { public void codeGen(MethodVisitor mv, HashMap<String, HashMap<String, String>> typeContext, LinkedHashMap<String, String> localVars) throws Exception {
left.codeGen(mv); //TODO: Do we need the value on the stack after assigning it?
right.codeGen(mv); //TODO: WE do not differentiate between InstanceVar and FieldVar
// if (left instanceof VarRefExpression varRef) { // Call the codeGen on the right expression which will push the value of the right expression onto the stack
// //TODO: Implement the handling of a variable reference --> I need a list of local variables right.codeGen(mv, typeContext, localVars);
// // for that to determine if the variable is a local or field variable
// } else if (left instanceof InstVarExpression instVar) { if (left instanceof LocalVarIdentifier) {
// mv.visitInsn(Opcodes.DUP_X1); LocalVarIdentifier localVar = (LocalVarIdentifier) left;
// String varName = localVar.getIdentifier();
// // We now again need the owner (class reference), name (of the Field in the owner) and type of the field
// //mv.visitFieldInsn(Opcodes.PUTFIELD, instVar.className, instVar.varName, instVar.type); //Get the index of the local variable
// } int index = -1;
int counter = 0;
for (String key : localVars.keySet()){
if (key.equals(varName)){
index = counter;
break;
}
counter++;
}
if (index == -1){
throw new Exception("Variable " + varName + " not found");
}
String type = localVars.get(localVar.getIdentifier());
switch (type) {
case "int":
case "bool":
mv.visitVarInsn(Opcodes.ISTORE, index);
break;
default:
mv.visitVarInsn(Opcodes.ASTORE, index);
break;
}
} else if (left instanceof InstVarExpression){
instVar = (InstVarExpression) left;
// Load "this" onto the stack
mv.visitVarInsn(Opcodes.ALOAD, 0);
String fieldType = typeContext.get(instVar.classRef.name).get(instVar.fieldName);
String fieldDescriptor;
switch (fieldType) {
case "int":
fieldDescriptor = "I";
break;
case "boolean":
fieldDescriptor = "Z";
break;
default:
//TODO: We need the fully qualified name of the class here in field type
fieldDescriptor = "L" + fieldType + ";";
break;
}
mv.visitFieldInsn(Opcodes.PUTFIELD, instVar.classRef.name, instVar.fieldName, fieldDescriptor);
}
} }
} }

View File

@ -12,6 +12,7 @@ import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
public class MethodCallStatementExpression extends AbstractType implements IExpression, IStatement { public class MethodCallStatementExpression extends AbstractType implements IExpression, IStatement {
@ -50,27 +51,44 @@ public class MethodCallStatementExpression extends AbstractType implements IExpr
return null; return null;
} }
@Override
public void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception {
}
//Errors occur due to the change in parameter in the RefType class //Errors occur due to the change in parameter in the RefType class
// I need the methodContext here to get the method descriptor
@Override @Override
public void codeGen(MethodVisitor mv) throws Exception { public void codeGen(MethodVisitor mv, HashMap<String, HashMap<String, String>> typeContext, LinkedHashMap<String, String> localVars) throws Exception {
//Generate Bytecode for the receiver //Generate Bytecode for the receiver
if(classThatHasTheMethodIfNotThis != null){ if(classThatHasTheMethodIfNotThis != null){
// classThatHasTheMethodIfNotThis.codeGen(new ClassWriter(ClassWriter.COMPUTE_FRAMES)); //TODO: classThatHasTheMethodIfNotThis must be an object --> instance of the class not the class itself
//classThatHasTheMethodIfNotThis.codeGen();
String descriptor;
List<MethodDecl> 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 { } else {
// Load this onto the stack
mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitVarInsn(Opcodes.ALOAD, 0);
} }
for (IExpression argument : arguments) { for (IExpression argument : arguments) {
argument.codeGen(mv); argument.codeGen(mv, typeContext, localVars);
} }
//We need the class reference and the return type of the method // Get the method descriptor
//mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, thisClass.name, methodName, return type); String descriptor;
List<MethodDecl> methodDecls = thisClass.methodDecls;
for (MethodDecl methodDecl : methodDecls) {
if (methodDecl.name.equals(methodName)) {
//Get the method descriptor
descriptor = methodDecl.getMethodDescriptor(methodContext);
}
}
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, thisClass.name, methodName, descriptor, false);
} }
} }