diff --git a/src/main/java/CompilerInput.txt b/src/main/java/CompilerInput.txt index b784cf7..918c686 100644 --- a/src/main/java/CompilerInput.txt +++ b/src/main/java/CompilerInput.txt @@ -5,9 +5,7 @@ public class Example { public static int testMethod(char b){ int a; - boolean b; - char c; - b = 3; + int a; } diff --git a/src/main/java/Main.java b/src/main/java/Main.java index 9b803ca..97ea0ef 100644 --- a/src/main/java/Main.java +++ b/src/main/java/Main.java @@ -1,3 +1,4 @@ +import ast.ASTNode; import ast.ClassNode; import ast.ProgramNode; import bytecode.ByteCodeGenerator; @@ -17,14 +18,14 @@ public class Main { public static void main(String[] args) throws Exception { try { CharStream codeCharStream = CharStreams.fromPath(Paths.get("src/main/java/CompilerInput.txt")); - parsefile(codeCharStream); + parseFile(codeCharStream); } catch (IOException e) { System.err.println("Error reading the file: " + e.getMessage()); } } - static void parsefile(CharStream codeCharStream){ + static void parseFile(CharStream codeCharStream){ SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream); CommonTokenStream tokens = new CommonTokenStream(lexer); SimpleJavaParser parser = new SimpleJavaParser(tokens); @@ -34,9 +35,9 @@ public class Main { ASTBuilder builder = new ASTBuilder(); ProgramNode ast = (ProgramNode) builder.visit(tree); // build the AST - SemanticAnalyzer.generateTast(ast); + ProgramNode typedAst = (ProgramNode) SemanticAnalyzer.generateTast(ast); ByteCodeGenerator byteCodeGenerator = new ByteCodeGenerator(); - byteCodeGenerator.visit(ast); + byteCodeGenerator.visit(typedAst); } } \ No newline at end of file diff --git a/src/main/java/ast/ClassNode.java b/src/main/java/ast/ClassNode.java index 2f09f41..947a977 100644 --- a/src/main/java/ast/ClassNode.java +++ b/src/main/java/ast/ClassNode.java @@ -11,7 +11,7 @@ import java.util.List; import bytecode.visitor.ClassVisitor; import semantic.SemanticVisitor; import typechecker.TypeCheckResult; -import typechecker.Visitable; +import visitor.Visitable; public class ClassNode implements ASTNode, Visitable { public String identifier; diff --git a/src/main/java/ast/LiteralNode.java b/src/main/java/ast/LiteralNode.java index 8fa060a..3873465 100644 --- a/src/main/java/ast/LiteralNode.java +++ b/src/main/java/ast/LiteralNode.java @@ -1,8 +1,10 @@ package ast; import ast.expression.ExpressionNode; +import semantic.SemanticVisitor; +import typechecker.TypeCheckResult; -public class LiteralNode extends ExpressionNode { +public class LiteralNode implements ExpressionNode { int value; private String type; @@ -20,4 +22,8 @@ public class LiteralNode extends ExpressionNode { } + @Override + public TypeCheckResult accept(SemanticVisitor visitor) { + return null; + } } diff --git a/src/main/java/ast/ProgramNode.java b/src/main/java/ast/ProgramNode.java index 116c5a2..1aac1b1 100644 --- a/src/main/java/ast/ProgramNode.java +++ b/src/main/java/ast/ProgramNode.java @@ -6,7 +6,7 @@ import java.util.List; import bytecode.visitor.ProgramVisitor; import semantic.SemanticVisitor; import typechecker.TypeCheckResult; -import typechecker.Visitable; +import visitor.Visitable; public class ProgramNode implements ASTNode, Visitable{ public List classes = new ArrayList<>(); diff --git a/src/main/java/ast/VarNode.java b/src/main/java/ast/VarNode.java index e27f080..9349eb4 100644 --- a/src/main/java/ast/VarNode.java +++ b/src/main/java/ast/VarNode.java @@ -1,6 +1,10 @@ package ast; -public class VarNode implements ASTNode{ +import semantic.SemanticVisitor; +import typechecker.TypeCheckResult; +import visitor.Visitable; + +public class VarNode implements ASTNode, Visitable { private String identifier; private String type; @@ -18,4 +22,8 @@ public class VarNode implements ASTNode{ return identifier; } + @Override + public TypeCheckResult accept(SemanticVisitor visitor) { + return visitor.analyze(this); + } } diff --git a/src/main/java/ast/expression/BinaryExpressionNode.java b/src/main/java/ast/expression/BinaryExpressionNode.java index e63bbca..c912408 100644 --- a/src/main/java/ast/expression/BinaryExpressionNode.java +++ b/src/main/java/ast/expression/BinaryExpressionNode.java @@ -1,6 +1,10 @@ package ast.expression; -public class BinaryExpressionNode extends ExpressionNode { +import semantic.SemanticVisitor; +import typechecker.TypeCheckResult; +import visitor.Visitable; + +public class BinaryExpressionNode implements ExpressionNode, Visitable { public ExpressionNode left; public ExpressionNode right; public String operator; // Stores the operator as a string (e.g., "+", "-", "&&") @@ -10,4 +14,9 @@ public class BinaryExpressionNode extends ExpressionNode { this.right = right; this.operator = operator; } + + @Override + public TypeCheckResult accept(SemanticVisitor visitor) { + return visitor.analyze(this); + } } \ No newline at end of file diff --git a/src/main/java/ast/expression/ExpressionNode.java b/src/main/java/ast/expression/ExpressionNode.java index 5dbead0..e790795 100644 --- a/src/main/java/ast/expression/ExpressionNode.java +++ b/src/main/java/ast/expression/ExpressionNode.java @@ -1,9 +1,8 @@ package ast.expression; import ast.ASTNode; +import visitor.Visitable; -public class ExpressionNode implements ASTNode { - - +public interface ExpressionNode extends ASTNode, Visitable { } diff --git a/src/main/java/ast/expression/IdentifierExpressionNode.java b/src/main/java/ast/expression/IdentifierExpressionNode.java index 7631429..1bb8d56 100644 --- a/src/main/java/ast/expression/IdentifierExpressionNode.java +++ b/src/main/java/ast/expression/IdentifierExpressionNode.java @@ -1,9 +1,22 @@ package ast.expression; -public class IdentifierExpressionNode extends ExpressionNode { +import ast.type.TypeNode; +import semantic.SemanticVisitor; + +import typechecker.TypeCheckResult; +import visitor.Visitable; + +public class IdentifierExpressionNode implements ExpressionNode, Visitable { public String name; + public TypeNode type; + public IdentifierExpressionNode(String name) { this.name = name; } + + @Override + public TypeCheckResult accept(SemanticVisitor visitor) { + return visitor.analyze(this); + } } diff --git a/src/main/java/ast/expression/UnaryExpressionNode.java b/src/main/java/ast/expression/UnaryExpressionNode.java index 0c77ef5..24d1832 100644 --- a/src/main/java/ast/expression/UnaryExpressionNode.java +++ b/src/main/java/ast/expression/UnaryExpressionNode.java @@ -1,6 +1,10 @@ package ast.expression; -public class UnaryExpressionNode extends ExpressionNode { +import semantic.SemanticVisitor; +import typechecker.TypeCheckResult; +import visitor.Visitable; + +public class UnaryExpressionNode implements ExpressionNode, Visitable { public ExpressionNode expression; public String operator; // Stores the operator (e.g., "-", "!") @@ -8,4 +12,9 @@ public class UnaryExpressionNode extends ExpressionNode { this.expression = expression; this.operator = operator; } + + @Override + public TypeCheckResult accept(SemanticVisitor visitor) { + return visitor.analyze(this); + } } diff --git a/src/main/java/ast/member/ConstructorNode.java b/src/main/java/ast/member/ConstructorNode.java index c729dc1..998d727 100644 --- a/src/main/java/ast/member/ConstructorNode.java +++ b/src/main/java/ast/member/ConstructorNode.java @@ -2,7 +2,7 @@ package ast.member; import ast.type.AccessTypeNode; import bytecode.visitor.MethodVisitor; -import typechecker.Visitable; +import visitor.Visitable; public class ConstructorNode extends MethodNode implements Visitable { public ConstructorNode(AccessTypeNode visibility, String name) { diff --git a/src/main/java/ast/member/FieldNode.java b/src/main/java/ast/member/FieldNode.java index 70880c5..60c5411 100644 --- a/src/main/java/ast/member/FieldNode.java +++ b/src/main/java/ast/member/FieldNode.java @@ -5,7 +5,7 @@ import ast.type.TypeNode; import bytecode.visitor.ClassVisitor; import semantic.SemanticVisitor; import typechecker.TypeCheckResult; -import typechecker.Visitable; +import visitor.Visitable; public class FieldNode implements MemberNode, Visitable { public AccessTypeNode accessTypeNode; diff --git a/src/main/java/ast/member/MethodNode.java b/src/main/java/ast/member/MethodNode.java index 88ed182..c50f6af 100644 --- a/src/main/java/ast/member/MethodNode.java +++ b/src/main/java/ast/member/MethodNode.java @@ -3,15 +3,15 @@ package ast.member; import ast.parameter.ParameterListNode; import ast.statement.StatementNode; import ast.type.AccessTypeNode; -import ast.type.TypeNode; import java.util.ArrayList; import java.util.List; +import ast.type.TypeNode; import bytecode.visitor.MethodVisitor; import semantic.SemanticVisitor; import typechecker.TypeCheckResult; -import typechecker.Visitable; +import visitor.Visitable; public class MethodNode implements MemberNode, Visitable { public AccessTypeNode visibility; diff --git a/src/main/java/ast/parameter/ParameterListNode.java b/src/main/java/ast/parameter/ParameterListNode.java index 69d12f3..ff1c58d 100644 --- a/src/main/java/ast/parameter/ParameterListNode.java +++ b/src/main/java/ast/parameter/ParameterListNode.java @@ -6,7 +6,7 @@ import java.util.ArrayList; import java.util.List; public class ParameterListNode implements ASTNode { - List parameters = new ArrayList<>(); + public List parameters = new ArrayList<>(); public ParameterListNode(List parameters){ this.parameters = parameters; diff --git a/src/main/java/ast/statement/AssignmentStatementNode.java b/src/main/java/ast/statement/AssignmentStatementNode.java index 7efbd73..9f6a395 100644 --- a/src/main/java/ast/statement/AssignmentStatementNode.java +++ b/src/main/java/ast/statement/AssignmentStatementNode.java @@ -4,7 +4,7 @@ import ast.VarNode; import ast.expression.ExpressionNode; import semantic.SemanticVisitor; import typechecker.TypeCheckResult; -import typechecker.Visitable; +import visitor.Visitable; public class AssignmentStatementNode extends StatementNode implements Visitable { public VarNode varNode; diff --git a/src/main/java/ast/statement/IfStatementNode.java b/src/main/java/ast/statement/IfStatementNode.java index 93eec91..3f585dd 100644 --- a/src/main/java/ast/statement/IfStatementNode.java +++ b/src/main/java/ast/statement/IfStatementNode.java @@ -1,6 +1,8 @@ package ast.statement; import ast.expression.ExpressionNode; +import semantic.SemanticVisitor; +import typechecker.TypeCheckResult; public class IfStatementNode extends StatementNode { public ExpressionNode condition; @@ -12,4 +14,9 @@ public class IfStatementNode extends StatementNode { this.thenStatement = thenStatement; this.elseStatement = elseStatement; } + + @Override + public TypeCheckResult accept(SemanticVisitor visitor) { + return visitor.analyze(this); + } } \ No newline at end of file diff --git a/src/main/java/ast/statement/ReturnStatementNode.java b/src/main/java/ast/statement/ReturnStatementNode.java index 4ca4dfa..c5e4d6b 100644 --- a/src/main/java/ast/statement/ReturnStatementNode.java +++ b/src/main/java/ast/statement/ReturnStatementNode.java @@ -1,6 +1,8 @@ package ast.statement; import ast.expression.ExpressionNode; +import semantic.SemanticVisitor; +import typechecker.TypeCheckResult; public class ReturnStatementNode extends StatementNode { public ExpressionNode expression; @@ -8,4 +10,9 @@ public class ReturnStatementNode extends StatementNode { public ReturnStatementNode(ExpressionNode expression) { this.expression = expression; } + + @Override + public TypeCheckResult accept(SemanticVisitor visitor) { + return visitor.analyze(this); + } } \ No newline at end of file diff --git a/src/main/java/ast/statement/StatementNode.java b/src/main/java/ast/statement/StatementNode.java index 6c90f8c..eff1804 100644 --- a/src/main/java/ast/statement/StatementNode.java +++ b/src/main/java/ast/statement/StatementNode.java @@ -1,7 +1,8 @@ package ast.statement; import ast.ASTNode; +import visitor.Visitable; -public abstract class StatementNode implements ASTNode { +public abstract class StatementNode implements ASTNode, Visitable { } diff --git a/src/main/java/ast/statement/VariableDeclarationStatementNode.java b/src/main/java/ast/statement/VariableDeclarationStatementNode.java index e7f6e32..4302177 100644 --- a/src/main/java/ast/statement/VariableDeclarationStatementNode.java +++ b/src/main/java/ast/statement/VariableDeclarationStatementNode.java @@ -1,7 +1,9 @@ package ast.statement; -import ast.type.TypeNode; import ast.expression.ExpressionNode; +import ast.type.TypeNode; +import semantic.SemanticVisitor; +import typechecker.TypeCheckResult; public class VariableDeclarationStatementNode extends StatementNode { public TypeNode type; @@ -12,4 +14,9 @@ public class VariableDeclarationStatementNode extends StatementNode { this.identifier = identifier; this.expression = expression; } + + @Override + public TypeCheckResult accept(SemanticVisitor visitor) { + return visitor.analyze(this); + } } \ No newline at end of file diff --git a/src/main/java/ast/statement/WhileStatementNode.java b/src/main/java/ast/statement/WhileStatementNode.java index e6a10b1..a3f4007 100644 --- a/src/main/java/ast/statement/WhileStatementNode.java +++ b/src/main/java/ast/statement/WhileStatementNode.java @@ -1,6 +1,8 @@ package ast.statement; import ast.expression.ExpressionNode; +import semantic.SemanticVisitor; +import typechecker.TypeCheckResult; public class WhileStatementNode extends StatementNode { public ExpressionNode condition; @@ -10,4 +12,9 @@ public class WhileStatementNode extends StatementNode { this.condition = condition; this.body = body; } + + @Override + public TypeCheckResult accept(SemanticVisitor visitor) { + return visitor.analyze(this); + } } diff --git a/src/main/java/ast/type/BaseTypeNode.java b/src/main/java/ast/type/BaseTypeNode.java index 81cdf43..2d871ab 100644 --- a/src/main/java/ast/type/BaseTypeNode.java +++ b/src/main/java/ast/type/BaseTypeNode.java @@ -1,6 +1,8 @@ package ast.type; -public class BaseTypeNode implements TypeNode{ +import ast.ASTNode; + +public class BaseTypeNode implements ASTNode, TypeNode { public EnumTypeNode enumType; diff --git a/src/main/java/ast/type/ReferenceTypeNode.java b/src/main/java/ast/type/ReferenceTypeNode.java index 1937054..88225f3 100644 --- a/src/main/java/ast/type/ReferenceTypeNode.java +++ b/src/main/java/ast/type/ReferenceTypeNode.java @@ -1,4 +1,6 @@ package ast.type; -public class ReferenceTypeNode implements TypeNode{ +import ast.ASTNode; + +public class ReferenceTypeNode implements ASTNode, TypeNode { } diff --git a/src/main/java/bytecode/ClassCodeGen.java b/src/main/java/bytecode/ClassCodeGen.java index 59be9ee..b0afa69 100644 --- a/src/main/java/bytecode/ClassCodeGen.java +++ b/src/main/java/bytecode/ClassCodeGen.java @@ -4,6 +4,7 @@ import ast.ClassNode; import ast.member.FieldNode; import ast.member.MemberNode; import ast.member.MethodNode; +import ast.type.BaseTypeNode; import bytecode.visitor.ClassVisitor; import java.io.File; import org.objectweb.asm.ClassWriter; @@ -12,14 +13,19 @@ import org.objectweb.asm.Opcodes; import java.io.FileOutputStream; import java.io.IOException; + public class ClassCodeGen implements ClassVisitor { - Mapper mapper = new Mapper(); - ClassWriter classWriter; + private Mapper mapper; + private ClassWriter classWriter; + + public ClassCodeGen() { + 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_5, mapper.mapAccessTypeToOpcode(classNode.accessType), classNode.identifier, null, "java/lang/Object", null); for (MemberNode memberNode : classNode.members) { @@ -39,7 +45,9 @@ public class ClassCodeGen implements ClassVisitor { @Override public void visit(FieldNode fieldNode) { - classWriter.visitField(mapper.mapAccesTypeToOpcode(fieldNode.accessTypeNode), fieldNode.identifier, mapper.getTypeChar(fieldNode.type.enumTypeNode), null, null ); + if(fieldNode.type instanceof BaseTypeNode baseTypeNode){ + classWriter.visitField(mapper.mapAccessTypeToOpcode(fieldNode.accessTypeNode), fieldNode.identifier, mapper.getTypeChar(baseTypeNode.enumType), null, null ); + } classWriter.visitEnd(); } diff --git a/src/main/java/bytecode/FieldCodeGen.java b/src/main/java/bytecode/FieldCodeGen.java deleted file mode 100644 index abbda43..0000000 --- a/src/main/java/bytecode/FieldCodeGen.java +++ /dev/null @@ -1,13 +0,0 @@ -package bytecode; - -import ast.member.FieldNode; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.FieldVisitor; - -public class FieldCodeGen { - - public void generateFieldCode(ClassWriter classWriter, FieldNode fieldNode) { - Mapper mapper = new Mapper(); - FieldVisitor fieldVisitor = classWriter.visitField(mapper.mapAccesTypeToOpcode(fieldNode.accessTypeNode), fieldNode.identifier, "", null, null); - } -} diff --git a/src/main/java/bytecode/Mapper.java b/src/main/java/bytecode/Mapper.java index 7f1b219..4f25846 100644 --- a/src/main/java/bytecode/Mapper.java +++ b/src/main/java/bytecode/Mapper.java @@ -1,13 +1,13 @@ package bytecode; -import ast.type.AccessTypeNode; -import ast.type.EnumAccessTypeNode; -import ast.type.EnumTypeNode; -import ast.type.TypeNode; +import ast.parameter.ParameterListNode; +import ast.parameter.ParameterNode; +import ast.type.*; import org.objectweb.asm.Opcodes; +import ast.type.BaseTypeNode; public class Mapper { - public int mapAccesTypeToOpcode(AccessTypeNode type) { + public int mapAccessTypeToOpcode(AccessTypeNode type) { switch (type.enumAccessTypeNode) { case EnumAccessTypeNode.PUBLIC: return Opcodes.ACC_PUBLIC; @@ -17,9 +17,13 @@ public class Mapper { return 0; } - public String generateMethodDescriptor(TypeNode typeNode) { - String descriptor = "()"; - descriptor += getTypeChar(typeNode.enumTypeNode); + public String generateMethodDescriptor(BaseTypeNode baseTypeNode, ParameterListNode parameterListNode) { + String descriptor = "("; + for(ParameterNode parameterNode : parameterListNode.parameters) { + descriptor += getTypeChar(EnumTypeNode.INT); + } + descriptor += ")"; + descriptor += getTypeChar(baseTypeNode.enumType); return descriptor; } diff --git a/src/main/java/bytecode/MethodCodeGen.java b/src/main/java/bytecode/MethodCodeGen.java index fd8a29a..a4249f1 100644 --- a/src/main/java/bytecode/MethodCodeGen.java +++ b/src/main/java/bytecode/MethodCodeGen.java @@ -2,37 +2,99 @@ package bytecode; import ast.member.ConstructorNode; import ast.member.MethodNode; +import ast.parameter.ParameterListNode; +import ast.parameter.ParameterNode; +import ast.type.BaseTypeNode; +import ast.type.EnumTypeNode; import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +import java.util.ArrayList; +import java.util.List; + +import static org.objectweb.asm.Opcodes.*; + public class MethodCodeGen implements bytecode.visitor.MethodVisitor { private ClassWriter classWriter; - Mapper mapper = new Mapper(); + private Mapper mapper; + private MethodVisitor methodVisitor; + + private List localVaribales; public MethodCodeGen(ClassWriter classWriter) { this.classWriter = classWriter; + mapper = new Mapper(); + localVaribales = new ArrayList<>(); } @Override public void visit(ConstructorNode constructorNode) { - MethodVisitor constructor = - classWriter.visitMethod(mapper.mapAccesTypeToOpcode(constructorNode.visibility), + methodVisitor = + classWriter.visitMethod(mapper.mapAccessTypeToOpcode(constructorNode.visibility), "", "()V", null, null); - constructor.visitEnd(); + methodVisitor.visitCode(); + methodVisitor.visitVarInsn(ALOAD, 0); + methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + methodVisitor.visitInsn(RETURN); + methodVisitor.visitMaxs(1, 1); + methodVisitor.visitEnd(); } @Override public void visit(MethodNode methodNode) { - MethodVisitor method = classWriter.visitMethod(mapper.mapAccesTypeToOpcode(methodNode.visibility), - methodNode.identifier, - mapper.generateMethodDescriptor(methodNode.type), - null, - null); + if (methodNode.type instanceof BaseTypeNode baseTypeNode) { + methodVisitor = classWriter.visitMethod(mapper.mapAccessTypeToOpcode(methodNode.visibility), + methodNode.identifier, + mapper.generateMethodDescriptor(baseTypeNode, methodNode.parameters), + null, + null); - method.visitEnd(); + methodVisitor.visitCode(); + localVaribales.add("this"); + for (ParameterNode parameterNode : methodNode.parameters.parameters) { + localVaribales.add(parameterNode.identifier); + } + + //test(); + methodVisitor.visitMaxs(1, localVaribales.size()); + methodVisitor.visitEnd(); + } + } + + public void test() { + Label start = new Label(); + Label loop = new Label(); + Label end = new Label(); + methodVisitor.visitLabel(start); + //methodVisitor.visitVarInsn(Opcodes.ICONST_M1, 99); + //methodVisitor.visitInsn(Opcodes.ICONST_5); + methodVisitor.visitLdcInsn(99); + // methodVisitor.visitInsn(Opcodes.ICONST_0); + //methodVisitor.visitVarInsn(Opcodes.ILOAD, 2); + methodVisitor.visitVarInsn(Opcodes.ISTORE, 1); + methodVisitor.visitLabel(loop); + methodVisitor.visitVarInsn(Opcodes.ILOAD, 1); + methodVisitor.visitInsn(Opcodes.ICONST_5); + methodVisitor.visitJumpInsn(Opcodes.IF_ICMPGE, end); + methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, + "java/lang/System", "out", + "Ljava/io/PrintStream;"); + methodVisitor.visitLdcInsn("Bytecode"); + methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, + "java/io/PrintStream", "println", + "(Ljava/lang/String;)V", false); + methodVisitor.visitIincInsn(1, 1); + methodVisitor.visitJumpInsn(Opcodes.GOTO, loop); + methodVisitor.visitLabel(end); + methodVisitor.visitVarInsn(Opcodes.ILOAD, 1); + methodVisitor.visitInsn(Opcodes.IRETURN); + methodVisitor.visitEnd(); } } diff --git a/src/main/java/classFileOutput/Example.class b/src/main/java/classFileOutput/Example.class index e299480..c99f3e0 100644 Binary files a/src/main/java/classFileOutput/Example.class and b/src/main/java/classFileOutput/Example.class differ diff --git a/src/main/java/parser/ASTBuilder.java b/src/main/java/parser/ASTBuilder.java index 1e8cbc3..ee61b9b 100644 --- a/src/main/java/parser/ASTBuilder.java +++ b/src/main/java/parser/ASTBuilder.java @@ -13,10 +13,12 @@ import ast.parameter.ParameterNode; import ast.statement.*; import ast.type.*; import org.antlr.v4.runtime.tree.TerminalNode; + import java.util.ArrayList; import java.util.List; import parser.generated.*; import parser.generated.SimpleJavaParser.LiteralContext; +import ast.type.BaseTypeNode; public class ASTBuilder extends SimpleJavaBaseVisitor { @Override @@ -74,9 +76,9 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { @Override public ASTNode visitParameter(SimpleJavaParser.ParameterContext ctx) { - TypeNode type = (TypeNode) visit(ctx.type()); + TypeNode typeNode = (TypeNode) visit(ctx.type()); String identifier = ctx.IDENTIFIER().getText(); - return new ParameterNode(type, identifier); + return new ParameterNode(typeNode, identifier); } @Override @@ -204,6 +206,7 @@ public class ASTBuilder extends SimpleJavaBaseVisitor { try { int intValue = Integer.parseInt(literalContext.getText()); LiteralNode literalNode = new LiteralNode(intValue); + literalNode.setType("int"); return literalNode; } catch (NumberFormatException ignored) {} diff --git a/src/main/java/semantic/Scope.java b/src/main/java/semantic/Scope.java new file mode 100644 index 0000000..ab5c0cb --- /dev/null +++ b/src/main/java/semantic/Scope.java @@ -0,0 +1,36 @@ +package semantic; + +import ast.type.TypeNode; + +import java.util.HashMap; +import java.util.Stack; + +public class Scope { + + private Stack> localVars; + + public void addLocalVar(String name, TypeNode type) { + if (this.contains(name)) { + throw new RuntimeException("Variable " + name + " already exists in this scope"); + } + localVars.peek().put(name, type); + } + + public boolean contains(String name) { + for (HashMap map : localVars) { + if (map.containsKey(name)) { + return true; + } + } + return false; + } + + public void pushScope() { + localVars.push(new HashMap()); + } + + public void popScope() { + localVars.pop(); + } + +} diff --git a/src/main/java/semantic/SemanticAnalyzer.java b/src/main/java/semantic/SemanticAnalyzer.java index d499be2..7a6002b 100644 --- a/src/main/java/semantic/SemanticAnalyzer.java +++ b/src/main/java/semantic/SemanticAnalyzer.java @@ -2,91 +2,145 @@ package semantic; import ast.*; -import ast.expression.ExpressionNode; -import ast.member.ConstructorNode; +import ast.expression.BinaryExpressionNode; +import ast.expression.IdentifierExpressionNode; +import ast.expression.UnaryExpressionNode; import ast.member.FieldNode; import ast.member.MemberNode; import ast.member.MethodNode; -import ast.statement.AssignmentStatementNode; -import ast.statement.StatementNode; +import ast.statement.*; + import java.util.ArrayList; import java.util.List; + import typechecker.TypeCheckResult; public class SemanticAnalyzer implements SemanticVisitor { - private ArrayList currentFields = new ArrayList<>(); + private ArrayList currentFields = new ArrayList<>(); - public static ASTNode generateTast(ASTNode node) throws RuntimeException { - SemanticAnalyzer semanticCheck = new SemanticAnalyzer(); - ProgramNode programNode = (ProgramNode) node; - var result = programNode.accept(semanticCheck); - if (result.isValid()) { - return node; - } else { - throw new RuntimeException("Not Valid"); - } - } + private Scope currentScope; - @Override - public TypeCheckResult analyze(ProgramNode node) { - - var valid = true; - - List classes = node.classes; - for (ClassNode classNode : classes) { - classNode.accept(this); - } - return new TypeCheckResult(valid, null); - } - - @Override - public TypeCheckResult analyze(ClassNode classNode) { - List members = classNode.members; - for (MemberNode memberNode : members) { - if (memberNode instanceof FieldNode fieldNode) { - fieldNode.accept(this); - } else if (memberNode instanceof MethodNode methodNode) { - methodNode.accept(this); - } + public static ASTNode generateTast(ASTNode node) throws RuntimeException { + SemanticAnalyzer semanticCheck = new SemanticAnalyzer(); + ProgramNode programNode = (ProgramNode) node; + var result = programNode.accept(semanticCheck); + if (result.isValid()) { + return node; + } else { + throw new RuntimeException("Not Valid"); + } } - return null; - } + @Override + public TypeCheckResult analyze(ProgramNode node) { - @Override - public TypeCheckResult analyze(MethodNode methodNode) { - List statements = methodNode.statements; - for (StatementNode statement : statements) { - if(statement instanceof AssignmentStatementNode assignmentStatementNode) { - assignmentStatementNode.accept(this); - } - } - return null; - } + var valid = true; - @Override - public TypeCheckResult analyze(FieldNode toCheck) { - if(currentFields.contains(toCheck.identifier)){ - throw new RuntimeException(toCheck.identifier + " Is Already Declared"); - }else { - currentFields.add(toCheck.identifier); + List classes = node.classes; + for (ClassNode classNode : classes) { + var result = classNode.accept(this); + valid = valid && result.isValid(); + } + return new TypeCheckResult(valid, null); } - return null; - } - @Override - public TypeCheckResult analyze(AssignmentStatementNode assignmentStatementNode) { - if(assignmentStatementNode.expression instanceof LiteralNode literalNode) { - VarNode varNode = assignmentStatementNode.varNode; - if(varNode.getType().equals(literalNode.getType())) { - System.out.println("Type is same"); - } else { - throw new RuntimeException("Type mismatch"); - } + @Override + public TypeCheckResult analyze(ClassNode classNode) { + var valid = true; + List members = classNode.members; + for (MemberNode memberNode : members) { + if (memberNode instanceof FieldNode fieldNode) { + var result = fieldNode.accept(this); + valid = valid && result.isValid(); + } else if (memberNode instanceof MethodNode methodNode) { + var result = methodNode.accept(this); + valid = valid && result.isValid(); + } + } + + return new TypeCheckResult(valid, null); + + } + + @Override + public TypeCheckResult analyze(MethodNode methodNode) { + var valid = true; + + currentLocalScope.pushScope(); + + List statements = methodNode.statements; + for (StatementNode statement : statements) { + if (statement instanceof AssignmentStatementNode assignmentStatementNode) { + var result = assignmentStatementNode.accept(this); + valid = valid && result.isValid(); + } else if (statement instanceof VariableDeclarationStatementNode variableDeclarationStatementNode) { + var result = variableDeclarationStatementNode.accept(this); + valid = valid && result.isValid(); + } + } + return new TypeCheckResult(valid, null); + } + + @Override + public TypeCheckResult analyze(FieldNode toCheck) { + if (currentFields.contains(toCheck.identifier)) { + throw new RuntimeException(toCheck.identifier + " Is Already Declared"); + } else { + currentFields.add(toCheck.identifier); + } + return new TypeCheckResult(true, null); + } + + @Override + public TypeCheckResult analyze(AssignmentStatementNode assignmentStatementNode) { + if (assignmentStatementNode.expression instanceof LiteralNode literalNode) { + TypeCheckResult varResult = assignmentStatementNode.varNode.accept(this); + TypeCheckResult expressionResult = assignmentStatementNode.expression.accept(this); + } + return new TypeCheckResult(true, null); + } + + @Override + public TypeCheckResult analyze(VarNode toCheck) { + return new TypeCheckResult(true, null); + } + + @Override + public TypeCheckResult analyze(BinaryExpressionNode toCheck) { + return null; + } + + @Override + public TypeCheckResult analyze(IdentifierExpressionNode toCheck) { + return null; + } + + @Override + public TypeCheckResult analyze(UnaryExpressionNode toCheck) { + return null; + } + + @Override + public TypeCheckResult analyze(VariableDeclarationStatementNode toCheck) { + + return new TypeCheckResult(true, null); + } + + @Override + public TypeCheckResult analyze(IfStatementNode toCheck) { + return null; + } + + @Override + public TypeCheckResult analyze(ReturnStatementNode toCheck) { + return null; + } + + @Override + public TypeCheckResult analyze(WhileStatementNode toCheck) { + return null; } - return null; - } } \ No newline at end of file diff --git a/src/main/java/semantic/SemanticVisitor.java b/src/main/java/semantic/SemanticVisitor.java index f1228bb..99d0cb8 100644 --- a/src/main/java/semantic/SemanticVisitor.java +++ b/src/main/java/semantic/SemanticVisitor.java @@ -3,13 +3,16 @@ package semantic; import ast.ClassNode; import ast.ProgramNode; +import ast.VarNode; +import ast.expression.BinaryExpressionNode; +import ast.expression.IdentifierExpressionNode; +import ast.expression.UnaryExpressionNode; import ast.member.FieldNode; import ast.member.MethodNode; -import ast.statement.AssignmentStatementNode; +import ast.statement.*; import typechecker.TypeCheckResult; public interface SemanticVisitor { -// TypeCheckResult typeCheck(ASTNode toCheck); TypeCheckResult analyze(ProgramNode toCheck); @@ -20,43 +23,20 @@ public interface SemanticVisitor { TypeCheckResult analyze(FieldNode toCheck); TypeCheckResult analyze(AssignmentStatementNode toCheck); -// -// TypeCheckResult typeCheck(MethodParameter toCheck); -// -// TypeCheckResult typeCheck(ForStmt forStmt); -// -// TypeCheckResult typeCheck(WhileStmt whileStmt); -// -// TypeCheckResult typeCheck(ReturnStmt returnStmt); -// -// TypeCheckResult typeCheck(LocalVarDecl localVarDecl); -// -// TypeCheckResult typeCheck(IfStmt ifStmt); -// -// TypeCheckResult typeCheck(Block block); -// -// TypeCheckResult typeCheck(NewDecl newDecl); -// -// TypeCheckResult typeCheck(MethodCall methodCall); -// -// TypeCheckResult typeCheck(Unary unary); -// -// TypeCheckResult typeCheck(This aThis); -// -// TypeCheckResult typeCheck(Null aNull); -// -// TypeCheckResult typeCheck(LocalOrFieldVar localOrFieldVar); -// -// TypeCheckResult typeCheck(IntegerExpr integerExpr); -// -// TypeCheckResult typeCheck(InstVar instVar); -// -// TypeCheckResult typeCheck(CharExpr charExpr); -// -// TypeCheckResult typeCheck(BoolExpr boolExpr); -// -// TypeCheckResult typeCheck(Binary binary); -// -// TypeCheckResult typeCheck(StringExpr instVar); + TypeCheckResult analyze(VarNode toCheck); + + TypeCheckResult analyze(BinaryExpressionNode toCheck); + + TypeCheckResult analyze(IdentifierExpressionNode toCheck); + + TypeCheckResult analyze(UnaryExpressionNode toCheck); + + TypeCheckResult analyze(VariableDeclarationStatementNode toCheck); + + TypeCheckResult analyze(IfStatementNode toCheck); + + TypeCheckResult analyze(ReturnStatementNode toCheck); + + TypeCheckResult analyze(WhileStatementNode toCheck); } \ No newline at end of file diff --git a/src/main/java/typechecker/Type.java b/src/main/java/typechecker/Type.java deleted file mode 100644 index 89b1c16..0000000 --- a/src/main/java/typechecker/Type.java +++ /dev/null @@ -1,5 +0,0 @@ -package typechecker; - -public interface Type { - boolean equals(Object obj); -} \ No newline at end of file diff --git a/src/main/java/typechecker/TypeCheckResult.java b/src/main/java/typechecker/TypeCheckResult.java index 9068c0d..12143b2 100644 --- a/src/main/java/typechecker/TypeCheckResult.java +++ b/src/main/java/typechecker/TypeCheckResult.java @@ -1,12 +1,14 @@ package typechecker; +import ast.type.TypeNode; + public class TypeCheckResult { private boolean valid; - private Type type; + private TypeNode type; - public TypeCheckResult(boolean valid, Type type) { + public TypeCheckResult(boolean valid, TypeNode type) { this.valid = valid; this.type = type; } @@ -15,7 +17,7 @@ public class TypeCheckResult { return valid; } - public Type getType() { + public TypeNode getType() { return type; } } \ No newline at end of file diff --git a/src/main/java/typechecker/Typer.java b/src/main/java/typechecker/Typer.java deleted file mode 100644 index 3f8872a..0000000 --- a/src/main/java/typechecker/Typer.java +++ /dev/null @@ -1,9 +0,0 @@ -package typechecker; - -public class Typer { - - public static void Typeify(){ - - } - -} diff --git a/src/main/java/typechecker/Visitable.java b/src/main/java/visitor/Visitable.java similarity index 88% rename from src/main/java/typechecker/Visitable.java rename to src/main/java/visitor/Visitable.java index 111c58f..bd69777 100644 --- a/src/main/java/typechecker/Visitable.java +++ b/src/main/java/visitor/Visitable.java @@ -1,9 +1,10 @@ -package typechecker; +package visitor; import bytecode.visitor.ClassVisitor; import bytecode.visitor.MethodVisitor; import bytecode.visitor.ProgramVisitor; import semantic.SemanticVisitor; +import typechecker.TypeCheckResult; public interface Visitable { default void accept(ProgramVisitor programVisitor) {