Object Oriented Programming Patterns for Geeks

The Interpreter Pattern

 

namespace ooppatterns
{
    using System;
    using System.Collections.Generic;

    internal class Program
    {
        private static void Main( string[] args )
        {
            string expression = "8 ++ 1 4 + N 200 * +";

            PostFixParser PFP = new PostFixParser( expression );

            Console.WriteLine( "'{0}' equals {1}", expression, PFP.Evaluate() );

            Console.ReadLine();
        }
    }

    interface IExpression
    {
        void Parse( Stack<double> s );
    }

    class PostFixParser
    {
        private List<IExpression> tokenList = new List<IExpression>();

        public PostFixParser( string s )
        {
            foreach ( string token in s.Split( ' ' ) )
                switch ( token )
                {
                    case "AND":
                    case "&&":
                        this.tokenList.Add( new LAnd() );
                        break;
                    case "!":
                        this.tokenList.Add( new LNot() );
                        break;
                    case "N":
                        this.tokenList.Add( new Neg() );
                        break;
                    case "OR":
                    case "||":
                        this.tokenList.Add( new LOr() );
                        break;
                    case "&":
                        this.tokenList.Add( new BAnd() );
                        break;
                    case "~":
                        this.tokenList.Add( new BNot() );
                        break;
                    case "|":
                        this.tokenList.Add( new BOr() );
                        break;
                    case "<>":
                    case "!=":
                        this.tokenList.Add( new NotEquals() );
                        break;
                    case "==":
                        this.tokenList.Add( new Equals() );
                        break;
                    case ">":
                        this.tokenList.Add( new GreaterThan() );
                        break;
                    case "<":
                        this.tokenList.Add( new LessThan() );
                        break;
                    case ">=":
                        this.tokenList.Add( new GreaterOrEqualThan() );
                        break;
                    case "<=":
                        this.tokenList.Add( new LessOrEqualThan() );
                        break;
                    case "+":
                        this.tokenList.Add( new Plus() );
                        break;
                    case "++":
                        this.tokenList.Add( new Inc() );
                        break;
                    case "-":
                        this.tokenList.Add( new Minus() );
                        break;
                    case "--":
                        this.tokenList.Add( new Dec() );
                        break;
                    case "*":
                        this.tokenList.Add( new Multiply() );
                        break;
                    case "/":
                        this.tokenList.Add( new Divide() );
                        break;
                    case "%":
                        this.tokenList.Add( new Modulus() );
                        break;
                    case "^":
                        this.tokenList.Add( new Power() );
                        break;
                    default:
                        this.tokenList.Add( new Number( double.Parse( token ) ) );
                        break;
                }
        }

        public double Evaluate()
        {
            Stack<double> evalStack = new Stack<double>();

            foreach ( IExpression e in this.tokenList )
                e.Parse( evalStack );

            return evalStack.Pop();
        }
    }


    // Mathmatical operators
    class Number : IExpression
    {
        private double number;

        public Number( double number )
        {
            this.number = number;
        }

        public void Parse( Stack<double> s )
        {
            s.Push( number );
        }
    }

    class Plus : IExpression
    {
        public void Parse( Stack<double> s )
        {
            s.Push( s.Pop() + s.Pop() );
        }
    }

    class Inc : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( ++tmp );
        }
    }

    class Dec : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( --tmp );
        }
    }

    class Minus : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( s.Pop() - tmp );
        }
    }

    class Multiply : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( s.Pop() * tmp );
        }
    }

    class Divide : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( s.Pop() / tmp );
        }
    }

    class Modulus : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( s.Pop() % tmp );
        }
    }

    class Power : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( Convert.ToInt32( Math.Pow( s.Pop(), tmp ) ) );
        }
    }

    // Equality operators
    class Equals : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( s.Pop() == tmp ? -1 : 0 );
        }
    }

    class NotEquals : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( s.Pop() == tmp ? 0 : -1 );
        }
    }

    class GreaterThan : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( s.Pop() > tmp ? -1 : 0 );
        }
    }

    class LessThan : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( s.Pop() < tmp ? 0 : -1 );
        }
    }

    class GreaterOrEqualThan : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( s.Pop() >= tmp ? -1 : 0 );
        }
    }

    class LessOrEqualThan : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( s.Pop() <= tmp ? 0 : -1 );
        }
    }

    // Logical operators
    class LAnd : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double LHS = s.Pop();
            double RHS = s.Pop();

            if ( LHS < -1 || RHS < -1 || LHS > 0 || RHS > 0 )
                throw new InvalidOperationException();

            if ( LHS == RHS )
                s.Push( -1 );
            else
                s.Push( 0 );
        }
    }

    class LOr : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double LHS = s.Pop();
            double RHS = s.Pop();

            if ( LHS < -1 || RHS < -1 || LHS > 0 || RHS > 0 )
                throw new InvalidOperationException();

            if ( LHS == -1 || RHS == -1 )
                s.Push( -1 );
            else
                s.Push( 0 );
        }
    }

    class Neg : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double LHS = s.Pop();

            s.Push( -LHS );
        }
    }

    class LNot : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double LHS = s.Pop();

            if ( LHS < -1 || LHS > 0 )
                throw new InvalidOperationException();

            if ( LHS == -1 )
                s.Push( 0 );
            else
                s.Push( -1 );
        }
    }

    // Bitwise operators
    class BAnd : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double LHS = s.Pop();
            double RHS = s.Pop();

            s.Push( Convert.ToInt32(LHS) & Convert.ToInt32(RHS) );
        }
    }

    class BOr : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double LHS = s.Pop();
            double RHS = s.Pop();

            s.Push( Convert.ToInt32(LHS) | Convert.ToInt32(RHS) );
        }
    }

    class BNot : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double LHS = s.Pop();

            s.Push( ~Convert.ToInt32(LHS) );
        }
    }
}