Image Map of Navigational Panel to Home / Contents / Search Parsing Expressions of Interest

Part II : I'm The Bracket Creep

Image of line

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).


Image of arrow to previous article Image of arrow to previous article

Image of line

[HOME] [TABLE OF CONTENTS] [SEARCH]