Second Summer 2002


Lab Notes Twelve: Help with the last assignment.
This is the code you will develop in lab today.

import java.io.*; 
import java.util.*;

class Eval {

    /* this Hashtable must be shared between two static methods 
       (main, which creates it and process, which is using it 
       for lookup,) so it must be global enough */
    static Hashtable env = new Hashtable(); 

    // here's the main method getting away with a try/catch
    public static void main(String[] args) throws IOException {
        
        //this is why we need to acknowledge the IOException
        BufferedReader console = 
            new BufferedReader
                (new InputStreamReader(System.in));       

        //checked after the loop, must be visible enough
        String line; 
        
        do {
            //prompt
            System.out.print("Eval> "); 
            //... and read
            line = console.readLine(); 
  
            //stop if you have to     
            if (line.equals("bye")) break; 

            //get ready to take things apart
            StringTokenizer st = new StringTokenizer(line); 

            //prepare the storage for the resulting tokens
            Vector v = new Vector(); 

            //and now just do it
            while (st.hasMoreTokens()) {
                v.addElement(st.nextToken()); 
            }
            //so now the tokens are in a Vector, v


            //could be an assignment statement
            if (v.size() > 2 && v.elementAt(1).equals("=")) { 

                //in which case you take the name at the front
                String name = (String)(v.elementAt(0)); 
                //... and keep it in the variable called 'name'

                //then remove the string and the equal sign 
                v.removeElementAt(1); 
                v.removeElementAt(0); 
                //the Vector is shrinking as you remove elements so,
                //either remove backwards or twice at index 0 (zero)!

                //now process the remaining expression and store the 
                // value in the Hashtable in the entry for the name 
                // you found in position 0 in the original Vector
                env.put(name, Eval.process(v));


            } else {// if it's not an assignment statement,
              
              // ... then you can start evaluating it
              Eval.process(v); 


            }//end of conditional processing

            // getting ready to report the result
            System.out.print("Done: ");
            Eval.show(v); //the Vector is shown here

        } while (true);//loop if you have to (exit with break!)
        
    }// end of main

    // straghtforward procedure for showing a Vector
    static void show(Vector v) {
        for (int i = 0; i < v.size(); i++) {
            System.out.print(" " + v.elementAt(i)); 
        }
        System.out.println(); 
    }

    // this is the heart of the evaluator
    static String process (Vector v) {// receives the Vector as a param

        // wishful thinking (see do/while test below)
        boolean finished = true; 

        // first replace identifiers by their values
        for (int i = 0; i < v.size(); i++) {
            // get the String that's there (position i)
            // this could be anything: +, -, 123, a, *
            String element = (String) (v.elementAt(i));
            // look it up in env (nevermind how it got there)
            Object value = env.get(element); 
            // if you find it, there's a value associated with  
            if (value != null) {
                // replace it (index i) by the value it has
                v.setElementAt((String)value, i); 
            }

        }// all identifiers have been replaced

        // we're ready for the real processing

        do {

            // remove parens and update your agenda
            finished = Eval.removeParens(v); 
            // all three methods used here return true when
            // they could not find anything to work on within 
            // the expression, and they return false if they 
            // could change it in at least one aspect; therefore 
            // your hope of being finished is true only when none 
            // of the workers find anything to work on...
            finished = finished && Eval.removeStars(v); 
            finished = finished && Eval.removePluses(v);

            // report the current status of the Vector
            // from within the process of changing it 
            System.out.print("Processing: "); Eval.show(v);  

        } while (! finished); // if not finished keep going...

        // return the first element in the resulting Vector
        return (String) (v.elementAt(0)); 

    }

    static boolean removeParens(Vector v) { 
        // empty procedure, reports true
        return true; 
        // this means it 'thinks' it's done...
    }

    static boolean removeStars(Vector v) { 
        // same here, you need to provide these methods... 
        return true; 
    
    }

    static boolean removePluses(Vector v) { 
        // the only one that works 
        boolean done = true;// assume nothing will have to be done 

        // look everywhere in the Vector
        for (int i = 0; i < v.size(); i++) {
 
            // if you find a plus sign 
            if (v.elementAt(i).equals("+")) { 

                done = false; // there's work to be done 

                // expect two numbers on its sides
                int n = Integer.parseInt((String) (v.elementAt(i - 1))), 
                    m = Integer.parseInt((String) (v.elementAt(i + 1))); 

                // store the sum where the first operand was 
                v.setElementAt((n + m) + "", i - 1); 
               // carefully remove the plus and the second operand
                v.removeElementAt(i + 1);
                v.removeElementAt(i); 

                // don't skip the next token 
                i -= 1; 
                // the Vector has shrunk so it's in front 
                // of you, and the for loop will increment i by default 

            }// end of determining if you're looking at a '+' sign

        }// end of the for loop

        return done; // report whether we're done or not 

    }// end of the removePluses method

}// end of story
The emphasis here is on

A lab assignment will be determined and then posted here soon.

Most likely it will have something to do with the following:

(Here's an example due to Alex Basyrov, Spring 2002 A597)

How do you evaluate this?

(1 + 1) * 2 + 2 * ( 1 + 1 )
Our substitution rules need to be revised once the parens are added.

Parens can delay the evaluation of operators (such as "*") and when that happens we need to propagate this delay throughout. So, in our case, we only need to take care of pluses and minuses, which should NOT be evaluated if there are stars and slashes waiting to be processed (they bind stronger to the numbers than their lower precedence counterparts).

So the code more or less becomes (only an if statement changes):

static boolean reducePlusesAndMinuses(Vector expr) {
    boolean done = true; 

    for (int i = 0; i < expr.size(); i++) {

        if (expr.elementAt(i).equals("+") || expr.elementAt(i).equals("-")) { 

            if (
                // value to its left
                isValue((String)expr.elementAt(i - 1)) && 
                // value to its right                 
                isValue((String)expr.elementAt(i + 1)) && 

                // and not a higher priority operator to wait on 
                ! ( ( // value on left not at end of vector 
                      (i - 2) >= 0 && 
                      // higher precedence operator waiting there 
                      ( ((String)expr.elementAt(i - 2)).equals("*") ||
                        // note there are two such operators 
                        ((String)expr.elementAt(i - 2)).equals("/")
                      ) 

                    ) // this can happen on the left 

                    || // or (it can happen on the right)

                    ( // value on right not at end of vector 
                      (i + 2) < expr.size() && 
                      // higher precedence operator waiting there 
                      ( ((String)expr.elementAt(i + 2)).equals("*") ||
                        // note there are two such operators 
                        ((String)expr.elementAt(i + 2)).equals("/")
                      )

                    )
                  ) 


               ) {

                Integer a = new Integer((String)expr.elementAt(i - 1)); 
                Integer b = new Integer((String)expr.elementAt(i + 1)); 

                // ... reduce the plus sign 
You should include this change in your programs.

You should also be aware of all the context dependencies that it relies on.


Last updated: Jul 28, 2002 by Adrian German for A201