 |
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 |
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.
//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 );
}
}
//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;
}
}
//Visitor
public interface Visitor
{
public void visitBinaryNode( BinaryNode aNode);
public void visitUnaryNode( UnaryNode aNode);
public void visitExternalNode( ExternalNode aNode);
}
//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;
}
}
//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 );
}
}
//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 );
}
}
//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 );
}
}
//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