Updated the codeGen Methods in FieldDecl, MethodDecl and BlockStatement

This commit is contained in:
Jochen Seyfried 2024-05-13 21:04:09 +02:00
parent cc05c58159
commit b5b6f763e0
10 changed files with 128 additions and 11 deletions

View File

@ -6,6 +6,8 @@ import TypeCheck.TypeCheckResult;
import abstractSyntaxTree.Node; import abstractSyntaxTree.Node;
import abstractSyntaxTree.Program; import abstractSyntaxTree.Program;
import org.objectweb.asm.ClassWriter; import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Opcodes;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -39,6 +41,22 @@ public class FieldDecl extends AbstractType implements IClass, Node {
@Override @Override
public void codeGen(ClassWriter cw) { public void codeGen(ClassWriter cw) {
//TODO: Do we have fields with initial values?
FieldVisitor fv = cw.visitField(Opcodes.ACC_PUBLIC, identifier, getFieldDescriptor(), null, null);
fv.visitEnd();
}
private String getFieldDescriptor() {
//TODO: Maybe we have to check for arrays?
switch (type) {
case "int":
return "I";
case "boolean":
return "Z";
case "char":
return "C";
default:
return "L" + type + ";";
}
} }
} }

View File

@ -2,25 +2,30 @@ package abstractSyntaxTree.Class;
import TypeCheck.TypeCheckResult; import TypeCheck.TypeCheckResult;
import abstractSyntaxTree.Node; import abstractSyntaxTree.Node;
import abstractSyntaxTree.Parameter.Parameter;
import abstractSyntaxTree.Parameter.ParameterList; import abstractSyntaxTree.Parameter.ParameterList;
import abstractSyntaxTree.Program; import abstractSyntaxTree.Program;
import abstractSyntaxTree.Statement.BlockStatement; import abstractSyntaxTree.Statement.BlockStatement;
import abstractSyntaxTree.Statement.IStatement; import abstractSyntaxTree.Statement.IStatement;
import org.objectweb.asm.ClassWriter; import org.objectweb.asm.*;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Stack;
public class MethodDecl implements IClass, Node { public class MethodDecl implements IClass, Node {
//Class Name
public String classThatContainsMethod; public String classThatContainsMethod;
//Method Name
public String name; public String name;
public ParameterList parameters; public ParameterList parameters;
public String returnType; public String returnType;
public BlockStatement codeBlock; public BlockStatement codeBlock;
public Map<String, String> localVars; public HashMap<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;
@ -28,6 +33,7 @@ public class MethodDecl implements IClass, Node {
this.name = name; this.name = name;
this.parameters = parameters; this.parameters = parameters;
this.codeBlock = codeBlock; this.codeBlock = codeBlock;
this.localVars = new HashMap<>();
} }
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext) throws Exception { public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext) throws Exception {
@ -40,5 +46,92 @@ public class MethodDecl implements IClass, Node {
@Override @Override
public void codeGen(ClassWriter cw) throws Exception { public void codeGen(ClassWriter cw) throws Exception {
localVars.put("this", classThatContainsMethod);
for (Parameter param : parameters.parameterList) {
localVars.put(param.identifier, param.type);
}
// check if the method is a constructor
if (classThatContainsMethod.equals(name) && returnType == null) {
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", getMethodDescriptor(), null, null);
//Call the superclass constructor
mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
mv.visitCode();
codeBlock.codeGen(mv, localVars); //TODO: pass the local vars? --> codeGen for block not yet implemented
mv.visitInsn(Opcodes.RETURN);
//automatically computed max stack and max locals
mv.visitMaxs(0, 0);
mv.visitEnd();
} else if (name.equals("main")) { //TODO: Check how we distinguish the main method
int access = Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC;
MethodVisitor mv = cw.visitMethod(access, name, "([Ljava/lang/String;)V", null, null);
mv.visitCode();
codeBlock.codeGen(mv, localVars); //TODO: pass the local vars? --> codeGen for block not yet implemented
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
} else {
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, name, getMethodDescriptor(), null, null);
mv.visitCode();
codeBlock.codeGen(mv, localVars); //TODO: pass the local vars? --> codeGen for block not yet implemented
// We have to check the return type to get the return opcode
// For methods which return an actual value, the return opcode is created in the method body to ensure the
// correct return value is on the stack
if (returnType.equals("void")) mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
}
private String getMethodDescriptor() {
// get the method descriptor
StringBuilder descriptor = new StringBuilder("(");
// Iterate over the parameters and add them to the descriptor
for (Parameter param : parameters.parameterList) {
switch (param.type) {
case "int" -> descriptor.append("I");
case "boolean" -> descriptor.append("Z");
case "char" -> descriptor.append("C");
case "void" -> descriptor.append("V");
default ->
// object
//TODO: This is not finished
descriptor.append("L").append(param.type).append(";");
}
}
descriptor.append(")");
// Get the return type
// If the return type is null, it is a constructor and we need to append V
if (returnType == null) {
descriptor.append("V");
} else {
switch (returnType) {
case "int" -> descriptor.append("I");
case "boolean" -> descriptor.append("Z");
case "char" -> descriptor.append("C");
case "void" -> descriptor.append("V");
//TODO: This is not finished --> we need to append the fully qualified name of the object
// Need to make sure what we get
default ->
// object
descriptor.append("L").append(returnType).append(";");
}
}
return descriptor.toString();
} }
} }

View File

@ -12,10 +12,10 @@ import java.util.List;
public class RefType extends AbstractType implements IClass, Node { public class RefType extends AbstractType implements IClass, Node {
//Class Name
public String name; public String name;
public List<FieldDecl> fieldDecls; public List<FieldDecl> fieldDecls;
public List<MethodDecl> methodDecls; public List<MethodDecl> methodDecls;
private boolean hasMain;
public RefType(String name, public RefType(String name,
List<FieldDecl> fieldDecls, List<FieldDecl> fieldDecls,

View File

@ -46,9 +46,15 @@ public class BlockStatement extends AbstractType implements IStatement{
} }
@Override @Override
public void codeGen(MethodVisitor mv) throws Exception { public void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception {
// Create a new HashMap for the local variables of the block
// It has every variable of the parent block
// This Map is discarded at the end of the block
//TODO: Do this for every block --> if, while, ...
HashMap<String, String> blockLocalVars = new HashMap<>(localVars);
for (IStatement statement : statements) { for (IStatement statement : statements) {
statement.codeGen(mv); //TODO: I think we need to pass the symbol table here statement.codeGen(mv, blockLocalVars);
} }
} }
} }

View File

@ -21,7 +21,7 @@ public class EmptyStatement extends AbstractType implements IStatement{
} }
@Override @Override
public void codeGen(MethodVisitor mv) throws Exception { public void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception {
//An empty statement does not generate any code //An empty statement does not generate any code
} }
} }

View File

@ -14,5 +14,5 @@ public interface IStatement {
TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext) throws Exception; TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext, HashMap<String, HashMap<String, String>> typeContext) throws Exception;
void codeGen(MethodVisitor mv) throws Exception; void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception;
} }

View File

@ -46,7 +46,7 @@ public class IfElseStatement extends AbstractType implements IStatement{
} }
@Override @Override
public void codeGen(MethodVisitor mv) throws Exception { public void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception {
Label conditionFalse = new Label(); Label conditionFalse = new Label();
Label statementEnd = new Label(); Label statementEnd = new Label();

View File

@ -39,7 +39,7 @@ public class IfStatement extends AbstractType implements IStatement{
} }
@Override @Override
public void codeGen(MethodVisitor mv) throws Exception { public void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception {
Label conditionFalse = new Label(); Label conditionFalse = new Label();

View File

@ -39,7 +39,7 @@ public class ReturnStatement extends AbstractType implements IStatement{
// This is a problem at "BinaryExpression" and here because we need to know the type to return // This is a problem at "BinaryExpression" and here because we need to know the type to return
// At this point in time we can either return reference types or have an error message // At this point in time we can either return reference types or have an error message
@Override @Override
public void codeGen(MethodVisitor mv) throws Exception { public void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception {
if (expression != null) { if (expression != null) {
expression.codeGen(mv); expression.codeGen(mv);

View File

@ -39,7 +39,7 @@ public class WhileStatement extends AbstractType implements IStatement {
} }
@Override @Override
public void codeGen(MethodVisitor mv) throws Exception { public void codeGen(MethodVisitor mv, HashMap<String, String> localVars) throws Exception {
Label conditionFalse = new Label(); Label conditionFalse = new Label();
Label LoopStart = new Label(); Label LoopStart = new Label();