From f34ccd138dc3c89a7a68b340c9bea649449de32d Mon Sep 17 00:00:00 2001 From: Joshua Potter Date: Wed, 5 Mar 2014 12:00:24 -0500 Subject: [PATCH] Basic Error Handling Added Scanner and Parsing Exceptions as well as keeping track of the source position. --- miniJava/src/miniJava/Compiler.java | 11 +- .../Errors/ParsingException.java | 17 +++ .../Errors/ScanningException.java | 11 ++ .../miniJava/SyntacticAnalyzer/Parser.java | 87 +++++++------- .../miniJava/SyntacticAnalyzer/Scanner.java | 110 ++++++++++++------ 5 files changed, 155 insertions(+), 81 deletions(-) create mode 100644 miniJava/src/miniJava/SyntacticAnalyzer/Errors/ParsingException.java create mode 100644 miniJava/src/miniJava/SyntacticAnalyzer/Errors/ScanningException.java diff --git a/miniJava/src/miniJava/Compiler.java b/miniJava/src/miniJava/Compiler.java index c850c20..fe2a7c3 100644 --- a/miniJava/src/miniJava/Compiler.java +++ b/miniJava/src/miniJava/Compiler.java @@ -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); } } diff --git a/miniJava/src/miniJava/SyntacticAnalyzer/Errors/ParsingException.java b/miniJava/src/miniJava/SyntacticAnalyzer/Errors/ParsingException.java new file mode 100644 index 0000000..5751350 --- /dev/null +++ b/miniJava/src/miniJava/SyntacticAnalyzer/Errors/ParsingException.java @@ -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()); + } + +} diff --git a/miniJava/src/miniJava/SyntacticAnalyzer/Errors/ScanningException.java b/miniJava/src/miniJava/SyntacticAnalyzer/Errors/ScanningException.java new file mode 100644 index 0000000..8a754a8 --- /dev/null +++ b/miniJava/src/miniJava/SyntacticAnalyzer/Errors/ScanningException.java @@ -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); + } + +} diff --git a/miniJava/src/miniJava/SyntacticAnalyzer/Parser.java b/miniJava/src/miniJava/SyntacticAnalyzer/Parser.java index 9808272..813ea37 100644 --- a/miniJava/src/miniJava/SyntacticAnalyzer/Parser.java +++ b/miniJava/src/miniJava/SyntacticAnalyzer/Parser.java @@ -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; } diff --git a/miniJava/src/miniJava/SyntacticAnalyzer/Scanner.java b/miniJava/src/miniJava/SyntacticAnalyzer/Scanner.java index c3dec71..bf696a0 100644 --- a/miniJava/src/miniJava/SyntacticAnalyzer/Scanner.java +++ b/miniJava/src/miniJava/SyntacticAnalyzer/Scanner.java @@ -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 { - input.mark(1); - int next = input.read(); - input.reset(); - - return next == -1 ? '\0' : (char) next; + 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 { - input.mark(1); - int next = input.read(); - input.reset(); - - return c == next; + 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,15 +229,19 @@ public class Scanner { * Consumes input until an end of comment has been reached. * @throws IOException */ - private void readComment() throws IOException { - char prev = '\0', current = '\0'; - while(prev != '*' || current != '/') { - - prev = current; - - int next = input.read(); - if(next == -1) throw new IOException(); - else current = (char) next; + private void readComment() throws ScanningException { + try { + char prev = '\0', current = '\0'; + while(prev != '*' || current != '/') { + + prev = current; + + int next = input.read(); + if(next == -1) throw new IOException(); + else current = (char) next; + } + } catch(IOException e) { + throw new ScanningException(col, line); } } @@ -216,8 +250,12 @@ public class Scanner { * Consumes input until the end of line is reached * @throws IOException */ - private void readLine() throws IOException { - for(int n = 0; n != '\n' && n != '\r' && n != -1; n = input.read()) {} + 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); + } }