diff --git a/src/main/java/ast/ClassNode.java b/src/main/java/ast/ClassNode.java index 61134ab..6060237 100644 --- a/src/main/java/ast/ClassNode.java +++ b/src/main/java/ast/ClassNode.java @@ -4,6 +4,7 @@ import ast.type.AccessModifierNode; import ast.members.ConstructorNode; import ast.members.MemberNode; import ast.members.MethodNode; +import bytecode.visitor.ClassVisitor; import semantic.SemanticVisitor; import typechecker.TypeCheckResult; import visitor.Visitable; @@ -44,4 +45,9 @@ public class ClassNode implements ASTNode, Visitable { return visitor.analyze(this); } + @Override + public void accept(ClassVisitor classVisitor) { + classVisitor.visit(this); + } + } diff --git a/src/main/java/ast/expressions/binaryexpressions/DotNode.java b/src/main/java/ast/expressions/binaryexpressions/DotNode.java index 20b6513..8e9c183 100644 --- a/src/main/java/ast/expressions/binaryexpressions/DotNode.java +++ b/src/main/java/ast/expressions/binaryexpressions/DotNode.java @@ -1,6 +1,5 @@ package ast.expressions.binaryexpressions; -import ast.type.type.*; import bytecode.visitor.MethodVisitor; import semantic.SemanticVisitor; import typechecker.TypeCheckResult; diff --git a/src/main/java/ast/literal/LiteralNode.java b/src/main/java/ast/literal/LiteralNode.java index e18ab7b..43a16f9 100644 --- a/src/main/java/ast/literal/LiteralNode.java +++ b/src/main/java/ast/literal/LiteralNode.java @@ -1,4 +1,5 @@ package ast.literal; + import ast.expressions.IExpressionNode; import ast.type.type.ITypeNode; import semantic.SemanticVisitor; diff --git a/src/main/java/ast/statementexpressions/crementexpressions/DecrementNode.java b/src/main/java/ast/statementexpressions/crementexpressions/DecrementNode.java index 97a359f..8308e07 100644 --- a/src/main/java/ast/statementexpressions/crementexpressions/DecrementNode.java +++ b/src/main/java/ast/statementexpressions/crementexpressions/DecrementNode.java @@ -20,10 +20,4 @@ public class DecrementNode implements IStatementExpressionNode { public TypeCheckResult accept(SemanticVisitor visitor) { return visitor.analyze(this); } - - @Override - public void accept(MethodVisitor methodVisitor) { - methodVisitor.visit(this); - } - } diff --git a/src/main/java/ast/statementexpressions/crementexpressions/IncrementNode.java b/src/main/java/ast/statementexpressions/crementexpressions/IncrementNode.java index 105f11f..d736d3f 100644 --- a/src/main/java/ast/statementexpressions/crementexpressions/IncrementNode.java +++ b/src/main/java/ast/statementexpressions/crementexpressions/IncrementNode.java @@ -19,10 +19,4 @@ public class IncrementNode implements IStatementExpressionNode { public TypeCheckResult accept(SemanticVisitor visitor) { return visitor.analyze(this); } - - @Override - public void accept(MethodVisitor methodVisitor) { - methodVisitor.visit(this); - } - } diff --git a/src/main/java/bytecode/ByteCodeGenerator.java b/src/main/java/bytecode/ByteCodeGenerator.java index 280bda1..dc47a4f 100644 --- a/src/main/java/bytecode/ByteCodeGenerator.java +++ b/src/main/java/bytecode/ByteCodeGenerator.java @@ -18,49 +18,60 @@ public class ByteCodeGenerator implements ProgramVisitor { private JarOutputStream jarOutputStream; private ByteArrayOutputStream byteArrayOutputStream; private String outputDirectory; + private boolean generateJar; + private boolean generateClassFiles; - public ByteCodeGenerator(String outputDirectory) { + public ByteCodeGenerator(String outputDirectory, boolean generateJar, boolean generateClassFiles) { this.outputDirectory = outputDirectory; + this.generateJar = generateJar; + this.generateClassFiles = generateClassFiles; } @Override public void visit(ProgramNode programNode) { - byteArrayOutputStream = new ByteArrayOutputStream(); - try { - Manifest manifest = new Manifest(); - manifest.getMainAttributes().putValue("Manifest-Version", "1.0"); - boolean foundMainClass = false; - for (ClassNode classNode : programNode.classes) { - if (foundMainClass) { - break; - } - for (MemberNode memberNode : classNode.members) { - if (memberNode instanceof MainMethodNode) { - manifest.getMainAttributes().putValue("Main-Class", classNode.identifier); - foundMainClass = true; + if(generateJar) { + byteArrayOutputStream = new ByteArrayOutputStream(); + try { + Manifest manifest = new Manifest(); + manifest.getMainAttributes().putValue("Manifest-Version", "1.0"); + boolean foundMainClass = false; + for (ClassNode classNode : programNode.classes) { + if (foundMainClass) { break; } + for (MemberNode memberNode : classNode.members) { + if (memberNode instanceof MainMethodNode) { + manifest.getMainAttributes().putValue("Main-Class", classNode.identifier); + foundMainClass = true; + break; + } + } } + + + jarOutputStream = new JarOutputStream(byteArrayOutputStream, manifest); + } catch (IOException e) { + throw new RuntimeException(e); } + for (ClassNode classDeclarationNode : programNode.classes) { + ClassCodeGen classCodeGen = new ClassCodeGen(jarOutputStream, outputDirectory, generateJar, generateClassFiles); + classDeclarationNode.accept(classCodeGen); + } - jarOutputStream = new JarOutputStream(byteArrayOutputStream, manifest); - } catch (IOException e) { - throw new RuntimeException(e); + try { + jarOutputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + saveJarFile(byteArrayOutputStream.toByteArray(), "output.jar"); + } else { + for (ClassNode classDeclarationNode : programNode.classes) { + ClassCodeGen classCodeGen = new ClassCodeGen(jarOutputStream, outputDirectory, generateJar, generateClassFiles); + classDeclarationNode.accept(classCodeGen); + } } - - for (ClassNode classDeclarationNode : programNode.classes) { - ClassCodeGen classCodeGen = new ClassCodeGen(jarOutputStream, outputDirectory); - classDeclarationNode.accept(classCodeGen); - } - - try { - jarOutputStream.close(); - } catch (IOException e) { - e.printStackTrace(); - } - - saveJarFile(byteArrayOutputStream.toByteArray(), "output.jar"); } private void saveJarFile(byte[] jarBytes, String jarFileName) { diff --git a/src/main/java/bytecode/ClassCodeGen.java b/src/main/java/bytecode/ClassCodeGen.java index 84c8b92..e7475f1 100644 --- a/src/main/java/bytecode/ClassCodeGen.java +++ b/src/main/java/bytecode/ClassCodeGen.java @@ -23,11 +23,15 @@ public class ClassCodeGen implements ClassVisitor { private ClassWriter classWriter; private JarOutputStream jarOutputStream; private String outputDirectory; + private boolean generateJar; + private boolean generateClassFiles; - public ClassCodeGen(JarOutputStream jarOutputStream, String outputDirectory) { + public ClassCodeGen(JarOutputStream jarOutputStream, String outputDirectory, boolean generateJar, boolean generateClassFiles) { mapper = new Mapper(); this.jarOutputStream = jarOutputStream; this.outputDirectory = outputDirectory; + this.generateJar = generateJar; + this.generateClassFiles = generateClassFiles; } @Override @@ -45,9 +49,12 @@ public class ClassCodeGen implements ClassVisitor { } } - classWriter.visitEnd(); - printIntoClassFile(classWriter.toByteArray(), classNode.identifier, outputDirectory); - writeToJar(classWriter.toByteArray(), classNode.identifier); + if (generateJar) { + writeToJar(classWriter.toByteArray(), classNode.identifier); + } + if (generateClassFiles) { + printIntoClassFile(classWriter.toByteArray(), classNode.identifier, outputDirectory); + } classWriter.visitEnd(); } diff --git a/src/main/java/bytecode/Mapper.java b/src/main/java/bytecode/Mapper.java index b8170d2..0c842ba 100644 --- a/src/main/java/bytecode/Mapper.java +++ b/src/main/java/bytecode/Mapper.java @@ -27,18 +27,18 @@ public class Mapper { public String generateMethodDescriptor(BaseType type, List parameters) { String descriptor = "("; for (ParameterNode parameterNode : parameters) { - descriptor += getTypeChar((BaseType) parameterNode.type); + if(parameterNode.type instanceof BaseType) { + descriptor += getTypeChar((BaseType) parameterNode.type); + } else { + ReferenceType referenceType = (ReferenceType) parameterNode.type; + descriptor += "L" + referenceType.getIdentifier() + ";"; + } } descriptor += ")"; descriptor += getTypeChar(type); return descriptor; } - public String generateMethodDescriptor(ReferenceType type, List parameters) { - String descriptor = "()V"; - return descriptor; - } - public String getTypeChar(BaseType type) { String typeChar = ""; switch (type.getTypeEnum()) { diff --git a/src/main/java/bytecode/MethodCodeGen.java b/src/main/java/bytecode/MethodCodeGen.java index a1776c6..ab6e8e1 100644 --- a/src/main/java/bytecode/MethodCodeGen.java +++ b/src/main/java/bytecode/MethodCodeGen.java @@ -1,5 +1,6 @@ package bytecode; +import ast.expressions.IExpressionNode; import ast.expressions.binaryexpressions.*; import ast.expressions.unaryexpressions.MemberAccessNode; import ast.expressions.unaryexpressions.NotNode; @@ -10,6 +11,7 @@ import ast.members.MethodNode; import ast.parameters.ParameterNode; import ast.statementexpressions.AssignNode; import ast.statementexpressions.NewDeclarationNode; +import ast.statementexpressions.crementexpressions.CrementType; import ast.statementexpressions.crementexpressions.DecrementNode; import ast.statementexpressions.crementexpressions.IncrementNode; import ast.statementexpressions.methodcallstatementnexpressions.ChainedMethodNode; @@ -18,6 +20,7 @@ import ast.statementexpressions.methodcallstatementnexpressions.TargetNode; import ast.statements.*; import ast.type.ValueNode; import ast.type.type.BaseType; +import ast.type.type.ReferenceType; import ast.type.type.TypeEnum; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Label; @@ -68,7 +71,9 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor { // Visit all statements for (IStatementNode statementNode : constructorNode.block.statements) { - statementNode.accept(this); + if (statementNode != null) { + statementNode.accept(this); + } } methodVisitor.visitMaxs(0, 0); @@ -130,32 +135,44 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor { @Override public void visit(CalculationNode calculationNode) { - calculationNode.dotExpression.accept(this); - calculationNode.calculationExpression.accept(this); - switch (calculationNode.operator) { - case PLUS: - methodVisitor.visitInsn(IADD); - break; - case MINUS: - methodVisitor.visitInsn(ISUB); - break; + if (calculationNode.dotExpression != null) { + calculationNode.dotExpression.accept(this); + } + if (calculationNode.calculationExpression != null) { + calculationNode.calculationExpression.accept(this); + } + if (calculationNode.operator != null) { + switch (calculationNode.operator) { + case PLUS: + methodVisitor.visitInsn(IADD); + break; + case MINUS: + methodVisitor.visitInsn(ISUB); + break; + } } } @Override public void visit(DotNode dotNode) { - dotNode.dotExpression.accept(this); - dotNode.dotSubstractionExpression.accept(this); - switch (dotNode.operator) { - case DIV: - methodVisitor.visitInsn(IDIV); - break; - case MULT: - methodVisitor.visitInsn(IMUL); - break; - case MOD: - methodVisitor.visitInsn(IREM); - break; + if (dotNode.dotExpression != null) { + dotNode.dotExpression.accept(this); + } + if (dotNode.dotSubstractionExpression != null) { + dotNode.dotSubstractionExpression.accept(this); + } + if (dotNode.operator != null) { + switch (dotNode.operator) { + case DIV: + methodVisitor.visitInsn(IDIV); + break; + case MULT: + methodVisitor.visitInsn(IMUL); + break; + case MOD: + methodVisitor.visitInsn(IREM); + break; + } } } @@ -178,6 +195,7 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor { public void visit(NonCalculationNode nonCalculationNode) { Label labelFalse = new Label(); Label labelTrue = new Label(); + // TODO: Null check switch (nonCalculationNode.operator) { case AND: nonCalculationNode.unaryExpression.accept(this); @@ -249,7 +267,7 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor { @Override public void visit(MemberAccessNode memberAccessNode) { if (memberAccessNode.thisExpr) { - //methodVisitor.visitFieldInsn(PUTFIELD); + // methodVisitor.visitFieldInsn(PUTFIELD, memberAccessNode.identifiers.get(0), memberAccessNode.identifiers.get(1), ); } } @@ -275,7 +293,21 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor { @Override public void visit(UnaryNode unaryNode) { - + if (unaryNode.thisExp != null) { + methodVisitor.visitVarInsn(ALOAD, 0); // this + } else if (unaryNode.identifier != null) { + methodVisitor.visitVarInsn(ILOAD, localVaribales.indexOf(unaryNode.identifier)); + } else if (unaryNode.memberAccess != null) { + unaryNode.memberAccess.accept(this); + } else if (unaryNode.value != null) { + unaryNode.value.accept(this); + } else if (unaryNode.notExpression != null) { + unaryNode.notExpression.accept(this); + } else if (unaryNode.statement != null) { + unaryNode.statement.accept(this); + } else if (unaryNode.expression != null) { + unaryNode.expression.accept(this); + } } @@ -286,7 +318,7 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor { Label elseLabel = new Label(); Label[] elseIfLabels = new Label[ifElseNode.elseIfStatements.size()]; - for(int i = 0; i < ifElseNode.elseIfStatements.size(); i++) { + for (int i = 0; i < ifElseNode.elseIfStatements.size(); i++) { elseIfLabels[i] = new Label(); } @@ -303,12 +335,12 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor { Label endLabel = new Label(); methodVisitor.visitJumpInsn(GOTO, endLabel); - for(int i = 0; i < ifElseNode.elseIfStatements.size(); i++) { + for (int i = 0; i < ifElseNode.elseIfStatements.size(); i++) { methodVisitor.visitLabel(elseIfLabels[i]); ifElseNode.elseIfStatements.get(i).expression.accept(this); - if(i + 1 < elseIfLabels.length) { + if (i + 1 < elseIfLabels.length) { // at least one more else if - methodVisitor.visitJumpInsn(IFEQ, elseIfLabels[i+1]); + methodVisitor.visitJumpInsn(IFEQ, elseIfLabels[i + 1]); } else { methodVisitor.visitJumpInsn(IFEQ, elseLabel); } @@ -316,7 +348,7 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor { methodVisitor.visitJumpInsn(GOTO, endLabel); } - if(ifElseNode.elseStatement != null) { + if (ifElseNode.elseStatement != null) { methodVisitor.visitLabel(elseLabel); ifElseNode.elseStatement.block.accept(this); } @@ -326,29 +358,88 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor { @Override public void visit(LocalVariableDeclarationNode localVariableDeclarationNode) { - // Process expression - localVariableDeclarationNode.expression.accept(this); - // Store result of expression in variable - methodVisitor.visitVarInsn(ISTORE, localVaribales.indexOf(localVariableDeclarationNode.identifier)); + if (localVariableDeclarationNode.expression != null) { + // Process expression + localVariableDeclarationNode.expression.accept(this); + // Store result of expression in variable + if (localVaribales.contains(localVariableDeclarationNode.identifier)) { + if (localVariableDeclarationNode.type instanceof BaseType) { + methodVisitor.visitVarInsn(ISTORE, localVaribales.indexOf(localVariableDeclarationNode.identifier)); + } else if (localVariableDeclarationNode.type instanceof ReferenceType) { + methodVisitor.visitVarInsn(ASTORE, localVaribales.indexOf(localVariableDeclarationNode.identifier)); + } + } else { + localVaribales.add(localVariableDeclarationNode.identifier); + if (localVariableDeclarationNode.type instanceof BaseType) { + methodVisitor.visitVarInsn(ISTORE, localVaribales.indexOf(localVariableDeclarationNode.identifier)); + } else if (localVariableDeclarationNode.type instanceof ReferenceType) { + methodVisitor.visitVarInsn(ASTORE, localVaribales.indexOf(localVariableDeclarationNode.identifier)); + } + } + } else { + if (!localVaribales.contains(localVariableDeclarationNode.identifier)) { + localVaribales.add(localVariableDeclarationNode.identifier); + } + } } @Override public void visit(AssignNode assignNode) { // Process expression - assignNode.expression.accept(this); + if (assignNode.expression instanceof IncrementNode) { + IncrementNode incrementNode = (IncrementNode) assignNode.expression; + if (incrementNode.crementType.equals(CrementType.PREFIX)) { // ++i + methodVisitor.visitIincInsn(localVaribales.indexOf(incrementNode.assignableExpression.identifier), 1); + assign(assignNode); + } else if (incrementNode.crementType.equals(CrementType.SUFFIX)) { // Suffix: i++ + assign(assignNode); + methodVisitor.visitIincInsn(localVaribales.indexOf(incrementNode.assignableExpression.identifier), 1); + } + } else if (assignNode.expression instanceof DecrementNode) { + DecrementNode decrementNode = (DecrementNode) assignNode.expression; + if (decrementNode.crementType.equals(CrementType.PREFIX)) { + methodVisitor.visitIincInsn(localVaribales.indexOf(decrementNode.assignableExpression.identifier), -1); + assign(assignNode); + } else if (decrementNode.crementType.equals(CrementType.SUFFIX)) { + assign(assignNode); + methodVisitor.visitIincInsn(localVaribales.indexOf(decrementNode.assignableExpression.identifier), 1); + } + } else { + assignNode.expression.accept(this); + } + } + + private void assign(AssignNode assignNode) { // Store result of expression in variable if (assignNode.assignable.memberAccess.thisExpr) { // Global var - // /methodVisitor.visitFieldInsn(PUTFIELD, identifierExpressionNode.name, identifierExpressionNode1.name, mapper.getTypeChar(((BaseTypeNode) type).enumType)); + methodVisitor.visitVarInsn(ALOAD, 0); + if (assignNode.expression instanceof BaseType) { + //methodVisitor.visitFieldInsn(PUTFIELD, class name, var identifier, mapper.getTypeChar(((BaseTypeNode) type).enumType)); + } else if (assignNode.expression instanceof ReferenceType) { + //methodVisitor.visitFieldInsn(PUTFIELD, class name, var identifier, "L"class name object +";"); + } } else { // Local var - methodVisitor.visitVarInsn(ISTORE, localVaribales.indexOf(assignNode.assignable.identifier)); + if (assignNode.expression instanceof BaseType) { + methodVisitor.visitVarInsn(ISTORE, localVaribales.indexOf(assignNode.assignable.identifier)); + } else if (assignNode.expression instanceof ReferenceType) { + methodVisitor.visitVarInsn(ASTORE, localVaribales.indexOf(assignNode.assignable.identifier)); + } } } @Override public void visit(NewDeclarationNode newDeclarationNode) { - + methodVisitor.visitTypeInsn(NEW, newDeclarationNode.identifier); + methodVisitor.visitInsn(DUP); + for (IExpressionNode expressionNode : newDeclarationNode.expressions) { + expressionNode.accept(this); + } + // TODO + //methodVisitor.visitMethodInsn(INVOKESPECIAL, class name, "", mapper.generateMethodDescriptor(), false); + // TODO: kann ein Field auch definiert werden? Abfrage ob local var oder field + localVaribales.add(newDeclarationNode.identifier); } @Override @@ -395,7 +486,11 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor { // Process expression returnNode.expression.accept(this); // Return result of expression - methodVisitor.visitInsn(IRETURN); + if (returnNode.expression.getType() instanceof BaseType) { + methodVisitor.visitInsn(IRETURN); + } else if (returnNode.expression.getType() instanceof ReferenceType) { + methodVisitor.visitInsn(ARETURN); + } } } @@ -410,55 +505,19 @@ public class MethodCodeGen implements bytecode.visitor.MethodVisitor { whileNode.expression.accept(this); methodVisitor.visitJumpInsn(IFEQ, endOfLoopLabel); // if condition is false, jump out of loop + // TODO: Unterscheidung bei increment/decrement der for Schleife + if (whileNode.block.statements.size() == 2) { // For loop + whileNode.block.statements.get(0).accept(this); + + } else { + whileNode.block.statements.get(0).accept(this); + } whileNode.block.accept(this); methodVisitor.visitJumpInsn(GOTO, loopLabel); methodVisitor.visitLabel(endOfLoopLabel); } - @Override - public void visit(DecrementNode decrementNode) { - switch (decrementNode.crementType) { - case PREFIX: // --i - if (decrementNode.assignableExpression.memberAccess == null) { // local Var - methodVisitor.visitIincInsn(localVaribales.indexOf(decrementNode.assignableExpression.identifier), -1); - } else { // Field or var from other object - - } - break; - case SUFFIX: // i-- - if (decrementNode.assignableExpression.memberAccess == null) { // local Var - methodVisitor.visitIincInsn(localVaribales.indexOf(decrementNode.assignableExpression.identifier), -1); - } else { // Field or var from other object - - } - break; - } - } - - @Override - public void visit(IncrementNode incrementNode) { - switch (incrementNode.crementType) { - case PREFIX: // ++i - if (incrementNode.assignableExpression.memberAccess == null) { // local Var - methodVisitor.visitIincInsn(localVaribales.indexOf(incrementNode.assignableExpression.identifier), 1); - methodVisitor.visitVarInsn(ISTORE, localVaribales.indexOf(incrementNode.assignableExpression.identifier)); - - } else { // Field or var from other object - - } - break; - case SUFFIX: // i++ - if (incrementNode.assignableExpression.memberAccess == null) { // local Var - methodVisitor.visitVarInsn(ISTORE, localVaribales.indexOf(incrementNode.assignableExpression.identifier)); - methodVisitor.visitIincInsn(localVaribales.indexOf(incrementNode.assignableExpression.identifier), 1); - } else { // Field or var from other object - - } - break; - } - } - @Override public void visit(ChainedMethodNode chainedMethodNode) { diff --git a/src/main/java/bytecode/visitor/MethodVisitor.java b/src/main/java/bytecode/visitor/MethodVisitor.java index 8baf220..b38b210 100644 --- a/src/main/java/bytecode/visitor/MethodVisitor.java +++ b/src/main/java/bytecode/visitor/MethodVisitor.java @@ -44,9 +44,6 @@ public interface MethodVisitor { void visit(WhileNode whileNode); // statement expression - void visit(DecrementNode decrementNode); - void visit(IncrementNode incrementNode); - void visit(ChainedMethodNode chainedMethodNode); void visit(MethodCallNode methodCallNode); void visit(TargetNode targetNode);