From 83c72019f5b99b00925453990fb9b19f7569891c Mon Sep 17 00:00:00 2001 From: Joshua Potter Date: Fri, 21 Mar 2014 00:06:09 -0400 Subject: [PATCH] Identification/Type Checking Most of Identification and Type Checking implemented. --- .../AbstractSyntaxTrees/Declaration.java | 9 + .../AbstractSyntaxTrees/Declarators.java | 6 +- .../AbstractSyntaxTrees/FieldDeclList.java | 5 + .../AbstractSyntaxTrees/Identifier.java | 5 +- .../AbstractSyntaxTrees/MethodDeclList.java | 7 +- .../ParameterDeclList.java | 5 + .../AbstractSyntaxTrees/Reference.java | 3 +- .../AbstractSyntaxTrees/TypeKind.java | 3 +- miniJava/src/miniJava/Compiler.java | 24 +- .../miniJava/ContextualAnalyzer/Analyzer.java | 455 ++++++++++++++++++ .../IdentificationTable.java | 145 ++++++ .../miniJava/ContextualAnalyzer/Reporter.java | 122 +++++ .../Exceptions/IdentificationException.java | 10 + .../ParsingException.java | 2 +- .../ScanningException.java | 2 +- .../miniJava/SyntacticAnalyzer/Parser.java | 176 ++++--- .../miniJava/SyntacticAnalyzer/Scanner.java | 45 +- .../SyntacticAnalyzer/SourcePosition.java | 5 + .../src/miniJava/SyntacticAnalyzer/Token.java | 2 + miniJava/test.java | 12 +- 20 files changed, 920 insertions(+), 123 deletions(-) create mode 100644 miniJava/src/miniJava/ContextualAnalyzer/Analyzer.java create mode 100644 miniJava/src/miniJava/ContextualAnalyzer/IdentificationTable.java create mode 100644 miniJava/src/miniJava/ContextualAnalyzer/Reporter.java create mode 100644 miniJava/src/miniJava/Exceptions/IdentificationException.java rename miniJava/src/miniJava/{SyntacticAnalyzer/Errors => Exceptions}/ParsingException.java (87%) rename miniJava/src/miniJava/{SyntacticAnalyzer/Errors => Exceptions}/ScanningException.java (84%) diff --git a/miniJava/src/miniJava/AbstractSyntaxTrees/Declaration.java b/miniJava/src/miniJava/AbstractSyntaxTrees/Declaration.java index 2be0aae..cf5c22d 100644 --- a/miniJava/src/miniJava/AbstractSyntaxTrees/Declaration.java +++ b/miniJava/src/miniJava/AbstractSyntaxTrees/Declaration.java @@ -15,6 +15,15 @@ public abstract class Declaration extends AST { this.type = type; } + @Override + public String toString() { + if(posn != null) { + return this.name + "(Line: " + posn.line + ", Column: " + posn.col + ")"; + } else { + return super.toString(); + } + } + public String name; public Type type; } diff --git a/miniJava/src/miniJava/AbstractSyntaxTrees/Declarators.java b/miniJava/src/miniJava/AbstractSyntaxTrees/Declarators.java index b42e736..4e0cce2 100644 --- a/miniJava/src/miniJava/AbstractSyntaxTrees/Declarators.java +++ b/miniJava/src/miniJava/AbstractSyntaxTrees/Declarators.java @@ -1,14 +1,18 @@ package miniJava.AbstractSyntaxTrees; +import miniJava.SyntacticAnalyzer.SourcePosition; + public class Declarators { - public Declarators(boolean isPrivate, boolean isStatic, Type mt) { + public Declarators(boolean isPrivate, boolean isStatic, Type mt, SourcePosition posn) { this.isPrivate = isPrivate; this.isStatic = isStatic; this.mt = mt; + this.posn = posn; } public boolean isPrivate; public boolean isStatic; public Type mt; + public SourcePosition posn; } diff --git a/miniJava/src/miniJava/AbstractSyntaxTrees/FieldDeclList.java b/miniJava/src/miniJava/AbstractSyntaxTrees/FieldDeclList.java index 2f6d96c..18b0843 100644 --- a/miniJava/src/miniJava/AbstractSyntaxTrees/FieldDeclList.java +++ b/miniJava/src/miniJava/AbstractSyntaxTrees/FieldDeclList.java @@ -12,6 +12,11 @@ public class FieldDeclList implements Iterable public FieldDeclList() { fieldDeclList = new ArrayList(); } + + public FieldDeclList(FieldDecl f) { + fieldDeclList = new ArrayList(); + fieldDeclList.add(f); + } public void add(FieldDecl cd){ fieldDeclList.add(cd); diff --git a/miniJava/src/miniJava/AbstractSyntaxTrees/Identifier.java b/miniJava/src/miniJava/AbstractSyntaxTrees/Identifier.java index ebffefa..54e98ac 100644 --- a/miniJava/src/miniJava/AbstractSyntaxTrees/Identifier.java +++ b/miniJava/src/miniJava/AbstractSyntaxTrees/Identifier.java @@ -8,13 +8,14 @@ package miniJava.AbstractSyntaxTrees; import miniJava.SyntacticAnalyzer.SourcePosition; public class Identifier extends Terminal { - + public Identifier (String s, SourcePosition posn) { - super (s,posn); + super (s,posn); } public R visit(Visitor v, A o) { return v.visitIdentifier(this, o); } + public Declaration decl = null; } diff --git a/miniJava/src/miniJava/AbstractSyntaxTrees/MethodDeclList.java b/miniJava/src/miniJava/AbstractSyntaxTrees/MethodDeclList.java index f9b98a9..609da53 100644 --- a/miniJava/src/miniJava/AbstractSyntaxTrees/MethodDeclList.java +++ b/miniJava/src/miniJava/AbstractSyntaxTrees/MethodDeclList.java @@ -11,7 +11,12 @@ public class MethodDeclList implements Iterable { public MethodDeclList() { methodDeclList = new ArrayList(); - } + } + + public MethodDeclList(MethodDecl m) { + methodDeclList = new ArrayList(); + methodDeclList.add(m); + } public void add(MethodDecl cd){ methodDeclList.add(cd); diff --git a/miniJava/src/miniJava/AbstractSyntaxTrees/ParameterDeclList.java b/miniJava/src/miniJava/AbstractSyntaxTrees/ParameterDeclList.java index 64ae1cc..b0e5332 100644 --- a/miniJava/src/miniJava/AbstractSyntaxTrees/ParameterDeclList.java +++ b/miniJava/src/miniJava/AbstractSyntaxTrees/ParameterDeclList.java @@ -13,6 +13,11 @@ public class ParameterDeclList implements Iterable parameterDeclList = new ArrayList(); } + public ParameterDeclList(ParameterDecl p) { + parameterDeclList = new ArrayList(); + parameterDeclList.add(p); + } + public void add(ParameterDecl s){ parameterDeclList.add(s); } diff --git a/miniJava/src/miniJava/AbstractSyntaxTrees/Reference.java b/miniJava/src/miniJava/AbstractSyntaxTrees/Reference.java index 7ba8450..5600ed8 100644 --- a/miniJava/src/miniJava/AbstractSyntaxTrees/Reference.java +++ b/miniJava/src/miniJava/AbstractSyntaxTrees/Reference.java @@ -12,5 +12,6 @@ public abstract class Reference extends AST public Reference(SourcePosition posn){ super(posn); } - + + public Declaration decl; } diff --git a/miniJava/src/miniJava/AbstractSyntaxTrees/TypeKind.java b/miniJava/src/miniJava/AbstractSyntaxTrees/TypeKind.java index b6bd818..16d16b7 100644 --- a/miniJava/src/miniJava/AbstractSyntaxTrees/TypeKind.java +++ b/miniJava/src/miniJava/AbstractSyntaxTrees/TypeKind.java @@ -12,5 +12,6 @@ public enum TypeKind { CLASS, ARRAY, UNSUPPORTED, - ERROR; + ERROR, + VALID; } diff --git a/miniJava/src/miniJava/Compiler.java b/miniJava/src/miniJava/Compiler.java index fe2a7c3..74543e2 100644 --- a/miniJava/src/miniJava/Compiler.java +++ b/miniJava/src/miniJava/Compiler.java @@ -3,9 +3,11 @@ package miniJava; import java.io.*; import miniJava.SyntacticAnalyzer.*; -import miniJava.SyntacticAnalyzer.Errors.*; -import miniJava.AbstractSyntaxTrees.*; +import miniJava.AbstractSyntaxTrees.ASTDisplay; import miniJava.AbstractSyntaxTrees.Package; +import miniJava.ContextualAnalyzer.Analyzer; +import miniJava.ContextualAnalyzer.Reporter; +import miniJava.Exceptions.*; public class Compiler { @@ -26,18 +28,24 @@ public class Compiler { Package p = parser.parse(); // Display - ASTDisplay display = new ASTDisplay(); - display.showTree(p); + // ASTDisplay display = new ASTDisplay(); + // display.showTree(p); + + // Identification/Type Checking + Analyzer analyzer = new Analyzer(); + analyzer.visitPackage(p, null); + if(Reporter.error) System.exit(rc); + System.exit(0); } catch(FileNotFoundException e) { - System.out.println(e.getMessage()); + System.out.println("***" + e.getMessage()); } catch(IOException e) { - System.out.println(e.getMessage()); + System.out.println("***" + e.getMessage()); }catch(ScanningException e) { - System.out.println(e.getMessage()); + System.out.println("***" + e.getMessage()); } catch(ParsingException e) { - System.out.println(e.getMessage()); + System.out.println("***" + e.getMessage()); } System.exit(rc); diff --git a/miniJava/src/miniJava/ContextualAnalyzer/Analyzer.java b/miniJava/src/miniJava/ContextualAnalyzer/Analyzer.java new file mode 100644 index 0000000..0026c65 --- /dev/null +++ b/miniJava/src/miniJava/ContextualAnalyzer/Analyzer.java @@ -0,0 +1,455 @@ +package miniJava.ContextualAnalyzer; + +import miniJava.AbstractSyntaxTrees.*; +import miniJava.AbstractSyntaxTrees.Package; +import miniJava.SyntacticAnalyzer.Parser; +import miniJava.SyntacticAnalyzer.Scanner; +import miniJava.Exceptions.*; + +// Check types +// Ensure static members +// Check for main function +public class Analyzer implements Visitor { + + // Topmost Identification Table + private IdentificationTable table = new IdentificationTable(); + + // Current class decl is for use with the 'this' keyword + private Declaration currentClassDecl = null; + + /** + * Adds predefined names to identification table. + */ + public Analyzer() { + try { + String __PrintStream = "class _PrintStream { public void println(int n){} }"; + new Parser(new Scanner(__PrintStream)).parse().visit(this, table); + + String _System = "class System { public static _PrintStream out; }"; + new Parser(new Scanner(_System)).parse().visit(this, table); + + String _String = "class String { }"; + new Parser(new Scanner(_String)).parse().visit(this, table); + + } catch(ParsingException e) { + System.out.println("Predefined declarations parsing error!"); + } catch(ScanningException e) { + System.out.println("Predefined declarations scanning error!"); + } + } + + /** + * Check that two types match. + * @param t1 + * @param t2 + * @return + */ + private void match(Type t1, Type t2) { + + // Check class types match + if(t1.typeKind == TypeKind.CLASS) { + if(t2.typeKind != TypeKind.CLASS) { + Reporter.report(ErrorType.TYPE_MISMATCH, t1, t2); + } else { + ClassType c1 = (ClassType) t1; + ClassType c2 = (ClassType) t2; + if(!c1.className.spelling.equals(c2.className.spelling)) { + Reporter.report(ErrorType.TYPE_CLASS_MISMATCH, t1, t2); + } + } + } + + // Check array types match + else if(t1.typeKind == TypeKind.ARRAY) { + if(t2.typeKind != TypeKind.ARRAY) { + Reporter.report(ErrorType.TYPE_MISMATCH, t1, t2); + } else { + ArrayType a1 = (ArrayType) t1; + ArrayType a2 = (ArrayType) t2; + if(a1.eltType.typeKind != a2.eltType.typeKind) { + Reporter.report(ErrorType.TYPE_ARRAY_MISMATCH, t1, t2); + } + } + } + + // Check primitive types match + else if(t1.typeKind != t2.typeKind) { + Reporter.report(ErrorType.TYPE_MISMATCH, t1, t2); + } + } + + @Override + public Type visitPackage(Package prog, IdentificationTable arg) { + + /* Since classes and static methods/fields can be referenced + * before the classes themselves are declared, we preprocess + * all classes and methods first. + */ + for(ClassDecl cd : prog.classDeclList) { + + IdentificationTable cdTable = table.openScope(cd); + if(cdTable != null) { + + // Simply add fields to current scope + for(FieldDecl fd : cd.fieldDeclList) { + cdTable.setDeclarationAtScope(fd); + } + + // Just Add Declaration (also creates another identification table) + for(MethodDecl md : cd.methodDeclList) { + cdTable.openScope(md); + } + } + } + + // Begin Traversal + for(ClassDecl cd : prog.classDeclList) { + currentClassDecl = cd; + cd.visit(this, table); + } + + return null; + } + + @Override + public Type visitClassDecl(ClassDecl cd, IdentificationTable arg) { + IdentificationTable cdTable = arg.getScope(cd); + if(cdTable != null) { + + for(FieldDecl fd : cd.fieldDeclList) { + fd.visit(this, cdTable); + } + + for(MethodDecl md : cd.methodDeclList) { + md.visit(this, cdTable); + } + } + + return cd.type; + } + + @Override + public Type visitFieldDecl(FieldDecl fd, IdentificationTable arg) { + + // Must check that the type of the field can be identified + table.validateClassId(fd.type); + + return fd.type; + } + + @Override + public Type visitMethodDecl(MethodDecl md, IdentificationTable arg) { + + IdentificationTable mdTable = arg.getScope(md); + + // Must check that the type of the method can be identified + table.validateClassId(md.type); + + // Continue Traversal + if(mdTable != null) { + for(ParameterDecl pd : md.parameterDeclList) { + pd.visit(this, mdTable); + } + + for(Statement s : md.statementList) { + s.visit(this, mdTable); + } + + // Check that return type matches expected type + if(md.returnExp != null) { + Type returnType = md.returnExp.visit(this, mdTable); + match(md.type, returnType); + } else if(md.type.typeKind != TypeKind.VOID) { + Reporter.report(ErrorType.NO_RETURN_EXPRESSION, md.type); + } + } + + return md.type; + } + + @Override + public Type visitParameterDecl(ParameterDecl pd, IdentificationTable arg) { + arg.setDeclarationAtScope(pd); + table.validateClassId(pd.type); + return pd.type; + } + + @Override + public Type visitVarDecl(VarDecl decl, IdentificationTable arg) { + arg.setDeclarationAtScope(decl); + table.validateClassId(decl.type); + return decl.type; + } + + @Override + public Type visitBaseType(BaseType type, IdentificationTable arg) { + + return type; + } + + @Override + public Type visitClassType(ClassType type, IdentificationTable arg) { + type.className.visit(this, arg); + return type; + } + + @Override + public Type visitArrayType(ArrayType type, IdentificationTable arg) { + type.eltType.visit(this, arg); + return type; + } + + @Override + public Type visitBlockStmt(BlockStmt stmt, IdentificationTable arg) { + arg.pushLevel(); + for(Statement s : stmt.sl) { + s.visit(this, arg); + } + arg.popLevel(); + + return null; + } + + @Override + public Type visitVardeclStmt(VarDeclStmt stmt, IdentificationTable arg) { + + // The stmt of the vardecl may not refer to the variable itself so we check the stmt first + Type initExpType = stmt.initExp.visit(this, arg); + Type varDeclType = stmt.varDecl.visit(this, arg); + match(varDeclType, initExpType); + + return varDeclType; + } + + @Override + public Type visitAssignStmt(AssignStmt stmt, IdentificationTable arg) { + Type valType = stmt.val.visit(this, arg); + Type refType = stmt.ref.visit(this, arg); + match(valType, refType); + + return refType; + } + + @Override + public Type visitCallStmt(CallStmt stmt, IdentificationTable arg) { + Type methodType = stmt.methodRef.visit(this, arg); + + // Check that parameter count is correct and each type is correct + MethodDecl decl = (MethodDecl) stmt.methodRef.decl; + if(decl.parameterDeclList.size() != stmt.argList.size()) { + Reporter.report(ErrorType.INVALID_PARAM_COUNT, stmt); + } else { + for(int i = 0; i < stmt.argList.size(); i++) { + Type exprType = stmt.argList.get(i).visit(this, arg); + Type pdType = decl.parameterDeclList.get(i).type; + match(pdType, exprType); + } + } + + return methodType; + } + + @Override + public Type visitIfStmt(IfStmt stmt, IdentificationTable arg) { + + // The conditional statment must be a boolean + Type condType = stmt.cond.visit(this, arg); + match(new BaseType(TypeKind.BOOLEAN, null), condType); + + // A single vardecl cannot exist after a conditional statement + if(stmt.thenStmt instanceof VarDeclStmt) { + Reporter.report(ErrorType.VAR_COND_ONLY, stmt.thenStmt); + } else { + stmt.thenStmt.visit(this, arg); + if(stmt.elseStmt != null) { + if(stmt.elseStmt instanceof VarDeclStmt) { + Reporter.report(ErrorType.VAR_COND_ONLY, stmt.elseStmt); + } else { + stmt.elseStmt.visit(this, arg); + } + } + } + + return null; + } + + @Override + public Type visitWhileStmt(WhileStmt stmt, IdentificationTable arg) { + + // The conditional statment must be a boolean + Type condType = stmt.cond.visit(this, arg); + match(new BaseType(TypeKind.BOOLEAN, null), condType); + + if(stmt.body instanceof VarDeclStmt) { + Reporter.report(ErrorType.VAR_COND_ONLY, stmt.body); + } else { + stmt.body.visit(this, arg); + } + + return null; + } + + @Override + public Type visitUnaryExpr(UnaryExpr expr, IdentificationTable arg) { + Type opType = expr.operator.visit(this, arg); + Type exprType = expr.expr.visit(this, arg); + match(opType, exprType); + + return null; + } + + @Override + public Type visitBinaryExpr(BinaryExpr expr, IdentificationTable arg) { + Type opType = expr.operator.visit(this, arg); + Type leftType = expr.left.visit(this, arg); + Type rightType = expr.right.visit(this, arg); + + match(opType, leftType); + match(opType, rightType); + + return null; + } + + @Override + public Type visitRefExpr(RefExpr expr, IdentificationTable arg) { + + return expr.ref.visit(this, arg); + } + + @Override + public Type visitCallExpr(CallExpr expr, IdentificationTable arg) { + Type functionType = expr.functionRef.visit(this, arg); + + // Check that parameter count is correct and each type is correct + MethodDecl decl = (MethodDecl) expr.functionRef.decl; + if(decl.parameterDeclList.size() != expr.argList.size()) { + Reporter.report(ErrorType.INVALID_PARAM_COUNT, expr); + } else { + for(int i = 0; i < expr.argList.size(); i++) { + Type exprType = expr.argList.get(i).visit(this, arg); + Type pdType = decl.parameterDeclList.get(i).type; + match(pdType, exprType); + } + } + + return functionType; + } + + @Override + public Type visitLiteralExpr(LiteralExpr expr, IdentificationTable arg) { + + return expr.literal.visit(this, arg); + } + + @Override + public Type visitNewObjectExpr(NewObjectExpr expr, IdentificationTable arg) { + + return expr.classtype.visit(this, arg); + } + + @Override + public Type visitNewArrayExpr(NewArrayExpr expr, IdentificationTable arg) { + Type sizeExprType = expr.sizeExpr.visit(this, arg); + if(sizeExprType.typeKind != TypeKind.INT) { + Reporter.report(ErrorType.INVALID_INDEX, expr.sizeExpr); + } + + return expr.eltType.visit(this, arg); + } + + @Override + public Type visitQualifiedRef(QualifiedRef ref, IdentificationTable arg) { + ref.ref.visit(this, arg); + ref.id.visit(this, arg); + + // Check that each declaration is nested properly + if(ref.decl == null || table.getDeclaration(ref.decl.name) == null) { + System.out.println(ref.id.spelling); + // report(ErrorType.MISSING_DECL, ref.ref.decl); + } + + return null; + } + + @Override + public Type visitIndexedRef(IndexedRef ref, IdentificationTable arg) { + ref.ref.visit(this, arg); + ref.decl = ref.ref.decl; + + // Make sure index is an integer + Type indexExprType = ref.indexExpr.visit(this, arg); + if(indexExprType.typeKind != TypeKind.INT) { + Reporter.report(ErrorType.INVALID_INDEX, ref.indexExpr); + } + + return ref.decl.type; + } + + @Override + public Type visitIdRef(IdRef ref, IdentificationTable arg) { + ref.id.visit(this, arg); + ref.decl = ref.id.decl; + + return ref.decl.type; + } + + @Override + public Type visitThisRef(ThisRef ref, IdentificationTable arg) { + ref.decl = currentClassDecl; + + return ref.decl.type; + } + + @Override + public Type visitIdentifier(Identifier id, IdentificationTable arg) { + // Try to find identifier, reporting a message if it cannot be found + Declaration decl = arg.getDeclaration(id.spelling); + if(decl == null) { + Reporter.report(ErrorType.UNIDENTIFIED, id); + return new BaseType(TypeKind.ERROR, null); + } else { + id.decl = decl; + return decl.type; + } + } + + @Override + public Type visitOperator(Operator op, IdentificationTable arg) { + + switch(op.token.spelling) { + case "!": + case ">": + case "<": + case "==": + case "<=": + case ">=": + case "!=": + case "&&": + case "||": + return new BaseType(TypeKind.BOOLEAN, op.posn); + + case "+": + case "-": + case "*": + case "/": + return new BaseType(TypeKind.INT, op.posn); + + default: + Reporter.report(ErrorType.UNIDENTIFIED_TYPE, op); + return new BaseType(TypeKind.ERROR, op.posn); + } + } + + @Override + public Type visitIntLiteral(IntLiteral num, IdentificationTable arg) { + + return new BaseType(TypeKind.INT, num.posn); + } + + @Override + public Type visitBooleanLiteral(BooleanLiteral bool, IdentificationTable arg) { + + return new BaseType(TypeKind.BOOLEAN, bool.posn); + } + +} diff --git a/miniJava/src/miniJava/ContextualAnalyzer/IdentificationTable.java b/miniJava/src/miniJava/ContextualAnalyzer/IdentificationTable.java new file mode 100644 index 0000000..d2d56e4 --- /dev/null +++ b/miniJava/src/miniJava/ContextualAnalyzer/IdentificationTable.java @@ -0,0 +1,145 @@ +package miniJava.ContextualAnalyzer; + +import java.util.HashMap; +import java.util.ArrayList; + +import miniJava.AbstractSyntaxTrees.ClassType; +import miniJava.AbstractSyntaxTrees.Declaration; +import miniJava.AbstractSyntaxTrees.Type; +import miniJava.AbstractSyntaxTrees.TypeKind; + +public class IdentificationTable { + + private IdentificationTable parent; + private HashMap scope; + private ArrayList> table; + + /** + * + */ + public IdentificationTable() { + this(null); + } + + /** + * + * @param parent + */ + public IdentificationTable(IdentificationTable parent) { + this.parent = parent; + this.scope = new HashMap(); + this.table = new ArrayList>(); + this.table.add(new HashMap()); + } + + /** + * Adds another level for variables to be stored at (they will be + * removed when popping said level). + */ + public void pushLevel() { + table.add(new HashMap()); + } + + /** + * Removes all variables declared at the current level (these are + * no longer accessible). + */ + public void popLevel() { + table.remove(table.size() - 1); + } + + /** + * This method will only ever be called with class/method declarations + * @param decl + * @return + */ + public IdentificationTable openScope(Declaration decl) { + if(scope.containsKey(decl.name) || getDeclarationAtScope(decl.name) != null) { + Reporter.report(ErrorType.REDEFINITION, decl); + return null; + } else { + table.get(table.size() - 1).put(decl.name, decl); + scope.put(decl.name, new IdentificationTable(this)); + return scope.get(decl.name); + } + } + + /** + * Return nested scope corresponding to declaration (or null if non-existant). + * @param decl + * @return + */ + public IdentificationTable getScope(Declaration decl) { + if(scope.containsKey(decl.name)) { + return scope.get(decl.name); + } + + return null; + } + + /** + * Iterates through all parents and tries to find the specified + * declaration by name. + * @param name + * @return + */ + public Declaration getDeclaration(String name) { + IdentificationTable current = this; + while(current != null) { + Declaration decl = current.getDeclarationAtScope(name); + if(decl == null) { + current = current.parent; + } else { + return decl; + } + } + + return null; + } + + /** + * Iterates through levels (from higher to lower) for declaration, + * returning none if it does not exist. + * @param name + * @return + */ + public Declaration getDeclarationAtScope(String name) { + for(int i = table.size() - 1; i >= 0; i--) { + HashMap level = table.get(i); + if(level.containsKey(name)) { + return level.get(name); + } + } + + return null; + } + + /** + * Add declaration to current table's table member. + * @param name + */ + public void setDeclarationAtScope(Declaration decl) { + for(int i = 0; i < table.size(); i++) { + HashMap level = table.get(i); + if(level.containsKey(decl.name)) { + Reporter.report(ErrorType.REDEFINITION, decl); + return; + } + } + + table.get(table.size() - 1).put(decl.name, decl); + } + + /** + * Checks that the passed class type does exist. + * @param ct + */ + public void validateClassId(Type t) { + if(t.typeKind == TypeKind.CLASS) { + ClassType ct = (ClassType) t; + if(getDeclaration(ct.className.spelling) == null) { + Reporter.report(ErrorType.MISSING_DECL, ct); + } + } + } +} diff --git a/miniJava/src/miniJava/ContextualAnalyzer/Reporter.java b/miniJava/src/miniJava/ContextualAnalyzer/Reporter.java new file mode 100644 index 0000000..b1c21dc --- /dev/null +++ b/miniJava/src/miniJava/ContextualAnalyzer/Reporter.java @@ -0,0 +1,122 @@ +package miniJava.ContextualAnalyzer; + +import miniJava.AbstractSyntaxTrees.*; + +enum ErrorType { + VAR_COND_ONLY, + MISSING_DECL, + UNIDENTIFIED, + REDEFINITION, + INVALID_PARAM_COUNT, + INVALID_INDEX, + TYPE_MISMATCH, + UNIDENTIFIED_TYPE, + TYPE_CLASS_MISMATCH, + TYPE_ARRAY_MISMATCH, + NO_RETURN_EXPRESSION; +} + +public class Reporter { + + public static boolean error = false; + + /** + * Prints out to console correct error message. + * @param type + * @param ast + */ + public static void report(ErrorType type, AST ast) { + error = true; + switch(type) { + + // VarDeclStmt is only statement in conditional branch + case VAR_COND_ONLY: { + System.out.println("***Conditional statment cannot be followed by a variable declaration statement " + ast.posn); + break; + } + + // Declaration does not exist for reference + case MISSING_DECL: { + System.out.println("***Reference to a non-existant type " + ast.posn); + break; + } + + // Reports when a reference could not be found + case UNIDENTIFIED: { + System.out.println("***Reference refers to a declaration that does not exist " + ast.posn); + break; + } + + // Attempting to redeclare a variable + case REDEFINITION: { + System.out.println("***Variable has already been defined earlier " + ast.posn); + break; + } + + // A non void function does not have a return statement + case NO_RETURN_EXPRESSION: { + System.out.println("***Non-void method does not have a return statement " + ast.posn); + break; + } + + // The number of parameters passed is either too few or too great + case INVALID_PARAM_COUNT: { + System.out.println("***The number of passed parameters does not equal expected count " + ast.posn); + } + + // The expected expression MUST return an int (such as the index of an array) + case INVALID_INDEX: { + System.out.println("***Expected an integer value as the index of an array " + ast.posn); + break; + } + + // Hmmm..... + case UNIDENTIFIED_TYPE: { + System.out.println("***Unexpected type " + ast.posn); + break; + } + + // Clear Warning + default: + break; + } + } + + /** + * Type specific error reporting. + * @param type + * @param t1 + * @param t2 + */ + public static void report(ErrorType type, Type t1, Type t2) { + error = true; + switch(type) { + + // Non class/array types don't match + case TYPE_MISMATCH: { + System.out.println("***Expected type " + t1.typeKind + " but got " + t2.typeKind + t2.posn); + break; + } + + // Two classes don't match + case TYPE_CLASS_MISMATCH: { + ClassType c1 = (ClassType) t1; + ClassType c2 = (ClassType) t2; + System.out.println("***Expected type " + c1.className.spelling + " but got " + c2.className.spelling + c2.posn); + break; + } + + // Two arrays don't match + case TYPE_ARRAY_MISMATCH: { + ArrayType a1 = (ArrayType) t1; + ArrayType a2 = (ArrayType) t2; + System.out.println("***Expected array type " + a1.eltType.typeKind + " but got " + a2.eltType.typeKind + t2.posn); + break; + } + + // Clear Warning + default: + break; + } + } +} diff --git a/miniJava/src/miniJava/Exceptions/IdentificationException.java b/miniJava/src/miniJava/Exceptions/IdentificationException.java new file mode 100644 index 0000000..167ee93 --- /dev/null +++ b/miniJava/src/miniJava/Exceptions/IdentificationException.java @@ -0,0 +1,10 @@ +package miniJava.Exceptions; + +public class IdentificationException extends Exception { + + private static final long serialVersionUID = 1L; + + public IdentificationException() { + super("Identification Error!"); + } +} diff --git a/miniJava/src/miniJava/SyntacticAnalyzer/Errors/ParsingException.java b/miniJava/src/miniJava/Exceptions/ParsingException.java similarity index 87% rename from miniJava/src/miniJava/SyntacticAnalyzer/Errors/ParsingException.java rename to miniJava/src/miniJava/Exceptions/ParsingException.java index 5751350..97e760e 100644 --- a/miniJava/src/miniJava/SyntacticAnalyzer/Errors/ParsingException.java +++ b/miniJava/src/miniJava/Exceptions/ParsingException.java @@ -1,4 +1,4 @@ -package miniJava.SyntacticAnalyzer.Errors; +package miniJava.Exceptions; import miniJava.SyntacticAnalyzer.Token; diff --git a/miniJava/src/miniJava/SyntacticAnalyzer/Errors/ScanningException.java b/miniJava/src/miniJava/Exceptions/ScanningException.java similarity index 84% rename from miniJava/src/miniJava/SyntacticAnalyzer/Errors/ScanningException.java rename to miniJava/src/miniJava/Exceptions/ScanningException.java index 8a754a8..4bbfd3a 100644 --- a/miniJava/src/miniJava/SyntacticAnalyzer/Errors/ScanningException.java +++ b/miniJava/src/miniJava/Exceptions/ScanningException.java @@ -1,4 +1,4 @@ -package miniJava.SyntacticAnalyzer.Errors; +package miniJava.Exceptions; public class ScanningException extends Exception { diff --git a/miniJava/src/miniJava/SyntacticAnalyzer/Parser.java b/miniJava/src/miniJava/SyntacticAnalyzer/Parser.java index 813ea37..686ef42 100644 --- a/miniJava/src/miniJava/SyntacticAnalyzer/Parser.java +++ b/miniJava/src/miniJava/SyntacticAnalyzer/Parser.java @@ -4,7 +4,7 @@ import java.util.LinkedList; import miniJava.AbstractSyntaxTrees.*; import miniJava.AbstractSyntaxTrees.Package; -import miniJava.SyntacticAnalyzer.Errors.*; +import miniJava.Exceptions.*; public class Parser { @@ -28,7 +28,7 @@ public class Parser { } accept(Token.TYPE.EOT); - return new Package(decls, null); + return new Package(decls, new SourcePosition(0, 0)); } /** @@ -42,7 +42,7 @@ public class Parser { private ClassDecl parseClassDeclaration() throws ParsingException, ScanningException { // Class Header - accept(Token.TYPE.CLASS); + Token classToken = accept(Token.TYPE.CLASS); String cn = accept(Token.TYPE.ID).spelling; accept(Token.TYPE.LBRACKET); @@ -54,7 +54,7 @@ public class Parser { while(peek(1).type != Token.TYPE.RBRACKET) { Declarators d = parseDeclarators(); String name = accept(Token.TYPE.ID).spelling; - FieldDecl f = new FieldDecl(d.isPrivate, d.isStatic, d.mt, name, null); + FieldDecl f = new FieldDecl(d.isPrivate, d.isStatic, d.mt, name, d.posn); // Field Declarations if(peek(1).type == Token.TYPE.SEMICOLON) { @@ -67,7 +67,7 @@ public class Parser { } accept(Token.TYPE.RBRACKET); - return new ClassDecl(cn, fdl, mdl, null); + return new ClassDecl(cn, fdl, mdl, classToken.posn); } /** @@ -78,23 +78,33 @@ public class Parser { private Declarators parseDeclarators() throws ParsingException, ScanningException { // Visibility + SourcePosition start = null; boolean isPrivate = false; + if(peek(1).type == Token.TYPE.PUBLIC) { - accept(Token.TYPE.PUBLIC); + start = accept(Token.TYPE.PUBLIC).posn; } else if(peek(1).type == Token.TYPE.PRIVATE) { isPrivate = true; - accept(Token.TYPE.PRIVATE); + start = accept(Token.TYPE.PRIVATE).posn; } // Class Methods boolean isStatic = false; if(peek(1).type == Token.TYPE.STATIC) { isStatic = true; - accept(Token.TYPE.STATIC); + if(start == null) { + start = accept(Token.TYPE.STATIC).posn; + } else { + accept(Token.TYPE.STATIC); + } } Type t = parseType(); - return new Declarators(isPrivate, isStatic, t); + if(start == null) { + start = t.posn; + } + + return new Declarators(isPrivate, isStatic, t, start); } /** @@ -134,7 +144,7 @@ public class Parser { } accept(Token.TYPE.RBRACKET); - return new MethodDecl(f, pdl, stl, re, null); + return new MethodDecl(f, pdl, stl, re, f.posn); } /** @@ -144,38 +154,40 @@ public class Parser { */ private Type parseType() throws ParsingException, ScanningException { + SourcePosition posn = null; + switch(peek(1).type) { case BOOLEAN: - accept(Token.TYPE.BOOLEAN); - return new BaseType(TypeKind.BOOLEAN, null); + posn = accept(Token.TYPE.BOOLEAN).posn; + return new BaseType(TypeKind.BOOLEAN, posn); case VOID: - accept(Token.TYPE.VOID); - return new BaseType(TypeKind.VOID, null); + posn = accept(Token.TYPE.VOID).posn; + return new BaseType(TypeKind.VOID, posn); case INT: { - accept(Token.TYPE.INT); - BaseType b = new BaseType(TypeKind.INT, null); + posn = accept(Token.TYPE.INT).posn; + BaseType b = new BaseType(TypeKind.INT, posn); if(peek(1).type == Token.TYPE.LSQUARE) { accept(Token.TYPE.LSQUARE); accept(Token.TYPE.RSQUARE); - return new ArrayType(b, null); + return new ArrayType(b, posn); } return b; } case ID: { - String cn = accept(peek(1).type).spelling; - Identifier i = new Identifier(cn, null); - ClassType c = new ClassType(i, null); + Token id = accept(peek(1).type); + Identifier i = new Identifier(id.spelling, id.posn); + ClassType c = new ClassType(i, id.posn); if(peek(1).type == Token.TYPE.LSQUARE) { accept(Token.TYPE.LSQUARE); accept(Token.TYPE.RSQUARE); - return new ArrayType(c, null); + return new ArrayType(c, id.posn); } return c; @@ -197,15 +209,15 @@ public class Parser { // First Parameter Type t = parseType(); - String name = accept(Token.TYPE.ID).spelling; - decls.add(new ParameterDecl(t, name, null)); + Token id = accept(Token.TYPE.ID); + decls.add(new ParameterDecl(t, id.spelling, id.posn)); // Remainder of List while(peek(1).type == Token.TYPE.COMMA) { accept(Token.TYPE.COMMA); - t = parseType(); - name = accept(Token.TYPE.ID).spelling; - decls.add(new ParameterDecl(t, name, null)); + Type nextType = parseType(); + Token nextId = accept(Token.TYPE.ID); + decls.add(new ParameterDecl(nextType, nextId.spelling, nextId.posn)); } return decls; @@ -236,15 +248,15 @@ public class Parser { Reference r = parseBaseRef(); while(peek(1).type == Token.TYPE.PERIOD) { accept(Token.TYPE.PERIOD); - String name = accept(Token.TYPE.ID).spelling; - Identifier id = new Identifier(name, null); - r = new QualifiedRef(r, id, null); + Token tokenId = accept(Token.TYPE.ID); + Identifier id = new Identifier(tokenId.spelling, tokenId.posn); + r = new QualifiedRef(r, id, tokenId.posn); if(peek(1).type == Token.TYPE.LSQUARE) { accept(Token.TYPE.LSQUARE); Expression e = parseExpression(); accept(Token.TYPE.RSQUARE); - r = new IndexedRef(r, e, null); + r = new IndexedRef(r, e, tokenId.posn); } } @@ -259,21 +271,22 @@ public class Parser { private Reference parseBaseRef() throws ParsingException, ScanningException { switch(peek(1).type) { - case THIS: - accept(Token.TYPE.THIS); - return new ThisRef(null); + case THIS: { + Token thisToken = accept(Token.TYPE.THIS); + return new ThisRef(thisToken.posn); + } // id ([ Expression])? default: { - String id = accept(Token.TYPE.ID).spelling; - Identifier i = new Identifier(id, null); - IdRef r = new IdRef(i, null); + Token id = accept(Token.TYPE.ID); + Identifier i = new Identifier(id.spelling, id.posn); + IdRef r = new IdRef(i, id.posn); if(peek(1).type == Token.TYPE.LSQUARE) { accept(Token.TYPE.LSQUARE); Expression e = parseExpression(); accept(Token.TYPE.RSQUARE); - return new IndexedRef(r, e, null); + return new IndexedRef(r, e, id.posn); } return r; @@ -298,19 +311,19 @@ public class Parser { // { Statement* } case LBRACKET: { - accept(Token.TYPE.LBRACKET); + Token leftToken = accept(Token.TYPE.LBRACKET); StatementList stl = new StatementList(); while(peek(1).type != Token.TYPE.RBRACKET) { stl.add(parseStatement()); } accept(Token.TYPE.RBRACKET); - return new BlockStmt(stl, null); + return new BlockStmt(stl, leftToken.posn); } // if (Expression) Statement (else Statement)? case IF: { - accept(Token.TYPE.IF); + Token ifToken = accept(Token.TYPE.IF); accept(Token.TYPE.LPAREN); Expression e = parseExpression(); accept(Token.TYPE.RPAREN); @@ -318,21 +331,21 @@ public class Parser { if(peek(1).type == Token.TYPE.ELSE) { accept(Token.TYPE.ELSE); Statement s2 = parseStatement(); - return new IfStmt(e, s1, s2, null); + return new IfStmt(e, s1, s2, ifToken.posn); } - return new IfStmt(e, s1, null); + return new IfStmt(e, s1, ifToken.posn); } // while (Expression) Statement case WHILE: { - accept(Token.TYPE.WHILE); + Token whileToken = accept(Token.TYPE.WHILE); accept(Token.TYPE.LPAREN); Expression e = parseExpression(); accept(Token.TYPE.RPAREN); Statement s = parseStatement(); - return new WhileStmt(e, s, null); + return new WhileStmt(e, s, whileToken.posn); } // Type id = Expression ; @@ -343,13 +356,13 @@ public class Parser { ||(peek(2).type == Token.TYPE.LSQUARE && peek(3).type == Token.TYPE.RSQUARE)) { Type t = parseType(); String name = accept(Token.TYPE.ID).spelling; - VarDecl v = new VarDecl(t, name, null); + VarDecl v = new VarDecl(t, name, t.posn); accept(Token.TYPE.EQUALS); Expression e = parseExpression(); accept(Token.TYPE.SEMICOLON); - return new VarDeclStmt(v, e, null); + return new VarDeclStmt(v, e, t.posn); } /* Fall Through */ @@ -367,14 +380,14 @@ public class Parser { e = parseArgumentList(); } accept(Token.TYPE.RPAREN); - s = new CallStmt(r, e, null); + s = new CallStmt(r, e, r.posn); } // Reference = Expression ; else { accept(Token.TYPE.EQUALS); Expression e = parseExpression(); - s = new AssignStmt(r, e, null); + s = new AssignStmt(r, e, r.posn); } accept(Token.TYPE.SEMICOLON); @@ -401,18 +414,18 @@ public class Parser { // num case NUM: { - String number = accept(Token.TYPE.NUM).spelling; - IntLiteral i = new IntLiteral(number, null); - e = new LiteralExpr(i, null); + Token number = accept(Token.TYPE.NUM); + IntLiteral i = new IntLiteral(number.spelling, number.posn); + e = new LiteralExpr(i, number.posn); break; } // true | false case TRUE: case FALSE: { - String bool = accept(peek(1).type).spelling; - BooleanLiteral b = new BooleanLiteral(bool, null); - e = new LiteralExpr(b, null); + Token bool = accept(peek(1).type); + BooleanLiteral b = new BooleanLiteral(bool.spelling, bool.posn); + e = new LiteralExpr(b, bool.posn); break; } @@ -428,8 +441,9 @@ public class Parser { case UNOP: case BINOP: { if(peek(1).spelling.equals("!") || peek(1).spelling.equals("-")) { - Operator o = new Operator(accept(peek(1).type), null); - e = new UnaryExpr(o, parseSingleExpression(), null); + Token opToken = accept(peek(1).type); + Operator o = new Operator(opToken, opToken.posn); + e = new UnaryExpr(o, parseSingleExpression(), opToken.posn); } else throw new ParsingException(); break; @@ -437,7 +451,7 @@ public class Parser { // new ( int [ Expression ] | id ( ) | id [ Expression ] ) case NEW: { - accept(Token.TYPE.NEW); + Token newToken = accept(Token.TYPE.NEW); if(peek(1).type == Token.TYPE.INT) { accept(Token.TYPE.INT); @@ -445,24 +459,24 @@ public class Parser { Expression e2 = parseExpression(); accept(Token.TYPE.RSQUARE); - BaseType b = new BaseType(TypeKind.INT, null); - e = new NewArrayExpr(b, e2, null); + BaseType b = new BaseType(TypeKind.INT, newToken.posn); + e = new NewArrayExpr(b, e2, newToken.posn); } else { - String cn = accept(Token.TYPE.ID).spelling; - Identifier i = new Identifier(cn, null); - ClassType c = new ClassType(i, null); + Token id = accept(Token.TYPE.ID); + Identifier i = new Identifier(id.spelling, id.posn); + ClassType c = new ClassType(i, id.posn); if(peek(1).type == Token.TYPE.LPAREN){ accept(Token.TYPE.LPAREN); accept(Token.TYPE.RPAREN); - e = new NewObjectExpr(c, null); + e = new NewObjectExpr(c, id.posn); } else { accept(Token.TYPE.LSQUARE); Expression e2 = parseExpression(); accept(Token.TYPE.RSQUARE); - e = new NewArrayExpr(c, e2, null); + e = new NewArrayExpr(c, e2, id.posn); } } @@ -479,9 +493,9 @@ public class Parser { el = parseArgumentList(); } accept(Token.TYPE.RPAREN); - e = new CallExpr(r, el, null); + e = new CallExpr(r, el, r.posn); } else { - e = new RefExpr(r, null); + e = new RefExpr(r, r.posn); } break; @@ -504,8 +518,9 @@ public class Parser { Expression e = parseCExpression(); while(peek(1).spelling.equals("||")) { - Operator o = new Operator(accept(Token.TYPE.BINOP), null); - e = new BinaryExpr(o, e, parseCExpression(), null); + Token opToken = accept(Token.TYPE.BINOP); + Operator o = new Operator(opToken, opToken.posn); + e = new BinaryExpr(o, e, parseCExpression(), e.posn); } return e; @@ -520,8 +535,9 @@ public class Parser { Expression e = parseEExpression(); while(peek(1).spelling.equals("&&")) { - Operator o = new Operator(accept(Token.TYPE.BINOP), null); - e = new BinaryExpr(o, e, parseEExpression(), null); + Token opToken = accept(Token.TYPE.BINOP); + Operator o = new Operator(opToken, opToken.posn); + e = new BinaryExpr(o, e, parseEExpression(), e.posn); } return e; @@ -536,8 +552,9 @@ public class Parser { Expression e = parseRExpression(); while(peek(1).spelling.equals("==") || peek(1).spelling.equals("!=")) { - Operator o = new Operator(accept(Token.TYPE.BINOP), null); - e = new BinaryExpr(o, e, parseRExpression(), null); + Token opToken = accept(Token.TYPE.BINOP); + Operator o = new Operator(opToken, opToken.posn); + e = new BinaryExpr(o, e, parseRExpression(), e.posn); } return e; @@ -553,8 +570,9 @@ public class Parser { Expression e = parseAExpression(); while(peek(1).spelling.equals("<") || peek(1).spelling.equals("<=") || peek(1).spelling.equals(">") || peek(1).spelling.equals(">=")) { - Operator o = new Operator(accept(Token.TYPE.BINOP), null); - e = new BinaryExpr(o, e, parseAExpression(), null); + Token opToken = accept(Token.TYPE.BINOP); + Operator o = new Operator(opToken, opToken.posn); + e = new BinaryExpr(o, e, parseAExpression(), e.posn); } return e; @@ -569,8 +587,9 @@ public class Parser { Expression e = parseMExpression(); while(peek(1).spelling.equals("+") || peek(1).spelling.equals("-")) { - Operator o = new Operator(accept(Token.TYPE.BINOP), null); - e = new BinaryExpr(o, e, parseMExpression(), null); + Token opToken = accept(Token.TYPE.BINOP); + Operator o = new Operator(opToken, opToken.posn); + e = new BinaryExpr(o, e, parseMExpression(), e.posn); } return e; @@ -585,8 +604,9 @@ public class Parser { Expression e = parseSingleExpression(); while(peek(1).spelling.equals("*") || peek(1).spelling.equals("/")) { - Operator o = new Operator(accept(Token.TYPE.BINOP), null); - e = new BinaryExpr(o, e, parseSingleExpression(), null); + Token opToken = accept(Token.TYPE.BINOP); + Operator o = new Operator(opToken, opToken.posn); + e = new BinaryExpr(o, e, parseSingleExpression(), e.posn); } return e; diff --git a/miniJava/src/miniJava/SyntacticAnalyzer/Scanner.java b/miniJava/src/miniJava/SyntacticAnalyzer/Scanner.java index bf696a0..0c2aea9 100644 --- a/miniJava/src/miniJava/SyntacticAnalyzer/Scanner.java +++ b/miniJava/src/miniJava/SyntacticAnalyzer/Scanner.java @@ -1,8 +1,7 @@ package miniJava.SyntacticAnalyzer; import java.io.*; - -import miniJava.SyntacticAnalyzer.Errors.ScanningException; +import miniJava.Exceptions.*; public class Scanner { @@ -14,6 +13,11 @@ public class Scanner { this.input = input; } + public Scanner(String input) { + StringReader reader = new StringReader(input); + this.input = new BufferedReader(reader); + } + /** * Scans in input, returning next token. * @return @@ -132,7 +136,7 @@ public class Scanner { // Identifier or Keyword if(isAlpha((char) c)) { - for(char n = peek(); isAlpha(n) || isDigit(n) || n == '_';) { + for(char n = peek(); isAlpha(n) || isDigit(n);) { attr += (char) read(); n = peek(); } @@ -166,6 +170,7 @@ public class Scanner { } } + token.posn = new SourcePosition(line, col - token.spelling.length()); return token; } @@ -216,7 +221,10 @@ public class Scanner { try { int next = input.read(); if(next != '\n' && next != '\r') col += 1; - else { col = 1; line += 1; } + else { + col = 1; line += 1; + if(peek('\r') || peek('\n')) next = input.read(); + } return next; } catch(IOException e) { @@ -230,18 +238,14 @@ public class Scanner { * @throws IOException */ private void readComment() throws ScanningException { - try { - char prev = '\0', current = '\0'; - while(prev != '*' || current != '/') { - - prev = current; - - int next = input.read(); - if(next == -1) throw new IOException(); - else current = (char) next; - } - } catch(IOException e) { - throw new ScanningException(col, line); + char prev = '\0', current = '\0'; + while(prev != '*' || current != '/') { + + prev = current; + + int next = read(); + if(next == -1) throw new ScanningException(col, line); + else current = (char) next; } } @@ -251,11 +255,7 @@ public class Scanner { * @throws IOException */ private void readLine() throws ScanningException { - try { - for(int n = 0; n != '\n' && n != '\r' && n != -1; n = input.read()) {} - } catch(IOException e) { - throw new ScanningException(col, line); - } + for(int n = 0; n != '\n' && n != '\r' && n != -1; n = read()) {} } @@ -266,7 +266,8 @@ public class Scanner { */ private boolean isAlpha(char c) { return (c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z'); + || (c >= 'A' && c <= 'Z') + || c == '_'; } diff --git a/miniJava/src/miniJava/SyntacticAnalyzer/SourcePosition.java b/miniJava/src/miniJava/SyntacticAnalyzer/SourcePosition.java index 38ddb6c..3855ab2 100644 --- a/miniJava/src/miniJava/SyntacticAnalyzer/SourcePosition.java +++ b/miniJava/src/miniJava/SyntacticAnalyzer/SourcePosition.java @@ -9,4 +9,9 @@ public class SourcePosition { this.col = col; this.line = line; } + + @Override + public String toString() { + return "(Line: " + line + ", Column: " + col + ")"; + } } diff --git a/miniJava/src/miniJava/SyntacticAnalyzer/Token.java b/miniJava/src/miniJava/SyntacticAnalyzer/Token.java index 7c78681..519dc58 100644 --- a/miniJava/src/miniJava/SyntacticAnalyzer/Token.java +++ b/miniJava/src/miniJava/SyntacticAnalyzer/Token.java @@ -69,10 +69,12 @@ public class Token { } public final TYPE type; + public SourcePosition posn; public final String spelling; public Token(String spelling, TYPE type) { this.type = type; + this.posn = null; this.spelling = spelling; } } diff --git a/miniJava/test.java b/miniJava/test.java index 6286286..cf43519 100644 --- a/miniJava/test.java +++ b/miniJava/test.java @@ -1,7 +1,5 @@ -// PA1 lex binop pass -class id { - void p(){ - int x = 1 + 2 * 3 / 4 > 5 >= 6 < 7 <= 8 != 9 && 0 || 1; - } -} - +class Test { + public int Test() { + + } +} \ No newline at end of file