Compare commits

...

8 Commits

Author SHA1 Message Date
Jochen Seyfried
d1da1c6eee Deleted TODOs which are done 2024-06-28 20:31:21 +02:00
Jochen Seyfried
b787b333fb Fixed usage of fields 2024-06-28 20:29:58 +02:00
Jochen Seyfried
27ca4a978f Updated the handling of fields 2024-06-28 20:16:19 +02:00
Jochen Seyfried
289231030a Merge remote-tracking branch 'origin/master' 2024-06-28 19:46:45 +02:00
Jochen Seyfried
127726d342 Merge remote-tracking branch 'origin/master' 2024-06-28 19:36:24 +02:00
Jochen Seyfried
34f4f307f3 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	src/main/java/abstractSyntaxTree/Program.java
2024-06-28 18:44:47 +02:00
Jochen Seyfried
c30dcdb773 Updated switch statements in case of char 2024-06-28 18:44:03 +02:00
Jochen Seyfried
66c7722728 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
2024-06-28 18:23:19 +02:00
6 changed files with 123 additions and 68 deletions

View File

@ -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;
@ -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();
}

View File

@ -54,11 +54,11 @@ 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)))
public void codeGen(ClassWriter cw, HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext) throws Exception {
// typeContext (class, (type, identifier))
public void codeGen(ClassWriter cw, HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext, List<FieldDecl> fieldDecls) throws Exception {
localVars.put("this", classThatContainsMethod);
for (Parameter param : parameters.parameterList) {
@ -73,18 +73,40 @@ public class MethodDecl implements Node {
//Call the superclass constructor
mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
HashMap<String, String> classFields = typeContext.get(classThatContainsMethod);
for (Map.Entry<String, String> 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", "<init>", descriptor, false);
mv.visitCode();
codeBlock.codeGen(mv, localVars, typeContext, methodContext);
@ -171,6 +193,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;

View File

@ -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<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext) throws Exception {
public void codeGen(ClassWriter cw, HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext, HashMap<String, HashMap<String, String>> typeContext) throws Exception {
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, name, null,
"java/lang/Object", null);
@ -88,8 +89,21 @@ public class RefType extends AbstractType implements Node {
field.codeGen(cw);
}
boolean hasCustomConstructor = false;
for (MethodDecl method : methodDecls) {
method.codeGen(cw, methodContext, typeContext);
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, fieldDecls);
}
for (MethodDecl method : methodDecls) {
method.codeGen(cw, methodContext, typeContext, fieldDecls);
}
cw.visitEnd();
}

View File

@ -46,40 +46,60 @@ public class LocalVarIdentifier extends AbstractType implements IExpression{
@Override
public void codeGen(MethodVisitor mv, LinkedHashMap<String, String> localVars, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext) 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");
}
String type = null;
// 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;
// if it's a local variable
if (localVars.containsKey(identifier)) {
type = localVars.get(identifier);
// 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){
//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":
mv.visitVarInsn(Opcodes.ILOAD, index);
break;
return "I";
case "boolean":
mv.visitVarInsn(Opcodes.ILOAD, index);
break;
case "void":
break;
return "Z";
case "char":
return "C";
default:
mv.visitVarInsn(Opcodes.ALOAD, index);
break;
return "L" + type + ";";
}
}

View File

@ -42,6 +42,7 @@ public class Program implements Node {
typeContext.put(oneClass.name, classVars);
// build method context
HashMap<String, HashMap<String, ParameterList>> identifierAndMethod = new HashMap<>();
for (MethodDecl methodDecl : oneClass.methodDecls){
if(methodDecl.returnType == null) continue;
@ -52,15 +53,14 @@ public class Program implements Node {
methodContext.put(oneClass.name, identifierAndMethod);
}
int mainCounter = 0;
// check if main exists
for(RefType oneClass : classes){
if(oneClass.hasMain)
mainCounter++;
}
// if(mainCounter != 1)
// throw new TypeCheckException("There is not 1 Main method.");
if(mainCounter != 1)
throw new TypeCheckException("There is not 1 Main method.");
// typecheck each class
TypeCheckResult result = new TypeCheckResult();
@ -72,7 +72,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);
@ -88,30 +88,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

View File

@ -55,7 +55,19 @@ public class LocalVarDecl extends AbstractType implements IStatement{
public void codeGen(MethodVisitor mv, LinkedHashMap<String, String> localVars, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext) throws Exception {
localVars.put(identifier, type);
int index = localVars.size() - 1;
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++;
}
if (index == -1){
throw new Exception("Variable " + identifier + " not found");
}
if (expression != null) {
expression.codeGen(mv, localVars, typeContext,methodContext);
@ -72,11 +84,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;