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:
commit
74e3cb8016
3
.idea/.gitignore
vendored
3
.idea/.gitignore
vendored
@ -2,4 +2,5 @@
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
|
||||
.idea/
|
||||
.idea/# GitHub Copilot persisted chat sessions
|
||||
/copilot/chatSessions
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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
@ -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}
|
||||
*
|
||||
|
@ -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}
|
||||
*
|
||||
|
@ -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
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user