SDSU CS 635: Advanced Object-Oriented Design & Programming
Spring Semester, 1998
Interpreter

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

Contents of Doc 30, Interpreter

CS 635 Doc 30 Interpreter

Interpreter slide # 2
...Structure slide # 2
...Example - Boolean Expressions slide # 3
......And slide # 4
......Or slide # 5
......Not slide # 6
......Constant slide # 7
......Variable slide # 8
......Context slide # 9
......Sample Use slide # 10
...Consequences slide # 11
...Implementation slide # 11

Reference
Design Patterns: Elements of Reusable Object-Oriented Software, Gamma, Helm, Johnson, Vlissides, Addison Wesley, 1995, pp 243-256

Doc 30, Interpreter Slide # 2

Interpreter


Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language

Structure


Given a language defined by a simple grammar with rules like:

R ::= R1 R2 ... Rn

you create a class for each rule

The classes can be used to construct a tree that represents elements of the language


Doc 30, Interpreter Slide # 3

Example - Boolean Expressions


BooleanExpression ::= Variable |
Constant |
Or |
And |
Not |
BooleanExpression

And ::= BooleanExpression 'and' BooleanExpression
Or ::= BooleanExpression 'or' BooleanExpression
Not ::= 'not' BooleanExpression

Constant ::= 'true' | 'false'
Variable ::= String

public interface BooleanExpression{
     public boolean evaluate( Context values );
     public BooleanExpression replace( String varName,
                                              BooleanExpression replacement );
     public Object clone();
     public String toString();
}



Doc 30, Interpreter Slide # 4

And


And ::= BooleanExpression '&&' BooleanExpression

public class And implements BooleanExpression {
     private BooleanExpression leftOperand;
     private BooleanExpression rightOperand;
     
     public And( BooleanExpression leftOperand, 
                         BooleanExpression rightOperand) {
          this.leftOperand = leftOperand;
          this.rightOperand = rightOperand;
     }

     public boolean evaluate( Context values ) {
          return leftOperand.evaluate( values ) && 
                     rightOperand.evaluate( values ); 
     }

     public BooleanExpression replace( String varName,
                BooleanExpression replacement ) {
          return new And( leftOperand.replace( varName, replacement),
                         rightOperand.replace( varName, replacement) );
     }

     public Object clone() {
          return new And( (BooleanExpression) leftOperand.clone( ),
                         (BooleanExpression)rightOperand.clone( ) );
     }

     public String toString(){
          return "(" + leftOperand.toString() + " and " +
                     rightOperand.toString() + ")";
     }
}


Doc 30, Interpreter Slide # 5

Or


Or ::= BooleanExpression 'or' BooleanExpression

public class Or implements BooleanExpression {
     private BooleanExpression leftOperand;
     private BooleanExpression rightOperand;
     
     public Or( BooleanExpression leftOperand, 
                         BooleanExpression rightOperand) {
          this.leftOperand = leftOperand;
          this.rightOperand = rightOperand;
     }

     public boolean evaluate( Context values ) {
          return leftOperand.evaluate( values ) ||  
                    rightOperand.evaluate( values ); 
     }

     public BooleanExpression replace( String varName,
                BooleanExpression replacement ) {
          return new Or( leftOperand.replace( varName, replacement),
                         rightOperand.replace( varName, replacement) );
     }

     public Object clone() {
          return new Or( (BooleanExpression) leftOperand.clone( ),
                         (BooleanExpression)rightOperand.clone( ) );
     }

     public String toString() {
          return "(" + leftOperand.toString() + " or " +
                     rightOperand.toString() + ")";
     }
}


Doc 30, Interpreter Slide # 6

Not


Not ::= 'not' BooleanExpression

public class Not implements BooleanExpression {
     private BooleanExpression operand;
     
     public Not( BooleanExpression operand) {
          this.operand = operand;
     }

     public boolean evaluate( Context values ) {
          return  ! operand.evaluate( values ); 
     }

     public BooleanExpression replace( String varName,
           BooleanExpression replacement ) {
          return new Not( operand.replace( varName, replacement) );
     }

     public Object clone() {
          return new Not( (BooleanExpression) operand.clone( ) );
     }
     
     public String toString() {
          return "( not " +  operand.toString() + ")";
     }



Doc 30, Interpreter Slide # 7

Constant

Constant ::= 'true' | 'false'

public class Constant implements BooleanExpression {
     private boolean value;
     private static Constant True = new Constant( true );
     private static Constant False = new Constant( false );
     
     public static Constant getTrue() {
          return True;
     }

     public static Constant getFalse(){
          return False;
     }

     private Constant( boolean value) {
          this.value = value;
     }

     public boolean evaluate( Context values ) {
          return  value; 
     }

     public BooleanExpression replace( String varName,
                BooleanExpression replacement ) {
          return this;
     }
     
     public Object clone() {
          return this;
          }
     
     public String toString() {
          return String.valueOf( value );
     }
}

Doc 30, Interpreter Slide # 8

Variable

Variable ::= String

public class Variable implements BooleanExpression {
     private static Hashtable flyWeights = new Hashtable();

     private String name;

     public static Variable get( String name ) {
          if ( ! flyWeights.contains( name ))
               flyWeights.put( name , new Variable( name ));
               
          return (Variable) flyWeights.get( name );
     }

     private Variable( String name ) {
          this.name = name;
     }
     
     public boolean evaluate( Context values ) {
          return values.getValue( name ); 
     }
     
     public BooleanExpression replace( String varName,
                BooleanExpression replacement ) {
          if ( varName.equals( name ) )
               return (BooleanExpression) replacement.clone();
          else
               return this;
     }
     
     public Object clone() {
          return this;
     }
     
     public String toString() { return name; }
}

Doc 30, Interpreter Slide # 9

Context


public class Context {
     Hashtable values = new Hashtable();
     
     public boolean getValue( String variableName ) {
          Boolean wrappedValue = (Boolean) values.get( variableName );
          return wrappedValue.booleanValue();
     }

     public void setValue( String variableName, boolean value ) {
          values.put( variableName, new Boolean( value ) );
     }
}



Doc 30, Interpreter Slide # 10

Sample Use


public class Test {
     public static void main( String args[] ) throws Exception  {
          BooleanExpression left = 
               new Or(  Constant.getTrue(), Variable.get( "x" ) );
          BooleanExpression right = 
               new And(  Variable.get( "w" ), Variable.get( "x" ) );

          BooleanExpression all = new And(  left, right );

          System.out.println( all );
          Context values = new Context();
          values.setValue( "x", true );
          values.setValue( "w", false );

          System.out.println( all.evaluate( values ) );
          System.out.println( all.replace( "x", right ) );
          }
     }

Output
((true or x) and (w and x)) false ((true or (w and x)) and (w and (w and x)))


Doc 30, Interpreter Slide # 11

Consequences


It's easy to change and extend the grammar

Implementing the grammar is easy

Complex grammars are hard to maintain

Adding new ways to interpret expressions

The visiter pattern is useful here

Implementation


The pattern does not talk about parsing!

Flyweight

If terminal symbols are repeated many times using the Flyweight pattern can reduce space usage

The above example has each terminal class manage the flyweights for its objects, since Java does limited support for protecting constructors

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

visitors since 11-May-98