Basic Error Handling
Added Scanner and Parsing Exceptions as well as keeping track of the source position.master
parent
242ca887f9
commit
f34ccd138d
|
@ -3,6 +3,7 @@ package miniJava;
|
|||
import java.io.*;
|
||||
|
||||
import miniJava.SyntacticAnalyzer.*;
|
||||
import miniJava.SyntacticAnalyzer.Errors.*;
|
||||
import miniJava.AbstractSyntaxTrees.*;
|
||||
import miniJava.AbstractSyntaxTrees.Package;
|
||||
|
||||
|
@ -30,10 +31,16 @@ public class Compiler {
|
|||
System.exit(0);
|
||||
|
||||
} catch(FileNotFoundException e) {
|
||||
System.exit(rc);
|
||||
System.out.println(e.getMessage());
|
||||
} catch(IOException e) {
|
||||
System.exit(rc);
|
||||
System.out.println(e.getMessage());
|
||||
}catch(ScanningException e) {
|
||||
System.out.println(e.getMessage());
|
||||
} catch(ParsingException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
System.exit(rc);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
package miniJava.SyntacticAnalyzer.Errors;
|
||||
|
||||
import miniJava.SyntacticAnalyzer.Token;
|
||||
|
||||
public class ParsingException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ParsingException() {
|
||||
super("Unidentified parsing error!");
|
||||
}
|
||||
|
||||
public ParsingException(Token t) {
|
||||
super("Parsing error with " + t.toString());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package miniJava.SyntacticAnalyzer.Errors;
|
||||
|
||||
public class ScanningException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ScanningException(int col, int line) {
|
||||
super("Scanning error at Column: " + col + ", Line: " + line);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,9 +1,10 @@
|
|||
package miniJava.SyntacticAnalyzer;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import miniJava.AbstractSyntaxTrees.*;
|
||||
import miniJava.AbstractSyntaxTrees.Package;
|
||||
import miniJava.SyntacticAnalyzer.Errors.*;
|
||||
|
||||
public class Parser {
|
||||
|
||||
|
@ -18,9 +19,9 @@ public class Parser {
|
|||
/**
|
||||
* Program ::= (ClassDeclaration)* eot
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ScanningException
|
||||
*/
|
||||
public Package parse() throws IOException {
|
||||
public Package parse() throws ParsingException, ScanningException {
|
||||
ClassDeclList decls = new ClassDeclList();
|
||||
while(peek(1).type == Token.TYPE.CLASS) {
|
||||
decls.add(parseClassDeclaration());
|
||||
|
@ -36,9 +37,9 @@ public class Parser {
|
|||
* (Declarators id (; | MethodDeclaration))*
|
||||
* }
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ScanningException
|
||||
*/
|
||||
private ClassDecl parseClassDeclaration() throws IOException {
|
||||
private ClassDecl parseClassDeclaration() throws ParsingException, ScanningException {
|
||||
|
||||
// Class Header
|
||||
accept(Token.TYPE.CLASS);
|
||||
|
@ -72,9 +73,9 @@ public class Parser {
|
|||
/**
|
||||
* Declarators ::= (public | private)? static? Type
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ScanningException
|
||||
*/
|
||||
private Declarators parseDeclarators() throws IOException {
|
||||
private Declarators parseDeclarators() throws ParsingException, ScanningException {
|
||||
|
||||
// Visibility
|
||||
boolean isPrivate = false;
|
||||
|
@ -103,9 +104,9 @@ public class Parser {
|
|||
* }
|
||||
* @param f describes the declaratory aspect of the method
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ScanningException
|
||||
*/
|
||||
private MethodDecl parseMethodDeclaration(FieldDecl f) throws IOException {
|
||||
private MethodDecl parseMethodDeclaration(FieldDecl f) throws ParsingException, ScanningException {
|
||||
|
||||
// Method Header
|
||||
accept(Token.TYPE.LPAREN);
|
||||
|
@ -139,9 +140,9 @@ public class Parser {
|
|||
/**
|
||||
* Type ::= boolean | void | int ([])? | id ([])?
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ScanningException
|
||||
*/
|
||||
private Type parseType() throws IOException {
|
||||
private Type parseType() throws ParsingException, ScanningException {
|
||||
|
||||
switch(peek(1).type) {
|
||||
|
||||
|
@ -181,16 +182,16 @@ public class Parser {
|
|||
}
|
||||
|
||||
default:
|
||||
throw new IOException();
|
||||
throw new ParsingException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ParameterList ::= Type id (, Type id)*
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ScanningException
|
||||
*/
|
||||
private ParameterDeclList parseParameterList() throws IOException {
|
||||
private ParameterDeclList parseParameterList() throws ParsingException, ScanningException {
|
||||
|
||||
ParameterDeclList decls = new ParameterDeclList();
|
||||
|
||||
|
@ -213,9 +214,9 @@ public class Parser {
|
|||
/**
|
||||
* ArgumentList ::= Expression (, Expression)*
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ScanningException
|
||||
*/
|
||||
private ExprList parseArgumentList() throws IOException {
|
||||
private ExprList parseArgumentList() throws ParsingException, ScanningException {
|
||||
ExprList e = new ExprList();
|
||||
e.add(parseExpression());
|
||||
while(peek(1).type == Token.TYPE.COMMA) {
|
||||
|
@ -229,9 +230,9 @@ public class Parser {
|
|||
/**
|
||||
* Reference ::= BaseRef (. BaseRef)*
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ScanningException
|
||||
*/
|
||||
private Reference parseReference() throws IOException {
|
||||
private Reference parseReference() throws ParsingException, ScanningException {
|
||||
Reference r = parseBaseRef();
|
||||
while(peek(1).type == Token.TYPE.PERIOD) {
|
||||
accept(Token.TYPE.PERIOD);
|
||||
|
@ -253,9 +254,9 @@ public class Parser {
|
|||
/**
|
||||
* BaseRef ::= this | id ([ Expression])?
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ScanningException
|
||||
*/
|
||||
private Reference parseBaseRef() throws IOException {
|
||||
private Reference parseBaseRef() throws ParsingException, ScanningException {
|
||||
|
||||
switch(peek(1).type) {
|
||||
case THIS:
|
||||
|
@ -289,9 +290,9 @@ public class Parser {
|
|||
* | if (Expression) Statement (else Statement)?
|
||||
* | while (Expression) Statement
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ScanningException
|
||||
*/
|
||||
private Statement parseStatement() throws IOException {
|
||||
private Statement parseStatement() throws ParsingException, ScanningException {
|
||||
|
||||
switch(peek(1).type) {
|
||||
|
||||
|
@ -391,9 +392,9 @@ public class Parser {
|
|||
* | num | true | false
|
||||
* | new (id() | int [ Expression ] | id [ Expression ] )
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ScanningException
|
||||
*/
|
||||
private Expression parseSingleExpression() throws IOException {
|
||||
private Expression parseSingleExpression() throws ParsingException, ScanningException {
|
||||
|
||||
Expression e = null;
|
||||
switch(peek(1).type) {
|
||||
|
@ -430,7 +431,7 @@ public class Parser {
|
|||
Operator o = new Operator(accept(peek(1).type), null);
|
||||
e = new UnaryExpr(o, parseSingleExpression(), null);
|
||||
}
|
||||
else throw new IOException();
|
||||
else throw new ParsingException();
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -487,7 +488,7 @@ public class Parser {
|
|||
}
|
||||
|
||||
default:
|
||||
throw new IOException();
|
||||
throw new ParsingException();
|
||||
}
|
||||
|
||||
return e;
|
||||
|
@ -497,9 +498,9 @@ public class Parser {
|
|||
* Disjunction & Initial Call:
|
||||
* Expression ::= Expression binop Expression
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ScanningException
|
||||
*/
|
||||
private Expression parseExpression() throws IOException {
|
||||
private Expression parseExpression() throws ParsingException, ScanningException {
|
||||
|
||||
Expression e = parseCExpression();
|
||||
while(peek(1).spelling.equals("||")) {
|
||||
|
@ -513,9 +514,9 @@ public class Parser {
|
|||
/**
|
||||
* Conjunction
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ScanningException
|
||||
*/
|
||||
private Expression parseCExpression() throws IOException {
|
||||
private Expression parseCExpression() throws ParsingException, ScanningException {
|
||||
|
||||
Expression e = parseEExpression();
|
||||
while(peek(1).spelling.equals("&&")) {
|
||||
|
@ -529,9 +530,9 @@ public class Parser {
|
|||
/**
|
||||
* Equality
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ScanningException
|
||||
*/
|
||||
private Expression parseEExpression() throws IOException {
|
||||
private Expression parseEExpression() throws ParsingException, ScanningException {
|
||||
|
||||
Expression e = parseRExpression();
|
||||
while(peek(1).spelling.equals("==") || peek(1).spelling.equals("!=")) {
|
||||
|
@ -545,9 +546,9 @@ public class Parser {
|
|||
/**
|
||||
* Relational
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ScanningException
|
||||
*/
|
||||
private Expression parseRExpression() throws IOException {
|
||||
private Expression parseRExpression() throws ParsingException, ScanningException {
|
||||
|
||||
Expression e = parseAExpression();
|
||||
while(peek(1).spelling.equals("<") || peek(1).spelling.equals("<=")
|
||||
|
@ -562,9 +563,9 @@ public class Parser {
|
|||
/**
|
||||
* Additive
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ScanningException
|
||||
*/
|
||||
private Expression parseAExpression() throws IOException {
|
||||
private Expression parseAExpression() throws ParsingException, ScanningException {
|
||||
|
||||
Expression e = parseMExpression();
|
||||
while(peek(1).spelling.equals("+") || peek(1).spelling.equals("-")) {
|
||||
|
@ -578,9 +579,9 @@ public class Parser {
|
|||
/**
|
||||
* Multiplicative
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ScanningException
|
||||
*/
|
||||
private Expression parseMExpression() throws IOException {
|
||||
private Expression parseMExpression() throws ParsingException, ScanningException {
|
||||
|
||||
Expression e = parseSingleExpression();
|
||||
while(peek(1).spelling.equals("*") || peek(1).spelling.equals("/")) {
|
||||
|
@ -594,9 +595,9 @@ public class Parser {
|
|||
/**
|
||||
* Sees what the next token is, caching the result.
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ScanningException
|
||||
*/
|
||||
private Token peek(int lookahead) throws IOException {
|
||||
private Token peek(int lookahead) throws ScanningException {
|
||||
|
||||
// Cache tokens
|
||||
while(stream.size() < lookahead) {
|
||||
|
@ -610,12 +611,12 @@ public class Parser {
|
|||
|
||||
/**
|
||||
* Consumes token or throws exception.
|
||||
* @throws IOException
|
||||
* @throws ScanningException
|
||||
*/
|
||||
private Token accept(Token.TYPE type) throws IOException {
|
||||
private Token accept(Token.TYPE type) throws ParsingException, ScanningException {
|
||||
Token next = peek(1);
|
||||
if(next.type == type) stream.poll();
|
||||
else throw new IOException();
|
||||
else throw new ParsingException(next);
|
||||
|
||||
return next;
|
||||
}
|
||||
|
|
|
@ -2,8 +2,12 @@ package miniJava.SyntacticAnalyzer;
|
|||
|
||||
import java.io.*;
|
||||
|
||||
import miniJava.SyntacticAnalyzer.Errors.ScanningException;
|
||||
|
||||
public class Scanner {
|
||||
|
||||
private int col = 1;
|
||||
private int line = 1;
|
||||
private BufferedReader input;
|
||||
|
||||
public Scanner(BufferedReader input) {
|
||||
|
@ -15,7 +19,7 @@ public class Scanner {
|
|||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public Token scan() throws IOException {
|
||||
public Token scan() throws ScanningException {
|
||||
|
||||
String attr = "";
|
||||
Token token = null;
|
||||
|
@ -23,7 +27,7 @@ public class Scanner {
|
|||
while(token == null) {
|
||||
|
||||
// Check for EOF
|
||||
int c = input.read();
|
||||
int c = read();
|
||||
if(c == -1) return new Token("", Token.TYPE.EOT);
|
||||
|
||||
// Setup
|
||||
|
@ -37,18 +41,18 @@ public class Scanner {
|
|||
break;
|
||||
|
||||
case '+':
|
||||
if(peek('+')) throw new IOException();
|
||||
if(peek('+')) throw new ScanningException(col, line);
|
||||
token = new Token(attr, Token.TYPE.BINOP);
|
||||
break;
|
||||
|
||||
case '-':
|
||||
if(peek('-')) throw new IOException();
|
||||
if(peek('-')) throw new ScanningException(col, line);
|
||||
token = new Token(attr, Token.TYPE.BINOP);
|
||||
break;
|
||||
|
||||
// Check for comment
|
||||
case '/':
|
||||
if(peek('*')) { input.read(); readComment(); attr = ""; }
|
||||
if(peek('*')) { read(); readComment(); attr = ""; }
|
||||
else if(peek('/')) { readLine(); attr = ""; }
|
||||
else token = new Token(attr, Token.TYPE.BINOP);
|
||||
break;
|
||||
|
@ -56,7 +60,7 @@ public class Scanner {
|
|||
// Check for c or c=
|
||||
case '>':
|
||||
case '<':
|
||||
if(peek('=')) attr += (char) input.read();
|
||||
if(peek('=')) attr += (char) read();
|
||||
token = new Token(attr, Token.TYPE.BINOP);
|
||||
break;
|
||||
|
||||
|
@ -64,7 +68,7 @@ public class Scanner {
|
|||
case '!':
|
||||
if(!peek('=')) token = new Token(attr, Token.TYPE.UNOP);
|
||||
else {
|
||||
attr += (char) input.read();
|
||||
attr += (char) read();
|
||||
token = new Token(attr, Token.TYPE.BINOP);
|
||||
}
|
||||
break;
|
||||
|
@ -72,9 +76,9 @@ public class Scanner {
|
|||
// Check for && or ||
|
||||
case '&':
|
||||
case '|':
|
||||
if(!peek((char) c)) throw new IOException();
|
||||
if(!peek((char) c)) throw new ScanningException(col, line);
|
||||
else {
|
||||
attr += (char) input.read();
|
||||
attr += (char) read();
|
||||
token = new Token(attr, Token.TYPE.BINOP);
|
||||
}
|
||||
break;
|
||||
|
@ -83,7 +87,7 @@ public class Scanner {
|
|||
case '=':
|
||||
if(!peek('=')) token = new Token(attr, Token.TYPE.EQUALS);
|
||||
else {
|
||||
attr += (char) input.read();
|
||||
attr += (char) read();
|
||||
token = new Token(attr, Token.TYPE.BINOP);
|
||||
}
|
||||
break;
|
||||
|
@ -129,7 +133,7 @@ public class Scanner {
|
|||
// Identifier or Keyword
|
||||
if(isAlpha((char) c)) {
|
||||
for(char n = peek(); isAlpha(n) || isDigit(n) || n == '_';) {
|
||||
attr += (char) input.read();
|
||||
attr += (char) read();
|
||||
n = peek();
|
||||
}
|
||||
|
||||
|
@ -143,7 +147,7 @@ public class Scanner {
|
|||
// Number
|
||||
else if(isDigit((char) c)) {
|
||||
for(char n = peek(); isDigit(n);) {
|
||||
attr += (char) input.read();
|
||||
attr += (char) read();
|
||||
n = peek();
|
||||
}
|
||||
|
||||
|
@ -156,7 +160,7 @@ public class Scanner {
|
|||
}
|
||||
|
||||
// Unrecognized Character
|
||||
else throw new IOException();
|
||||
else throw new ScanningException(col, line);;
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -171,12 +175,16 @@ public class Scanner {
|
|||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private char peek() throws IOException {
|
||||
private char peek() throws ScanningException {
|
||||
try {
|
||||
input.mark(1);
|
||||
int next = input.read();
|
||||
input.reset();
|
||||
|
||||
return next == -1 ? '\0' : (char) next;
|
||||
} catch(IOException e) {
|
||||
throw new ScanningException(col, line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -186,12 +194,34 @@ public class Scanner {
|
|||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private boolean peek(char c) throws IOException {
|
||||
private boolean peek(char c) throws ScanningException {
|
||||
try {
|
||||
input.mark(1);
|
||||
int next = input.read();
|
||||
input.reset();
|
||||
|
||||
return c == next;
|
||||
} catch(IOException e) {
|
||||
throw new ScanningException(col, line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Alternative reading that keeps track of position.
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private int read() throws ScanningException {
|
||||
try {
|
||||
int next = input.read();
|
||||
if(next != '\n' && next != '\r') col += 1;
|
||||
else { col = 1; line += 1; }
|
||||
|
||||
return next;
|
||||
} catch(IOException e) {
|
||||
throw new ScanningException(col, line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -199,7 +229,8 @@ public class Scanner {
|
|||
* Consumes input until an end of comment has been reached.
|
||||
* @throws IOException
|
||||
*/
|
||||
private void readComment() throws IOException {
|
||||
private void readComment() throws ScanningException {
|
||||
try {
|
||||
char prev = '\0', current = '\0';
|
||||
while(prev != '*' || current != '/') {
|
||||
|
||||
|
@ -209,6 +240,9 @@ public class Scanner {
|
|||
if(next == -1) throw new IOException();
|
||||
else current = (char) next;
|
||||
}
|
||||
} catch(IOException e) {
|
||||
throw new ScanningException(col, line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -216,8 +250,12 @@ public class Scanner {
|
|||
* Consumes input until the end of line is reached
|
||||
* @throws IOException
|
||||
*/
|
||||
private void readLine() 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue