Identification/Type Checking
Most of Identification and Type Checking implemented.master
parent
f34ccd138d
commit
83c72019f5
|
@ -15,6 +15,15 @@ public abstract class Declaration extends AST {
|
||||||
this.type = type;
|
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 String name;
|
||||||
public Type type;
|
public Type type;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,18 @@
|
||||||
package miniJava.AbstractSyntaxTrees;
|
package miniJava.AbstractSyntaxTrees;
|
||||||
|
|
||||||
|
import miniJava.SyntacticAnalyzer.SourcePosition;
|
||||||
|
|
||||||
public class Declarators {
|
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.isPrivate = isPrivate;
|
||||||
this.isStatic = isStatic;
|
this.isStatic = isStatic;
|
||||||
this.mt = mt;
|
this.mt = mt;
|
||||||
|
this.posn = posn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPrivate;
|
public boolean isPrivate;
|
||||||
public boolean isStatic;
|
public boolean isStatic;
|
||||||
public Type mt;
|
public Type mt;
|
||||||
|
public SourcePosition posn;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,11 @@ public class FieldDeclList implements Iterable<FieldDecl>
|
||||||
fieldDeclList = new ArrayList<FieldDecl>();
|
fieldDeclList = new ArrayList<FieldDecl>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FieldDeclList(FieldDecl f) {
|
||||||
|
fieldDeclList = new ArrayList<FieldDecl>();
|
||||||
|
fieldDeclList.add(f);
|
||||||
|
}
|
||||||
|
|
||||||
public void add(FieldDecl cd){
|
public void add(FieldDecl cd){
|
||||||
fieldDeclList.add(cd);
|
fieldDeclList.add(cd);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,4 +17,5 @@ public class Identifier extends Terminal {
|
||||||
return v.visitIdentifier(this, o);
|
return v.visitIdentifier(this, o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Declaration decl = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,11 @@ public class MethodDeclList implements Iterable<MethodDecl>
|
||||||
methodDeclList = new ArrayList<MethodDecl>();
|
methodDeclList = new ArrayList<MethodDecl>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MethodDeclList(MethodDecl m) {
|
||||||
|
methodDeclList = new ArrayList<MethodDecl>();
|
||||||
|
methodDeclList.add(m);
|
||||||
|
}
|
||||||
|
|
||||||
public void add(MethodDecl cd){
|
public void add(MethodDecl cd){
|
||||||
methodDeclList.add(cd);
|
methodDeclList.add(cd);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,11 @@ public class ParameterDeclList implements Iterable<ParameterDecl>
|
||||||
parameterDeclList = new ArrayList<ParameterDecl>();
|
parameterDeclList = new ArrayList<ParameterDecl>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ParameterDeclList(ParameterDecl p) {
|
||||||
|
parameterDeclList = new ArrayList<ParameterDecl>();
|
||||||
|
parameterDeclList.add(p);
|
||||||
|
}
|
||||||
|
|
||||||
public void add(ParameterDecl s){
|
public void add(ParameterDecl s){
|
||||||
parameterDeclList.add(s);
|
parameterDeclList.add(s);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,4 +13,5 @@ public abstract class Reference extends AST
|
||||||
super(posn);
|
super(posn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Declaration decl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,5 +12,6 @@ public enum TypeKind {
|
||||||
CLASS,
|
CLASS,
|
||||||
ARRAY,
|
ARRAY,
|
||||||
UNSUPPORTED,
|
UNSUPPORTED,
|
||||||
ERROR;
|
ERROR,
|
||||||
|
VALID;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,11 @@ package miniJava;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
|
||||||
import miniJava.SyntacticAnalyzer.*;
|
import miniJava.SyntacticAnalyzer.*;
|
||||||
import miniJava.SyntacticAnalyzer.Errors.*;
|
import miniJava.AbstractSyntaxTrees.ASTDisplay;
|
||||||
import miniJava.AbstractSyntaxTrees.*;
|
|
||||||
import miniJava.AbstractSyntaxTrees.Package;
|
import miniJava.AbstractSyntaxTrees.Package;
|
||||||
|
import miniJava.ContextualAnalyzer.Analyzer;
|
||||||
|
import miniJava.ContextualAnalyzer.Reporter;
|
||||||
|
import miniJava.Exceptions.*;
|
||||||
|
|
||||||
public class Compiler {
|
public class Compiler {
|
||||||
|
|
||||||
|
@ -26,18 +28,24 @@ public class Compiler {
|
||||||
Package p = parser.parse();
|
Package p = parser.parse();
|
||||||
|
|
||||||
// Display
|
// Display
|
||||||
ASTDisplay display = new ASTDisplay();
|
// ASTDisplay display = new ASTDisplay();
|
||||||
display.showTree(p);
|
// display.showTree(p);
|
||||||
|
|
||||||
|
// Identification/Type Checking
|
||||||
|
Analyzer analyzer = new Analyzer();
|
||||||
|
analyzer.visitPackage(p, null);
|
||||||
|
if(Reporter.error) System.exit(rc);
|
||||||
|
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
|
|
||||||
} catch(FileNotFoundException e) {
|
} catch(FileNotFoundException e) {
|
||||||
System.out.println(e.getMessage());
|
System.out.println("***" + e.getMessage());
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
System.out.println(e.getMessage());
|
System.out.println("***" + e.getMessage());
|
||||||
}catch(ScanningException e) {
|
}catch(ScanningException e) {
|
||||||
System.out.println(e.getMessage());
|
System.out.println("***" + e.getMessage());
|
||||||
} catch(ParsingException e) {
|
} catch(ParsingException e) {
|
||||||
System.out.println(e.getMessage());
|
System.out.println("***" + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
System.exit(rc);
|
System.exit(rc);
|
||||||
|
|
|
@ -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<IdentificationTable, Type> {
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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<String, IdentificationTable> scope;
|
||||||
|
private ArrayList<HashMap<String, Declaration>> table;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public IdentificationTable() {
|
||||||
|
this(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param parent
|
||||||
|
*/
|
||||||
|
public IdentificationTable(IdentificationTable parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.scope = new HashMap<String, IdentificationTable>();
|
||||||
|
this.table = new ArrayList<HashMap<String, Declaration>>();
|
||||||
|
this.table.add(new HashMap<String, Declaration>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds another level for variables to be stored at (they will be
|
||||||
|
* removed when popping said level).
|
||||||
|
*/
|
||||||
|
public void pushLevel() {
|
||||||
|
table.add(new HashMap<String, Declaration>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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<String, Declaration> 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<String, Declaration> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package miniJava.Exceptions;
|
||||||
|
|
||||||
|
public class IdentificationException extends Exception {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public IdentificationException() {
|
||||||
|
super("Identification Error!");
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package miniJava.SyntacticAnalyzer.Errors;
|
package miniJava.Exceptions;
|
||||||
|
|
||||||
import miniJava.SyntacticAnalyzer.Token;
|
import miniJava.SyntacticAnalyzer.Token;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package miniJava.SyntacticAnalyzer.Errors;
|
package miniJava.Exceptions;
|
||||||
|
|
||||||
public class ScanningException extends Exception {
|
public class ScanningException extends Exception {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import java.util.LinkedList;
|
||||||
|
|
||||||
import miniJava.AbstractSyntaxTrees.*;
|
import miniJava.AbstractSyntaxTrees.*;
|
||||||
import miniJava.AbstractSyntaxTrees.Package;
|
import miniJava.AbstractSyntaxTrees.Package;
|
||||||
import miniJava.SyntacticAnalyzer.Errors.*;
|
import miniJava.Exceptions.*;
|
||||||
|
|
||||||
public class Parser {
|
public class Parser {
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ public class Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
accept(Token.TYPE.EOT);
|
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 {
|
private ClassDecl parseClassDeclaration() throws ParsingException, ScanningException {
|
||||||
|
|
||||||
// Class Header
|
// Class Header
|
||||||
accept(Token.TYPE.CLASS);
|
Token classToken = accept(Token.TYPE.CLASS);
|
||||||
String cn = accept(Token.TYPE.ID).spelling;
|
String cn = accept(Token.TYPE.ID).spelling;
|
||||||
accept(Token.TYPE.LBRACKET);
|
accept(Token.TYPE.LBRACKET);
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ public class Parser {
|
||||||
while(peek(1).type != Token.TYPE.RBRACKET) {
|
while(peek(1).type != Token.TYPE.RBRACKET) {
|
||||||
Declarators d = parseDeclarators();
|
Declarators d = parseDeclarators();
|
||||||
String name = accept(Token.TYPE.ID).spelling;
|
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
|
// Field Declarations
|
||||||
if(peek(1).type == Token.TYPE.SEMICOLON) {
|
if(peek(1).type == Token.TYPE.SEMICOLON) {
|
||||||
|
@ -67,7 +67,7 @@ public class Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
accept(Token.TYPE.RBRACKET);
|
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 {
|
private Declarators parseDeclarators() throws ParsingException, ScanningException {
|
||||||
|
|
||||||
// Visibility
|
// Visibility
|
||||||
|
SourcePosition start = null;
|
||||||
boolean isPrivate = false;
|
boolean isPrivate = false;
|
||||||
|
|
||||||
if(peek(1).type == Token.TYPE.PUBLIC) {
|
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) {
|
} else if(peek(1).type == Token.TYPE.PRIVATE) {
|
||||||
isPrivate = true;
|
isPrivate = true;
|
||||||
accept(Token.TYPE.PRIVATE);
|
start = accept(Token.TYPE.PRIVATE).posn;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Class Methods
|
// Class Methods
|
||||||
boolean isStatic = false;
|
boolean isStatic = false;
|
||||||
if(peek(1).type == Token.TYPE.STATIC) {
|
if(peek(1).type == Token.TYPE.STATIC) {
|
||||||
isStatic = true;
|
isStatic = true;
|
||||||
|
if(start == null) {
|
||||||
|
start = accept(Token.TYPE.STATIC).posn;
|
||||||
|
} else {
|
||||||
accept(Token.TYPE.STATIC);
|
accept(Token.TYPE.STATIC);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Type t = parseType();
|
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);
|
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 {
|
private Type parseType() throws ParsingException, ScanningException {
|
||||||
|
|
||||||
|
SourcePosition posn = null;
|
||||||
|
|
||||||
switch(peek(1).type) {
|
switch(peek(1).type) {
|
||||||
|
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
accept(Token.TYPE.BOOLEAN);
|
posn = accept(Token.TYPE.BOOLEAN).posn;
|
||||||
return new BaseType(TypeKind.BOOLEAN, null);
|
return new BaseType(TypeKind.BOOLEAN, posn);
|
||||||
|
|
||||||
case VOID:
|
case VOID:
|
||||||
accept(Token.TYPE.VOID);
|
posn = accept(Token.TYPE.VOID).posn;
|
||||||
return new BaseType(TypeKind.VOID, null);
|
return new BaseType(TypeKind.VOID, posn);
|
||||||
|
|
||||||
case INT: {
|
case INT: {
|
||||||
accept(Token.TYPE.INT);
|
posn = accept(Token.TYPE.INT).posn;
|
||||||
BaseType b = new BaseType(TypeKind.INT, null);
|
BaseType b = new BaseType(TypeKind.INT, posn);
|
||||||
|
|
||||||
if(peek(1).type == Token.TYPE.LSQUARE) {
|
if(peek(1).type == Token.TYPE.LSQUARE) {
|
||||||
accept(Token.TYPE.LSQUARE);
|
accept(Token.TYPE.LSQUARE);
|
||||||
accept(Token.TYPE.RSQUARE);
|
accept(Token.TYPE.RSQUARE);
|
||||||
return new ArrayType(b, null);
|
return new ArrayType(b, posn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ID: {
|
case ID: {
|
||||||
String cn = accept(peek(1).type).spelling;
|
Token id = accept(peek(1).type);
|
||||||
Identifier i = new Identifier(cn, null);
|
Identifier i = new Identifier(id.spelling, id.posn);
|
||||||
ClassType c = new ClassType(i, null);
|
ClassType c = new ClassType(i, id.posn);
|
||||||
|
|
||||||
if(peek(1).type == Token.TYPE.LSQUARE) {
|
if(peek(1).type == Token.TYPE.LSQUARE) {
|
||||||
accept(Token.TYPE.LSQUARE);
|
accept(Token.TYPE.LSQUARE);
|
||||||
accept(Token.TYPE.RSQUARE);
|
accept(Token.TYPE.RSQUARE);
|
||||||
return new ArrayType(c, null);
|
return new ArrayType(c, id.posn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
|
@ -197,15 +209,15 @@ public class Parser {
|
||||||
|
|
||||||
// First Parameter
|
// First Parameter
|
||||||
Type t = parseType();
|
Type t = parseType();
|
||||||
String name = accept(Token.TYPE.ID).spelling;
|
Token id = accept(Token.TYPE.ID);
|
||||||
decls.add(new ParameterDecl(t, name, null));
|
decls.add(new ParameterDecl(t, id.spelling, id.posn));
|
||||||
|
|
||||||
// Remainder of List
|
// Remainder of List
|
||||||
while(peek(1).type == Token.TYPE.COMMA) {
|
while(peek(1).type == Token.TYPE.COMMA) {
|
||||||
accept(Token.TYPE.COMMA);
|
accept(Token.TYPE.COMMA);
|
||||||
t = parseType();
|
Type nextType = parseType();
|
||||||
name = accept(Token.TYPE.ID).spelling;
|
Token nextId = accept(Token.TYPE.ID);
|
||||||
decls.add(new ParameterDecl(t, name, null));
|
decls.add(new ParameterDecl(nextType, nextId.spelling, nextId.posn));
|
||||||
}
|
}
|
||||||
|
|
||||||
return decls;
|
return decls;
|
||||||
|
@ -236,15 +248,15 @@ public class Parser {
|
||||||
Reference r = parseBaseRef();
|
Reference r = parseBaseRef();
|
||||||
while(peek(1).type == Token.TYPE.PERIOD) {
|
while(peek(1).type == Token.TYPE.PERIOD) {
|
||||||
accept(Token.TYPE.PERIOD);
|
accept(Token.TYPE.PERIOD);
|
||||||
String name = accept(Token.TYPE.ID).spelling;
|
Token tokenId = accept(Token.TYPE.ID);
|
||||||
Identifier id = new Identifier(name, null);
|
Identifier id = new Identifier(tokenId.spelling, tokenId.posn);
|
||||||
r = new QualifiedRef(r, id, null);
|
r = new QualifiedRef(r, id, tokenId.posn);
|
||||||
|
|
||||||
if(peek(1).type == Token.TYPE.LSQUARE) {
|
if(peek(1).type == Token.TYPE.LSQUARE) {
|
||||||
accept(Token.TYPE.LSQUARE);
|
accept(Token.TYPE.LSQUARE);
|
||||||
Expression e = parseExpression();
|
Expression e = parseExpression();
|
||||||
accept(Token.TYPE.RSQUARE);
|
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 {
|
private Reference parseBaseRef() throws ParsingException, ScanningException {
|
||||||
|
|
||||||
switch(peek(1).type) {
|
switch(peek(1).type) {
|
||||||
case THIS:
|
case THIS: {
|
||||||
accept(Token.TYPE.THIS);
|
Token thisToken = accept(Token.TYPE.THIS);
|
||||||
return new ThisRef(null);
|
return new ThisRef(thisToken.posn);
|
||||||
|
}
|
||||||
|
|
||||||
// id ([ Expression])?
|
// id ([ Expression])?
|
||||||
default: {
|
default: {
|
||||||
String id = accept(Token.TYPE.ID).spelling;
|
Token id = accept(Token.TYPE.ID);
|
||||||
Identifier i = new Identifier(id, null);
|
Identifier i = new Identifier(id.spelling, id.posn);
|
||||||
IdRef r = new IdRef(i, null);
|
IdRef r = new IdRef(i, id.posn);
|
||||||
|
|
||||||
if(peek(1).type == Token.TYPE.LSQUARE) {
|
if(peek(1).type == Token.TYPE.LSQUARE) {
|
||||||
accept(Token.TYPE.LSQUARE);
|
accept(Token.TYPE.LSQUARE);
|
||||||
Expression e = parseExpression();
|
Expression e = parseExpression();
|
||||||
accept(Token.TYPE.RSQUARE);
|
accept(Token.TYPE.RSQUARE);
|
||||||
return new IndexedRef(r, e, null);
|
return new IndexedRef(r, e, id.posn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
|
@ -298,19 +311,19 @@ public class Parser {
|
||||||
|
|
||||||
// { Statement* }
|
// { Statement* }
|
||||||
case LBRACKET: {
|
case LBRACKET: {
|
||||||
accept(Token.TYPE.LBRACKET);
|
Token leftToken = accept(Token.TYPE.LBRACKET);
|
||||||
StatementList stl = new StatementList();
|
StatementList stl = new StatementList();
|
||||||
while(peek(1).type != Token.TYPE.RBRACKET) {
|
while(peek(1).type != Token.TYPE.RBRACKET) {
|
||||||
stl.add(parseStatement());
|
stl.add(parseStatement());
|
||||||
}
|
}
|
||||||
accept(Token.TYPE.RBRACKET);
|
accept(Token.TYPE.RBRACKET);
|
||||||
|
|
||||||
return new BlockStmt(stl, null);
|
return new BlockStmt(stl, leftToken.posn);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (Expression) Statement (else Statement)?
|
// if (Expression) Statement (else Statement)?
|
||||||
case IF: {
|
case IF: {
|
||||||
accept(Token.TYPE.IF);
|
Token ifToken = accept(Token.TYPE.IF);
|
||||||
accept(Token.TYPE.LPAREN);
|
accept(Token.TYPE.LPAREN);
|
||||||
Expression e = parseExpression();
|
Expression e = parseExpression();
|
||||||
accept(Token.TYPE.RPAREN);
|
accept(Token.TYPE.RPAREN);
|
||||||
|
@ -318,21 +331,21 @@ public class Parser {
|
||||||
if(peek(1).type == Token.TYPE.ELSE) {
|
if(peek(1).type == Token.TYPE.ELSE) {
|
||||||
accept(Token.TYPE.ELSE);
|
accept(Token.TYPE.ELSE);
|
||||||
Statement s2 = parseStatement();
|
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
|
// while (Expression) Statement
|
||||||
case WHILE: {
|
case WHILE: {
|
||||||
accept(Token.TYPE.WHILE);
|
Token whileToken = accept(Token.TYPE.WHILE);
|
||||||
accept(Token.TYPE.LPAREN);
|
accept(Token.TYPE.LPAREN);
|
||||||
Expression e = parseExpression();
|
Expression e = parseExpression();
|
||||||
accept(Token.TYPE.RPAREN);
|
accept(Token.TYPE.RPAREN);
|
||||||
Statement s = parseStatement();
|
Statement s = parseStatement();
|
||||||
|
|
||||||
return new WhileStmt(e, s, null);
|
return new WhileStmt(e, s, whileToken.posn);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type id = Expression ;
|
// Type id = Expression ;
|
||||||
|
@ -343,13 +356,13 @@ public class Parser {
|
||||||
||(peek(2).type == Token.TYPE.LSQUARE && peek(3).type == Token.TYPE.RSQUARE)) {
|
||(peek(2).type == Token.TYPE.LSQUARE && peek(3).type == Token.TYPE.RSQUARE)) {
|
||||||
Type t = parseType();
|
Type t = parseType();
|
||||||
String name = accept(Token.TYPE.ID).spelling;
|
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);
|
accept(Token.TYPE.EQUALS);
|
||||||
Expression e = parseExpression();
|
Expression e = parseExpression();
|
||||||
accept(Token.TYPE.SEMICOLON);
|
accept(Token.TYPE.SEMICOLON);
|
||||||
|
|
||||||
return new VarDeclStmt(v, e, null);
|
return new VarDeclStmt(v, e, t.posn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fall Through */
|
/* Fall Through */
|
||||||
|
@ -367,14 +380,14 @@ public class Parser {
|
||||||
e = parseArgumentList();
|
e = parseArgumentList();
|
||||||
}
|
}
|
||||||
accept(Token.TYPE.RPAREN);
|
accept(Token.TYPE.RPAREN);
|
||||||
s = new CallStmt(r, e, null);
|
s = new CallStmt(r, e, r.posn);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reference = Expression ;
|
// Reference = Expression ;
|
||||||
else {
|
else {
|
||||||
accept(Token.TYPE.EQUALS);
|
accept(Token.TYPE.EQUALS);
|
||||||
Expression e = parseExpression();
|
Expression e = parseExpression();
|
||||||
s = new AssignStmt(r, e, null);
|
s = new AssignStmt(r, e, r.posn);
|
||||||
}
|
}
|
||||||
|
|
||||||
accept(Token.TYPE.SEMICOLON);
|
accept(Token.TYPE.SEMICOLON);
|
||||||
|
@ -401,18 +414,18 @@ public class Parser {
|
||||||
|
|
||||||
// num
|
// num
|
||||||
case NUM: {
|
case NUM: {
|
||||||
String number = accept(Token.TYPE.NUM).spelling;
|
Token number = accept(Token.TYPE.NUM);
|
||||||
IntLiteral i = new IntLiteral(number, null);
|
IntLiteral i = new IntLiteral(number.spelling, number.posn);
|
||||||
e = new LiteralExpr(i, null);
|
e = new LiteralExpr(i, number.posn);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// true | false
|
// true | false
|
||||||
case TRUE:
|
case TRUE:
|
||||||
case FALSE: {
|
case FALSE: {
|
||||||
String bool = accept(peek(1).type).spelling;
|
Token bool = accept(peek(1).type);
|
||||||
BooleanLiteral b = new BooleanLiteral(bool, null);
|
BooleanLiteral b = new BooleanLiteral(bool.spelling, bool.posn);
|
||||||
e = new LiteralExpr(b, null);
|
e = new LiteralExpr(b, bool.posn);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,8 +441,9 @@ public class Parser {
|
||||||
case UNOP:
|
case UNOP:
|
||||||
case BINOP: {
|
case BINOP: {
|
||||||
if(peek(1).spelling.equals("!") || peek(1).spelling.equals("-")) {
|
if(peek(1).spelling.equals("!") || peek(1).spelling.equals("-")) {
|
||||||
Operator o = new Operator(accept(peek(1).type), null);
|
Token opToken = accept(peek(1).type);
|
||||||
e = new UnaryExpr(o, parseSingleExpression(), null);
|
Operator o = new Operator(opToken, opToken.posn);
|
||||||
|
e = new UnaryExpr(o, parseSingleExpression(), opToken.posn);
|
||||||
}
|
}
|
||||||
else throw new ParsingException();
|
else throw new ParsingException();
|
||||||
break;
|
break;
|
||||||
|
@ -437,7 +451,7 @@ public class Parser {
|
||||||
|
|
||||||
// new ( int [ Expression ] | id ( ) | id [ Expression ] )
|
// new ( int [ Expression ] | id ( ) | id [ Expression ] )
|
||||||
case NEW: {
|
case NEW: {
|
||||||
accept(Token.TYPE.NEW);
|
Token newToken = accept(Token.TYPE.NEW);
|
||||||
|
|
||||||
if(peek(1).type == Token.TYPE.INT) {
|
if(peek(1).type == Token.TYPE.INT) {
|
||||||
accept(Token.TYPE.INT);
|
accept(Token.TYPE.INT);
|
||||||
|
@ -445,24 +459,24 @@ public class Parser {
|
||||||
Expression e2 = parseExpression();
|
Expression e2 = parseExpression();
|
||||||
accept(Token.TYPE.RSQUARE);
|
accept(Token.TYPE.RSQUARE);
|
||||||
|
|
||||||
BaseType b = new BaseType(TypeKind.INT, null);
|
BaseType b = new BaseType(TypeKind.INT, newToken.posn);
|
||||||
e = new NewArrayExpr(b, e2, null);
|
e = new NewArrayExpr(b, e2, newToken.posn);
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
String cn = accept(Token.TYPE.ID).spelling;
|
Token id = accept(Token.TYPE.ID);
|
||||||
Identifier i = new Identifier(cn, null);
|
Identifier i = new Identifier(id.spelling, id.posn);
|
||||||
ClassType c = new ClassType(i, null);
|
ClassType c = new ClassType(i, id.posn);
|
||||||
|
|
||||||
if(peek(1).type == Token.TYPE.LPAREN){
|
if(peek(1).type == Token.TYPE.LPAREN){
|
||||||
accept(Token.TYPE.LPAREN);
|
accept(Token.TYPE.LPAREN);
|
||||||
accept(Token.TYPE.RPAREN);
|
accept(Token.TYPE.RPAREN);
|
||||||
e = new NewObjectExpr(c, null);
|
e = new NewObjectExpr(c, id.posn);
|
||||||
} else {
|
} else {
|
||||||
accept(Token.TYPE.LSQUARE);
|
accept(Token.TYPE.LSQUARE);
|
||||||
Expression e2 = parseExpression();
|
Expression e2 = parseExpression();
|
||||||
accept(Token.TYPE.RSQUARE);
|
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();
|
el = parseArgumentList();
|
||||||
}
|
}
|
||||||
accept(Token.TYPE.RPAREN);
|
accept(Token.TYPE.RPAREN);
|
||||||
e = new CallExpr(r, el, null);
|
e = new CallExpr(r, el, r.posn);
|
||||||
} else {
|
} else {
|
||||||
e = new RefExpr(r, null);
|
e = new RefExpr(r, r.posn);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -504,8 +518,9 @@ public class Parser {
|
||||||
|
|
||||||
Expression e = parseCExpression();
|
Expression e = parseCExpression();
|
||||||
while(peek(1).spelling.equals("||")) {
|
while(peek(1).spelling.equals("||")) {
|
||||||
Operator o = new Operator(accept(Token.TYPE.BINOP), null);
|
Token opToken = accept(Token.TYPE.BINOP);
|
||||||
e = new BinaryExpr(o, e, parseCExpression(), null);
|
Operator o = new Operator(opToken, opToken.posn);
|
||||||
|
e = new BinaryExpr(o, e, parseCExpression(), e.posn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
|
@ -520,8 +535,9 @@ public class Parser {
|
||||||
|
|
||||||
Expression e = parseEExpression();
|
Expression e = parseEExpression();
|
||||||
while(peek(1).spelling.equals("&&")) {
|
while(peek(1).spelling.equals("&&")) {
|
||||||
Operator o = new Operator(accept(Token.TYPE.BINOP), null);
|
Token opToken = accept(Token.TYPE.BINOP);
|
||||||
e = new BinaryExpr(o, e, parseEExpression(), null);
|
Operator o = new Operator(opToken, opToken.posn);
|
||||||
|
e = new BinaryExpr(o, e, parseEExpression(), e.posn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
|
@ -536,8 +552,9 @@ public class Parser {
|
||||||
|
|
||||||
Expression e = parseRExpression();
|
Expression e = parseRExpression();
|
||||||
while(peek(1).spelling.equals("==") || peek(1).spelling.equals("!=")) {
|
while(peek(1).spelling.equals("==") || peek(1).spelling.equals("!=")) {
|
||||||
Operator o = new Operator(accept(Token.TYPE.BINOP), null);
|
Token opToken = accept(Token.TYPE.BINOP);
|
||||||
e = new BinaryExpr(o, e, parseRExpression(), null);
|
Operator o = new Operator(opToken, opToken.posn);
|
||||||
|
e = new BinaryExpr(o, e, parseRExpression(), e.posn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
|
@ -553,8 +570,9 @@ public class Parser {
|
||||||
Expression e = parseAExpression();
|
Expression e = parseAExpression();
|
||||||
while(peek(1).spelling.equals("<") || peek(1).spelling.equals("<=")
|
while(peek(1).spelling.equals("<") || peek(1).spelling.equals("<=")
|
||||||
|| 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);
|
Token opToken = accept(Token.TYPE.BINOP);
|
||||||
e = new BinaryExpr(o, e, parseAExpression(), null);
|
Operator o = new Operator(opToken, opToken.posn);
|
||||||
|
e = new BinaryExpr(o, e, parseAExpression(), e.posn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
|
@ -569,8 +587,9 @@ public class Parser {
|
||||||
|
|
||||||
Expression e = parseMExpression();
|
Expression e = parseMExpression();
|
||||||
while(peek(1).spelling.equals("+") || peek(1).spelling.equals("-")) {
|
while(peek(1).spelling.equals("+") || peek(1).spelling.equals("-")) {
|
||||||
Operator o = new Operator(accept(Token.TYPE.BINOP), null);
|
Token opToken = accept(Token.TYPE.BINOP);
|
||||||
e = new BinaryExpr(o, e, parseMExpression(), null);
|
Operator o = new Operator(opToken, opToken.posn);
|
||||||
|
e = new BinaryExpr(o, e, parseMExpression(), e.posn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
|
@ -585,8 +604,9 @@ public class Parser {
|
||||||
|
|
||||||
Expression e = parseSingleExpression();
|
Expression e = parseSingleExpression();
|
||||||
while(peek(1).spelling.equals("*") || peek(1).spelling.equals("/")) {
|
while(peek(1).spelling.equals("*") || peek(1).spelling.equals("/")) {
|
||||||
Operator o = new Operator(accept(Token.TYPE.BINOP), null);
|
Token opToken = accept(Token.TYPE.BINOP);
|
||||||
e = new BinaryExpr(o, e, parseSingleExpression(), null);
|
Operator o = new Operator(opToken, opToken.posn);
|
||||||
|
e = new BinaryExpr(o, e, parseSingleExpression(), e.posn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
package miniJava.SyntacticAnalyzer;
|
package miniJava.SyntacticAnalyzer;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import miniJava.Exceptions.*;
|
||||||
import miniJava.SyntacticAnalyzer.Errors.ScanningException;
|
|
||||||
|
|
||||||
public class Scanner {
|
public class Scanner {
|
||||||
|
|
||||||
|
@ -14,6 +13,11 @@ public class Scanner {
|
||||||
this.input = input;
|
this.input = input;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Scanner(String input) {
|
||||||
|
StringReader reader = new StringReader(input);
|
||||||
|
this.input = new BufferedReader(reader);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scans in input, returning next token.
|
* Scans in input, returning next token.
|
||||||
* @return
|
* @return
|
||||||
|
@ -132,7 +136,7 @@ public class Scanner {
|
||||||
|
|
||||||
// Identifier or Keyword
|
// Identifier or Keyword
|
||||||
if(isAlpha((char) c)) {
|
if(isAlpha((char) c)) {
|
||||||
for(char n = peek(); isAlpha(n) || isDigit(n) || n == '_';) {
|
for(char n = peek(); isAlpha(n) || isDigit(n);) {
|
||||||
attr += (char) read();
|
attr += (char) read();
|
||||||
n = peek();
|
n = peek();
|
||||||
}
|
}
|
||||||
|
@ -166,6 +170,7 @@ public class Scanner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
token.posn = new SourcePosition(line, col - token.spelling.length());
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,7 +221,10 @@ public class Scanner {
|
||||||
try {
|
try {
|
||||||
int next = input.read();
|
int next = input.read();
|
||||||
if(next != '\n' && next != '\r') col += 1;
|
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;
|
return next;
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
|
@ -230,19 +238,15 @@ public class Scanner {
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private void readComment() throws ScanningException {
|
private void readComment() throws ScanningException {
|
||||||
try {
|
|
||||||
char prev = '\0', current = '\0';
|
char prev = '\0', current = '\0';
|
||||||
while(prev != '*' || current != '/') {
|
while(prev != '*' || current != '/') {
|
||||||
|
|
||||||
prev = current;
|
prev = current;
|
||||||
|
|
||||||
int next = input.read();
|
int next = read();
|
||||||
if(next == -1) throw new IOException();
|
if(next == -1) throw new ScanningException(col, line);
|
||||||
else current = (char) next;
|
else current = (char) next;
|
||||||
}
|
}
|
||||||
} catch(IOException e) {
|
|
||||||
throw new ScanningException(col, line);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -251,11 +255,7 @@ public class Scanner {
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private void readLine() throws ScanningException {
|
private void readLine() throws ScanningException {
|
||||||
try {
|
for(int n = 0; n != '\n' && n != '\r' && n != -1; n = read()) {}
|
||||||
for(int n = 0; n != '\n' && n != '\r' && n != -1; n = input.read()) {}
|
|
||||||
} catch(IOException e) {
|
|
||||||
throw new ScanningException(col, line);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -266,7 +266,8 @@ public class Scanner {
|
||||||
*/
|
*/
|
||||||
private boolean isAlpha(char c) {
|
private boolean isAlpha(char c) {
|
||||||
return (c >= 'a' && c <= 'z')
|
return (c >= 'a' && c <= 'z')
|
||||||
|| (c >= 'A' && c <= 'Z');
|
|| (c >= 'A' && c <= 'Z')
|
||||||
|
|| c == '_';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,4 +9,9 @@ public class SourcePosition {
|
||||||
this.col = col;
|
this.col = col;
|
||||||
this.line = line;
|
this.line = line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "(Line: " + line + ", Column: " + col + ")";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,10 +69,12 @@ public class Token {
|
||||||
}
|
}
|
||||||
|
|
||||||
public final TYPE type;
|
public final TYPE type;
|
||||||
|
public SourcePosition posn;
|
||||||
public final String spelling;
|
public final String spelling;
|
||||||
|
|
||||||
public Token(String spelling, TYPE type) {
|
public Token(String spelling, TYPE type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
this.posn = null;
|
||||||
this.spelling = spelling;
|
this.spelling = spelling;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
// PA1 lex binop pass
|
class Test {
|
||||||
class id {
|
public int Test() {
|
||||||
void p(){
|
|
||||||
int x = 1 + 2 * 3 / 4 > 5 >= 6 < 7 <= 8 != 9 && 0 || 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue