Click here to Skip to main content
15,886,560 members
Articles / Programming Languages / C#
Article

C# Expression Parser using RPN

Rate me:
Please Sign up or sign in to vote.
4.57/5 (26 votes)
17 Jan 20045 min read 210.7K   7.4K   85   32
Design & implementation of an Expression Parser using RPN in C#.

Introduction

The aim of this article is to demonstrate an interface-based programming paradigm in the design and implementation of a simple Expression Parser & Evaluator using RPN in C#. The intended audience skill set would be Beginner to Intermediate.

Background

For introduction about Expressions & Reverse Polish Notation, refer to this article - Expression Evaluator: using RPN by lallous, in the C++/MFC section.

Design Description

(All code referred here is inside RPNParser.cs file.)

Interfaces

Every expression is made of operands and operators. These are reflected in the interfaces - IOperand and IOperator.

  • IArithmeticOperations defines methods for binary arithmetic operators (+, -, *, \, %).
  • IComparisonOperations defines methods for all comparison operators (>, >=, <, <=, ==, !=).
  • ILogicalOperations defines methods for logical operators (&& , ||).

The idea behind these interfaces is as follows -

Each Operand supports a set of Operations and the Operators evaluate a pair of Operands using the Operations supported by the two Operands.

E.g. A Long Operand supports Arithmetic and Comparison Operations, whereas a String might support only Comparison Operations. Boolean Operands support only the Logical Operations.

An Operator like + needs only to know that it has to call the Plus method on an IOperand implementing the IArithmeticOperations interface. This keeps the algorithm of expression parsing & evaluation (in this case the RPN sequencing) separated from the data type that does the actual evaluations and hence makes it very extensible to newer data types.

Operands

Operand class is an abstract base class implementing the IOperand interface and additionally providing data storage.

LongOperand is an Operand class specific to Long & Int (Int64 and Int32) types of operands and implements the IArithmeticOperations, IComparisonOperations interfaces.

BoolOperand is an Operand class specific to bool type of operands and implements only the ILogicalOperations interface.

OperandHelper is a static class providing object factory functionality to create appropriate Operand objects based on the Type passed to it (OperandHelper.CreateOperand).

For new types of Operands like Decimal/String or user-defined types, e.g. a Matrix, this factory method would have to be extended.

Operators

IOperator defines one method called Eval and is used to evaluate the LHS and RHS of the expression.

Operator is an abstract base class implementing this interface and provides data storage for the operator.

ArithmeticOperator, ComparisonOperator, LogicalOperator are operator classes to support IArithmeticOperations, IComparisonOperations, ILogicalOperations respectively.

OperatorHelper is a helper class providing object factory functionality for creation of appropriate Operator objects (OperatorHelper.CreateOperator). This class provides services to determine operator-precedence. This is based on the relative indexes of the operators defined in the m_AllOps variable. It also provides Regular Expressions used during parsing of the input expression string. E.g. The regex [=<>!]{1,2} is used to parse for Comparison operators.

Expression Parsing

The Tokenizer class provides functionality of parsing the input expression string using regular expressions.

The TokenEnumerator class supports the IEnumerator interface and is used to loop through the various tokens in the input expression string. The tokens in the expression are returned to the caller as Token objects.

The given expression can be parsed as either Arithmetic or Logical or Comparison Expression Types. This is controlled by the enums ExpressionType::ET_ARITHMETIC, ExpressionType::ET_COMPARISON and ExpressionType::ET_LOGICAL. A combination of these enum types can also be given.

E.g. To parse the expression as all of these, pass ExpressionType.ET_ARITHMETIC| ExpressionType.ET_COMPARISON|ExpressionType.ET_LOGICAL to the Tokenizer c'tor.

The generation of the RPN sequence is in the RPNParser::GetPostFixNotation method and it uses the algorithm as described in the above mentioned C++ article. The return value is an ArrayList consisting of Operands and Operators in the RPN sequence.

This method takes an argument bFormula that determines if the expression being parsed is a formula (in the form of x+y*z/t) or has direct values (3+6*7/2). If the expression is not a formula, then the values are extracted by this method and stored in the Token object for later evaluation. If the expression is a formula, then the values for the corresponding variables need to be passed separately as a hashtable for evaluation.

Expression Evaluation

RPNParser::EvaluateRPN is the method performing actual evaluation of the RPN generated by the RPNParser::GetPostFixNotation method and is again based on the algorithm described in the above mentioned C++ article. This method takes as input the ArrayList with the RPN sequence and if the expression is a formula, a hashtable with values for the variables in the expression.

Usage

A typical usage of the parser would be as follows -

C#
RPNParser parser = new RPNParser();

string szExpression = @"((2+3)*2<10 || 1!=1) && 2*2==4";

parser.EvaluateExpression( szExpression, 
    Type.GetType("System.Int64" ), false, null );

The attached code contains a small form-based application to test the logic.

It uses the RPN_Parser::Convert2String() method to get a string representation of the RPN sequence.

Extensibility

The Parser can be easily extended to support new Operand types and Operators by subclassing the Operand and Operator classes. Since the Parsing and Evaluation logic works totally on interfaces, typically nothing would have to be changed there. Of course, the factory classes need to be extended to support the new types and if adding new operators, the regular expressions used & their precedence information present inside the Operatorhelper class would have to be modified accordingly.

Hope someone out there finds this useful.

Current Shortcomings

  1. Unary operators (+,-,!) not handled.
  2. Does not yet support expressions having mixture of variables and values (e.g. x+y/3*z%2 ).
  3. Bitwise & and | not handled.
  4. Does not handle a combo expression with multiple braces as just one of the ExpressionTypes?

    // E.g. ((2+3)*2<10 || 1!=1) && 2*2==4 as just a logical expression cannot be done.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionGiving some examples Pin
Member 139396026-Aug-18 12:47
Member 139396026-Aug-18 12:47 
Questionpossibility to reuse the source code? Pin
Member 1228813111-Apr-16 5:48
Member 1228813111-Apr-16 5:48 
QuestionDivide error Pin
Imanloo27-May-14 22:00
Imanloo27-May-14 22:00 
GeneralMy vote of 5 Pin
stofel9-Sep-13 1:51
stofel9-Sep-13 1:51 
GeneralVB eqivalent Pin
coarist20-Jun-13 2:48
coarist20-Jun-13 2:48 
deepedie's RPN Parser and staarkannan's inclusion of ! operator are useful. VB source code equivalent of staarkannan's posting:
VB
'------------------------------------------------------------------------------
' VB equivalent of RPNParser, tested using VB 2010 Express, 20 June 2013
'------------------------------------------------------------------------------
'source http://www.codeproject.com/Articles/5875/C-Expression-Parser-using-RPN
'------------------------------------------------------------------------------

Imports System.Collections
Imports System.Text
Imports System.Text.RegularExpressions

#Region "RPN"
 
' Summary description for RPNParser.
'
Public Class RPNParser
    Public Sub New()
    End Sub
    Public Function EvaluateExpression(szExpr As String, varType As Type, bFormula As Boolean, htValues As Hashtable) As Object
        Dim arrExpr As ArrayList = GetPostFixNotation(szExpr, varType, bFormula)
        Return EvaluateRPN(arrExpr, varType, htValues)
    End Function

    Public Function EvaluateExpression(szExpr As String) As Object
        Dim myType As Long = 0
        Dim arrExpr As ArrayList = GetPostFixNotation(szExpr, myType.[GetType](), False)
        Return EvaluateRPN(arrExpr, myType.[GetType](), Nothing)
    End Function

#Region "RPN_Parser"
    '
    ' Algo of GetPostFixNotation (source : Expression Evaluator : using RPN by lallous
    ' in the C++/MFC section of www.CodeProject.com.
    ' 1. Initialize an empty stack (string stack), prepare input infix expression and clear RPN string
    ' 2. Repeat until we reach end of infix expression
    ' I. Get token (operand or operator); skip white spaces
    ' II. If token is:
    ' a. Left parenthesis: Push it into stack
    ' b. Right parenthesis: Keep popping from the stack and appending to
    ' RPN string until we reach the left parenthesis.
    ' If stack becomes empty and we didn't reach the left parenthesis
    ' then break out with error "Unbalanced parenthesis"
    ' c. Operator: If stack is empty or operator has a higher precedence than
    ' the top of the stack then push operator into stack.
    ' Else if operator has lower precedence then we keep popping and
    ' appending to RPN string, this is repeated until operator in stack
    ' has lower precedence than the current operator.
    ' d. An operand: we simply append it to RPN string.
    ' III. When the infix expression is finished, we start popping off the stack and
    ' appending to RPN string till stack becomes empty.
    '
    '
    '
    '
    Public Function GetPostFixNotation(szExpr As String, varType As Type, bFormula As Boolean) As ArrayList
        Dim stkOp As New Stack()
        Dim arrFinalExpr As New ArrayList()
        Dim szResult As String = ""
        Dim szLastItem As String = ""
        Dim bApplyNegative As Boolean = False

        Dim tknzr As Tokenizer = Nothing
        Select Case varType.ToString()
            Case "System.Int32", "System.Int64"
                tknzr = New Tokenizer(szExpr, ExpressionType.ET_ARITHMETIC Or ExpressionType.ET_COMPARISON Or ExpressionType.ET_LOGICAL)
                Exit Select
            Case "System.String"
                tknzr = New Tokenizer(szExpr, ExpressionType.ET_COMPARISON)
                Exit Select
        End Select

        For Each token As Token In tknzr
            Dim szToken As String = token.Value.Trim()
            If szToken.Length = 0 Then
                Continue For
            End If
            Select Case varType.ToString()
                Case "System.Int32", "System.Int64"
                    If Not OperatorHelper.IsOperator(szToken) Then
                        Dim oprnd As Operand
                        'if contains " then it's a string type
                        If szToken.IndexOf("""") <> -1 Then
                            Dim myStringType As String = ""
                            oprnd = OperandHelper.CreateOperand(szToken, myStringType.[GetType]())
                        Else
                            oprnd = OperandHelper.CreateOperand(szToken, varType)
                        End If
                        oprnd.ExtractAndSetValue(szToken, bFormula)
                        arrFinalExpr.Add(oprnd)

                        szResult += szToken
                        szLastItem = szToken

                        Continue For
                    End If
                    Exit Select
                Case "System.String"
                    If Not OperatorHelper.IsComparisonOperator(szToken) Then
                        Dim oprnd As Operand = OperandHelper.CreateOperand(szToken, varType)
                        oprnd.ExtractAndSetValue(szToken, bFormula)
                        arrFinalExpr.Add(oprnd)

                        szResult += szToken
                        szLastItem = szToken
                        Continue For
                    End If

                    Exit Select
            End Select

            Dim szOp As String = szToken
            If szOp = "(" Then
                stkOp.Push(szOp)
            ElseIf szOp = "!" Then
                stkOp.Push(szOp)
            ElseIf szOp = ")" Then
                Dim szTop As String
                While (InlineAssignHelper(szTop, DirectCast(stkOp.Pop(), String))) <> "("
                    Dim oprtr As IOperator = OperatorHelper.CreateOperator(szTop)
                    arrFinalExpr.Add(oprtr)

                    szResult += szTop

                    If stkOp.Count = 0 Then
                        Throw New RPN_Exception("Unmatched braces!")
                    End If
                End While

            ElseIf szOp = "==" Then
                If stkOp.Count = 0 OrElse DirectCast(stkOp.Peek(), String) = "(" OrElse OperatorHelper.IsHigherPrecOperator(szOp, DirectCast(stkOp.Peek(), String)) Then
                    stkOp.Push(szOp)
                Else
                    While stkOp.Count <> 0
                        If OperatorHelper.IsLowerPrecOperator(szOp, DirectCast(stkOp.Peek(), String)) OrElse OperatorHelper.IsEqualPrecOperator(szOp, DirectCast(stkOp.Peek(), String)) Then
                            Dim szTop As String = DirectCast(stkOp.Peek(), String)
                            If szTop = "(" Then
                                Exit While
                            End If
                            szTop = DirectCast(stkOp.Pop(), String)

                            Dim oprtr As IOperator = OperatorHelper.CreateOperator(szTop)
                            arrFinalExpr.Add(oprtr)

                            szResult += szTop
                        Else
                            Exit While
                        End If
                    End While
                    stkOp.Push(szOp)
                End If
            Else
                If szOp = "-" AndAlso (Not StringContentCheck.IsAlphaNumeric(szLastItem) OrElse szLastItem = "") Then
                    bApplyNegative = True
                    'Operand oprnd = OperandHelper.CreateOperand("0", varType);
                    'oprnd.ExtractAndSetValue("0", bFormula);
                    'arrFinalExpr.Add(oprnd);

                    'szResult += "0";
                    'stkOp.Push("(");
                    'string szTop;
                    'while ((szTop = (string)stkOp.Pop()) != "(")
                    '{
                    ' IOperator oprtr = OperatorHelper.CreateOperator(szTop);
                    ' arrFinalExpr.Add(oprtr);

                    ' szResult += szTop;

                    ' if (stkOp.Count == 0)
                    ' throw new RPN_Exception("Unmatched braces!");
                    '}
                    stkOp.Push("~")
                Else
                    If stkOp.Count = 0 OrElse DirectCast(stkOp.Peek(), String) = "(" OrElse OperatorHelper.IsHigherPrecOperator(szOp, DirectCast(stkOp.Peek(), String)) Then
                        stkOp.Push(szOp)
                    Else
                        While stkOp.Count <> 0
                            If OperatorHelper.IsLowerPrecOperator(szOp, DirectCast(stkOp.Peek(), String)) OrElse OperatorHelper.IsEqualPrecOperator(szOp, DirectCast(stkOp.Peek(), String)) Then
                                Dim szTop As String = DirectCast(stkOp.Peek(), String)
                                If szTop = "(" Then
                                    Exit While
                                End If
                                szTop = DirectCast(stkOp.Pop(), String)

                                Dim oprtr As IOperator = OperatorHelper.CreateOperator(szTop)
                                arrFinalExpr.Add(oprtr)

                                szResult += szTop
                            Else
                                Exit While
                            End If
                        End While
                        stkOp.Push(szOp)
                    End If


                End If
            End If
            szLastItem = szToken
        Next
        While stkOp.Count <> 0
            Dim szTop As String = DirectCast(stkOp.Pop(), String)
            If szTop = "(" Then
                Throw New RPN_Exception("Unmatched braces")
            End If

            Dim oprtr As IOperator = OperatorHelper.CreateOperator(szTop)
            arrFinalExpr.Add(oprtr)

            szResult += szTop
        End While
        Return arrFinalExpr
    End Function

#End Region

    Public Function Convert2String(arrExpr As ArrayList) As String
        Dim szResult As String = ""
        For Each obj As Object In arrExpr
            szResult += obj.ToString()
        Next
        Return szResult
    End Function


#Region "RPN_Evaluator"
     '
    ' Algo of EvaluateRPN (source : Expression Evaluator : using RPN by lallous
    ' in the C++/MFC section of www.CodeProject.com.
    ' 1. Initialize stack for storing results, prepare input postfix (or RPN) expression.
    ' 2. Start scanning from left to right till we reach end of RPN expression
    ' 3. Get token, if token is:
    ' I. An operator:
    ' a. Get top of stack and store into variable op2; Pop the stack
    ' b. Get top of stack and store into variable op1; Pop the stack
    ' c. Do the operation expression in operator on both op1 and op2
    ' d. Push the result into the stack
    ' II. An operand: stack its numerical representation into our numerical stack.
    ' 4. At the end of the RPN expression, the stack should only have one value and
    ' that should be the result and can be retrieved from the top of the stack.
    '
    ' Expression to be evaluated in RPNotation with
    ' single character variables
    ' Values for each of the variables in the expression
    '
    Public Function EvaluateRPN(arrExpr As ArrayList, varType As Type, htValues As Hashtable) As Object
        ' initialize stack (integer stack) for results
        Dim stPad As New Stack()
        ' begin loop : scan from left to right till end of RPN expression
        For Each var As Object In arrExpr
            Dim op1 As Operand = Nothing
            Dim op2 As Operand = Nothing
            Dim oprtr As IOperator = Nothing
            ' Get token
            ' if token is
            If TypeOf var Is IOperand Then
                ' Operand : push onto top of numerical stack
                stPad.Push(var)
            ElseIf TypeOf var Is IOperator Then
                If OperatorHelper.IsUnaryOperator(DirectCast(var, [Operator]).ToString()) Then
                    ' Operator :
                    ' Pop top of stack into var 1
                    op1 = DirectCast(stPad.Pop(), Operand)
                    If htValues IsNot Nothing Then
                        op1.Value = htValues(op1.Name)
                    End If
                    ' Do operation exp for 'this' operator on var1 and var2
                    oprtr = DirectCast(var, IOperator)
                    Dim opRes As IOperand = oprtr.Eval(op1)
                    ' Push results onto stack
                    stPad.Push(opRes)
                Else
                    ' Operator :
                    ' Pop top of stack into var 1 - op2 first as top of stack is rhs
                    op2 = DirectCast(stPad.Pop(), Operand)
                    If htValues IsNot Nothing Then
                        op2.Value = htValues(op2.Name)
                    End If
                    ' Pop top of stack into var 2
                    op1 = DirectCast(stPad.Pop(), Operand)
                    If htValues IsNot Nothing Then
                        op1.Value = htValues(op1.Name)
                    End If
                    ' Do operation exp for 'this' operator on var1 and var2
                    oprtr = DirectCast(var, IOperator)
                    Dim opRes As IOperand = oprtr.Eval(op1, op2)
                    ' Push results onto stack
                    stPad.Push(opRes)
                End If
            End If
        Next
        ' end loop
        ' stack ends up with single value with final result
        Return DirectCast(stPad.Pop(), Operand).Value
    End Function
    Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, value As T) As T
        target = value
        Return value
    End Function
#End Region
End Class
#End Region

#Region "UtilClasses"
 '
' The given expression can be parsed as either Arithmetic or Logical or
' Comparison ExpressionTypes. This is controlled by the enums
' ExpressionType::ET_ARITHMETIC, ExpressionType::ET_COMPARISON and
' ExpressionType::ET_LOGICAL. A combination of these enum types can also be given.
' E.g. To parse the expression as all of these, pass
' ExpressionType.ET_ARITHMETIC|ExpressionType.ET_COMPARISON|ExpressionType.ET_LOGICAL
' to the Tokenizer c'tor.
'
<Flags()> _
Public Enum ExpressionType
    ET_ARITHMETIC = &H1
    ET_COMPARISON = &H2
    ET_LOGICAL = &H4
End Enum
'
' Currently not used.
'
Public Enum TokenType
    TT_OPERATOR
    TT_OPERAND
End Enum
'
' Represents each token in the expression
'
Public Class Token
    Public Sub New(szValue As String)
        m_szValue = szValue
    End Sub
    Public ReadOnly Property Value() As String
        Get
            Return m_szValue
        End Get
    End Property
    Private m_szValue As String
End Class
'
' Is the tokenizer which does the actual parsing of the expression.
'
Public Class Tokenizer
    Implements IEnumerable
    Public Sub New(szExpression As String)
        Me.New(szExpression, ExpressionType.ET_ARITHMETIC Or ExpressionType.ET_COMPARISON Or ExpressionType.ET_LOGICAL)
    End Sub
    Public Sub New(szExpression As String, exType As ExpressionType)
        m_szExpression = szExpression
        m_exType = exType
        m_RegEx = New Regex(OperatorHelper.GetOperatorsRegEx(m_exType))
        m_strarrTokens = SplitExpression(szExpression)
    End Sub
    Public Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
        Return New TokenEnumerator(m_strarrTokens)
    End Function
    Public Function SplitExpression(szExpression As String) As String()
        Return m_RegEx.Split(szExpression)
    End Function
    Private m_exType As ExpressionType
    Private m_szExpression As String
    Private m_strarrTokens As String()
    Private m_RegEx As Regex
End Class

'
' Enumerator to enumerate over the tokens.
'
Public Class TokenEnumerator
    Implements IEnumerator
    Private m_Token As Token
    Private m_nIdx As Integer
    Private m_strarrTokens As String()

    Public Sub New(strarrTokens As String())
        m_strarrTokens = strarrTokens
        Reset()
    End Sub
    Public ReadOnly Property Current() As Object Implements IEnumerator.Current
        Get
            Return m_Token
        End Get
    End Property
    Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
        If m_nIdx >= m_strarrTokens.Length Then
            Return False
        End If

        m_Token = New Token(m_strarrTokens(m_nIdx))
        m_nIdx += 1
        Return True
    End Function
    Public Sub Reset() Implements IEnumerator.Reset
        m_nIdx = 0
    End Sub
End Class
#Region "Exceptions"
 
' For the exceptions thrown by this module.
'
Public Class RPN_Exception
    Inherits ApplicationException
    Public Sub New()
    End Sub
    Public Sub New(szMessage As String)
        MyBase.New(szMessage)
    End Sub
    Public Sub New(szMessage As String, innerException As Exception)
        MyBase.New(szMessage, innerException)
    End Sub
End Class
#End Region
#End Region

#Region "Interfaces"
 ublic Interface IOperand
End Interface
Public Interface IOperator
    Function Eval(lhs As IOperand, rhs As IOperand) As IOperand
    Function Eval(lhs As IOperand) As IOperand
End Interface

Public Interface IArithmeticOperations
    ' to support {"+", "-", "*", "/", "%"} operators
    Function Plus(rhs As IOperand) As IOperand
    Function Minus(rhs As IOperand) As IOperand
    Function Multiply(rhs As IOperand) As IOperand
    Function Divide(rhs As IOperand) As IOperand
    Function Modulo(rhs As IOperand) As IOperand
    Function [Not]() As IOperand
    Function Negate() As IOperand
End Interface
Public Interface IComparisonOperations
    ' to support {"==", "!=","<", "<=", ">", ">="} operators
    Function EqualTo(rhs As IOperand) As IOperand
    Function NotEqualTo(rhs As IOperand) As IOperand
    Function LessThan(rhs As IOperand) As IOperand
    Function LessThanOrEqualTo(rhs As IOperand) As IOperand
    Function GreaterThan(rhs As IOperand) As IOperand
    Function GreaterThanOrEqualTo(rhs As IOperand) As IOperand
End Interface
Public Interface ILogicalOperations
    ' to support {"||", "&&" } operators
    Function [OR](rhs As IOperand) As IOperand
    Function [AND](rhs As IOperand) As IOperand
End Interface
#End Region

#Region "Operands"
 
' Base class for all Operands. Provides datastorage
'
Public MustInherit Class Operand
    Implements IOperand
    Public Sub New(szVarName As String, varValue As Object)
        m_szVarName = szVarName
        m_VarValue = varValue
    End Sub
    Public Sub New(szVarName As String)
        m_szVarName = szVarName
    End Sub
    Public Overrides Function ToString() As String
        Return m_szVarName
    End Function
    Public MustOverride Sub ExtractAndSetValue(szValue As String, bFormula As Boolean)
    Public Property Name() As String
        Get
            Return m_szVarName
        End Get
        Set(value As String)
            m_szVarName = value
        End Set
    End Property
    Public Property Value() As Object
        Get
            Return m_VarValue
        End Get
        Set(value As Object)
            m_VarValue = value
        End Set
    End Property
    Protected m_szVarName As String = ""
    Protected m_VarValue As Object = Nothing
End Class
'
' Operand corresponding to the Long (Int32/Int64) datatypes.
'
Public Class LongOperand
    Inherits Operand
    Implements IArithmeticOperations
    Implements IComparisonOperations
    Public Sub New(szVarName As String, varValue As Object)
        MyBase.New(szVarName, varValue)
    End Sub
    Public Sub New(szVarName As String)
        MyBase.New(szVarName)
    End Sub
    Public Overrides Function ToString() As String
        Return m_szVarName
    End Function
    Public Overrides Sub ExtractAndSetValue(szValue As String, bFormula As Boolean)
        Select Case szValue
            Case "true"
                szValue = "1"
                m_VarValue = If(Not bFormula, Convert.ToInt64(szValue), 0)
                Exit Select
            Case "false"
                szValue = "0"
                m_VarValue = If(Not bFormula, Convert.ToInt64(szValue), 0)
                Exit Select
            Case Else
                m_VarValue = If(Not bFormula, Convert.ToInt64(szValue), 0)
                Exit Select
        End Select
        ' m_VarValue = !bFormula ? Convert.ToInt64(szValue) : 0;
    End Sub
    ' IArithmeticOperations methods. Return of these methods is again a LongOperand
    Public Function Plus(rhs As IOperand) As IOperand Implements IArithmeticOperations.Plus
        If Not (TypeOf rhs Is LongOperand) Then
            Throw New RPN_Exception("Argument invalid in LongOperand.Plus : rhs")
        End If
        Dim oprResult As New LongOperand("Result", Type.[GetType]("System.Int64"))
        oprResult.Value = CLng(Me.Value) + CLng(DirectCast(rhs, Operand).Value)
        Return oprResult
    End Function
    Public Function Minus(rhs As IOperand) As IOperand Implements IArithmeticOperations.Minus
        If Not (TypeOf rhs Is LongOperand) Then
            Throw New RPN_Exception("Argument invalid in LongOperand.Minus : rhs")
        End If
        Dim oprResult As New LongOperand("Result", Type.[GetType]("System.Int64"))
        oprResult.Value = CLng(Me.Value) - CLng(DirectCast(rhs, Operand).Value)
        Return oprResult
    End Function
    Public Function Multiply(rhs As IOperand) As IOperand Implements IArithmeticOperations.Multiply
        If Not (TypeOf rhs Is LongOperand) Then
            Throw New ArgumentException("Argument invalid in LongOperand.Multiply : rhs")
        End If
        Dim oprResult As New LongOperand("Result", Type.[GetType]("System.Int64"))
        oprResult.Value = CLng(Me.Value) * CLng(DirectCast(rhs, Operand).Value)
        Return oprResult
    End Function

    Public Function Negate() As IOperand Implements IArithmeticOperations.Negate
        Dim oprResult As New LongOperand("Result", Type.[GetType]("System.Int64"))
        oprResult.Value = CLng(Me.Value) * -1
        Return oprResult
    End Function

    Public Function [Not]() As IOperand Implements IArithmeticOperations.[Not]
        Dim oprResult As New BoolOperand("Result", Type.[GetType]("System.Boolean"))

        Select Case Convert.ToString(Me.Value)
            Case "0"
                oprResult.Value = Not (False)
                Exit Select
            Case "1"
                oprResult.Value = Not (True)
                Exit Select
            Case Else
                Exit Select
        End Select

        Return oprResult
    End Function

    Public Function Divide(rhs As IOperand) As IOperand Implements IArithmeticOperations.Divide
        If Not (TypeOf rhs Is LongOperand) Then
            Throw New RPN_Exception("Argument invalid in LongOperand.Divide : rhs")
        End If
        Dim oprResult As New LongOperand("Result", Type.[GetType]("System.Int64"))
        oprResult.Value = CLng(Me.Value) \ CLng(DirectCast(rhs, Operand).Value)
        Return oprResult
    End Function
    Public Function Modulo(rhs As IOperand) As IOperand Implements IArithmeticOperations.Modulo
        If Not (TypeOf rhs Is LongOperand) Then
            Throw New RPN_Exception("Argument invalid in LongOperand.Modulo : rhs")
        End If
        Dim oprResult As New LongOperand("Result", Type.[GetType]("System.Int64"))
        oprResult.Value = CLng(Me.Value) Mod CLng(DirectCast(rhs, Operand).Value)
        Return oprResult
    End Function

    ' IComparisonOperators methods. Return values are always BooleanOperands type
    Public Function EqualTo(rhs As IOperand) As IOperand Implements IComparisonOperations.EqualTo
        If Not (TypeOf rhs Is LongOperand) Then
            Throw New RPN_Exception("Argument invalid in LongOperand.== : rhs")
        End If
        Dim oprResult As New BoolOperand("Result")
        oprResult.Value = CLng(Me.Value) = CLng(DirectCast(rhs, Operand).Value)
        Return oprResult
    End Function
    Public Function NotEqualTo(rhs As IOperand) As IOperand Implements IComparisonOperations.NotEqualTo
        If Not (TypeOf rhs Is LongOperand) Then
            Throw New RPN_Exception("Argument invalid in LongOperand.!= : rhs")
        End If
        Dim oprResult As New BoolOperand("Result")
        oprResult.Value = If((CLng(Me.Value) <> CLng(DirectCast(rhs, Operand).Value)), True, False)
        Return oprResult
    End Function
    Public Function LessThan(rhs As IOperand) As IOperand Implements IComparisonOperations.LessThan
        If Not (TypeOf rhs Is LongOperand) Then
            Throw New RPN_Exception("Argument invalid in LongOperand.< : rhs")
        End If
        Dim oprResult As New BoolOperand("Result")
        oprResult.Value = If((CLng(Me.Value) < CLng(DirectCast(rhs, Operand).Value)), True, False)
        Return oprResult
    End Function
    Public Function LessThanOrEqualTo(rhs As IOperand) As IOperand Implements IComparisonOperations.LessThanOrEqualTo
        If Not (TypeOf rhs Is LongOperand) Then
            Throw New RPN_Exception("Argument invalid in LongOperand.<= : rhs")
        End If
        Dim oprResult As New BoolOperand("Result")
        oprResult.Value = If((CLng(Me.Value) <= CLng(DirectCast(rhs, Operand).Value)), True, False)
        Return oprResult
    End Function
    Public Function GreaterThan(rhs As IOperand) As IOperand Implements IComparisonOperations.GreaterThan
        If Not (TypeOf rhs Is LongOperand) Then
            Throw New RPN_Exception("Argument invalid in LongOperand.> : rhs")
        End If
        Dim oprResult As New BoolOperand("Result")
        oprResult.Value = If((CLng(Me.Value) > CLng(DirectCast(rhs, Operand).Value)), True, False)
        Return oprResult
    End Function
    Public Function GreaterThanOrEqualTo(rhs As IOperand) As IOperand Implements IComparisonOperations.GreaterThanOrEqualTo
        If Not (TypeOf rhs Is LongOperand) Then
            Throw New RPN_Exception("Argument invalid in LongOperand.>= : rhs")
        End If
        Dim oprResult As New BoolOperand("Result")
        oprResult.Value = If((CLng(Me.Value) >= CLng(DirectCast(rhs, Operand).Value)), True, False)
        Return oprResult
    End Function
End Class
'
' Operand corresponding to Boolean Type
'
Public Class BoolOperand
    Inherits Operand
    Implements ILogicalOperations
    Public Sub New(szVarName As String, varValue As Object)
        MyBase.New(szVarName, varValue)
    End Sub
    Public Sub New(szVarName As String)
        MyBase.New(szVarName)
    End Sub
    Public Overrides Function ToString() As String
        Return Me.Value.ToString()
    End Function
    Public Overrides Sub ExtractAndSetValue(szValue As String, bFormula As Boolean)
        m_VarValue = If(Not bFormula, Convert.ToBoolean(szValue), False)
    End Sub
    Public Function [AND](rhs As IOperand) As IOperand Implements ILogicalOperations.[AND]
        If Not (TypeOf rhs Is BoolOperand) Then
            Throw New RPN_Exception("Argument invalid in BoolOperand.&& : rhs")
        End If
        Dim oprResult As New BoolOperand("Result")
        oprResult.Value = If((CBool(Me.Value) AndAlso CBool(DirectCast(rhs, Operand).Value)), True, False)
        Return oprResult
    End Function
    Public Function [OR](rhs As IOperand) As IOperand Implements ILogicalOperations.[OR]
        If Not (TypeOf rhs Is BoolOperand) Then
            Throw New RPN_Exception("Argument invalid in BoolOperand.|| : rhs")
        End If
        Dim oprResult As New BoolOperand("Result")
        oprResult.Value = If((CBool(Me.Value) OrElse CBool(DirectCast(rhs, Operand).Value)), True, False)
        Return oprResult
    End Function

    Public Function Negate() As IOperand
        Dim oprResult As New LongOperand("Result", Type.[GetType]("System.Int64"))
        oprResult.Value = CLng(Me.Value) * -1
        Return oprResult
    End Function

    Public Function [Not]() As IOperand
        Dim oprResult As New BoolOperand("Result", Type.[GetType]("System.Boolean"))

        Select Case Convert.ToString(Me.Value)
            Case "False"
                oprResult.Value = Not (False)
                Exit Select
            Case "True"
                oprResult.Value = Not (True)
                Exit Select
            Case Else
                Exit Select
        End Select

        Return oprResult
    End Function

End Class

Public Class OperandHelper
    '
    ' Factory method to create corresponding Operands.
    ' Extended this method to create newer datatypes.
    '
    '
    '
    '
    '
    Public Shared Function CreateOperand(szVarName As String, varType As Type, varValue As Object) As Operand
        Dim oprResult As Operand = Nothing
        Dim IsBoolean As Boolean
        If [Boolean].TryParse(szVarName, IsBoolean) Then
            oprResult = New BoolOperand(szVarName, varValue)
            Return oprResult
        Else
            Select Case varType.ToString()
                Case "System.Int32", "System.Int64"
                    oprResult = New LongOperand(szVarName, varValue)
                    Return oprResult
                    'break;
                    'case System.Decimal:
                    'case System.Single:
                    ' oprResult = new DecimalOperand( szVarName, varValue );
                    ' return oprResult;
                    ' break;
                Case "System.String"
                    oprResult = New StringOperand(szVarName, varValue)
                    Return oprResult
                    'break;




            End Select
        End If
        Throw New RPN_Exception("Unhandled type : " & varType.ToString())
    End Function
    Public Shared Function CreateOperand(szVarName As String, varType As Type) As Operand
        Return OperandHelper.CreateOperand(szVarName, varType, Nothing)
    End Function
End Class
Public Class StringOperand
    Inherits Operand
    Implements IComparisonOperations
    Public Sub New(szVarName As String, varValue As Object)
        MyBase.New(szVarName, varValue)
    End Sub
    Public Sub New(szVarName As String)
        MyBase.New(szVarName)
    End Sub
    Public Overrides Function ToString() As String
        Return m_szVarName
    End Function
    Public Overrides Sub ExtractAndSetValue(szValue As String, bFormula As Boolean)
        m_VarValue = If(Not bFormula, Convert.ToString(szValue), "")
    End Sub
    ' IComparisonOperators methods. Return values are always BooleanOperands type
    Public Function EqualTo(rhs As IOperand) As IOperand Implements IComparisonOperations.EqualTo
        If Not (TypeOf rhs Is StringOperand) Then
            Throw New RPN_Exception("Argument invalid in StringOperand.== : rhs")
        End If
        Dim oprResult As New BoolOperand("Result")
        oprResult.Value = DirectCast(Me.Value, String) = DirectCast(DirectCast(rhs, Operand).Value, String)
        Return oprResult
    End Function
    Public Function NotEqualTo(rhs As IOperand) As IOperand Implements IComparisonOperations.NotEqualTo
        If Not (TypeOf rhs Is StringOperand) Then
            Throw New RPN_Exception("Argument invalid in StringOperand.!= : rhs")
        End If
        Dim oprResult As New BoolOperand("Result")
        oprResult.Value = If((DirectCast(Me.Value, String) <> DirectCast(DirectCast(rhs, Operand).Value, String)), True, False)
        Return oprResult
    End Function
    Public Function LessThan(rhs As IOperand) As IOperand Implements IComparisonOperations.LessThan
        ' if( !(rhs is StringOperand) )
        Throw New RPN_Exception("LessThan operator is invalid for string")
        ' BoolOperand oprResult = new BoolOperand("Result");
        ' oprResult.Value = ((string)this.Value < (string)((Operand)rhs).Value) ? true : false;
        ' return oprResult;
    End Function
    Public Function LessThanOrEqualTo(rhs As IOperand) As IOperand Implements IComparisonOperations.LessThanOrEqualTo
        ' if( !(rhs is StringOperand) )
        Throw New RPN_Exception("LessThanOrEqualTo operator is invalid for string")
        ' BoolOperand oprResult = new BoolOperand("Result");
        ' oprResult.Value = ((string)this.Value <= (string)((Operand)rhs).Value) ? true : false;
        ' return oprResult;
    End Function
    Public Function GreaterThan(rhs As IOperand) As IOperand Implements IComparisonOperations.GreaterThan
        ' if( !(rhs is StringOperand) )
        Throw New RPN_Exception("GreaterThan operator is invalid for string")
        ' BoolOperand oprResult = new BoolOperand("Result");
        ' oprResult.Value = ((string)this.Value > (string)((Operand)rhs).Value) ? true : false;
        ' return oprResult;
    End Function
    Public Function GreaterThanOrEqualTo(rhs As IOperand) As IOperand Implements IComparisonOperations.GreaterThanOrEqualTo
        ' if( !(rhs is StringOperand) )
        Throw New RPN_Exception("GreaterThanOrEqualTo operator is invalid for string")
        ' BoolOperand oprResult = new BoolOperand("Result");
        ' oprResult.Value = ((string)this.Value >= (string)((Operand)rhs).Value) ? true : false;
        ' return oprResult;
    End Function
End Class
#End Region

#Region "Operators"
 
' Base class of all operators. Provides datastorage
'
Public MustInherit Class [Operator]
    Implements IOperator
    Public Sub New(cOperator As Char)
        m_szOperator = New [String](cOperator, 1)
    End Sub
    Public Sub New(szOperator As String)
        m_szOperator = szOperator
    End Sub
    Public Overrides Function ToString() As String
        Return m_szOperator
    End Function
    'Public MustOverride Function Eval(lhs As IOperand, rhs As IOperand) As IOperand
    'Public MustOverride Function Eval(lhs As IOperand) As IOperand
    Public MustOverride Function Eval(lhs As IOperand, rhs As IOperand) As IOperand Implements IOperator.Eval
    Public MustOverride Function Eval(lhs As IOperand) As IOperand Implements IOperator.Eval
    Public Property Value() As String
        Get
            Return m_szOperator
        End Get
        Set(value As String)
            m_szOperator = value
        End Set
    End Property
    Protected m_szOperator As String = ""
End Class
'
' Arithmetic Operator Class providing evaluation services for "+-/*%" operators.
'
Public Class ArithmeticOperator
    Inherits [Operator]
    Public Sub New(cOperator As Char)
        MyBase.New(cOperator)
    End Sub
    Public Sub New(szOperator As String)
        MyBase.New(szOperator)
    End Sub
    'bool bBinaryOperator = true;

    Public Overrides Function Eval(lhs As IOperand, rhs As IOperand) As IOperand
        If Not (TypeOf lhs Is IArithmeticOperations) Then
            Throw New RPN_Exception("Argument invalid in ArithmeticOperator.Eval - Invalid Expression : lhs")
        End If
        Select Case m_szOperator
            Case "+"
                Return DirectCast(lhs, IArithmeticOperations).Plus(rhs)
            Case "-"
                Return DirectCast(lhs, IArithmeticOperations).Minus(rhs)
            Case "*"
                Return DirectCast(lhs, IArithmeticOperations).Multiply(rhs)
            Case "/"
                Return DirectCast(lhs, IArithmeticOperations).Divide(rhs)
            Case "%"
                Return DirectCast(lhs, IArithmeticOperations).Modulo(rhs)
        End Select
        Throw New RPN_Exception("Unsupported Arithmetic operation " & m_szOperator)
    End Function

    Public Overrides Function Eval(lhs As IOperand) As IOperand
        If TypeOf lhs Is IArithmeticOperations Then
            'throw new RPN_Exception("Argument invalid in ArithmeticOperator.Eval - Invalid Expression : lhs");
            Select Case m_szOperator
                Case "~"
                    Return DirectCast(lhs, IArithmeticOperations).Negate()
                Case "!"
                    Return DirectCast(lhs, IArithmeticOperations).[Not]()

            End Select
        ElseIf TypeOf lhs Is BoolOperand Then
            Select Case m_szOperator
                Case "~"
                    Return DirectCast(lhs, BoolOperand).Negate()
                Case "!"
                    Return DirectCast(lhs, BoolOperand).[Not]()

            End Select
        End If
        Throw New RPN_Exception("Unsupported Arithmetic operation " & m_szOperator)
    End Function
End Class

'
' Comparison Operator Class providing evaluation services for "==", "!=","<", "<=", ">", ">=" operators.
'
Public Class ComparisonOperator
    Inherits [Operator]
    Public Sub New(cOperator As Char)
        MyBase.New(cOperator)
    End Sub
    Public Sub New(szOperator As String)
        MyBase.New(szOperator)
    End Sub
    'bool bBinaryOperator = true;

    Public Overrides Function Eval(lhs As IOperand) As IOperand
        Return Nothing
    End Function

    '{"==", "!=","<", "<=", ">", ">="}
    Public Overrides Function Eval(lhs As IOperand, rhs As IOperand) As IOperand
        If Not (TypeOf lhs Is IComparisonOperations) Then
            Throw New RPN_Exception("Argument invalid in ComparisonOperator.Eval - Invalid Expression : lhs")
        End If
        Select Case m_szOperator
            Case "=="
                Return DirectCast(lhs, IComparisonOperations).EqualTo(rhs)
            Case "!="
                Return DirectCast(lhs, IComparisonOperations).NotEqualTo(rhs)
            Case "<"
                Return DirectCast(lhs, IComparisonOperations).LessThan(rhs)
            Case "<="
                Return DirectCast(lhs, IComparisonOperations).LessThanOrEqualTo(rhs)
            Case ">"
                Return DirectCast(lhs, IComparisonOperations).GreaterThan(rhs)
            Case ">="
                Return DirectCast(lhs, IComparisonOperations).GreaterThanOrEqualTo(rhs)
        End Select
        Throw New RPN_Exception("Unsupported Comparison operation " & m_szOperator)
    End Function
End Class

'
' Logical Operator Class providing evaluation services for && and || operators.
'
Public Class LogicalOperator
    Inherits [Operator]
    Public Sub New(cOperator As Char)
        MyBase.New(cOperator)
    End Sub
    Public Sub New(szOperator As String)
        MyBase.New(szOperator)
    End Sub
    'bool bBinaryOperator = true;

    Public Overrides Function Eval(lhs As IOperand) As IOperand
        Return Nothing
    End Function

    '{"&&", "||"}
    Public Overrides Function Eval(lhs As IOperand, rhs As IOperand) As IOperand
        If Not (TypeOf lhs Is ILogicalOperations) Then
            Throw New RPN_Exception("Argument invalid in LogicalOperator.Eval - Invalid Expression : lhs")
        End If
        Select Case m_szOperator
            Case "&&"
                Return DirectCast(lhs, ILogicalOperations).[AND](rhs)
            Case "||"
                Return DirectCast(lhs, ILogicalOperations).[OR](rhs)
        End Select
        Throw New RPN_Exception("Unsupported Logical operation " & m_szOperator)
    End Function
End Class

Public Class OperatorHelper
    '
    ' Factory method to create Operator objects.
    '
    '
    '
    Public Shared Function CreateOperator(szOperator As String) As IOperator
        Dim oprtr As IOperator = Nothing
        If OperatorHelper.IsArithmeticOperator(szOperator) Then
            oprtr = New ArithmeticOperator(szOperator)
            Return oprtr
        End If
        If OperatorHelper.IsComparisonOperator(szOperator) Then
            oprtr = New ComparisonOperator(szOperator)
            Return oprtr
        End If
        If OperatorHelper.IsLogicalOperator(szOperator) Then
            oprtr = New LogicalOperator(szOperator)
            Return oprtr
        End If
        Throw New RPN_Exception("Unhandled Operator : " & szOperator)
    End Function
    Public Shared Function CreateOperator(cOperator As Char) As IOperator
        Return CreateOperator(New String(cOperator, 1))
    End Function
    ' Some helper functions.
    Public Shared Function IsOperator(currentOp As String) As Boolean
        Dim nPos As Integer = Array.IndexOf(m_AllOps, currentOp.Trim())
        If nPos <> -1 Then
            Return True
        Else
            Return False
        End If
    End Function
    Public Shared Function IsUnaryOperator(currentOp As String) As Boolean
        Dim nPos As Integer = Array.IndexOf(m_AllUnaryOps, currentOp.Trim())
        If nPos <> -1 Then
            Return True
        Else
            Return False
        End If
    End Function
    Public Shared Function IsArithmeticOperator(currentOp As String) As Boolean
        Dim nPos As Integer = Array.IndexOf(m_AllArithmeticOps, currentOp)
        If nPos <> -1 Then
            Return True
        Else
            Return False
        End If
    End Function
    Public Shared Function IsComparisonOperator(currentOp As String) As Boolean
        Dim nPos As Integer = Array.IndexOf(m_AllComparisonOps, currentOp)
        If nPos <> -1 Then
            Return True
        Else
            Return False
        End If
    End Function
    Public Shared Function IsLogicalOperator(currentOp As String) As Boolean
        Dim nPos As Integer = Array.IndexOf(m_AllLogicalOps, currentOp)
        If nPos <> -1 Then
            Return True
        Else
            Return False
        End If
    End Function
#Region "Precedence"
    ' Precedence is determined by relative indices of the operators defined in
    ' in m_AllOps variable

    '
    ' Summary of IsLowerPrecOperator.
    '
    '
    '
    '
    '
    Public Shared Function IsLowerPrecOperator(currentOp As String, prevOp As String) As Boolean
        Dim nCurrIdx As Integer
        Dim nPrevIdx As Integer
        GetCurrentAndPreviousIndex(m_AllOps, currentOp, prevOp, nCurrIdx, nPrevIdx)
        If nCurrIdx < nPrevIdx Then
            Return True
        End If
        Return False
    End Function

    '
    ' Summary of IsHigherPrecOperator.
    '
    '
    '
    '
    '
    Public Shared Function IsHigherPrecOperator(currentOp As String, prevOp As String) As Boolean
        Dim nCurrIdx As Integer
        Dim nPrevIdx As Integer
        GetCurrentAndPreviousIndex(m_AllOps, currentOp, prevOp, nCurrIdx, nPrevIdx)
        If nCurrIdx > nPrevIdx Then
            Return True
        End If
        Return False
    End Function

    '
    ' Summary of IsEqualPrecOperator.
    '
    '
    '
    '
    '
    Public Shared Function IsEqualPrecOperator(currentOp As String, prevOp As String) As Boolean
        Dim nCurrIdx As Integer
        Dim nPrevIdx As Integer
        GetCurrentAndPreviousIndex(m_AllOps, currentOp, prevOp, nCurrIdx, nPrevIdx)
        If nCurrIdx = nPrevIdx Then
            Return True
        End If
        Return False
    End Function
    '
    ' Summary of GetCurrentAndPreviousIndex.
    '
    '
    '
    '
    '
    '
    '
    Private Shared Sub GetCurrentAndPreviousIndex(allOps As String(), currentOp As String, prevOp As String, ByRef nCurrIdx As Integer, ByRef nPrevIdx As Integer)
        nCurrIdx = -1
        nPrevIdx = -1
        For nIdx As Integer = 0 To allOps.Length - 1
            If allOps(nIdx) = currentOp Then
                nCurrIdx = nIdx
            End If
            If allOps(nIdx) = prevOp Then
                nPrevIdx = nIdx
            End If
            If nPrevIdx <> -1 AndAlso nCurrIdx <> -1 Then
                Exit For
            End If
        Next
        If nCurrIdx = -1 Then
            Throw New RPN_Exception("Unknown operator - " & currentOp)
        End If
        If nPrevIdx = -1 Then
            Throw New RPN_Exception("Unknown operator - " & prevOp)
        End If

    End Sub
#End Region
#Region "RegEx"
    '
    ' This gets the regular expression used to find operators in the input
    ' expression.
    '
    '
    '
    Public Shared Function GetOperatorsRegEx(exType As ExpressionType) As String
        Dim strRegex As New StringBuilder()
        If (exType And ExpressionType.ET_ARITHMETIC).Equals(ExpressionType.ET_ARITHMETIC) Then
            If strRegex.Length = 0 Then
                strRegex.Append(m_szArthmtcRegEx)
            Else
                strRegex.Append("|" & m_szArthmtcRegEx)
            End If
        End If
        If (exType And ExpressionType.ET_COMPARISON).Equals(ExpressionType.ET_COMPARISON) Then
            If strRegex.Length = 0 Then
                strRegex.Append(m_szCmprsnRegEx)
            Else
                strRegex.Append("|" & m_szCmprsnRegEx)
            End If
        End If
        If (exType And ExpressionType.ET_LOGICAL).Equals(ExpressionType.ET_LOGICAL) Then
            If strRegex.Length = 0 Then
                strRegex.Append(m_szLgclRegEx)
            Else
                strRegex.Append("|" & m_szLgclRegEx)
            End If
        End If
        If strRegex.Length = 0 Then
            Throw New RPN_Exception("Invalid combination of ExpressionType value")
        End If
        Return "(" & strRegex.ToString() & ")"
    End Function
    '
    ' Expression to pattern match various operators
    '
    Shared m_szArthmtcRegEx As String = "[+\-*/%()]{1}"
    Shared m_szCmprsnRegEx As String = "[=<>!]{1,2}"
    Shared m_szLgclRegEx As String = "[&|]{2}"
#End Region

    Public Shared ReadOnly Property AllOperators() As String()
        Get
            Return m_AllOps
        End Get
    End Property

    '
    ' All Operators supported by this module currently.
    ' Modify here to add more operators IN ACCORDANCE WITH their precedence.
    ' Additionally add into individual variables to support some helper methods above.
    '
    Shared m_AllOps As String() = {"||", "&&", "|", "^", "&", "==", _
     "!=", "<", "<=", ">", ">=", "+", _
     "-", "*", "/", "~", "%", "(", _
     ")", "!"}
    Shared m_AllArithmeticOps As String() = {"+", "-", "~", "*", "/", "%", _
     "!"}
    Shared m_AllComparisonOps As String() = {"==", "!=", "<", "<=", ">", ">="}
    Shared m_AllLogicalOps As String() = {"&&", "||"}
    Shared m_AllUnaryOps As String() = {"~", "!"}
End Class

#End Region

#Region "TODO List"
  TODO: Support for unary operators
' TODO: Support for bitwise & and |
' TODO: how to handle a combo expression with multiple braces as a logical/comparison expression?
' e.g. ((2+3)*2<10 || 1!=1) && 2*2==4 as a logical expression?
' TODO: Form to accept values for formulae
#End Region
' Function to test for Positive Integers.
#Region "Content check"
 ublic Class StringContentCheck
    Public Shared Function IsNaturalNumber(strNumber As [String]) As Boolean
        Dim objNotNaturalPattern As New Regex("[^0-9]")
        Dim objNaturalPattern As New Regex("0*[1-9][0-9]*")
        Return Not objNotNaturalPattern.IsMatch(strNumber) AndAlso objNaturalPattern.IsMatch(strNumber)
    End Function

    ' Function to test for Positive Integers with zero inclusive

    Public Shared Function IsWholeNumber(strNumber As [String]) As Boolean
        Dim objNotWholePattern As New Regex("[^0-9]")
        Return Not objNotWholePattern.IsMatch(strNumber)
    End Function

    ' Function to Test for Integers both Positive & Negative

    Public Shared Function IsInteger(strNumber As [String]) As Boolean
        Dim objNotIntPattern As New Regex("[^0-9-]")
        Dim objIntPattern As New Regex("^-[0-9]+$|^[0-9]+$")
        Return Not objNotIntPattern.IsMatch(strNumber) AndAlso objIntPattern.IsMatch(strNumber)
    End Function

    ' Function to Test for Positive Number both Integer & Real

    Public Shared Function IsPositiveNumber(strNumber As [String]) As Boolean
        Dim objNotPositivePattern As New Regex("[^0-9.]")
        Dim objPositivePattern As New Regex("^[.][0-9]+$|[0-9]*[.]*[0-9]+$")
        Dim objTwoDotPattern As New Regex("[0-9]*[.][0-9]*[.][0-9]*")
        Return Not objNotPositivePattern.IsMatch(strNumber) AndAlso objPositivePattern.IsMatch(strNumber) AndAlso Not objTwoDotPattern.IsMatch(strNumber)
    End Function

    ' Function to test whether the string is valid number or not
    Public Shared Function IsNumber(strNumber As [String]) As Boolean
        Dim objNotNumberPattern As New Regex("[^0-9.-]")
        Dim objTwoDotPattern As New Regex("[0-9]*[.][0-9]*[.][0-9]*")
        Dim objTwoMinusPattern As New Regex("[0-9]*[-][0-9]*[-][0-9]*")
        Dim strValidRealPattern As [String] = "^([-]|[.]|[-.]|[0-9])[0-9]*[.]*[0-9]+$"
        Dim strValidIntegerPattern As [String] = "^([-]|[0-9])[0-9]*$"
        Dim objNumberPattern As New Regex("(" & strValidRealPattern & ")|(" & strValidIntegerPattern & ")")
        Return Not objNotNumberPattern.IsMatch(strNumber) AndAlso Not objTwoDotPattern.IsMatch(strNumber) AndAlso Not objTwoMinusPattern.IsMatch(strNumber) AndAlso objNumberPattern.IsMatch(strNumber)
    End Function

    ' Function To test for Alphabets.
    Public Shared Function IsAlpha(strToCheck As [String]) As Boolean
        Dim objAlphaPattern As New Regex("[^a-zA-Z ]")
        Return Not objAlphaPattern.IsMatch(strToCheck)
    End Function

    ' Function to Check for AlphaNumeric.
    Public Shared Function IsAlphaNumeric(strToCheck As [String]) As Boolean
        Dim objAlphaNumericPattern As New Regex("[^a-zA-Z0-9 ]")
        Return Not objAlphaNumericPattern.IsMatch(strToCheck)
    End Function
End Class
#End Region

Usage example:
VB
Dim p As RPNParser = New RPNParser
Dim testString as String = "1 != 2"
Textbox1.Text = p.EvaluateExpression(testString)

Expected result "True".
You may need to use also this line:
VB
Imports RPNParser

This code functioned properly on VB 2010 Express .NET Framework 4.

modified 21-Mar-19 15:12pm.

QuestionConditional operator Pin
Member 89200266-Aug-12 21:17
Member 89200266-Aug-12 21:17 
GeneralMy vote of 4 Pin
staarkannan20-Dec-10 23:05
staarkannan20-Dec-10 23:05 
GeneralHere is the updated code for unary operator Not(!). [modified] Pin
staarkannan20-Dec-10 23:02
staarkannan20-Dec-10 23:02 
GeneralYou did great job !!! Pin
actyrol24-Aug-10 5:32
actyrol24-Aug-10 5:32 
QuestionAny restriction to use this code? Pin
sree1234518-Mar-10 10:44
sree1234518-Mar-10 10:44 
AnswerRe: Any restriction to use this code? Pin
Member 122881318-Apr-16 0:15
Member 122881318-Apr-16 0:15 
QuestionAdding Exponent Operator Pin
Azra sultana7-Jun-09 4:12
Azra sultana7-Jun-09 4:12 
GeneralDecimal Value Cannot Evaluate Pin
RobertChan20003-May-09 12:51
RobertChan20003-May-09 12:51 
Questionsome bugs? Pin
Canic23-Apr-09 16:31
Canic23-Apr-09 16:31 
GeneralOperator Precedence Pin
cmptrkemist13-Dec-07 19:48
cmptrkemist13-Dec-07 19:48 
GeneralMinus unary operator support + string comparison [modified] Pin
zitun21-Jun-06 22:08
zitun21-Jun-06 22:08 
GeneralUnary operator support Pin
stuallenii5-May-06 5:59
stuallenii5-May-06 5:59 
GeneralBug Pin
Ihor Bobak12-Feb-06 9:44
Ihor Bobak12-Feb-06 9:44 
GeneralRe: Bug Pin
stuallenii5-May-06 5:53
stuallenii5-May-06 5:53 
GeneralSome changes for String comparing.... Pin
neuralc10-Nov-04 5:31
neuralc10-Nov-04 5:31 
GeneralRe: Some changes for String comparing.... Pin
zitun15-May-06 1:51
zitun15-May-06 1:51 
GeneralUPDATE : Some changes for String comparing.... Pin
zitun30-May-06 0:08
zitun30-May-06 0:08 
GeneralDecimal numbers Pin
Gian7-May-04 1:30
Gian7-May-04 1:30 
GeneralRe: Decimal numbers Pin
Ciprian Talaba22-Aug-06 23:43
Ciprian Talaba22-Aug-06 23:43 
GeneralRe: Decimal numbers Pin
asmgx16-May-07 16:22
asmgx16-May-07 16:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.