The Interpreter Pattern - and Postfix Notation

by Moridin8 20. April 2007 20:36

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) );
        }
    }
}
 

Tags: , ,

Comments

Powered by BlogEngine.NET 1.5.0.7

About Matt R.Warren

MeMy name is Matt and I am the current tenant of this small corner of the internet. I mostly architect, design and prototype applications that use .NET with C# and a little C++/CLI for Enterprise although I am aware of and enjoy fully embracing Java based solutions and alternatives such as Mono/Linux.  

I have worked on projects ranging from small tools to large distributed real-time Enterprise systems ranging from EPOS and real-time/JIT stock management systems, to distributed applications for National/International Utility, Healthcare, Insurance and Finance  in the private sector in both the USA and the EU.

My LinkedIn Profile (Opens new window/tab)

“Matt is one of the brightest people I've worked with. His in-depth knowledge of the .NET frameworks has been a tremendous benefit to nVISIA and our clients. His knowledge of software architecture in general allows him to architect systems for the best fit to his client's needs.” 
Dan Christopherson , Technical Director , nVISIA

“I had the distinct pleasure of working with Matt at nVisia. Matt's understanding of the Microsoft Technical space is outstanding. He is constantly working on improving his technical skills and rapidly masters any new technology that he encounters. He is an excellent teacher and a wonderful asset for any size team.” 
Jim Harnden , Senior Technical Architect , nVISIA

“Matt Warren is a very talented developer with great capacity for self study, investigation and adapts to new languages and frameworks with ease. He has an excellent grasp of software architecture and modern development principles. He has proven himself time and time again to be a hard worker and someone who can get the job done when you're in a tight spot.” 
Andrew Jump , Partner, C# Developer , Contegra

This website represents some of my spare time.  My small presence on the web between my family and my career.  I hope over time you find many useful things here.