Merge remote-tracking branch 'origin/master'

# Conflicts:
#	src/main/java/Compiler.java
#	src/main/java/abstractSyntaxTree/Class/MethodDecl.java
#	src/main/java/abstractSyntaxTree/Class/RefType.java
#	src/main/java/abstractSyntaxTree/Program.java
This commit is contained in:
Krauß, Josefine 2024-05-14 14:48:25 +02:00
commit 74e3cb8016
12 changed files with 611 additions and 441 deletions

3
.idea/.gitignore vendored
View File

@ -2,4 +2,5 @@
/shelf/
/workspace.xml
.idea/
.idea/# GitHub Copilot persisted chat sessions
/copilot/chatSessions

View File

@ -9,6 +9,7 @@ import abstractSyntaxTree.Statement.IStatement;
import abstractSyntaxTree.Statement.LocalVarDecl;
import abstractSyntaxTree.Statement.ReturnStatement;
import abstractSyntaxTree.StatementExpression.AssignStatementExpression;
import astGenerator.ASTGenerator;
import gen.DecafLexer;
import gen.DecafParser;
import org.antlr.v4.runtime.CharStream;
@ -90,15 +91,6 @@ public class Compiler {
// System.out.println(refType.name);
// }
abstractSyntaxTree.classes.get(1).methodDecls.get(0).codeBlock.returnType = "int";
List<IStatement> statementsList = abstractSyntaxTree.classes.get(1).methodDecls.get(0).codeBlock.statements;
statementsList.add(new LocalVarDecl("int", "localInt"));
statementsList.add(new LocalVarDecl("bool", "localBool"));
statementsList.add(new LocalVarDecl("char", "localChar"));
statementsList.add(new AssignStatementExpression("=", new LocalVarIdentifier("localInt"), new UnaryExpression("", new IntDatatype())));
//statementsList.add(new AssignStatementExpression("=", new InstVarExpression(abstractSyntaxTree.classes.get(1)), new UnaryExpression("instVarBool", new BoolDatatype())));
abstractSyntaxTree.classes.get(1).methodDecls.get(0).codeBlock.statements.add(new ReturnStatement(new UnaryExpression("", new IntDatatype())));
abstractSyntaxTree.typeCheck();
abstractSyntaxTree.codeGen();

View File

@ -14,7 +14,7 @@ import java.util.List;
import java.util.Map;
import java.util.Stack;
public class MethodDecl implements Node {
public class MethodDecl implements IClass, Node {
//Class Name
public String classThatContainsMethod;
@ -45,7 +45,10 @@ public class MethodDecl implements Node {
return result;
}
public void codeGen(ClassWriter cw) throws Exception {
//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) throws Exception {
localVars.put("this", classThatContainsMethod);
for (Parameter param : parameters.parameterList) {
@ -54,36 +57,49 @@ public class MethodDecl implements Node {
// check if the method is a constructor
if (classThatContainsMethod.equals(name) && returnType == null) {
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", getMethodDescriptor(), null, null);
String descriptor = getMethodDescriptor(methodContext);
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", descriptor, null, null);
//Call the superclass constructor
mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
//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);
}
localVarIndex++;
}
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", descriptor, false);
mv.visitCode();
codeBlock.codeGen(mv, localVars); //TODO: pass the local vars? --> codeGen for block not yet implemented
codeBlock.codeGen(mv, localVars);
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
} else if (name.equals("main")) {
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
codeBlock.codeGen(mv, localVars);
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
} else {
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, name, getMethodDescriptor(), null, null);
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, name, getMethodDescriptor(methodContext), null, null);
mv.visitCode();
codeBlock.codeGen(mv, localVars); //TODO: pass the local vars? --> codeGen for block not yet implemented
codeBlock.codeGen(mv, localVars);
// 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
@ -95,7 +111,7 @@ public class MethodDecl implements Node {
}
}
private String getMethodDescriptor() {
private String getMethodDescriptor(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext) {
// get the method descriptor
StringBuilder descriptor = new StringBuilder("(");
@ -106,17 +122,18 @@ public class MethodDecl implements Node {
case "boolean" -> descriptor.append("Z");
case "char" -> descriptor.append("C");
case "void" -> descriptor.append("V");
default ->
default -> {
// object
//TODO: This is not finished
descriptor.append("L").append(param.type).append(";");
//TODO: This is not finished for objects --> classes and methods
if (returnType != null) descriptor.append("L").append(returnType).append(";");
}
}
}
descriptor.append(")");
// Get the return type
// If the return type is null, it is a constructor and we need to append V
// If the return type is null, it is a constructor, and we need to append V
if (returnType == null) {
descriptor.append("V");
} else {
@ -125,12 +142,20 @@ public class MethodDecl implements Node {
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 ->
default -> {
// object
descriptor.append("L").append(returnType).append(";");
HashMap<String, HashMap<String, ParameterList>> classMethods = methodContext.get(classThatContainsMethod);
HashMap<String, ParameterList> methodDetails = classMethods.get(name);
String fullReturnType = null;
for (Map.Entry<String, ParameterList> entry : methodDetails.entrySet()) {
fullReturnType = entry.getKey();
}
// If it is a class reference replace the "." with "/" and return it
if (returnType.contains(".")) fullReturnType = fullReturnType.replaceAll("\\.", "/");
if (fullReturnType != null) descriptor.append("L").append(fullReturnType).append(";");
}
}
}
return descriptor.toString();

View File

@ -3,7 +3,6 @@ package abstractSyntaxTree.Class;
import TypeCheck.AbstractType;
import TypeCheck.TypeCheckResult;
import abstractSyntaxTree.Node;
import abstractSyntaxTree.Parameter.ParameterList;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
@ -30,7 +29,7 @@ public class RefType extends AbstractType implements Node {
this.hasMain = hasMain;
}
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext,
public TypeCheckResult typeCheck(HashMap<String, HashMap<String, HashMap<String, List<String>>>> methodContext,
HashMap<String, HashMap<String, String>> typeContext) throws Exception {
TypeCheckResult result = new TypeCheckResult();
@ -74,7 +73,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) throws Exception {
public void codeGen(ClassWriter cw, HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext) throws Exception {
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, name, null,
"java/lang/Object", null);

View File

@ -20,7 +20,7 @@ import java.util.jar.JarOutputStream;
public class Program implements Node {
public List<RefType> classes;
public HashMap<String, HashMap<String, String>> typeContext; // (class, (type, identifier))
public HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext; // (class, (returntype, (identifier, parameter)))
public HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext; // (class, (returntype, (identifier, parameterList)))
public Program(List<RefType> classes){
this.classes = classes;
@ -41,11 +41,11 @@ public class Program implements Node {
typeContext.put(oneClass.name, classVars);
// build method context
HashMap<String, ParameterList> methodIdentifierAndParameter = new HashMap<>();
HashMap<String, HashMap<String, ParameterList>> returnTypeAndMethod = new HashMap<>();
HashMap<String, List<String>> methodIdentifierAndParameter = new HashMap<>();
HashMap<String, HashMap<String, List<String >>> returnTypeAndMethod = new HashMap<>();
for (MethodDecl methodDecl : oneClass.methodDecls){
methodIdentifierAndParameter.put(methodDecl.name, methodDecl.parameters);
methodIdentifierAndParameter.put(methodDecl.name, (List<String>) methodDecl.parameters);
returnTypeAndMethod.put(methodDecl.returnType, methodIdentifierAndParameter);
}
methodContext.put(oneClass.name, returnTypeAndMethod);
@ -66,7 +66,7 @@ public class Program implements Node {
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);
oneClass.codeGen(cw, methodContext);
cw.visitEnd();
byte[] bytecode = cw.toByteArray();

View File

@ -1,3 +1,5 @@
package astGenerator;
import abstractSyntaxTree.Class.FieldDecl;
import abstractSyntaxTree.Class.MethodDecl;
import abstractSyntaxTree.Class.RefType;
@ -7,6 +9,7 @@ import abstractSyntaxTree.Parameter.Parameter;
import abstractSyntaxTree.Parameter.ParameterList;
import abstractSyntaxTree.Program;
import abstractSyntaxTree.Statement.*;
import abstractSyntaxTree.StatementExpression.AssignStatementExpression;
import gen.DecafBaseVisitor;
import gen.DecafParser;
@ -31,6 +34,7 @@ public class ASTGenerator extends DecafBaseVisitor<Node> {
boolean hasMain;
if(ctx.MainMethodDecl() != null) {
hasMain = true;
MethodDecl mainMethod = new MethodDecl(name, "void", "main", new ParameterList(new ArrayList<>()), new BlockStatement(new ArrayList<>(), "void"));
} else {
hasMain = false;
}
@ -66,13 +70,14 @@ public class ASTGenerator extends DecafBaseVisitor<Node> {
public Node visitMethodDecl(DecafParser.MethodDeclContext ctx) {
String type;
String name = ctx.Identifier().getText();
BlockStatement block = (BlockStatement) visitBlock(ctx.block());
ParameterList parameterList = (ParameterList) visit(ctx.parameterList());
if (ctx.Void() != null) {
type = "void";
} else {
type = ctx.type().getText();
}
return new MethodDecl("", type , name, parameterList, new BlockStatement(new ArrayList<>(), "void"));
return new MethodDecl("", type , name, parameterList, block);
}
@Override
@ -101,6 +106,8 @@ public class ASTGenerator extends DecafBaseVisitor<Node> {
return visitBlock(ctx.block());
} else if (ctx.stmtExpr() != null) {
return visitStmtExpr(ctx.stmtExpr());
} else if (ctx.emptyStatement() != null) {
return visitEmptyStatement(ctx.emptyStatement());
}
return null;
}
@ -110,6 +117,16 @@ public class ASTGenerator extends DecafBaseVisitor<Node> {
return new ReturnStatement(new BinaryExpression());
}
@Override
public Node visitBlock(DecafParser.BlockContext ctx) {
List<IStatement> stmts = new ArrayList<>();
for (DecafParser.StatementContext stmt: ctx.statement()) {
Node statement = visitStatement(stmt);
stmts.add((IStatement) statement);
}
return new BlockStatement(stmts, "void");
}
@Override
public Node visitIfElseStmt(DecafParser.IfElseStmtContext ctx) {
if (ctx.elseStmt() != null) {
@ -132,4 +149,37 @@ public class ASTGenerator extends DecafBaseVisitor<Node> {
Node statement = visitStatement(ctx.statement());
return new WhileStatement(new BinaryExpression(), (IStatement) statement);
}
@Override
public Node visitEmptyStatement(DecafParser.EmptyStatementContext ctx) {
return new EmptyStatement();
}
@Override
public Node visitStmtExpr(DecafParser.StmtExprContext ctx) {
if (ctx.assign() != null) {
return visitAssign(ctx.assign());
} else if (ctx.methodCall() != null) {
return visitMethodCall(ctx.methodCall());
} else if (ctx.newDecl() != null) {
return visitNewDecl(ctx.newDecl());
}
return null;
}
@Override
public Node visitAssign(DecafParser.AssignContext ctx) {
return new AssignStatementExpression();
}
@Override
public Node visitMethodCall(DecafParser.MethodCallContext ctx) {
return super.visitMethodCall(ctx);
}
@Override
public Node visitNewDecl(DecafParser.NewDeclContext ctx) {
return super.visitNewDecl(ctx);
}
}

File diff suppressed because one or more lines are too long

View File

@ -396,6 +396,18 @@ public class DecafBaseListener implements DecafListener {
* <p>The default implementation does nothing.</p>
*/
@Override public void exitReceivingMethod(DecafParser.ReceivingMethodContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterEmptyStatement(DecafParser.EmptyStatementContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitEmptyStatement(DecafParser.EmptyStatementContext ctx) { }
/**
* {@inheritDoc}
*

View File

@ -236,6 +236,13 @@ public class DecafBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitReceivingMethod(DecafParser.ReceivingMethodContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitEmptyStatement(DecafParser.EmptyStatementContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*

View File

@ -327,6 +327,16 @@ public interface DecafListener extends ParseTreeListener {
* @param ctx the parse tree
*/
void exitReceivingMethod(DecafParser.ReceivingMethodContext ctx);
/**
* Enter a parse tree produced by {@link DecafParser#emptyStatement}.
* @param ctx the parse tree
*/
void enterEmptyStatement(DecafParser.EmptyStatementContext ctx);
/**
* Exit a parse tree produced by {@link DecafParser#emptyStatement}.
* @param ctx the parse tree
*/
void exitEmptyStatement(DecafParser.EmptyStatementContext ctx);
/**
* Enter a parse tree produced by {@link DecafParser#type}.
* @param ctx the parse tree

File diff suppressed because it is too large Load Diff

View File

@ -202,6 +202,12 @@ public interface DecafVisitor<T> extends ParseTreeVisitor<T> {
* @return the visitor result
*/
T visitReceivingMethod(DecafParser.ReceivingMethodContext ctx);
/**
* Visit a parse tree produced by {@link DecafParser#emptyStatement}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitEmptyStatement(DecafParser.EmptyStatementContext ctx);
/**
* Visit a parse tree produced by {@link DecafParser#type}.
* @param ctx the parse tree