Results 1 to 12 of 12

Thread: Expression Evaluator

  1. #1

    Thread Starter
    Super Moderator dday9's Avatar
    Join Date
    Mar 2011
    Location
    South Louisiana
    Posts
    9,678

    Expression Evaluator

    Features
    Utilizes an expression evaluator that converts infix notation to reverse polish notation then solves the equation.

    Drawbacks
    Does not report on double operators.

    Plans
    Fix the drawback and expand to include variables

    Remarks
    I would really like to thank szlamany for suggesting that I convert the infix notation to reverse polish notation as well as Niya on his codebank contribution Understanding Lambdas and Delegates. Without them, I could not have made this evaluator.

    Code
    Code:
    Public Class ExpressionEvaluator
    
        'Create lambdas for all operations(add, subtract, multiply, divide, exponent)
        Private Function AddNumbers(ByVal operand1 As Double, ByVal operand2 As Double) As Double
            Return operand1 + operand2
        End Function
    
        Private Function SubtractNumbers(ByVal operand1 As Double, ByVal operand2 As Double) As Double
            Return operand1 - operand2
        End Function
    
        Private Function MultiplyNumbers(ByVal operand1 As Double, ByVal operand2 As Double) As Double
            Return operand1 * operand2
        End Function
    
        Private Function DivideNumbers(ByVal operand1 As Double, ByVal operand2 As Double) As Double
            Return operand1 / operand2
        End Function
    
        Private Function ModuloNumbers(ByVal operand1 As Double, ByVal operand2 As Double) As Double
            Return operand1 Mod operand2
        End Function
    
        Private Function RaiseNumbers(ByVal operand1 As Double, ByVal operand2 As Double) As Double
            Return operand1 ^ operand2
        End Function
    
        Private Function FormatExpression(ByVal source As String) As String
            'Add a space before an after any left parenthesis
            source = source.Replace("(", " ( ")
    
            'Add a space before an after any right parenthesis
            source = source.Replace(")", " ) ")
    
            Dim operators() As String = {"+", "-", "*", "/", "%", "^"}
            'Loop through each character in the source, backwards(except for the first character)
            For index As Int32 = source.Length - 1 To 1 Step -1
                Dim currentChar As String = source(index)
    
                'Check if the current character is an operator
                If operators.Contains(currentChar) Then
                    'If it is an operator check if the prior character that's not a whitespace is NOT an operator
                    Dim tempSource As String = source.Substring(0, index).Replace(" ", String.Empty)
    
                    'If the character before the current one is an operator too, then we have a unary operator
                    If Not operators.Contains(tempSource(index - (source.Substring(0, index).Length - tempSource.Length) - 1)) Then
                        'So if the prior character is not a unary operator, add a space after it
                        source = source.Insert(index + 1, " ")
                    End If
    
                    'Regardless of if the operator is a unary operator or not add a space before it
                    source = source.Insert(index, " ")
                End If
            Next
    
            'Return the formatted source
            Return source
        End Function
    
        Private Function Scan(ByVal source As String) As Token()
            'Create the following tokens:
            '1) Left Parenthesis
            '2) Right Parenthesis
            '3) Digit
            '4) Operators(by precedence)
            '   I)   Addition/Subtraction
            '   II)  Multiplication/Division/Modulo
            '   III) Exponent
            Dim definitions() As Token = {New Token() With {.Pattern = "^(\()$", .Type = Token.TokenType.LeftParenthesis, .Value = String.Empty}, _
                                          New Token() With {.Pattern = "^(\))$", .Type = Token.TokenType.RightParenthesis, .Value = String.Empty}, _
                                          New Token() With {.Pattern = "^([-+]?(\d*[.])?\d+)$", .Type = Token.TokenType.Digit, .Value = String.Empty}, _
                                          New Token() With {.Operation = New Token.MathOperation(AddressOf AddNumbers), .Pattern = "^(\+)$", .Precedence = 1, .Type = Token.TokenType.Operator, .Value = String.Empty}, _
                                          New Token() With {.Operation = New Token.MathOperation(AddressOf SubtractNumbers), .Pattern = "^(-)$", .Precedence = 1, .Type = Token.TokenType.Operator, .Value = String.Empty}, _
                                          New Token() With {.Operation = New Token.MathOperation(AddressOf MultiplyNumbers), .Pattern = "^(\*)$", .Precedence = 2, .Type = Token.TokenType.Operator, .Value = String.Empty}, _
                                          New Token() With {.Operation = New Token.MathOperation(AddressOf DivideNumbers), .Pattern = "^(\/)$", .Precedence = 2, .Type = Token.TokenType.Operator, .Value = String.Empty}, _
                                          New Token() With {.Operation = New Token.MathOperation(AddressOf ModuloNumbers), .Pattern = "^(%)$", .Precedence = 2, .Type = Token.TokenType.Operator, .Value = String.Empty}, _
                                          New Token() With {.Operation = New Token.MathOperation(AddressOf RaiseNumbers), .Pattern = "^(\^)$", .Precedence = 3, .Type = Token.TokenType.Operator, .Value = String.Empty}}
    
            'This is the token collection that will be returned
            Dim tokens As List(Of Token) = New List(Of Token)
    
            'Loop through each item in the source
            For Each item As String In source.Split({" "}, StringSplitOptions.RemoveEmptyEntries)
                Dim currentToken As Token = Nothing
                Dim regex As Text.RegularExpressions.Regex
    
                'Loop through each definition
                For Each definition As Token In definitions
                    'Check to see if the current item in the source matches a RegEx pattern
                    regex = New Text.RegularExpressions.Regex(definition.Pattern)
    
                    If regex.IsMatch(item) Then
                        'If there's a match then set the currentToken
                        currentToken = definition.Clone(item)
                        Exit For
                    End If
    
                Next
    
                'If the currentToken variable is nothing, then there's an error(the item's not a valid keyword)
                If currentToken Is Nothing Then
                    tokens.Add(New Token With {.Type = Token.TokenType.Error, .Value = String.Format("'{0}' is not a valid keyword.", item)})
    
                    'Return the tokens early because of the error
                    Return tokens.ToArray
                Else
                    'Otherwise, add the token to the collection
                    tokens.Add(currentToken)
                End If
            Next
    
            'Return the token collection as an array
            Return tokens.ToArray
        End Function
    
        Private Function ShuntingYardAlgorithm(ByVal tokens() As Token) As Token()
            'The output is what will be returned
            Dim output As List(Of Token) = New List(Of Token)
    
            'The operatorStack temporarily holds operators
            Dim operatorStack As Stack(Of Token) = New Stack(Of Token)
    
            'Read each token
            For Each item As Token In tokens
                If item.Type = Token.TokenType.Digit Then
                    'If the item is a digit then add it to the queue
                    output.Add(item)
                ElseIf item.Type = Token.TokenType.Operator Then
                    'If the token(a) is an operator then...
                    'While there is an operator(b) of higher or equal precident than (a) at the top of the stack,
                    'pop (b) off the stack and append it to the output
                    While operatorStack.Count > 0 AndAlso operatorStack.Peek.Precedence >= item.Precedence
                        output.Add(operatorStack.Pop)
                    End While
    
                    'Push (a) onto the stack
                    operatorStack.Push(item)
                ElseIf item.Type = Token.TokenType.LeftParenthesis Then
                    'If the token is an opening bracket, then push it onto the stack
                    operatorStack.Push(item)
                ElseIf item.Type = Token.TokenType.RightParenthesis Then
                    Dim found As Boolean = False
    
                    'Loop while there are still operators in the stack and we haven't found a left parenthesis
                    While operatorStack.Count > 0 AndAlso found = False
                        If operatorStack.Peek.Type <> Token.TokenType.LeftParenthesis Then
                            'Pop operators off the stack and append them to the output
                            output.Add(operatorStack.Pop)
                        ElseIf operatorStack.Peek.Type = Token.TokenType.LeftParenthesis Then
                            'Pop the left parentheses without adding it to the output and exit out the loop
                            operatorStack.Pop()
                            found = True
                        End If
                    End While
    
                    'If the left parenthesis then there was a error(too many right parenthesis)
                    If Not found Then
                        output.Add(New Token With {.Type = Token.TokenType.Error, .Value = "Syntax Error:" & Environment.NewLine & "There are too many closed parentheses."})
    
                        'Return the tokens early because of the error
                        Return output.ToArray
                    End If
                End If
            Next
    
            'When all the tokens have been read, if there are still tokens in the stack then...
            If operatorStack.Count > 0 Then
                'Loop until there are no more tokens in the stack
                Do
                    If operatorStack.Peek.Type = Token.TokenType.Operator Then
                        'Pop the operator on the top of the stack and append it to the output
                        output.Add(operatorStack.Pop)
                    Else
                        'There was a parentheses left, which means there was an error(too many open parenthesis)
                        output.Add(New Token With {.Type = Token.TokenType.Error, .Value = "Syntax Error:" & Environment.NewLine & "There are too many open parentheses."})
    
                        'Return the tokens early because of the error
                        Return output.ToArray
                    End If
                Loop Until operatorStack.Count = 0
            End If
    
            'Return the token collection as an array
            Return output.ToArray
        End Function
    
        ''' <summary>
        ''' Solves a mathematical equation.
        ''' </summary>
        ''' <param name="source">The mathematical equation in infix notation.</param>
        ''' <returns>Double</returns>
        Public Function Evaluate(ByVal source As String) As Double
            'Fomart the source
            source = FormatExpression(source)
    
            'Scan the source
            Dim tokens() As Token = Scan(source)
    
            'Make sure that the last token is not an error
            If tokens.Last IsNot Nothing AndAlso tokens.Last.Type <> Token.TokenType.Error Then
                'Convert the token stream into reverse polish notation
                tokens = ShuntingYardAlgorithm(tokens)
    
                'Make sure that the last token is not an error
                If tokens.Last IsNot Nothing AndAlso tokens.Last.Type <> Token.TokenType.Error Then
                    'Solve the reverse polish notation by storing values into a stack
                    'The last item in the stack is the final value
                    Dim valueStack As Stack(Of Token) = New Stack(Of Token)
    
                    'Loop through each item in our token stream
                    For Each item As Token In tokens
                        If item.Type <> Token.TokenType.Operator Then
                            'If the item isnot an operator then add it to the stack
                            valueStack.Push(item)
                        Else
                            'The second operand pop's first while the first operand pop's second
                            Dim part2 As Double = Double.Parse(valueStack.Pop.Value)
                            Dim part1 As Double = Double.Parse(valueStack.Pop.Value)
    
                            'Preform the correct mathematical operation using both operands
                            valueStack.Push(New Token With {.Type = Token.TokenType.Digit, .Value = item.Operation(part1, part2).ToString})
                        End If
                    Next
    
                    'Return the final item in the stack
                    Return Double.Parse(valueStack.Pop.Value)
                Else
                    'Otherwise, print the error and return prematurely
                    Console.WriteLine(tokens.Last.Value)
                    Return Nothing
                End If
            Else
                'Otherwise, print the error and return prematurely
                Console.WriteLine(tokens.Last.Value)
                Return Nothing
            End If
        End Function
    
        Friend Class Token
    
            Friend Enum TokenType
                Digit
                [Error]
                LeftParenthesis
                [Operator]
                RightParenthesis
            End Enum
    
            Friend Delegate Function MathOperation(ByVal operand1 As Double, ByVal operand2 As Double) As Double
    
            ''' <summary>
            ''' Gets or sets the operation that the token will preform
            ''' </summary>
            ''' <value>MathOperation</value>
            ''' <returns>Double</returns>
            ''' <remarks>Only applicable on Operators</remarks>
            Friend Property Operation As MathOperation
    
            ''' <summary>
            ''' Gets or sets the Regular Expression pattern
            ''' </summary>
            ''' <value>String</value>
            ''' <returns>String</returns>
            Friend Property Pattern As String
    
            ''' <summary>
            ''' Gets or sets the precedence of the operator
            ''' </summary>
            ''' <value>Int32</value>
            ''' <returns>Int32</returns>
            ''' <remarks>Only applicable on Operators</remarks>
            Friend Property Precedence As Int32
    
            ''' <summary>
            ''' Gets or sets the type of token
            ''' </summary>
            ''' <value>TokenType</value>
            ''' <returns>TokenType</returns>
            ''' <remarks>Can be expanded to include variables</remarks>
            Friend Property Type As TokenType
    
            ''' <summary>
            ''' Gets or sets the either the number literal or character representation of the token
            ''' </summary>
            ''' <value>String</value>
            ''' <returns>String</returns>
            Friend Property Value As String
    
            ''' <summary>
            ''' Returns a new token with all the same Properties, but a new Value.
            ''' </summary>
            ''' <param name="value">The value of the new token</param>
            ''' <returns>Token</returns>
            ''' <remarks></remarks>
            Friend Function Clone(ByVal value As String) As Token
                Return New Token With {.Operation = Me.Operation, .Pattern = Me.Pattern, .Precedence = Me.Precedence, .Type = Me.Type, .Value = value}
            End Function
    
        End Class
    
    End Class

  2. #2
    MS SQL Powerposter szlamany's Avatar
    Join Date
    Mar 2004
    Location
    CT
    Posts
    17,882

    Re: Expression Evaluator

    I just pasted that into a project and checked it out - very nice. Would be cool to see a simple UI that displays that stack and such so you can see the engine run the expression to completion.

    *** Read the sticky in the DB forum about how to get your question answered quickly!! ***

    Please remember to rate posts! Rate any post you find helpful - even in old threads! Use the link to the left - "Rate this Post".

    Some Informative Links:
    [ SQL Rules to Live By ] [ Reserved SQL keywords ] [ When to use INDEX HINTS! ] [ Passing Multi-item Parameters to STORED PROCEDURES ]
    [ Solution to non-domain Windows Authentication ] [ Crazy things we do to shrink log files ] [ SQL 2005 Features ] [ Loading Pictures from DB ]

    MS MVP 2006, 2007, 2008

  3. #3
    MS SQL Powerposter szlamany's Avatar
    Join Date
    Mar 2004
    Location
    CT
    Posts
    17,882

    Re: Expression Evaluator

    Just to put this into perspective - I actually used techniques like this back in the pre-PC early 1980's to evaluate homegrown database "formulas" for reporting purposes.

    No internet back then - learned about RPN from my TI-55 calculator (which I still have!).

    *** Read the sticky in the DB forum about how to get your question answered quickly!! ***

    Please remember to rate posts! Rate any post you find helpful - even in old threads! Use the link to the left - "Rate this Post".

    Some Informative Links:
    [ SQL Rules to Live By ] [ Reserved SQL keywords ] [ When to use INDEX HINTS! ] [ Passing Multi-item Parameters to STORED PROCEDURES ]
    [ Solution to non-domain Windows Authentication ] [ Crazy things we do to shrink log files ] [ SQL 2005 Features ] [ Loading Pictures from DB ]

    MS MVP 2006, 2007, 2008

  4. #4

    Thread Starter
    Super Moderator dday9's Avatar
    Join Date
    Mar 2011
    Location
    South Louisiana
    Posts
    9,678

    Re: Expression Evaluator

    Here is another implementation of an expression evaluator that does not use a lexical analyzer(aka scanner):
    Code:
    Option Strict On
    
    Imports System
    Imports System.Collections.Generic
    Imports System.Text.RegularExpressions
    
    Public Module ExpressionEvaluator
    
        Public Function Evaluate(ByVal expression As String) As Double
            Dim rpn As Queue(Of String) = ShuntingYardAlgorithm(expression)
            Dim value As Double
            If rpn.Count = 1 AndAlso Not Double.TryParse(rpn.Dequeue(), value) Then
                Throw New ArithmeticException("The expression is not in a valid format.")
            ElseIf rpn.Count > 1 Then
                Dim operations As New Dictionary(Of String, Operation) From {{"+", New Operation(AddressOf Sum)}, {"-", New Operation(AddressOf Difference)}, {"*", New Operation(AddressOf Multiplication)}, {"/", New Operation(AddressOf Division)}, {"%", New Operation(AddressOf Modulous)}, {"^", New Operation(AddressOf Power)}}
                Dim values As New Stack(Of Double)
                Dim currentValue As Double
                For Each lexeme As String In rpn
                    If Double.TryParse(lexeme, currentValue) Then
                        values.Push(currentValue)
                    ElseIf operations.ContainsKey(lexeme) Then
                        Dim value2 As Double = values.Pop()
                        values.Push(operations(lexeme).Invoke(values.Pop(), value2))
                    Else
                        Throw New ArithmeticException("The expression is not in a valid format.")
                    End If
                Next
    
                value = values.Pop()
            End If
    
            Return value
        End Function
    
        Private Function ShuntingYardAlgorithm(ByVal source As String) As Queue(Of String)
            Dim output As New Queue(Of String)
            Dim operators As New Stack(Of String)
            Dim operatorPrecedence As New Dictionary(Of String, Integer) From {{"+", 1}, {"-", 1}, {"*", 2}, {"/", 2}, {"%", 2}, {"^", 3}}
            Dim numberState As Boolean = True
            source = New Regex("\s").Replace(source, String.Empty)
            Dim lexeme As String = String.Empty
            Do Until String.IsNullOrWhiteSpace(source)
                If numberState Then
                    lexeme = Parse_Number(source)
                End If
    
                If Not String.IsNullOrWhiteSpace(lexeme) Then
                    output.Enqueue(lexeme)
                    numberState = Not numberState
                Else
                    If Not numberState Then
                        lexeme = Parse_Operator(source)
                    End If
    
                    If Not String.IsNullOrWhiteSpace(lexeme) Then
                        Do While operators.Count > 0 AndAlso operatorPrecedence.ContainsKey(operators.Peek()) AndAlso operatorPrecedence(lexeme) <= operatorPrecedence(operators.Peek)
                            output.Enqueue(operators.Pop())
                        Loop
    
                        operators.Push(lexeme)
                        numberState = Not numberState
                    ElseIf source(0) = "("c Then
                        operators.Push(source(0))
                        source = source.Remove(0, 1)
                    ElseIf source(0) = ")"c Then
                        Do Until operators.Peek() = "("
                            output.Enqueue(operators.Pop())
                        Loop
    
                        If operators.Count > 0 Then
                            operators.Pop()
                            source = source.Remove(0, 1)
                        Else
                            Throw New ArithmeticException("Parenthesis mismatch. There are more open parenthesis than closed parenthesis.")
                        End If
                    Else
                        Throw New ArithmeticException(String.Format("{0} is an invalid lexeme", source(0)))
                    End If
                End If
    
                lexeme = String.Empty
            Loop
    
            Do While operators.Count > 0
                lexeme = operators.Peek()
                If lexeme = "(" Then
                    Throw New ArithmeticException("Parenthesis mismatch. There are more open parenthesis than closed parenthesis.")
                ElseIf lexeme = ")" Then
                    Throw New ArithmeticException("Parenthesis mismatch. There are more closed parenthesis than open parenthesis.")
                Else
                    output.Enqueue(operators.Pop())
                End If
            Loop
    
            Return output
        End Function
    
        Private Function Parse_Number(ByRef source As String) As String
            Dim m As Match = New Regex("[+-]?\d+(\.\d+)?([eE][+-]?\d+)?").Match(source)
            Dim parsedNumber As String = String.Empty
            If m.Success AndAlso m.Index = 0 Then
                parsedNumber = m.Value
                source = source.Remove(0, m.Value.Length)
            End If
    
            Return parsedNumber
        End Function
    
        Private Function Parse_Operator(ByRef source As String) As String
            Dim operators As String = "+-*/%^"
            Dim parsedOperator As String = String.Empty
            If operators.IndexOf(source(0)) <> -1 Then
                parsedOperator = source(0)
                source = source.Remove(0, 1)
            End If
    
            Return parsedOperator
        End Function
    
        Private Function Sum(ByVal operand1 As Double, ByVal operand2 As Double) As Double
            Return operand1 + operand2
        End Function
    
        Private Function Difference(ByVal operand1 As Double, ByVal operand2 As Double) As Double
            Return operand1 - operand2
        End Function
    
        Private Function Multiplication(ByVal operand1 As Double, ByVal operand2 As Double) As Double
            Return operand1 * operand2
        End Function
    
        Private Function Division(ByVal operand1 As Double, ByVal operand2 As Double) As Double
            Return operand1 / operand2
        End Function
    
        Private Function Modulous(ByVal operand1 As Double, ByVal operand2 As Double) As Double
            Return operand1 Mod operand2
        End Function
    
        Private Function Power(ByVal operand1 As Double, ByVal operand2 As Double) As Double
            Return operand1 ^ operand2
        End Function
    
        Private Delegate Function Operation(ByVal operand1 As Double, ByVal operand2 As Double) As Double
    End Module
    Fiddle: https://dotnetfiddle.net/a3moLU

  5. #5
    MS SQL Powerposter szlamany's Avatar
    Join Date
    Mar 2004
    Location
    CT
    Posts
    17,882

    Re: Expression Evaluator

    That is so cool.

    Just seeing a formula with tons of parenthesis turned into simple pairs of RPN-with-stack operations - so cool!

    *** Read the sticky in the DB forum about how to get your question answered quickly!! ***

    Please remember to rate posts! Rate any post you find helpful - even in old threads! Use the link to the left - "Rate this Post".

    Some Informative Links:
    [ SQL Rules to Live By ] [ Reserved SQL keywords ] [ When to use INDEX HINTS! ] [ Passing Multi-item Parameters to STORED PROCEDURES ]
    [ Solution to non-domain Windows Authentication ] [ Crazy things we do to shrink log files ] [ SQL 2005 Features ] [ Loading Pictures from DB ]

    MS MVP 2006, 2007, 2008

  6. #6

    Thread Starter
    Super Moderator dday9's Avatar
    Join Date
    Mar 2011
    Location
    South Louisiana
    Posts
    9,678

    Re: Expression Evaluator

    One thing that I noticed is that both of my solutions do not handle negative parenthesis such as:
    Code:
    1 + 2 + -(3 * 4)
    This is because I use RegEx to parse numbers rather than parsing the numbers myself.

  7. #7
    MS SQL Powerposter szlamany's Avatar
    Join Date
    Mar 2004
    Location
    CT
    Posts
    17,882

    Re: Expression Evaluator

    You do not handle two unary minus either - and that should work.

    Code:
    --3
    Run-time exception (line -1): - is an invalid lexeme
    
    Stack Trace:
    
    [System.ArithmeticException: - is an invalid lexeme]

    *** Read the sticky in the DB forum about how to get your question answered quickly!! ***

    Please remember to rate posts! Rate any post you find helpful - even in old threads! Use the link to the left - "Rate this Post".

    Some Informative Links:
    [ SQL Rules to Live By ] [ Reserved SQL keywords ] [ When to use INDEX HINTS! ] [ Passing Multi-item Parameters to STORED PROCEDURES ]
    [ Solution to non-domain Windows Authentication ] [ Crazy things we do to shrink log files ] [ SQL 2005 Features ] [ Loading Pictures from DB ]

    MS MVP 2006, 2007, 2008

  8. #8

    Thread Starter
    Super Moderator dday9's Avatar
    Join Date
    Mar 2011
    Location
    South Louisiana
    Posts
    9,678

    Re: Expression Evaluator

    Quote Originally Posted by szlamany View Post
    You do not handle two unary minus either - and that should work.

    Code:
    --3
    Run-time exception (line -1): - is an invalid lexeme
    
    Stack Trace:
    
    [System.ArithmeticException: - is an invalid lexeme]
    No, it should work. What expression are you testing because the following give me the correct value:
    Code:
    1 - -1
    1 + -2
    1 + 2 - -4 / -6

  9. #9
    MS SQL Powerposter szlamany's Avatar
    Join Date
    Mar 2004
    Location
    CT
    Posts
    17,882

    Re: Expression Evaluator

    I put just --3

    -3 works

    --3 should work

    Unary minus is a tricky operand because it's only a single value being processed.

    *** Read the sticky in the DB forum about how to get your question answered quickly!! ***

    Please remember to rate posts! Rate any post you find helpful - even in old threads! Use the link to the left - "Rate this Post".

    Some Informative Links:
    [ SQL Rules to Live By ] [ Reserved SQL keywords ] [ When to use INDEX HINTS! ] [ Passing Multi-item Parameters to STORED PROCEDURES ]
    [ Solution to non-domain Windows Authentication ] [ Crazy things we do to shrink log files ] [ SQL 2005 Features ] [ Loading Pictures from DB ]

    MS MVP 2006, 2007, 2008

  10. #10

    Thread Starter
    Super Moderator dday9's Avatar
    Join Date
    Mar 2011
    Location
    South Louisiana
    Posts
    9,678

    Re: Expression Evaluator

    Well --3 is not a valid expression. At least not how I'm doing the evaluator. An expression in EBNF is:
    bnf Code:
    1. E ::= NUMBER | E OPERATOR E | '(' E ')'
    2. NUMBER ::= UNARY? DIGIT+ ('.' DIGIT+)? (('e' | 'E') UNARY? DIGIT+)*
    3. DIGIT ::= [0 - 9]
    4. OPERATOR ::= UNARY | '*' | '/' | '%' | '^'
    5. UNARY ::= '+' | '-'

    The expression --3 would be:
    Code:
    OPERATOR NUMBER
    Which does not meet the EBNF for E.
    Last edited by dday9; May 23rd, 2016 at 03:32 PM.

  11. #11
    MS SQL Powerposter szlamany's Avatar
    Join Date
    Mar 2004
    Location
    CT
    Posts
    17,882

    Re: Expression Evaluator

    This site

    http://www.csgnetwork.com/expresscalc.html

    Says that --3 is uncool

    But this does work: -(-3)

    *** Read the sticky in the DB forum about how to get your question answered quickly!! ***

    Please remember to rate posts! Rate any post you find helpful - even in old threads! Use the link to the left - "Rate this Post".

    Some Informative Links:
    [ SQL Rules to Live By ] [ Reserved SQL keywords ] [ When to use INDEX HINTS! ] [ Passing Multi-item Parameters to STORED PROCEDURES ]
    [ Solution to non-domain Windows Authentication ] [ Crazy things we do to shrink log files ] [ SQL 2005 Features ] [ Loading Pictures from DB ]

    MS MVP 2006, 2007, 2008

  12. #12

    Thread Starter
    Super Moderator dday9's Avatar
    Join Date
    Mar 2011
    Location
    South Louisiana
    Posts
    9,678

    Re: Expression Evaluator

    They've added an additional option in their expression:
    BNF Code:
    1. E ::= NUMBER | E OPERATOR E | '(' E ')' | UNARY '(' E ')'

    Which suggests that they're not using RPN to solve the expression but rather using a parser.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width