Merge pull request 'code-generator' (#5) from code-generator into main

Reviewed-on: #5
Reviewed-by: Johannes Ehlert <i22005@hb.dhbw-stuttgart.de>
This commit is contained in:
Johannes Ehlert 2024-05-14 09:04:37 +00:00
commit 8e7b64c38d
15 changed files with 147 additions and 27 deletions

View File

@ -37,6 +37,6 @@ public class Main {
SemanticAnalyzer.generateTast(ast); SemanticAnalyzer.generateTast(ast);
ByteCodeGenerator byteCodeGenerator = new ByteCodeGenerator(); ByteCodeGenerator byteCodeGenerator = new ByteCodeGenerator();
byteCodeGenerator.generateByteCode(ast); byteCodeGenerator.visit(ast);
} }
} }

View File

@ -7,6 +7,8 @@ import ast.type.EnumAccessTypeNode;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import bytecode.visitor.ClassVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
import typechecker.Visitable; import typechecker.Visitable;
@ -40,4 +42,9 @@ public class ClassNode extends ASTNode implements Visitable {
public TypeCheckResult accept(SemanticVisitor visitor) { public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.typeCheck(this); return visitor.typeCheck(this);
} }
@Override
public void accept(ClassVisitor classVisitor) {
classVisitor.visit(this);
}
} }

View File

@ -2,11 +2,13 @@ package ast;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import bytecode.visitor.ProgramVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
import typechecker.Visitable; import typechecker.Visitable;
public class ProgramNode extends ASTNode implements Visitable{ public class ProgramNode extends ASTNode implements Visitable {
public List<ClassNode> classes = new ArrayList<>(); public List<ClassNode> classes = new ArrayList<>();
public void addClass(ClassNode classNode) { public void addClass(ClassNode classNode) {
@ -17,4 +19,9 @@ public class ProgramNode extends ASTNode implements Visitable{
public TypeCheckResult accept(SemanticVisitor visitor) { public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.typeCheck(this); return visitor.typeCheck(this);
} }
@Override
public void accept(ProgramVisitor programVisitor) {
programVisitor.visit(this);
}
} }

View File

@ -1,9 +1,16 @@
package ast.member; package ast.member;
import ast.type.AccessTypeNode; import ast.type.AccessTypeNode;
import bytecode.visitor.MethodVisitor;
import typechecker.Visitable;
public class ConstructorNode extends MethodNode { public class ConstructorNode extends MethodNode implements Visitable {
public ConstructorNode(AccessTypeNode visibility, String name) { public ConstructorNode(AccessTypeNode visibility, String name) {
super(visibility, name); super(visibility, name);
} }
@Override
public void accept(MethodVisitor methodVisitor) {
methodVisitor.visit(this);
}
} }

View File

@ -2,6 +2,7 @@ package ast.member;
import ast.type.AccessTypeNode; import ast.type.AccessTypeNode;
import ast.type.TypeNode; import ast.type.TypeNode;
import bytecode.visitor.ClassVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
import typechecker.Visitable; import typechecker.Visitable;
@ -21,4 +22,9 @@ public class FieldNode extends MemberNode implements Visitable {
public TypeCheckResult accept(SemanticVisitor visitor) { public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.typeCheck(this); return visitor.typeCheck(this);
} }
@Override
public void accept(ClassVisitor classVisitor) {
classVisitor.visit(this);
}
} }

View File

@ -7,6 +7,8 @@ import ast.type.TypeNode;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import bytecode.visitor.MethodVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
import typechecker.TypeCheckResult; import typechecker.TypeCheckResult;
import typechecker.Visitable; import typechecker.Visitable;
@ -38,4 +40,9 @@ public class MethodNode extends MemberNode implements Visitable {
public TypeCheckResult accept(SemanticVisitor visitor) { public TypeCheckResult accept(SemanticVisitor visitor) {
return visitor.typeCheck(this); return visitor.typeCheck(this);
} }
@Override
public void accept(MethodVisitor methodVisitor) {
methodVisitor.visit(this);
}
} }

View File

@ -2,13 +2,15 @@ package bytecode;
import ast.ProgramNode; import ast.ProgramNode;
import ast.ClassNode; import ast.ClassNode;
import bytecode.visitor.ProgramVisitor;
public class ByteCodeGenerator { public class ByteCodeGenerator implements ProgramVisitor {
public void generateByteCode(ProgramNode ast) { @Override
for (ClassNode classDeclarationNode : ast.classes) { public void visit(ProgramNode programNode) {
for (ClassNode classDeclarationNode : programNode.classes) {
ClassCodeGen classCodeGen = new ClassCodeGen(); ClassCodeGen classCodeGen = new ClassCodeGen();
classCodeGen.generateClassCode(classDeclarationNode); classDeclarationNode.accept(classCodeGen);
} }
} }
} }

View File

@ -4,6 +4,7 @@ import ast.ClassNode;
import ast.member.FieldNode; import ast.member.FieldNode;
import ast.member.MemberNode; import ast.member.MemberNode;
import ast.member.MethodNode; import ast.member.MethodNode;
import bytecode.visitor.ClassVisitor;
import java.io.File; import java.io.File;
import org.objectweb.asm.ClassWriter; import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
@ -11,20 +12,22 @@ import org.objectweb.asm.Opcodes;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
public class ClassCodeGen { public class ClassCodeGen implements ClassVisitor {
public void generateClassCode(ClassNode classNode) { Mapper mapper = new Mapper();
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); ClassWriter classWriter;
Mapper mapper = new Mapper();
@Override
public void visit(ClassNode classNode) {
classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
classWriter.visit(Opcodes.V1_8, mapper.mapAccesTypeToOpcode(classNode.accessType), classNode.identifier, null, classWriter.visit(Opcodes.V1_8, mapper.mapAccesTypeToOpcode(classNode.accessType), classNode.identifier, null,
"java/lang/Object", null); "java/lang/Object", null);
for (MemberNode memberNode : classNode.members) { for (MemberNode memberNode : classNode.members) {
if (memberNode instanceof FieldNode) { if (memberNode instanceof FieldNode) {
FieldCodeGen fieldCodeGen = new FieldCodeGen(); visit((FieldNode) memberNode);
fieldCodeGen.generateFieldCode(classWriter, (FieldNode) memberNode);
} else if (memberNode instanceof MethodNode) { } else if (memberNode instanceof MethodNode) {
MethodCodeGen methodCodeGen = new MethodCodeGen(); MethodCodeGen methodCodeGen = new MethodCodeGen(classWriter);
methodCodeGen.generateMethodCode(classWriter, (MethodNode) memberNode); ((MethodNode) memberNode).accept(methodCodeGen);
} }
} }
@ -34,6 +37,12 @@ public class ClassCodeGen {
classWriter.visitEnd(); classWriter.visitEnd();
} }
@Override
public void visit(FieldNode fieldNode) {
classWriter.visitField(mapper.mapAccesTypeToOpcode(fieldNode.accessTypeNode), fieldNode.identifier, mapper.getTypeChar(fieldNode.type.enumTypeNode), null, null );
classWriter.visitEnd();
}
private void printIntoClassFile(byte[] byteCode, String name) { private void printIntoClassFile(byte[] byteCode, String name) {
String directoryPath = "src/main/java/classFileOutput"; String directoryPath = "src/main/java/classFileOutput";
File directory = new File(directoryPath); File directory = new File(directoryPath);

View File

@ -2,6 +2,8 @@ package bytecode;
import ast.type.AccessTypeNode; import ast.type.AccessTypeNode;
import ast.type.EnumAccessTypeNode; import ast.type.EnumAccessTypeNode;
import ast.type.EnumTypeNode;
import ast.type.TypeNode;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
public class Mapper { public class Mapper {
@ -14,4 +16,26 @@ public class Mapper {
} }
return 0; return 0;
} }
public String generateMethodDescriptor(TypeNode typeNode) {
String descriptor = "()";
descriptor += getTypeChar(typeNode.enumTypeNode);
return descriptor;
}
public String getTypeChar(EnumTypeNode enumTypeNode) {
String typeChar = "";
switch (enumTypeNode) {
case EnumTypeNode.INT:
typeChar = "I";
break;
case EnumTypeNode.CHAR:
typeChar = "C";
break;
case EnumTypeNode.BOOLEAN:
typeChar = "Z";
break;
}
return typeChar;
}
} }

View File

@ -1,17 +1,38 @@
package bytecode; package bytecode;
import ast.member.ConstructorNode;
import ast.member.MethodNode; import ast.member.MethodNode;
import org.objectweb.asm.ClassWriter; import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
public class MethodCodeGen { public class MethodCodeGen implements bytecode.visitor.MethodVisitor {
public void generateMethodCode(ClassWriter classWriter, MethodNode methodNode) {
Mapper mapper = new Mapper(); private ClassWriter classWriter;
Mapper mapper = new Mapper();
public MethodCodeGen(ClassWriter classWriter) {
this.classWriter = classWriter;
}
@Override
public void visit(ConstructorNode constructorNode) {
MethodVisitor constructor = MethodVisitor constructor =
classWriter.visitMethod(mapper.mapAccesTypeToOpcode(methodNode.visibility), classWriter.visitMethod(mapper.mapAccesTypeToOpcode(constructorNode.visibility),
"<init>", "<init>",
"()V", "()V",
null, null,
null); null);
constructor.visitEnd();
}
@Override
public void visit(MethodNode methodNode) {
MethodVisitor method = classWriter.visitMethod(mapper.mapAccesTypeToOpcode(methodNode.visibility),
methodNode.identifier,
mapper.generateMethodDescriptor(methodNode.type),
null,
null);
method.visitEnd();
} }
} }

View File

@ -0,0 +1,10 @@
package bytecode.visitor;
import ast.ClassNode;
import ast.member.FieldNode;
import org.objectweb.asm.ClassWriter;
public interface ClassVisitor {
void visit(ClassNode classNode);
void visit(FieldNode fieldNode);
}

View File

@ -0,0 +1,9 @@
package bytecode.visitor;
import ast.member.ConstructorNode;
import ast.member.MethodNode;
public interface MethodVisitor {
void visit(ConstructorNode constructorNode);
void visit(MethodNode methodNode);
}

View File

@ -0,0 +1,7 @@
package bytecode.visitor;
import ast.ProgramNode;
public interface ProgramVisitor {
void visit(ProgramNode programNode);
}

View File

@ -1,16 +1,20 @@
package typechecker; package typechecker;
import bytecode.visitor.ClassVisitor;
import bytecode.visitor.MethodVisitor;
import bytecode.visitor.ProgramVisitor;
import semantic.SemanticVisitor; import semantic.SemanticVisitor;
public interface Visitable { public interface Visitable {
// default void accept(ProgramCodeVisitor visitor) { default void accept(ProgramVisitor programVisitor) {
// }
// }
// default void accept(ClassCodeVisitor visitor) { default void accept(ClassVisitor classVisitor) {
// }
// }
// default void accept(MethodCodeVisitor visitor) { default void accept(MethodVisitor methodVisitor) {
// }
}
TypeCheckResult accept(SemanticVisitor visitor); TypeCheckResult accept(SemanticVisitor visitor);
} }