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 java.io.*;
import miniJava.SyntacticAnalyzer.*; import miniJava.SyntacticAnalyzer.*;
import miniJava.SyntacticAnalyzer.Errors.*;
import miniJava.AbstractSyntaxTrees.*; import miniJava.AbstractSyntaxTrees.*;
import miniJava.AbstractSyntaxTrees.Package; import miniJava.AbstractSyntaxTrees.Package;
@ -30,10 +31,16 @@ public class Compiler {
System.exit(0); System.exit(0);
} catch(FileNotFoundException e) { } catch(FileNotFoundException e) {
System.exit(rc); System.out.println(e.getMessage());
} catch(IOException e) { } 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; package miniJava.SyntacticAnalyzer;
import java.io.*;
import java.util.LinkedList; import java.util.LinkedList;
import miniJava.AbstractSyntaxTrees.*; import miniJava.AbstractSyntaxTrees.*;
import miniJava.AbstractSyntaxTrees.Package; import miniJava.AbstractSyntaxTrees.Package;
import miniJava.SyntacticAnalyzer.Errors.*;
public class Parser { public class Parser {
@ -18,9 +19,9 @@ public class Parser {
/** /**
* Program ::= (ClassDeclaration)* eot * Program ::= (ClassDeclaration)* eot
* @return * @return
* @throws IOException * @throws ScanningException
*/ */
public Package parse() throws IOException { public Package parse() throws ParsingException, ScanningException {
ClassDeclList decls = new ClassDeclList(); ClassDeclList decls = new ClassDeclList();
while(peek(1).type == Token.TYPE.CLASS) { while(peek(1).type == Token.TYPE.CLASS) {
decls.add(parseClassDeclaration()); decls.add(parseClassDeclaration());
@ -36,9 +37,9 @@ public class Parser {
* (Declarators id (; | MethodDeclaration))* * (Declarators id (; | MethodDeclaration))*
* } * }
* @return * @return
* @throws IOException * @throws ScanningException
*/ */
private ClassDecl parseClassDeclaration() throws IOException { private ClassDecl parseClassDeclaration() throws ParsingException, ScanningException {
// Class Header // Class Header
accept(Token.TYPE.CLASS); accept(Token.TYPE.CLASS);
@ -72,9 +73,9 @@ public class Parser {
/** /**
* Declarators ::= (public | private)? static? Type * Declarators ::= (public | private)? static? Type
* @return * @return
* @throws IOException * @throws ScanningException
*/ */
private Declarators parseDeclarators() throws IOException { private Declarators parseDeclarators() throws ParsingException, ScanningException {
// Visibility // Visibility
boolean isPrivate = false; boolean isPrivate = false;
@ -103,9 +104,9 @@ public class Parser {
* } * }
* @param f describes the declaratory aspect of the method * @param f describes the declaratory aspect of the method
* @return * @return
* @throws IOException * @throws ScanningException
*/ */
private MethodDecl parseMethodDeclaration(FieldDecl f) throws IOException { private MethodDecl parseMethodDeclaration(FieldDecl f) throws ParsingException, ScanningException {
// Method Header // Method Header
accept(Token.TYPE.LPAREN); accept(Token.TYPE.LPAREN);
@ -139,9 +140,9 @@ public class Parser {
/** /**
* Type ::= boolean | void | int ([])? | id ([])? * Type ::= boolean | void | int ([])? | id ([])?
* @return * @return
* @throws IOException * @throws ScanningException
*/ */
private Type parseType() throws IOException { private Type parseType() throws ParsingException, ScanningException {
switch(peek(1).type) { switch(peek(1).type) {
@ -181,16 +182,16 @@ public class Parser {
} }
default: default:
throw new IOException(); throw new ParsingException();
} }
} }
/** /**
* ParameterList ::= Type id (, Type id)* * ParameterList ::= Type id (, Type id)*
* @return * @return
* @throws IOException * @throws ScanningException
*/ */
private ParameterDeclList parseParameterList() throws IOException { private ParameterDeclList parseParameterList() throws ParsingException, ScanningException {
ParameterDeclList decls = new ParameterDeclList(); ParameterDeclList decls = new ParameterDeclList();
@ -213,9 +214,9 @@ public class Parser {
/** /**
* ArgumentList ::= Expression (, Expression)* * ArgumentList ::= Expression (, Expression)*
* @return * @return
* @throws IOException * @throws ScanningException
*/ */
private ExprList parseArgumentList() throws IOException { private ExprList parseArgumentList() throws ParsingException, ScanningException {
ExprList e = new ExprList(); ExprList e = new ExprList();
e.add(parseExpression()); e.add(parseExpression());
while(peek(1).type == Token.TYPE.COMMA) { while(peek(1).type == Token.TYPE.COMMA) {
@ -229,9 +230,9 @@ public class Parser {
/** /**
* Reference ::= BaseRef (. BaseRef)* * Reference ::= BaseRef (. BaseRef)*
* @return * @return
* @throws IOException * @throws ScanningException
*/ */
private Reference parseReference() throws IOException { private Reference parseReference() throws ParsingException, ScanningException {
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);
@ -253,9 +254,9 @@ public class Parser {
/** /**
* BaseRef ::= this | id ([ Expression])? * BaseRef ::= this | id ([ Expression])?
* @return * @return
* @throws IOException * @throws ScanningException
*/ */
private Reference parseBaseRef() throws IOException { private Reference parseBaseRef() throws ParsingException, ScanningException {
switch(peek(1).type) { switch(peek(1).type) {
case THIS: case THIS:
@ -289,9 +290,9 @@ public class Parser {
* | if (Expression) Statement (else Statement)? * | if (Expression) Statement (else Statement)?
* | while (Expression) Statement * | while (Expression) Statement
* @return * @return
* @throws IOException * @throws ScanningException
*/ */
private Statement parseStatement() throws IOException { private Statement parseStatement() throws ParsingException, ScanningException {
switch(peek(1).type) { switch(peek(1).type) {
@ -391,9 +392,9 @@ public class Parser {
* | num | true | false * | num | true | false
* | new (id() | int [ Expression ] | id [ Expression ] ) * | new (id() | int [ Expression ] | id [ Expression ] )
* @return * @return
* @throws IOException * @throws ScanningException
*/ */
private Expression parseSingleExpression() throws IOException { private Expression parseSingleExpression() throws ParsingException, ScanningException {
Expression e = null; Expression e = null;
switch(peek(1).type) { switch(peek(1).type) {
@ -430,7 +431,7 @@ public class Parser {
Operator o = new Operator(accept(peek(1).type), null); Operator o = new Operator(accept(peek(1).type), null);
e = new UnaryExpr(o, parseSingleExpression(), null); e = new UnaryExpr(o, parseSingleExpression(), null);
} }
else throw new IOException(); else throw new ParsingException();
break; break;
} }
@ -487,7 +488,7 @@ public class Parser {
} }
default: default:
throw new IOException(); throw new ParsingException();
} }
return e; return e;
@ -497,9 +498,9 @@ public class Parser {
* Disjunction & Initial Call: * Disjunction & Initial Call:
* Expression ::= Expression binop Expression * Expression ::= Expression binop Expression
* @return * @return
* @throws IOException * @throws ScanningException
*/ */
private Expression parseExpression() throws IOException { private Expression parseExpression() throws ParsingException, ScanningException {
Expression e = parseCExpression(); Expression e = parseCExpression();
while(peek(1).spelling.equals("||")) { while(peek(1).spelling.equals("||")) {
@ -513,9 +514,9 @@ public class Parser {
/** /**
* Conjunction * Conjunction
* @return * @return
* @throws IOException * @throws ScanningException
*/ */
private Expression parseCExpression() throws IOException { private Expression parseCExpression() throws ParsingException, ScanningException {
Expression e = parseEExpression(); Expression e = parseEExpression();
while(peek(1).spelling.equals("&&")) { while(peek(1).spelling.equals("&&")) {
@ -529,9 +530,9 @@ public class Parser {
/** /**
* Equality * Equality
* @return * @return
* @throws IOException * @throws ScanningException
*/ */
private Expression parseEExpression() throws IOException { private Expression parseEExpression() throws ParsingException, ScanningException {
Expression e = parseRExpression(); Expression e = parseRExpression();
while(peek(1).spelling.equals("==") || peek(1).spelling.equals("!=")) { while(peek(1).spelling.equals("==") || peek(1).spelling.equals("!=")) {
@ -545,9 +546,9 @@ public class Parser {
/** /**
* Relational * Relational
* @return * @return
* @throws IOException * @throws ScanningException
*/ */
private Expression parseRExpression() throws IOException { private Expression parseRExpression() throws ParsingException, ScanningException {
Expression e = parseAExpression(); Expression e = parseAExpression();
while(peek(1).spelling.equals("<") || peek(1).spelling.equals("<=") while(peek(1).spelling.equals("<") || peek(1).spelling.equals("<=")
@ -562,9 +563,9 @@ public class Parser {
/** /**
* Additive * Additive
* @return * @return
* @throws IOException * @throws ScanningException
*/ */
private Expression parseAExpression() throws IOException { private Expression parseAExpression() throws ParsingException, ScanningException {
Expression e = parseMExpression(); Expression e = parseMExpression();
while(peek(1).spelling.equals("+") || peek(1).spelling.equals("-")) { while(peek(1).spelling.equals("+") || peek(1).spelling.equals("-")) {
@ -578,9 +579,9 @@ public class Parser {
/** /**
* Multiplicative * Multiplicative
* @return * @return
* @throws IOException * @throws ScanningException
*/ */
private Expression parseMExpression() throws IOException { private Expression parseMExpression() throws ParsingException, ScanningException {
Expression e = parseSingleExpression(); Expression e = parseSingleExpression();
while(peek(1).spelling.equals("*") || peek(1).spelling.equals("/")) { 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. * Sees what the next token is, caching the result.
* @return * @return
* @throws IOException * @throws ScanningException
*/ */
private Token peek(int lookahead) throws IOException { private Token peek(int lookahead) throws ScanningException {
// Cache tokens // Cache tokens
while(stream.size() < lookahead) { while(stream.size() < lookahead) {
@ -610,12 +611,12 @@ public class Parser {
/** /**
* Consumes token or throws exception. * 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); Token next = peek(1);
if(next.type == type) stream.poll(); if(next.type == type) stream.poll();
else throw new IOException(); else throw new ParsingException(next);
return next; return next;
} }

View File

@ -2,8 +2,12 @@ package miniJava.SyntacticAnalyzer;
import java.io.*; import java.io.*;
import miniJava.SyntacticAnalyzer.Errors.ScanningException;
public class Scanner { public class Scanner {
private int col = 1;
private int line = 1;
private BufferedReader input; private BufferedReader input;
public Scanner(BufferedReader input) { public Scanner(BufferedReader input) {
@ -15,7 +19,7 @@ public class Scanner {
* @return * @return
* @throws IOException * @throws IOException
*/ */
public Token scan() throws IOException { public Token scan() throws ScanningException {
String attr = ""; String attr = "";
Token token = null; Token token = null;
@ -23,7 +27,7 @@ public class Scanner {
while(token == null) { while(token == null) {
// Check for EOF // Check for EOF
int c = input.read(); int c = read();
if(c == -1) return new Token("", Token.TYPE.EOT); if(c == -1) return new Token("", Token.TYPE.EOT);
// Setup // Setup
@ -37,18 +41,18 @@ public class Scanner {
break; break;
case '+': case '+':
if(peek('+')) throw new IOException(); if(peek('+')) throw new ScanningException(col, line);
token = new Token(attr, Token.TYPE.BINOP); token = new Token(attr, Token.TYPE.BINOP);
break; break;
case '-': case '-':
if(peek('-')) throw new IOException(); if(peek('-')) throw new ScanningException(col, line);
token = new Token(attr, Token.TYPE.BINOP); token = new Token(attr, Token.TYPE.BINOP);
break; break;
// Check for comment // Check for comment
case '/': case '/':
if(peek('*')) { input.read(); readComment(); attr = ""; } if(peek('*')) { read(); readComment(); attr = ""; }
else if(peek('/')) { readLine(); attr = ""; } else if(peek('/')) { readLine(); attr = ""; }
else token = new Token(attr, Token.TYPE.BINOP); else token = new Token(attr, Token.TYPE.BINOP);
break; break;
@ -56,7 +60,7 @@ public class Scanner {
// Check for c or c= // Check for c or c=
case '>': case '>':
case '<': case '<':
if(peek('=')) attr += (char) input.read(); if(peek('=')) attr += (char) read();
token = new Token(attr, Token.TYPE.BINOP); token = new Token(attr, Token.TYPE.BINOP);
break; break;
@ -64,7 +68,7 @@ public class Scanner {
case '!': case '!':
if(!peek('=')) token = new Token(attr, Token.TYPE.UNOP); if(!peek('=')) token = new Token(attr, Token.TYPE.UNOP);
else { else {
attr += (char) input.read(); attr += (char) read();
token = new Token(attr, Token.TYPE.BINOP); token = new Token(attr, Token.TYPE.BINOP);
} }
break; break;
@ -72,9 +76,9 @@ public class Scanner {
// Check for && or || // Check for && or ||
case '&': case '&':
case '|': case '|':
if(!peek((char) c)) throw new IOException(); if(!peek((char) c)) throw new ScanningException(col, line);
else { else {
attr += (char) input.read(); attr += (char) read();
token = new Token(attr, Token.TYPE.BINOP); token = new Token(attr, Token.TYPE.BINOP);
} }
break; break;
@ -83,7 +87,7 @@ public class Scanner {
case '=': case '=':
if(!peek('=')) token = new Token(attr, Token.TYPE.EQUALS); if(!peek('=')) token = new Token(attr, Token.TYPE.EQUALS);
else { else {
attr += (char) input.read(); attr += (char) read();
token = new Token(attr, Token.TYPE.BINOP); token = new Token(attr, Token.TYPE.BINOP);
} }
break; break;
@ -129,7 +133,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) || n == '_';) {
attr += (char) input.read(); attr += (char) read();
n = peek(); n = peek();
} }
@ -143,7 +147,7 @@ public class Scanner {
// Number // Number
else if(isDigit((char) c)) { else if(isDigit((char) c)) {
for(char n = peek(); isDigit(n);) { for(char n = peek(); isDigit(n);) {
attr += (char) input.read(); attr += (char) read();
n = peek(); n = peek();
} }
@ -156,7 +160,7 @@ public class Scanner {
} }
// Unrecognized Character // Unrecognized Character
else throw new IOException(); else throw new ScanningException(col, line);;
break; break;
} }
@ -171,12 +175,16 @@ public class Scanner {
* @return * @return
* @throws IOException * @throws IOException
*/ */
private char peek() throws IOException { private char peek() throws ScanningException {
input.mark(1); try {
int next = input.read(); input.mark(1);
input.reset(); int next = input.read();
input.reset();
return next == -1 ? '\0' : (char) next; return next == -1 ? '\0' : (char) next;
} catch(IOException e) {
throw new ScanningException(col, line);
}
} }
@ -186,12 +194,34 @@ public class Scanner {
* @return * @return
* @throws IOException * @throws IOException
*/ */
private boolean peek(char c) throws IOException { private boolean peek(char c) throws ScanningException {
input.mark(1); try {
int next = input.read(); input.mark(1);
input.reset(); int next = input.read();
input.reset();
return c == next; 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,15 +229,19 @@ public class Scanner {
* Consumes input until an end of comment has been reached. * Consumes input until an end of comment has been reached.
* @throws IOException * @throws IOException
*/ */
private void readComment() throws IOException { private void readComment() throws ScanningException {
char prev = '\0', current = '\0'; try {
while(prev != '*' || current != '/') { char prev = '\0', current = '\0';
while(prev != '*' || current != '/') {
prev = current; prev = current;
int next = input.read(); int next = input.read();
if(next == -1) throw new IOException(); if(next == -1) throw new IOException();
else current = (char) next; 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 * Consumes input until the end of line is reached
* @throws IOException * @throws IOException
*/ */
private void readLine() throws IOException { private void readLine() throws ScanningException {
for(int n = 0; n != '\n' && n != '\r' && n != -1; n = input.read()) {} try {
for(int n = 0; n != '\n' && n != '\r' && n != -1; n = input.read()) {}
} catch(IOException e) {
throw new ScanningException(col, line);
}
} }