1
Fork 0

Basic Error Handling

Added Scanner and Parsing Exceptions as well as keeping track of the
source position.
master
Joshua Potter 2014-03-05 12:00:24 -05:00
parent 242ca887f9
commit f34ccd138d
5 changed files with 155 additions and 81 deletions

View File

@ -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);
}
}

View File

@ -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());
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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);
}
}