/* This program evaluates standard expressions typed in by the user. The expressions can use positive real numbers and the binary operators +, -, *, and /. The unary minus operation is supported. The expressions are defined by the BNF rules: ::= [ "-" ] [ [ "+" | "-" ] ]... ::= [ [ "*" | "/" ] ]... ::= | "(" ")" A number must begin with a digit (i.e., not a decimal point). A line of input must contain exactly one such expression. If extra data is found on a line after an expression has been read, it is considered an error. */ public class SimpleParser2 { static class ParseError extends Exception { // Represents a syntax error found in the user's input. ParseError(String message) { super(message); } } // end nested class ParseError public static void main(String[] args) { while (true) { TextIO.putln("\n\nEnter an expression, or press return to end."); TextIO.put("\n? "); skipBlanks(); if ( TextIO.peek() == '\n' ) break; try { double val = expressionValue(); skipBlanks(); if ( TextIO.peek() != '\n' ) throw new ParseError("Extra data after end of expression."); TextIO.getln(); TextIO.putln("\nValue is " + val); } catch (ParseError e) { TextIO.putln("\n*** Error in input: " + e.getMessage()); TextIO.putln("*** Discarding input: " + TextIO.getln()); } } TextIO.putln("\n\nDone."); } // end main() static void skipBlanks() { // Skip past any spaces and tabs on the current line of input. // Stop at a non-blank character or end-of-line. while ( TextIO.peek() == ' ' || TextIO.peek() == '\t' ) TextIO.getAnyChar(); } static double expressionValue() throws ParseError { // Read an expression from the current line of input and // return its value. skipBlanks(); boolean negative; // True if there is a leading minus sign. negative = false; if (TextIO.peek() == '-') { TextIO.getAnyChar(); negative = true; } double val; // Value of the expression. val = termValue(); if (negative) val = -val; skipBlanks(); while ( TextIO.peek() == '+' || TextIO.peek() == '-' ) { // Read the next term and add it to or subtract it from // the value of previous terms in the expression. char op = TextIO.getAnyChar(); double nextVal = termValue(); if (op == '+') val += nextVal; else val -= nextVal; skipBlanks(); } return val; } // end expressionValue() static double termValue() throws ParseError { // Read a term from the current line of input and // return its value. skipBlanks(); double val; val = factorValue(); skipBlanks(); while ( TextIO.peek() == '*' || TextIO.peek() == '/' ) { // Read the next factor, and multiply or divide // the value-so-far by the value of this factor. char op = TextIO.getAnyChar(); double nextVal = factorValue(); if (op == '*') val *= nextVal; else val /= nextVal; skipBlanks(); } return val; } // end termValue() static double factorValue() throws ParseError { // Read a factor from the current line of input and // return its value. skipBlanks(); char ch = TextIO.peek(); if ( Character.isDigit(ch) ) { // The factor is a number. return TextIO.getDouble(); } else if ( ch == '(' ) { // The factor is an expression in parentheses. TextIO.getAnyChar(); // Read the "(" double val = expressionValue(); skipBlanks(); if ( TextIO.peek() != ')' ) throw new ParseError("Missing right parenthesis."); TextIO.getAnyChar(); // Read the ")" return val; } else if ( ch == '\n' ) throw new ParseError("End-of-line encountered in the middle of an expression."); else if ( ch == ')' ) throw new ParseError("Extra right parenthesis."); else if ( ch == '+' || ch == '-' || ch == '*' || ch == '/' ) throw new ParseError("Misplaced operator."); else throw new ParseError("Unexpected character \"" + ch + "\" encountered."); } } // end class SimpleParser2