SDSU CS 635: Advanced Object-Oriented Design & Programming
Spring Semester, 1998
Code for Assignment 3

To Lecture Notes Index
© 1998, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 01-May-98

Contents of Doc 28, Code for Assignment 3


Code For Assignment 3 slide # 2
...//Test Program slide # 3
...//ExpressionParser
slide # 4
...//Visitor slide # 5
...//Node slide # 6
...//External Node slide # 7
...//UnaryNode slide # 8
...//BinaryNode slide # 9
...//NullNode slide # 10


Doc 28, Code for Assignment 3 Slide # 2

Code For Assignment 3


The following classes can be used produce an expression tree given postfix notation. Most of the code here should translate easily into C++. Some of the items that will not be found directly in C++:

Writer
Convert Writer in the print method to cout.

Stack
STL has a stack, or you could write your own

Strings
I use Java's String indexOf operator to avoid using a case statement in the ExpressionParser class. Use the case statement. That is:

if ( token == "+" ) 
     process the +
else if ( token == "*" )
     process the *
etc.

StringTokenizer
I use this to parse a string that has tokens which are separated with spaces. A sample string would be "1 2 -3 + *" The StringTokenizer just breaks this into the strings "1", "2", "-3", "*". If reproducing this functionality is a problem, then use an array of strings as your input. This will remove the need for the StringTokenizer.

Doc 28, Code for Assignment 3 Slide # 3

//Test Program

// Simple Test program
public class Test
     {
     public static void main( String[] args ) throws IOException
          {
          String[] expressions = { "1 2 +" , "3 a", "1 2 3 + * ", 
                    " 1 2 + 3 a 4 5 * - +"};
          testParsing( expressions);
          }
     
     
     public static void  testParsing( String[] expressions   ) 
               throws IOException
          {
          ExpressionParser parser = new ExpressionParser();
          Node expressionTree;
          Writer out =  new OutputStreamWriter (System.out );
          
          for (int k = 0; k < expressions.length; k++ )
               {
               expressionTree = parser.parsePostfix( expressions[k] );
               expressionTree.print( out );
               }
          }


Doc 28, Code for Assignment 3 Slide # 4

//ExpressionParser

import java.util.*;

// This class converts postfix notation into a tree structure
// An example of postfix notation is "1 2 3 + *" which is the expression
//  (1 * ( 2  + 3 )
public class ExpressionParser
     {
     //the space character separates tokens
     String tokenSeparators = " "; 
     
     //the space character separates operators in the string
     String binaryOperators = "+ - *";
     String unaryOperators = "a";
     
     //Pass this method your postFixExpression 
     // It will return your tree
     public Node parsePostfix( String postFixExpression )
          {
          Stack treeNodes = new Stack();
          StringTokenizer parser = 
               new StringTokenizer( postFixExpression, 
                    tokenSeparators );
          
          while ( parser.hasMoreTokens() )
               {
               String token = parser.nextToken();
               
               if ( isUnaryOperator( token ) )
                    processUnaryOperator( token, treeNodes  );
               else if (  isBinaryOperator( token ) )
                    processBinaryOperator( token, treeNodes );
               else
                    processOperand( token, treeNodes );
                    
               }
          return (Node) treeNodes.pop();
          }

     private void processOperand( String operand, Stack treeNodes)
          {
          int intOperand = Integer.parseInt( operand );
          ExternalNode leaf = new ExternalNode( intOperand );
          treeNodes.push( leaf );
          }

     private void processBinaryOperator( String operator, Stack treeNodes)
          {
          BinaryNode nodeOperator = new BinaryNode( operator );
          Node rightOperand = (Node) treeNodes.pop();
          Node leftOperand = (Node) treeNodes.pop();
          nodeOperator.setRightChild( rightOperand );
          nodeOperator.setLeftChild( leftOperand );
          treeNodes.push( nodeOperator );
          }

     private void processUnaryOperator( String operator, Stack treeNodes)
          {
          UnaryNode nodeOperator = new UnaryNode( operator );
          Node operand = (Node) treeNodes.pop();
          nodeOperator.setChild( operand );
          treeNodes.push( nodeOperator );
          }

     private boolean isBinaryOperator( String operator)
          {
          return contains( binaryOperators, operator );
          }
     
     private boolean isUnaryOperator( String operator)
          {
          return contains( unaryOperators, operator );
          }
     private boolean contains( String text, String pattern )
          {
          if ( text.indexOf( pattern )  > -1 )
               return true;
          else
               return false;
          }
     }

Doc 28, Code for Assignment 3 Slide # 5

//Visitor


public interface Visitor
     {
     public void visitBinaryNode( BinaryNode aNode);
     public void visitUnaryNode( UnaryNode aNode);
     public void visitExternalNode( ExternalNode aNode);
     }

Doc 28, Code for Assignment 3 Slide # 6

//Node

import java.io.Writer;
import java.io.IOException;

// this class is the parent class of all the tree nodes
public abstract class Node
     {
     private Node parentNode;
     
     // Print out the tree rooted at current node
     // For testing only. Does not satisfy problem 1
     public abstract void print( Writer ouput) throws IOException;
     
     public abstract void accept( Visitor aVistor);
          
     // Useful in traversing trees
     public Node getParent()
          {
          return parentNode;
          }
     
     protected void setParent( Node myParent )
          {
          parentNode = myParent;
          }
     }



Doc 28, Code for Assignment 3 Slide # 7

//External Node

import java.io.Writer;
import java.io.IOException;

// this class is used to store the operands (ints) in the
// leaves of the tree
public class ExternalNode extends Node
     {
     private int data;

     public ExternalNode( int data )
          {
          setData( data );
          }
          
     public int getData()
          {
          return data;
          }

     public void setData( int newData)
          {
          data = newData;
          }
     
     public void print( Writer output) throws IOException
          {
          // The Writer's write statement only works with 
          // strings, so convert 
          output.write( String.valueOf( data ) );
          output.flush();
          }
          
     public void accept( Visitor aVisitor)
          {
          aVisitor.visitExternalNode( this );
          }
     
     }

Doc 28, Code for Assignment 3 Slide # 8

//UnaryNode

import java.io.Writer;
import java.io.IOException;

// this class is used to store unary operators
// In our assignment we only have one unary operator

public class UnaryNode extends Node
     {
     private Node child = NullNode.getInstance();
     String data;

     public UnaryNode( String data )
          {
          setData( data );
          }

     public String getData()
          {
          return data;
          }

     public void setData( String newData)
          {
          data = newData;
          }

     public Node getChild()
          {
          return child;
          }

     public void setChild( Node newChild)
          {
          child = newChild;
          newChild.setParent( this );
          }
     
     /**
      * Print out the tree rooted at this node as a fully
      * parenthesised expression. This is for testing the 
      * construction of  the tree. This print statement does
      * not satisfy the requirements of the assignment
      */     
     public void print( Writer output) throws IOException
          {
          output.write( " (" );
          output.write( data );
          child.print( output );
          output.write( ") " );
          output.flush();
          }


     /**
      * This accept assumes that the nodes are doing the 
      * traversal through the structure. You will need to change this
      * for problem 2
      */     
     public void accept( Visitor aVisitor)
          {
          child.accept( aVisitor );
          aVisitor.visitUnaryNode( this );
          }
     
     }


Doc 28, Code for Assignment 3 Slide # 9

//BinaryNode

import java.io.Writer;
import java.io.IOException;

// This class in used for binary operators
public class BinaryNode extends Node
     {
     private Node leftChild = NullNode.getInstance();
     private Node rightChild = NullNode.getInstance();
     private String data;
     
     public BinaryNode( String data )
          {
          setData( data );
          }
     
     public String getData()
          {
          return data;
          }

     public void setData( String newData)
          {
          data = newData;
          }
          
     public Node getLeftChild()
          {
          return leftChild;
          }

     public Node getRightChild()
          {
          return rightChild;
          }

     public void setLeftChild( Node newChild)
          {
          leftChild = newChild;
          newChild.setParent( this );
          }

     public void setRightChild( Node newChild)
          {
          rightChild = newChild;
          newChild.setParent( this );
          }
     
     /**
      * Print out the tree rooted at this node as a fully
      * parenthesised expression. This is for testing the 
      * construction of  the tree. This print statement does
      * not satisfy the requirements of the assignment
      */     
     public void print( Writer output) throws IOException
          {
          output.write( " (" );
          leftChild.print( output );
          output.write( data );
          rightChild.print( output );
          output.write( ") " );
          output.flush();
          }
     
     /**
      * This accept assumes that the nodes are doing the 
      * traversal through the structure. You will need to change this
      * for problem 2
      */     
     public void accept( Visitor aVisitor)
          {
          leftChild.accept( aVisitor );
          aVisitor.visitBinaryNode( this );
          rightChild.accept( aVisitor );
          }

     }

Doc 28, Code for Assignment 3 Slide # 10

//NullNode

import java.io.Writer;


/**
 * NullNode does nothing. Used to replace null reference
 * to childern in Binary and Unary nodes. Does the 
 * NullObject pattern make sense in this context?
 */
public class NullNode extends Node
     {
     // Java's static initilizers make the singleton's slightly
     // easier than in C++,
     private static NullNode singleton = new NullNode();
     
     private NullNode() {};

     public static Node getInstance()
          {
          return singleton;
          }

     public void print( Writer output)
          {
          }
          
     public void accept( Visitor aVisitor)
          {
          }
     }

 
 

Copyright © 1998 SDSU & Roger Whitney, 5500 Campanile Drive, San Diego, CA 92182-7700 USA
All rights reserved.

visitors since 01-May-98