Calculator with Expression Parcer - Visual Basic Source Code

Back to: Main Programming Page

This is an uncompleted project to make a decent calculator program with expression parsing. It allowed you to enter in an expression, such as "(3+2)*6", then hit enter to see the answer. The project kind of fizzled out when I realized that it's easier to just use my TI-85 for simple calculations, and Excel for more complex calculations. But I include the uncompleted program here because I did get the expression parser to work, which is a bit of code that could be useful for someone that's wanting to write their own calculator program.

 

Source Code:

FormCalculator:
FormCalculator Screenshot
Dim string1 As String
Dim value1 As Single
Dim ctr As Integer
Dim Equation() As String
Dim EquationLength As Integer
Dim ErrorCodes() As String
Private Sub Command1_Click()
  Call CountFunc
End Sub
Private Sub CountFunc()
  ctr = ctr + 1
  TextOutput.Text = TextOutput.Text + vbCrLf + Str(ctr)
  If ctr < 10 Then
    Call CountFunc
  End If
End Sub

Private Sub Command2_Click()
  test = 5
  string1 = "(3 + 2)*5"
  Call MathParser.EvaluateString(string1, Value, ErrorCodes())
  NumberErrors = Val(ErrorCodes(0, 0))
  If NumberErrors = 0 Then
    TextOutput.Text = string1 + vbCrLf + Str(Value) + vbCrLf + vbCrLf + TextOutput.Text
  Else
    TempString = "Error"
    For ctr = 1 To NumberErrors
      TempString = TempString + vbCrLf + "  " + ErrorCodes(ctr, 0)
      TempString = TempString + ", " + ErrorCodes(ctr, 1)
      TempString = TempString + ", " + Chr$(34) + ErrorCodes(ctr, 2) + Chr$(34)
    Next ctr
    TextOutput.Text = TempString + vbCrLf + vbCrLf + TextOutput.Text
  End If
End Sub

Private Sub EvaluateString2(somevar)
  somevar = somevar + 1
End Sub

Private Sub Form_Load()
  TextInput.Text = "Enter Expression Here"
  TextInput.SelStart = 0
  TextInput.SelLength = Len(TextInput.Text)
'    TextInput.SetFocus
End Sub

Private Sub TextInput_KeyUp(KeyCode As Integer, Shift As Integer)
  Dim EqString As String
  If KeyCode = vbKeyReturn Then
    TestString = TextInput.Text
    EqString = ""
        
    'Remove returns
    For ctr = 1 To Len(TextInput.Text)
      TestChar = Mid(TextInput.Text, ctr, 1)
      If Asc(TestChar) = 13 Or Asc(TestChar) = 10 Then
        EqString = EqString + ""
      Else
        EqString = EqString + TestChar
      End If
    Next ctr
    TextInput.Text = EqString

    TextInput.SelStart = 0
    TextInput.SelLength = Len(TextInput.Text)
    
    If Len(EqString) > 0 Then
      Call MathParser.EvaluateString(EqString, Value, ErrorCodes())
      NumberErrors = Val(ErrorCodes(0, 0))
      If NumberErrors = 0 Then
        TextOutput.Text = EqString + vbCrLf + Str(Value) + vbCrLf + vbCrLf + TextOutput.Text
      Else
        TempString = "Error"
        For ctr = 1 To NumberErrors
          TempString = TempString + vbCrLf + "  " + ErrorCodes(ctr, 0)
          TempString = TempString + ", " + ErrorCodes(ctr, 1)
          TempString = TempString + ", " + Chr$(34) + ErrorCodes(ctr, 2) + Chr$(34)
        Next ctr
        TextOutput.Text = TempString + vbCrLf + vbCrLf + TextOutput.Text
      End If
    End If
  End If
End Sub

Module- MathParser:
Option Explicit
Dim Eq() As String
Dim Parsed As Boolean
Dim EqLength As Integer
Dim ErrorCodes As String
Dim Errors() As String  '(0,0)- Number Errors, 0 - Error Code, 1 - Message, 2 - StartLoc, 3 - StopLoc

Public Sub EvaluateString(EqString As String, Value, ErrorCodes() As String)
  Dim ctr As Integer
  Dim ctr2 As Integer
  Dim TempString As String
  Dim TestChar As String
  
  'Do some initial processing to remove all spaces
  For ctr = 1 To Len(EqString)
    TestChar = Mid(EqString, ctr, 1)
    If TestChar <> " " Then
      TempString = TempString + TestChar
    End If
  Next ctr
  EqString = TempString

  'Initialize Variables
  ReDim Preserve Errors(3, 0) As String
  Errors(0, 0) = 0

  'Call ParseEquation(EqString)
  Call ParseToArray(EqString)
  
  If Parsed Then
    Call Evaluate(1, EqLength, Value)
  End If
  
  'If no errors, retype original equation as parsed equation
  If Val(Errors(0, 0)) = 0 Then
    EqString = ""
    For ctr = 1 To EqLength
      Select Case Eq(1, ctr)
        Case "+"
          EqString = EqString + " + "
        Case "-"
          EqString = EqString + " - "
        Case Else
          EqString = EqString + Eq(1, ctr)
      End Select
    Next ctr
  End If
    ReDim ErrorCodes(Val(Errors(0, 0)), 2)
    ErrorCodes(0, 0) = Errors(0, 0)
    For ctr = 1 To Val(Errors(0, 0))
      For ctr2 = 0 To 1
        ErrorCodes(ctr, ctr2) = Errors(ctr2, ctr)
      Next ctr2
      For ctr2 = Val(Errors(2, ctr)) To Val(Errors(3, ctr))
        ErrorCodes(ctr, 2) = ErrorCodes(ctr, 2) + Eq(1, ctr2)
      Next ctr2
    Next ctr
  'End If
  If Not Parsed Then
    EqString = TempString
  End If
End Sub

Private Sub Evaluate(StartLoc As Integer, StopLoc As Integer, Value)
  Dim ContEval As Boolean
  Dim ContCheck As Boolean
  Dim OpenPar As Integer
  Dim ClosedPar As Integer
  Dim NumErrs As Integer
  Dim ctr As Integer
  Dim LeftValue As Single
  Dim RightValue As Single
  Dim TestChar As String
  
  ContEval = True
  
  'If enclosed in parentheses, check to make sure that only one expression, then
  'evaluate the expression in between
  If ContEval And (Eq(1, StartLoc) = "(" Or Eq(1, StartLoc) = "[") And (Eq(1, StopLoc) = ")" Or Eq(1, StopLoc) = "]") Then
    ContEval = False
    OpenPar = 0
    For ctr = StartLoc To (StopLoc - 1)
      Select Case Eq(1, ctr)
        Case "("
          OpenPar = OpenPar + 1
          
        Case ")"
          OpenPar = OpenPar - 1

        Case "["
          OpenPar = OpenPar + 1
          
        Case "]"
          OpenPar = OpenPar - 1
      End Select
      If OpenPar = 0 Then 'parentheses have enclosed an expression
        ContEval = True
      End If
    Next ctr
    If Not ContEval Then 'never found a parentheses enclosing an expression
      If StopLoc > (StartLoc + 1) Then
        Call Evaluate(StartLoc + 1, StopLoc - 1, Value)
      Else
        'Assign Error Code
        NumErrs = Val(Errors(0, 0))
        NumErrs = NumErrs + 1
        ReDim Preserve Errors(3, NumErrs)
        Errors(0, 0) = NumErrs
        Errors(0, NumErrs) = "02"
        Errors(1, NumErrs) = "Bad parentheses"
        Errors(2, NumErrs) = StartLoc
        Errors(3, NumErrs) = StopLoc
        Value = 1 'Standard value for an error
      End If
    End If
  End If
  
  'If only one element long, look to see if it's a number or a defined variable
  If ContEval And StartLoc = StopLoc Then
    If Eq(0, StartLoc) = "N" Then
      Value = Val(Eq(1, StartLoc))
    Else
      'Look for variables.  If not a defined variable, assign an error code
      NumErrs = Val(Errors(0, 0))
      NumErrs = NumErrs + 1
      ReDim Preserve Errors(3, NumErrs)
      Errors(0, 0) = NumErrs
      Errors(0, NumErrs) = "01"
      Errors(1, NumErrs) = "Variable not defined or character out of place"
      Errors(2, NumErrs) = StartLoc
      Errors(3, NumErrs) = StopLoc
      Value = 1 'Standard value for an error
    End If
    ContEval = False
  End If
  
  'Look for a + sign
  ctr = StartLoc - 1
  ContCheck = True
  OpenPar = 0
  Do While ContEval And ContCheck
    ctr = ctr + 1
    TestChar = Eq(1, ctr)
    Select Case Eq(1, ctr)
      Case "("
        OpenPar = OpenPar + 1
        
      Case ")"
        OpenPar = OpenPar - 1
        
      Case "["
        OpenPar = OpenPar + 1
        
      Case "]"
        OpenPar = OpenPar - 1
        
      Case "+"
        If OpenPar = 0 And ctr <> StartLoc Then
          Call Evaluate(StartLoc, ctr - 1, LeftValue)
          Call Evaluate(ctr + 1, StopLoc, RightValue)
          Value = LeftValue + RightValue
          ContEval = False
          ContCheck = False
        End If
    End Select

    If OpenPar < 0 Then
      'Assign Error Code
      NumErrs = Val(Errors(0, 0))
      NumErrs = NumErrs + 1
      ReDim Errors(3, NumErrs)
      Errors(0, 0) = NumErrs
      Errors(0, NumErrs) = "02"
      Errors(1, NumErrs) = "Bad parentheses"
      Errors(2, NumErrs) = StartLoc
      Errors(3, NumErrs) = StopLoc
      Value = 1 'Standard value for an error
    End If
    
    If ctr = (StopLoc - 1) Then  'Stop the loop at the character one before the end of the expression
      ContCheck = False
    End If
  Loop
  
  'Look for a - sign
  ctr = StartLoc - 1
  ContCheck = True
  OpenPar = 0
  Do While ContEval And ContCheck
    ctr = ctr + 1  'note that the first loop starts at the second character of the expression
    Select Case Eq(1, ctr)
      Case "("
        OpenPar = OpenPar + 1
        
      Case ")"
        OpenPar = OpenPar - 1
        
      Case "["
        OpenPar = OpenPar + 1
        
      Case "]"
        OpenPar = OpenPar - 1
        
      Case "-"
        If OpenPar = 0 And ctr <> StartLoc Then
          Call Evaluate(StartLoc, ctr - 1, LeftValue)
          Call Evaluate(ctr + 1, StopLoc, RightValue)
          Value = LeftValue - RightValue
          ContEval = False
          ContCheck = False
        End If
    End Select

    If OpenPar < 0 Then
      'Assign Error Code
      NumErrs = Val(Errors(0, 0))
      NumErrs = NumErrs + 1
      ReDim Preserve Errors(3, NumErrs)
      Errors(0, 0) = NumErrs
      Errors(0, NumErrs) = "02"
      Errors(1, NumErrs) = "Bad parentheses"
      Errors(2, NumErrs) = StartLoc
      Errors(3, NumErrs) = StopLoc
      Value = 1 'Standard value for an error
    End If
    
    If ctr = (StopLoc - 1) Then  'Stop the loop at the character one before the end of the expression
      ContCheck = False
    End If
  Loop
  
  'Look for a * sign
  ctr = StartLoc - 1
  ContCheck = True
  OpenPar = 0
  Do While ContEval And ContCheck
    ctr = ctr + 1  'note that the first loop starts at the second character of the expression
    TestChar = Eq(1, ctr)
    Select Case Eq(1, ctr)
      Case "("
        OpenPar = OpenPar + 1
        
      Case ")"
        OpenPar = OpenPar - 1

      Case "["
        OpenPar = OpenPar + 1
        
      Case "]"
        OpenPar = OpenPar - 1
        
      Case "*"
        If OpenPar = 0 And ctr <> StartLoc Then
          Call Evaluate(StartLoc, ctr - 1, LeftValue)
          Call Evaluate(ctr + 1, StopLoc, RightValue)
          LeftValue = LeftValue
          Value = LeftValue * RightValue
          ContEval = False
          ContCheck = False
        End If
    End Select

    If OpenPar < 0 Then
      Call Evaluate(StartLoc, ctr - 1, LeftValue)
      Call Evaluate(ctr + 1, StopLoc, RightValue)
      Value = LeftValue + RightValue
      ContEval = False
      ContCheck = False

      'Assign Error Code
      NumErrs = Val(Errors(0, 0))
      NumErrs = NumErrs + 1
      ReDim Preserve Errors(3, NumErrs)
      Errors(0, 0) = NumErrs
      Errors(0, NumErrs) = "02"
      Errors(1, NumErrs) = "Bad parentheses"
      Errors(2, NumErrs) = StartLoc
      Errors(3, NumErrs) = StopLoc
      Value = 1 'Standard value for an error
    End If
    
    If ctr = (StopLoc - 1) Then  'Stop the loop at the character one before the end of the expression
      ContCheck = False
    End If
  Loop
  
  'Look for a / sign
  ctr = StartLoc - 1
  ContCheck = True
  OpenPar = 0
  Do While ContEval And ContCheck
    ctr = ctr + 1  'note that the first loop starts at the second character of the expression
    Select Case Eq(1, ctr)
      Case "("
        OpenPar = OpenPar + 1
        
      Case ")"
        OpenPar = OpenPar - 1

      Case "["
        OpenPar = OpenPar + 1
        
      Case "]"
        OpenPar = OpenPar - 1
        
      Case "/"
        If OpenPar = 0 And ctr <> StartLoc Then
          Call Evaluate(StartLoc, ctr - 1, LeftValue)
          Call Evaluate(ctr + 1, StopLoc, RightValue)
          If RightValue <> 0 Then
  Value = LeftValue / RightValue
          Else
  'Assign Error Code
  NumErrs = Val(Errors(0, 0))
  NumErrs = NumErrs + 1
  ReDim Preserve Errors(3, NumErrs)
  Errors(0, 0) = NumErrs
  Errors(0, NumErrs) = "03"
  Errors(1, NumErrs) = "Divide By Zero"
  Errors(2, NumErrs) = StartLoc
  Errors(3, NumErrs) = StopLoc
  Value = 1 'Standard value for an error
          End If
          ContEval = False
          ContCheck = False
        End If
    End Select

    If OpenPar < 0 Then
      Call Evaluate(StartLoc, ctr - 1, LeftValue)
      Call Evaluate(ctr + 1, StopLoc, RightValue)
      Value = LeftValue + RightValue
      ContEval = False
      ContCheck = False

      'Assign Error Code
      NumErrs = Val(Errors(0, 0))
      NumErrs = NumErrs + 1
      ReDim Preserve Errors(3, NumErrs)
      Errors(0, 0) = NumErrs
      Errors(0, NumErrs) = "02"
      Errors(1, NumErrs) = "Bad parentheses"
      Errors(2, NumErrs) = StartLoc
      Errors(3, NumErrs) = StopLoc
      Value = 1 'Standard value for an error
    End If
    
    If ctr = (StopLoc - 1) Then  'Stop the loop at the character one before the end of the expression
      ContCheck = False
    End If
  Loop
  
  'Look for a ^
  ctr = StartLoc - 1
  ContCheck = True
  OpenPar = 0
  Do While ContEval And ContCheck
    ctr = ctr + 1  'note that the first loop starts at the second character of the expression
    TestChar = Eq(1, ctr)
    Select Case Eq(1, ctr)
      Case "("
        OpenPar = OpenPar + 1
        
      Case ")"
        OpenPar = OpenPar - 1

      Case "["
        OpenPar = OpenPar + 1
        
      Case "]"
        OpenPar = OpenPar - 1
        
      Case "^"
        If OpenPar = 0 And ctr <> StartLoc Then
          Call Evaluate(StartLoc, ctr - 1, LeftValue)
          Call Evaluate(ctr + 1, StopLoc, RightValue)
          Value = LeftValue ^ RightValue
          ContEval = False
          ContCheck = False
        End If
    End Select

    If OpenPar < 0 Then
      Call Evaluate(StartLoc, ctr - 1, LeftValue)
      Call Evaluate(ctr + 1, StopLoc, RightValue)
      Value = LeftValue + RightValue
      ContEval = False
      ContCheck = False

      'Assign Error Code
      NumErrs = Val(Errors(0, 0))
      NumErrs = NumErrs + 1
      ReDim Preserve Errors(3, NumErrs)
      Errors(0, 0) = NumErrs
      Errors(0, NumErrs) = "02"
      Errors(1, NumErrs) = "Bad parentheses"
      Errors(2, NumErrs) = StartLoc
      Errors(3, NumErrs) = StopLoc
      Value = 1 'Standard value for an error
    End If
    
    If ctr = (StopLoc - 1) Then  'Stop the loop at the character one before the end of the expression
      ContCheck = False
    End If
  Loop
  
  'Check StopLoc for !
  
  'Check to see if a standard function
  If ContEval Then
    TestChar = LCase(Eq(1, StartLoc))
    Select Case LCase(Eq(1, StartLoc))
      Case "sin"
        Eq(1, StartLoc) = LCase(Eq(1, StartLoc))
        Call Evaluate(StartLoc + 1, StopLoc, RightValue)
        Value = Sin(RightValue * 3.14159 / 180)
        ContEval = False
      Case "cos"
        Eq(1, StartLoc) = LCase(Eq(1, StartLoc))
        Call Evaluate(StartLoc + 1, StopLoc, RightValue)
        Value = Cos(RightValue * 3.14159 / 180)
        ContEval = False
      Case "tan"
        Eq(1, StartLoc) = LCase(Eq(1, StartLoc))
        Call Evaluate(StartLoc + 1, StopLoc, RightValue)
        Value = Tan(RightValue * 3.14159 / 180)
        ContEval = False
    End Select
  End If 'ContEval
  'Check to see if a user defined function
  
  'Error Code
  If ContEval Then
    NumErrs = Val(Errors(0, 0))
    NumErrs = NumErrs + 1
    ReDim Preserve Errors(3, NumErrs)
    Errors(0, 0) = NumErrs
    Errors(0, NumErrs) = "00"
    Errors(1, NumErrs) = "Bad Expression"
    Errors(2, NumErrs) = StartLoc
    Errors(3, NumErrs) = StopLoc
    Value = 1 'Standard value for an error
  End If
End Sub

Private Sub ParseEquation(EqString As String)
  Dim TestChar As String
  Dim CharType As String
  Dim PrevCharType As String
  Dim StringLength As Integer
  Dim ctrEquation As Integer
  Dim continueParsing As Boolean
  Dim ctr As Integer
  Dim ElementLength As Integer
  Dim continue As Boolean
  Dim DecimalCount As Integer
  Dim NumErrs As Integer
  
  StringLength = Len(EqString)
  ctrEquation = 0
  continueParsing = True
  ReDim Preserve Eq(2, 1)
  
  Do While continueParsing = True
    ctrEquation = ctrEquation + 1
    ReDim Preserve Eq(2, ctrEquation)
    ctr = 0
    ElementLength = 0
    continue = True
    DecimalCount = 0
    Parsed = True
   
    'Do the loop
    Do
      ctr = ctr + 1
      TestChar = LCase(Mid(EqString, ctr, 1))
      PrevCharType = CharType
      If Asc(TestChar) >= 97 And Asc(TestChar) <= 122 Then
        CharType = "L" 'letter
      ElseIf Asc(TestChar) >= 48 And Asc(TestChar) <= 57 Or TestChar = "." Or TestChar = "," Then
        CharType = "N" 'number
        If TestChar = "." Then
          DecimalCount = DecimalCount + 1
        End If
        If DecimalCount > 1 Then
          continue = False
          continueParsing = False
          NumErrs = Val(Errors(0, 0))
          NumErrs = NumErrs + 1
          ReDim Preserve Errors(3, NumErrs)
          Errors(0, 0) = NumErrs
          Errors(0, NumErrs) = "02"
          Errors(1, NumErrs) = "Invalid Number"
          Parsed = False
        End If
      Else
        CharType = "S" 'symbol
        continue = False
      End If
      If ctr > 1 And CharType <> PrevCharType Then
        continue = False
      End If
      If ctr = Len(EqString) Then
        continue = False
      End If
    Loop Until Not continue
    
    If ctr <> Len(EqString) Then
      If CharType = "S" And ctr = 1 Then
        Eq(0, ctrEquation) = PrevCharType
        Eq(1, ctrEquation) = Left(EqString, ctr)
        EqString = Right(EqString, Len(EqString) - ctr)
      Else
        Eq(0, ctrEquation) = PrevCharType
        Eq(1, ctrEquation) = Left(EqString, ctr - 1)
        EqString = Right(EqString, Len(EqString) - ctr + 1)
      End If
    ElseIf ctr = 1 Then 'only one character left
      Eq(0, ctrEquation) = CharType
      Eq(1, ctrEquation) = EqString
      continueParsing = False
    ElseIf PrevCharType = CharType Then 'two characters together are the same
      Eq(0, ctrEquation) = CharType
      Eq(1, ctrEquation) = Left(EqString, ctr)
      continueParsing = False
      'EqString = Right(EqString, Len(EqString))
    Else 'last character is different
      Eq(0, ctrEquation) = PrevCharType
      Eq(1, ctrEquation) = Left(EqString, ctr - 1)
      EqString = Right(EqString, Len(EqString) - ctr + 1)
      
      ctrEquation = ctrEquation + 1 'only one character left
      Eq(0, ctrEquation) = CharType
      Eq(1, ctrEquation) = EqString
      continueParsing = False
      'EqString = Right(EqString, Len(EqString) - ctr)
    End If
    If Len(EqString) = 0 Then
      continueParsing = False
    End If
  Loop
  EqLength = ctrEquation
  Eq(0, 0) = EqLength
  FormCalculator.TextDebug.Text = ""
  For ctr = 1 To EqLength
    FormCalculator.TextDebug.Text = FormCalculator.TextDebug.Text + Eq(0, ctr) + ", " + Eq(1, ctr) + vbCrLf
  Next ctr
End Sub

Private Sub ParseToArray(EqString As String)
  Dim TestChar As String
  Dim CharType As String
  Dim PrevCharType As String
  Dim StringLength As Integer
  Dim ctrEquation As Integer
  Dim continueEquation As Boolean
  Dim continueElement As Boolean
  Dim ctr As Integer
  Dim ElementLength As Integer
  Dim DecimalCount As Integer
  Dim NumErrs As Integer
  
  StringLength = Len(EqString)
  ctrEquation = 0
  continueEquation = True
  ReDim Preserve Eq(2, 1)
  
  Do While continueEquation = True
    ctrEquation = ctrEquation + 1
    ReDim Preserve Eq(2, ctrEquation)
    continueElement = True
    ctr = 0
    ElementLength = 0
    DecimalCount = 0
    Parsed = True
   
    'Do the loop
    Do While continueElement
      ctr = ctr + 1
      
      If ctr > Len(EqString) Then
        CharType = "EOE" 'End of Equation
        continueEquation = False
      Else
        TestChar = LCase(Mid(EqString, ctr, 1))
        If Asc(TestChar) >= 97 And Asc(TestChar) <= 122 Then
          CharType = "L" 'letter
        ElseIf Asc(TestChar) >= 48 And Asc(TestChar) <= 57 Or TestChar = "." Or TestChar = "," Then
          CharType = "N" 'number
          If TestChar = "." Then
  DecimalCount = DecimalCount + 1
          End If
          If DecimalCount > 1 Then
  continueElement = False
  continueEquation = False
  NumErrs = Val(Errors(0, 0))
  NumErrs = NumErrs + 1
  ReDim Preserve Errors(3, NumErrs)
  Errors(0, 0) = NumErrs
  Errors(0, NumErrs) = "02"
  Errors(1, NumErrs) = "Invalid Number"
  Parsed = False
          End If
        Else
          CharType = "S" 'symbol
        End If
      End If 'ctr > Len(EqString)

      If CharType <> PrevCharType And ctr > 1 Then
        continueElement = False
        Eq(0, ctrEquation) = PrevCharType
        Eq(1, ctrEquation) = Left(EqString, ctr - 1)
      ElseIf CharType = "S" Then
        continueElement = False
        Eq(0, ctrEquation) = CharType
        Eq(1, ctrEquation) = Left(EqString, ctr)
        ctr = ctr + 1 'adding one to make the shorten string line below work properly, without
            'having to have an if statement there
        If Len(EqString) = 1 Then
          CharType = "EOE"
          continueEquation = False
        End If
      End If
      PrevCharType = CharType
    Loop 'continueElement
    If CharType <> "EOE" Then
      EqString = Right(EqString, Len(EqString) - (ctr - 1))
    End If
  Loop 'continueEquation
  EqLength = ctrEquation
  Eq(0, 0) = EqLength
  FormCalculator.TextDebug.Text = ""
  For ctr = 1 To EqLength
    FormCalculator.TextDebug.Text = FormCalculator.TextDebug.Text + Eq(0, ctr) + ", " + Eq(1, ctr) + vbCrLf
  Next ctr
End Sub