Compare commits
8 Commits
3b2a328182
...
d1da1c6eee
Author | SHA1 | Date | |
---|---|---|---|
|
d1da1c6eee | ||
|
b787b333fb | ||
|
27ca4a978f | ||
|
289231030a | ||
|
127726d342 | ||
|
34f4f307f3 | ||
|
c30dcdb773 | ||
|
66c7722728 |
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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 + ";";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user