Example to Evaluate Basic Numeric ExpressionsID: Q86688
|
This article contains an example program that evaluates a numeric expression contained in a string, mimicking the operators, built-in functions, and order of evaluation used by Microsoft Basic language products. This article also explains the operator precedence rules in detail.
The example program listed below recognizes the following operators
and subexpressions, listed by precedence from highest to lowest:
Expression Value
---------- -----
-1 ^ 2 -1
-(1 ^ 2) -1
(-1) ^ 2 1
2 ^ -2 .25
NOT 0 = 1 -1
NOT (0 = 1) -1
(NOT 0) = 1 0
NOT 0 AND 1 1
(NOT 0) AND 1 1
NOT (0 AND 1) -1
Sub Command1_Click ()
Dim n As Double
If e_eval(Text1.Text, n) Then
MsgBox Format$(n)
End If
End Sub
' To run this program in Visual Basic for MS-DOS, change the
' following Dim statements to DIM SHARED.
'
Dim e_input As String ' Expression input string.
Dim e_tok As String ' Current token kind.
Dim e_spelling As String ' Current token spelling.
Dim e_error As Integer ' Tells if syntax error occurred.
' e_eval
' Evaluate a string containing an infix numeric expression.
' If successful, return true and place result in <value>.
' This is the top-level function in the expression evaluator.
Function e_eval (ByVal s As String, value As Double) As Integer
' Initialize.
e_error = 0
e_input = s
Call e_nxt
' Evaluate.
value = e_prs(1)
' Check for unrecognized input.
If e_tok <> "" And Not e_error Then
MsgBox "syntax error, token = '" + e_spelling + "'"
e_error = -1
End If
e_eval = Not e_error
End Function
' e_prs
' Parse an expression, allowing operators of a specified
' precedence or higher. The lowest precedence is 1.
' This function gets tokens with e_nxt and recursively
' applies operator precedence rules.
Function e_prs (p As Integer) As Double
Dim n As Double ' Return value.
Dim fun As String ' Function name.
' Parse expression that begins with a token (precedence 12).
If e_tok = "num" Then
' number.
n = Val(e_spelling)
Call e_nxt
ElseIf e_tok = "-" Then
' unary minus.
Call e_nxt
n = -e_prs(11) ' Operand precedence 11.
ElseIf e_tok = "not" Then
' logical NOT.
Call e_nxt
n = Not e_prs(6) ' Operand precedence 6.
ElseIf e_tok = "(" Then
' parentheses.
Call e_nxt
n = e_prs(1)
Call e_match(")")
ElseIf e_tok = "id" Then
' Function call.
fun = e_spelling
Call e_nxt
Call e_match("(")
n = e_prs(1)
Call e_match(")")
n = e_function(fun, n)
Else
If Not e_error Then
MsgBox "syntax error, token = '" + e_spelling + "'"
e_error = -1
End If
End If
' Parse binary operators.
Do While Not e_error
If 0 Then ' To allow ElseIf .
ElseIf p <= 11 And e_tok = "^" Then Call e_nxt: n = n ^ e_prs(12)
ElseIf p <= 10 And e_tok = "*" Then Call e_nxt: n = n * e_prs(11)
ElseIf p <= 10 And e_tok = "/" Then Call e_nxt: n = n / e_prs(11)
ElseIf p <= 9 And e_tok = "\" Then Call e_nxt: n = n \ e_prs(10)
ElseIf p <= 8 And e_tok = "mod" Then Call e_nxt: n = n Mod e_prs(9)
ElseIf p <= 7 And e_tok = "+" Then Call e_nxt: n = n + e_prs(8)
ElseIf p <= 7 And e_tok = "-" Then Call e_nxt: n = n - e_prs(8)
ElseIf p <= 6 And e_tok = "=" Then Call e_nxt: n = n = e_prs(7)
ElseIf p <= 6 And e_tok = "<" Then Call e_nxt: n = n < e_prs(7)
ElseIf p <= 6 And e_tok = ">" Then Call e_nxt: n = n > e_prs(7)
ElseIf p <= 6 And e_tok = "<>" Then Call e_nxt: n = n <> e_prs(7)
ElseIf p <= 6 And e_tok = "<=" Then Call e_nxt: n = n <= e_prs(7)
ElseIf p <= 6 And e_tok = ">=" Then Call e_nxt: n = n >= e_prs(7)
ElseIf p <= 5 And e_tok = "and" Then Call e_nxt: n = n And e_prs(6)
ElseIf p <= 4 And e_tok = "or" Then Call e_nxt: n = n Or e_prs(5)
ElseIf p <= 3 And e_tok = "xor" Then Call e_nxt: n = n Xor e_prs(4)
ElseIf p <= 2 And e_tok = "eqv" Then Call e_nxt: n = n Eqv e_prs(3)
ElseIf p <= 1 And e_tok = "imp" Then Call e_nxt: n = n Imp e_prs(2)
Else
Exit Do
End If
Loop
e_prs = n
End Function
' e_function.
' Evaluate a function. This is a helper function to simplify
' e_prs.
Function e_function (fun As String, arg As Double) As Double
Dim n As Double
Select Case LCase$(fun)
Case "abs": n = Abs(arg)
Case "atn": n = Atn(arg)
Case "cos": n = Cos(arg)
Case "exp": n = Exp(arg)
Case "fix": n = Fix(arg)
Case "int": n = Int(arg)
Case "log": n = Log(arg)
Case "rnd": n = Rnd(arg)
Case "sgn": n = Sgn(arg)
Case "sin": n = Sin(arg)
Case "sqr": n = Sqr(arg)
Case "tan": n = Tan(arg)
Case Else
If Not e_error Then
MsgBox "undefined function '" + fun + "'"
e_error = -1
End If
End Select
e_function = n
End Function
' e_nxt
' Get the next token into e_tok and e_spelling and remove the
' token from e_input.
' This function groups the input into "words" like numbers,
' operators and function names.
Sub e_nxt ()
Dim is_keyword As Integer
Dim c As String ' Current input character.
e_tok = ""
e_spelling = ""
' Skip whitespace.
Do
c = Left$(e_input, 1)
e_input = Mid$(e_input, 2)
Loop While c = " " Or c = Chr$(9) Or c = Chr$(13) Or c = Chr$(10)
Select Case LCase$(c)
' Number constant. Modify this to support hexadecimal, etc.
Case "0" To "9", "."
e_tok = "num"
Do
e_spelling = e_spelling + c
c = Left$(e_input, 1)
e_input = Mid$(e_input, 2)
Loop While (c >= "0" And c <= "9") Or c = "."
e_input = c + e_input
' Identifier or keyword.
Case "a" To "z", "_"
e_tok = "id"
Do
e_spelling = e_spelling + c
c = LCase$(Left$(e_input, 1))
e_input = Mid$(e_input, 2)
is_id% = (c >= "a" And c <= "z")
is_id% = is_id% Or c = "_" Or (c >= "0" And c <= "9")
Loop While is_id%
e_input = c + e_input
' Check for keyword.
is_keyword = -1
Select Case LCase$(e_spelling)
Case "and"
Case "eqv"
Case "imp"
Case "mod"
Case "not"
Case "or"
Case "xor"
Case Else: is_keyword = 0
End Select
If is_keyword Then
e_tok = LCase$(e_spelling)
End If
' Check for <=, >=, <>.
Case "<", ">"
e_tok = c
c = Left$(e_input, 1)
If c = "=" Or c = ">" Then
e_tok = e_tok + c
e_input = Mid$(e_input, 2)
End If
' Single character token.
Case Else
e_tok = c
End Select
If e_spelling = "" Then
e_spelling = e_tok
End If
End Sub
' e_match
' Check the current token and skip past it.
' This function helps with syntax checking.
Sub e_match (token As String)
If Not e_error And e_tok <> token Then
MsgBox "expected " + token + ", got '" + e_spelling + "'"
e_error = -1
End If
Call e_nxt
End Sub
Additional query words: 2.00 3.00
Keywords :
Version :
Platform :
Issue type :
Last Reviewed: June 23, 1999