Computer Science 2311
Fall 2009
Laboratory Assignment 11

Handed out: 11/24/09


The assignment

Your assignment is to write a program that reads expressions involving real numbers and writes their values. Each expression is on one line. After reading a line, the program should display the answer and read the next line. It should keep going until it reads a line that only contains character $.

Here is a sample session. Parts in black are typed by the user. Parts in blue are written by the program.

23.1 + 5.0
28.1
2*2*2
8
2+3*4
14
2*(3.1 + 4.1)
14.4
25/2
12.5
s(16)+1
5
$

Expressions, terms and factors

The expressions that your program should be able to evaluate allow real number constants such as 4.2, addition (+), subtraction (-), multiplication (*) and division (/). Multiplication has the same precedence as division and addition has the same precedence as subtraction. Multiplication has higher precedence than addition. Operations of the same precedence are done from right to left.

Additionally, the expressions allow parentheses to override precedence rules. Expression s(A) yields the square root of expression A.

An expression is any kind of expression that the program supports.

A term is an expression that does not allow the use of + or - unless they occur inside parenthes. For example, 2.0*5.0 is a term. So is (9.0 + 1.0), since the + operator occurs inside parentheses. But 2.0 + 4.0 is not a term since it contains a + that is not inside parentheses.

A factor is an expression that does not allow any of the binary operators except within parentheses. For example, 5.2 is a factor, as is s(2.0*4.0). But 4.0*5.0 is not a factor since it uses a binary operator that is not inside parentheses.


Reading lines

For this assignments, use the Scanner class that is provided you. Do not try to use the standard Java scanner class.

Here is a main function that starts by building a scanner object, mainscan, that is responsible for reading lines from the standard input. After reading each line, it builds a new scanner object, linescan, that reads from that line. Then linescan is passed to evaluate to get the value of the expression written on the line.

public static void main(String[] args)
{
  Scanner mainscan = new Scanner(System.in);
  String line = mainscan.nextLine();
  while(!line.equals("$")) 
  {
    Scanner linescan = new Scanner(new java.io.StringReader(line));
    double val = evaluate(linescan);
    System.out.println(val);
    line = mainscan.nextLine();
  }
}
In evaluate, you can read a character, skipping over blanks, using
  int c = linescan.skipBlanks();
Then c will be -1 if there are no more nonblank characters or it will be the integer code of the character if there is a nonblank character to read. Make it into a character using
  char ch = (char) c;
To read a real number, use
  double x = linescan.nextDouble();


Evaluating an expression

Write three functions.

public static double evaluate(Scanner linescan)

evaluate(linescan) reads an expression from linescan and returns the value of the expression. It should work as follows.

  1. Read a term, using function term. Remember its value.

  2. Try to read a character.

    1. If there are no more characters, then the term was the entire expression. Return the value of the term.

    2. If there is a + or - character next, then read another term, using function term. Perform the indicated operation (addition or subtraction) on the two numbers that were returned by the two calls to term.

    3. If the next character is anything except + or -, then put it back into the input and return the value of the first term that was read. To put back the last character that was read, use

        linescan.backup();
      

public static double term(Scanner linescan)

term(linescan) reads a term from linescan and returns the value of the term. It should work as follows.

  1. Read a factor, using function factor. Remember its value.

  2. Try to read a character.

    1. If there are no more characters, then the term was the entire expression. Return the value of the term.

    2. If there is a * or / character next, then read another factor, using function factor. Perform the indicated operation on the two numbers that were returned by the two calls to factor.

    3. If the next character is found to be anything except * or /, then put it back into the input and return the value of the first factor.

public static double factor(Scanner linescan)

factor(linescan) reads a factor from linescan and returns the value of the factor. It should start by reading a character. Then it should work according to what the character is.

  1. If the character is a left parenthesis, then read an expression, using evaluate. Now read another character. It should be a right parenthesis. If not, print an error message. Return the value that was returned by evaluate.

  2. If the next character is s, then read another character, which should be a left parenthesis. Read an expression using evaluate. Then read another character, which should be a right parenthesis. If either the left parenthesis or the right parenthesis is not found, print an error message. In any event, return the square root of the value that was returned by evaluate. Use function Math.sqrt to get the square root.

  3. If the next character is a digit or a period, then put the character back into the input. Read a real number using linescan.nextDouble( ). Return the value that is returned to you by nextDouble.

  4. If the next character is not any of the above, then print an error message and return 0.0.


Testing and submitting your program

Test your program. Try several expressions. When you are satisfied that it is working, print it and turn in the printout.