Parsing Expressions of Interest
Part II : I'm The Bracket Creep
Having a method in place to resolve simple expressions like '2+2' (which we all know is 5 - just kidding) and '8*7/2-4', we then needed some way to deal with brackets as they were to be used to specify explicit order of operation and to make the more complex expressions more readable. To achieve this I used a simple recursive function to seek out the lowest levels of bracket pairs, resolve them, and replace all occurrences of that bracketed expression with its resolved value. This means that in the case of an expression like '5+(6*7)-8*(6*7)' we only calculate what 6*7 is once, and replace that bracketed pair with the answer wherever it appears. This, then, resolves to the following expression : '5+42-8*42' which can then be simply resolved by the simple expression parser.
The bracket handler code which returns the string bounded by the next most inner level of brackets looks like this:
Private Function GetNextBracketLayer (ByVal sArg As String) As String
Dim sResult As String
Dim iBraceCount As Integer
Dim iNum As Integer
Dim iStart As Integer
Dim iFinish As Integer
Dim sChar As String
' Initialise variables
iBraceCount = 0
sResult = ""
iStart = InStr(sArg, "(")
iNum = iStart
' This proc reads through the string and picks out a
' pair of brackets. Once we have a pair of brackets we
' have isolated an expression which needs to be
' evaluated before its "parent" expression can be
' evaluated.
Do
sChar = Mid$(sArg, iNum, 1)
If sChar = "(" Then
iBraceCount = iBraceCount + 1
ElseIf sChar = ")" Then
iBraceCount = iBraceCount - 1
If iBraceCount = 0 Then
iFinish = iNum
End If
End If
iNum = iNum + 1
Loop Until (iNum = (Len(sArg) + 1)) Or (iFinish <> 0)
GetNextBracketLayer = Mid$(sArg, iStart, (iFinish - iStart) + 1)
End Function
When called in a semi-recursive fashion, in combination with our simple expression parser, it creates a more comprehensive parser that works with bracketed expressions.
Function ResolveFormula (ByVal sFormula As String) As String
Dim sNextLevel As String
Dim sResult As String
Dim iPos As Integer
' Parses a formula string into a distinct, separately
' resolved expressions. This works sort of recursively,
' with a twist. Actual mathematical evaluation of
' expressions is handled by SimpleExpressionEvaluate.
sResult = sFormula
' Loop through all the subexpressions of the string.
iPos = InStr(sResult, "(") - 1
Do While iPos > -1
sNextLevel = GetNextBracketLayer(sResult)
sResult = StrReplaceAllWith(sResult, sNextLevel,
ResolveFormula(Mid$(sNextLevel, 2, Len(sNextLevel) - 2)))
iPos = InStr(sResult, "(") - 1
Loop
' Perform the calculation represented by the string we
' have.
sResult = SimpleExpressionEvaluate(sResult)
ResolveFormula = sResult
End Function
You will notice that I call a function called StrReplaceAllWith, to do the work of replacing expressions with results within the string. It's a stock library function I keep with me at all times (in case of string emergencies!).
So there you have a mathematical expression parser implemented entirely in VB3. The parser supports the following operators: +, -, /, *, \, and !. The ! operator I implemented for convenience. What it does is return the left operand if the right operand is non-zero, and returns zero if the right operand is zero. For example: 3!57 would return 3, while 3!0 would return 0. Similarly, because the parser is implemented in VB3, you can simply extend its functionality by adding or changing operators (play a joke on your fellow programmers by changing everything to + for a while).
![]()