home *** CD-ROM | disk | FTP | other *** search
/ Planet Source Code Jumbo …e CD Visual Basic 1 to 7 / 1_2002.ISO / Data / Zips / CODE_UPLOAD227312131999.psc / Evaluator.cls < prev    next >
Encoding:
Visual Basic class definition  |  1999-12-14  |  18.8 KB  |  521 lines

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4.   Persistable = 0  'NotPersistable
  5.   DataBindingBehavior = 0  'vbNone
  6.   DataSourceBehavior  = 0  'vbNone
  7.   MTSTransactionMode  = 0  'NotAnMTSObject
  8. END
  9. Attribute VB_Name = "Evaluator"
  10. Attribute VB_GlobalNameSpace = False
  11. Attribute VB_Creatable = True
  12. Attribute VB_PredeclaredId = False
  13. Attribute VB_Exposed = False
  14. Option Explicit
  15. 'Copyright⌐ 1999, Tretyakov Konstantin
  16. '_____________________________________________________
  17. 'This is the 'Evaluator' class: it inputs a string
  18. 'like "2+2" or "2+4*sin(3.4)^2-8*arccos(0.55)", etc
  19. '_____________________________________________________
  20. 'You may use the code for free, if you give me credit.
  21. 'If you modify it or make your own program with it,
  22. 'I would VERY APPRECIATE, if you mail me it (or better-
  23. 'a link to it)
  24. 'On the whole - just do not stamp your name on what you haven't
  25. 'done quite alone.
  26. 'This code was written totally by me, and 'it took me about
  27. '2 days to code it (and about a year
  28. '-that is,from the very moment I got interested in programming-
  29. 'I spent dreaming of having such a thing)
  30.  
  31. '(BTW this code seems to be quite unique-
  32. 'I searched all over the Internet for such, but NOONE
  33. 'is giving the source for such things)
  34. '______________________________________________________
  35. 'Yours Sincerely, Konstantin Tretyakov (kt_ee@yahoo.com)
  36.  
  37. '********************Here we go...********************
  38. 'Well, at the very beginning (when I had only + and -)
  39. 'These constants didplay a role:
  40. 'e.g. I could change the PLUS_SIGN to "plus"
  41. 'and the MINUS_SIGN to "minus", so that I could
  42. 'write an expression like "1 plus 2 minus 3"
  43. 'But now it will not go. :(
  44. Const PLUS_SIGN = "+"
  45. Const MINUS_SIGN = "-"
  46. Const MULTIPLY_SIGN = "*"
  47. Const DIVIDE_SIGN = "/"
  48. Const POWER_SIGN = "^"
  49. Const POINT_SIGN = ","
  50. Const BRACKET_LEFT = "("
  51. Const BRACKET_RIGHT = ")"
  52.  
  53. 'This is the part to be improved - I mean this error-handling
  54. Public Enum EvalError
  55.     ERR_NONE = 0
  56.     ERR_DBL_POINT = 1
  57.     ERR_WRONG_SYNTAX = 2
  58.     ERR_WRONG_SIGN = 4
  59.     ERR_WRONG_BRACKETS = 8
  60.     ERR_WRONG_FUNCTION = 16
  61. End Enum
  62.  
  63. 'This entry was needed for my other project - Function Analyzer
  64. '(look for it at the same place, where you found this one)
  65. Private m_Assigned As Boolean
  66. 'I hope you get, what these do
  67. Private m_Expression As String
  68. Private m_Result As Double
  69. Private m_Error As EvalError
  70.  
  71. Public Property Let Expression(ByVal NewExpr As String)
  72.     m_Expression = ReplaceText(UCase(RemoveSpaces(NewExpr)), ".", POINT_SIGN)
  73. End Property
  74. Public Property Get Expression() As String
  75.     Expression = m_Expression
  76. End Property
  77. Public Property Get Error() As EvalError
  78.     Error = m_Error
  79. End Property
  80.  
  81. Public Property Get Result() As Double
  82. 'Reset the Error
  83.     m_Error = ERR_NONE
  84. 'Calculate
  85.     m_Result = Eval(m_Expression)
  86.     m_Assigned = (m_Error = ERR_NONE)
  87. 'Return
  88.     Result = m_Result
  89. End Property
  90. Public Property Get Assigned() As Boolean
  91.     Assigned = m_Assigned
  92. End Property
  93. Public Function Evaluate(ByVal Expressn As String, Optional ByVal Silent As Boolean = False) As Double
  94. 'That's the wrapper for the main procedure
  95. 'You may use this class in 2 ways:
  96. '1) Set the 'Expression' property and then read the 'Result' property
  97. '2) Call this sub. If you set Silent to False, then the sub will generate a message automatically
  98.     Dim Res As Double
  99.     Expression = Expressn
  100.     Res = Result
  101.     If Not Silent Then
  102.         If m_Error <> ERR_NONE Then
  103.             Select Case m_Error
  104.                 Case ERR_DBL_POINT:  MsgBox "Error: Wrong decimal separator placement!", vbCritical, "Eval Error"
  105.                 Case ERR_WRONG_BRACKETS: MsgBox "Error: Wrong bracket placement!", vbCritical, "Eval Error"
  106.                 Case ERR_WRONG_SIGN: MsgBox "Error: Wrong sign or bracket placement!", vbCritical, "Eval Error"
  107.                 Case ERR_WRONG_SYNTAX: MsgBox "Error: Wrong syntax!", vbCritical, "Eval Error"
  108.             End Select
  109.         Else
  110.             MsgBox "Result: " & Res, vbExclamation, "Eval Result"
  111.         End If
  112.     End If
  113.     Evaluate = m_Result
  114. End Function
  115.  
  116. '***********************************************************
  117. ' 2 helper functions, well they are too 'universal' for this class
  118. ' (Here we use them only to remove spaces and replace the '.' to ','
  119.  
  120. Private Function RemoveSpaces(S$) As String
  121.     RemoveSpaces = ReplaceText(S$)
  122. End Function
  123.  
  124. Public Function ReplaceText(ByVal SourceText$, Optional ByVal StrToReplace$ = " ", Optional ByVal StrToInsert$ = "") As String
  125.     Dim RetS$, I%
  126.     If StrToReplace = StrToInsert Or StrToReplace = "" Then Exit Function
  127.     RetS = SourceText$
  128.     I = InStr(RetS, StrToReplace)
  129.     Do While I <> 0
  130.         RetS = IIf(I = 1, "", Left(RetS, I - 1)) & StrToInsert$ & IIf(I = Len(RetS) - Len(StrToReplace) + 1, "", Right(RetS, Len(RetS) - I - Len(StrToReplace) + 1))
  131.         I = InStr(RetS, StrToReplace)
  132.     Loop
  133.     ReplaceText = RetS
  134. End Function
  135. '***********************************************************
  136.  
  137. 'The HEART of the class.
  138. 'What it does? - it just splits the expression to monomials
  139. '(that is: 2*3+3^(3-2)-(2+3) has 3 monomials:
  140. '      +2*3,  +3^(3-2)  -(2+3)
  141. 'Then it calls the CalcMonomial for each and sums the result
  142.  
  143. Private Function Eval(ByVal Expr As String) As Double
  144.     Dim sEval$, I&, MonomArray As Variant, dResult As Double
  145.     sEval = Expr
  146.     MonomArray = SplitToMonomials(sEval)
  147.     For I = LBound(MonomArray) To UBound(MonomArray)
  148.         dResult = dResult + CalcMonomial(MonomArray(I))
  149.     Next
  150.     Eval = dResult
  151. End Function
  152.  
  153.  
  154.  
  155. Private Function SplitToMonomials(ByVal EvalStr As String, Optional ByVal Sign1 As String = PLUS_SIGN, Optional ByVal Sign2 As String = MINUS_SIGN) As Variant
  156. 'Divides the given string in parts using the given sign (Sign1 and Sign2) parameter
  157.  
  158. 'Returns an array where each item is a string
  159. 'For example SplitToMonomials("2+3*8-4","+","-") returns [2, +3*8, -4]
  160. '        and SplitToMonomials("3*2/23","*","/") returns [3, *2, /23]
  161.  
  162. 'The function also doesn't split brackets so that
  163. '      SplitToMonominals("(3+2)*2-3","+","-") will return [(3+2)*2, -3]
  164.                             
  165.     Dim MonomArray As Variant, I&, Count&
  166.     Dim CurMonom As String, sEval As String
  167.     ReDim MonomArray(0)
  168.     sEval = EvalStr
  169. 'Find the first PLUS or MINUS (MUL or DIV) that are not in Bracket
  170. '(GetSplitPos is Just an Improved Instr, that considers brackets)
  171.     I = GetSplitPos(EvalStr, Sign1, Sign2)
  172.     Do While I > 0
  173. 'NOT DONE:
  174.         'Check for expressions of a kind: "2-3*4+6*-5"
  175.         'because we must not split between 6 and 5
  176.         CurMonom = Left(sEval, I - 1)
  177. 'Populate the Array
  178.         ReDim Preserve MonomArray(Count)
  179.         MonomArray(Count) = CurMonom
  180.         Count = Count + 1
  181.         sEval = Mid(sEval, I)
  182.         I = GetSplitPos(sEval, Sign1, Sign2)
  183.     Loop
  184.  
  185.     CurMonom = sEval
  186.     ReDim Preserve MonomArray(Count)
  187.     MonomArray(Count) = CurMonom
  188.     SplitToMonomials = MonomArray
  189. End Function
  190.  
  191. 'Calculates a monomial (expression without PLUSes and MINUSes inside)
  192. 'The work is in fact like of the Eval function:
  193. 'We split it to smaller parts (the ones, that may contain only the ^ sign)
  194. 'and then Calculate each part separately
  195. Private Function CalcMonomial(ByVal Monomial As String) As Double
  196.     On Error GoTo ErrCalcMember
  197.     If m_Error <> ERR_NONE Then Exit Function
  198.     Dim MemberArray As Variant, Sign As String
  199.     Dim I&, dResult As Double, TempRes As Double
  200. 'Split again, but now by * and /
  201.     MemberArray = SplitToMonomials(Monomial, MULTIPLY_SIGN, DIVIDE_SIGN)
  202.     For I = LBound(MemberArray) To UBound(MemberArray)
  203.         TempRes = CalcMember(MemberArray(I), Sign)
  204.         Select Case Sign
  205. 'Remember - we may have the Plus_sign left in a monomial
  206. '(like a monomial may be "+2^2*3")
  207.             Case PLUS_SIGN: dResult = dResult + TempRes
  208.             Case MULTIPLY_SIGN: dResult = dResult * TempRes
  209.             Case DIVIDE_SIGN:  dResult = dResult / TempRes
  210.         End Select
  211.     Next
  212.     CalcMonomial = dResult
  213.     Exit Function
  214. ErrCalcMember:
  215.     m_Error = ERR_WRONG_FUNCTION
  216. End Function
  217.  
  218. 'Calculates an expression, that contains only the operands
  219. 'higher in proirity than * and /
  220.  
  221. 'TODO: It raises an error on X^Y^Z and calculates only X^Y,
  222. 'That is, for correct calculation you must specify either (X^Y)^Z
  223. 'or X^(Y^Z) (btw which is right ???)
  224. Private Function CalcMember(ByVal Member As String, ByRef Sign As String) As Double
  225.     Dim sSign As String, sEval As String, HaveMinus As Boolean, GotNum1 As Boolean
  226.     Dim Num1 As Double, Num2 As Double, Op As String, dResult As Double
  227.     Dim Func As String, FuncExpr As String
  228.     If m_Error <> ERR_NONE Then Exit Function
  229.     'Here we calculate the results of operations
  230.     'whose priority is higher than * and /
  231.     'The sample given string may be: "+5^2", "*4^2", "/6", "6^2,3"
  232.                         'or +(expr)^2, or (expr)^(expr)
  233.     Sign = PLUS_SIGN
  234.     sEval = Member
  235.     sSign = Left(sEval, 1)
  236.     'Determine the Sign (or find the Bracket or a function)
  237.     If Not IsNumeric(sSign) Then
  238.         Select Case sSign
  239.             Case MINUS_SIGN
  240.                 HaveMinus = True
  241.                 sEval = Mid(sEval, 2)
  242.                 If Left(sEval, 1) = BRACKET_LEFT Then GoTo LBrack
  243.                 If IsNumeric(Left(sEval, 1)) = False Then GoTo HaveFunc
  244.             Case PLUS_SIGN, MULTIPLY_SIGN, DIVIDE_SIGN
  245.                 Sign = sSign
  246.                 sEval = Mid(sEval, 2)
  247.                 If Left(sEval, 1) = BRACKET_LEFT Then GoTo LBrack
  248.                 If IsNumeric(Left(sEval, 1)) = False Then GoTo HaveFunc
  249.             Case BRACKET_LEFT
  250. LBrack:
  251. 'That's easy - when we find a bracket - we just 'Eval' the expression in the brackets
  252.                 Num1 = Eval(ExtractBrackets(sEval))
  253.                 GotNum1 = True
  254.             Case Else
  255. 'Here Must make some checks for Functions (like when it's SIN(expr))
  256. HaveFunc:
  257.                 Func = ExtractFunction(sEval, FuncExpr)
  258.                 Num1 = CalcFunction(Func, FuncExpr)
  259.                 GotNum1 = True
  260.         End Select
  261.     End If
  262. 'Now Do the Calculation
  263.     If Not GotNum1 Then Num1 = ExtractNumber(sEval)
  264.     If Len(sEval) <> 0 Then
  265.         Op = Left(sEval, 1)
  266.         sEval = Mid(sEval, 2)
  267. 'Check if the second number is a bracketed expression
  268.         If Left(sEval, 1) = BRACKET_LEFT Then
  269.             Num2 = Eval(ExtractBrackets(sEval))
  270.         Else
  271.             If IsNumeric(Left(sEval, 1)) = False Then
  272.                 Func = ExtractFunction(sEval, FuncExpr)
  273.                 Num2 = CalcFunction(Func, FuncExpr)
  274.             Else
  275.                 Num2 = ExtractNumber(sEval)
  276.             End If
  277.         End If
  278.         Select Case Op
  279.             Case POWER_SIGN
  280.                 On Error GoTo ErrCalcMember
  281.                 dResult = Num1 ^ Num2
  282.             Case Else
  283.                 m_Error = ERR_WRONG_SIGN
  284.         End Select
  285.     Else
  286.         dResult = Num1
  287.     End If
  288.     If Len(sEval) <> 0 Then m_Error = ERR_WRONG_SYNTAX
  289.     CalcMember = IIf(HaveMinus, -dResult, dResult)
  290.     Exit Function
  291. ErrCalcMember:
  292.     m_Error = ERR_WRONG_FUNCTION
  293. End Function
  294.  
  295. '***********************************************************
  296. 'This is nearly an equivalent of VAL,
  297. 'only here we may know if there was an error
  298. 'and it also modifies the string by removing the "Extracted" number
  299.  
  300. 'TODO: It doesn't support the "2.34E+2" notation
  301. Private Function ExtractNumber(ByRef EvalExpr$) As Double
  302.     Dim HavePoint As Boolean, I As Integer, NewNum As String
  303.     Dim TempChar As String, TempSign As String, HaveMinus As Boolean
  304.     Dim sEval As String
  305. 'Determine whether there is a sign in front of the string
  306.     TempSign = Left(EvalExpr, 1)
  307.     If TempSign = POINT_SIGN Then
  308.         sEval = "0" & EvalExpr
  309.     Else
  310.         If Not IsNumeric(TempSign) Then
  311.             sEval = Mid(EvalExpr, 2)
  312.             HaveMinus = (TempSign = MINUS_SIGN)
  313.         Else: sEval = EvalExpr
  314.         End If
  315.     End If
  316.     
  317.     For I = 1 To Len(sEval)
  318.         TempChar = Mid(sEval, I, 1)
  319.         If IsNumeric(TempChar) Then
  320.             NewNum = NewNum & TempChar
  321.         Else
  322.             If TempChar = POINT_SIGN Then
  323.                 If HavePoint Then
  324.                 'We have already a point, that's an error
  325.                     m_Error = ERR_DBL_POINT
  326.                     Exit For
  327.                 Else
  328.                     HavePoint = True
  329.                     NewNum = NewNum + "."   'We shall use val in the end
  330.                 End If
  331.             Else
  332.                 Exit For
  333.             End If
  334.         End If
  335.     Next
  336.     If NewNum = "" Then
  337.         m_Error = ERR_WRONG_SYNTAX
  338.     Else    'Cut out the number from the string
  339.         EvalExpr = Mid(sEval, Len(NewNum) + 1)
  340.     End If
  341.     ExtractNumber = IIf(HaveMinus, -Val(NewNum), Val(NewNum))
  342. End Function
  343.  
  344.  
  345. '***********************************************************
  346. 'This is a Helper-func to SplitToMonomials
  347. 'it returns the position in a string of a Sign(1 or 2)
  348. 'it doesn't return the signs that are in brackets and the sign on the 1st place
  349. Private Function GetSplitPos(ByVal EvalStr$, ByVal Sign1$, ByVal Sign2$, Optional StartPos As Integer = 1)
  350.     Dim I%, InBracket%, TempChar$
  351.     
  352.     For I = StartPos To Len(EvalStr$)
  353.         TempChar = Mid(EvalStr, I, 1)
  354.         Select Case TempChar
  355.             Case Sign1, Sign2
  356.                 If InBracket = 0 And I > 1 Then
  357.                     GetSplitPos = I
  358.                     Exit Function
  359.                 End If
  360.             Case BRACKET_LEFT
  361.                 InBracket = InBracket + 1
  362.             Case BRACKET_RIGHT
  363.                 InBracket = InBracket - 1
  364.                 If InBracket < 0 Then
  365.                     m_Error = ERR_WRONG_BRACKETS
  366.                     Exit Function
  367.                 End If
  368.         End Select
  369.     Next
  370. End Function
  371.  
  372. 'Gets a String, beginning with a Left Bracket and
  373. 'returns the expression in this bracket
  374. 'deletes this expression(with both brackets) from the string
  375. Private Function ExtractBrackets(ByRef EvalExpr As String) As String
  376.     Dim InBracket%, I&, TempChar$, RetStr$
  377.     'We Suppose that the first sign in the string is BRACKET_LEFT
  378.     InBracket = 1
  379.     For I = 2 To Len(EvalExpr)
  380.         TempChar = Mid(EvalExpr, I, 1)
  381.         Select Case TempChar
  382.             Case BRACKET_LEFT
  383.                 InBracket = InBracket + 1
  384.             Case BRACKET_RIGHT
  385.                 InBracket = InBracket - 1
  386.         End Select
  387.         If InBracket = 0 Then
  388.             RetStr = Mid(EvalExpr, 2, I - 2)
  389.             EvalExpr = Mid(EvalExpr, I + 1)
  390.             ExtractBrackets = RetStr
  391.             Exit Function
  392.         End If
  393.     Next
  394.     m_Error = ERR_WRONG_BRACKETS
  395. End Function
  396.  
  397. 'Process the expression "FUNC(expr)"
  398. 'Returns "FUNC"
  399. Private Function ExtractFunction(ByRef EvalExpr As String, ByRef FuncExpr As String)
  400.     Dim FuncID As String, I&
  401.     I = InStr(EvalExpr, BRACKET_LEFT)
  402.     If I = 0 Then
  403.         m_Error = ERR_WRONG_SYNTAX
  404.         Exit Function
  405.     Else
  406.         ExtractFunction = Left(EvalExpr, I - 1)
  407.         EvalExpr = Mid(EvalExpr, I)
  408.         FuncExpr = ExtractBrackets(EvalExpr)
  409.     End If
  410. End Function
  411.  
  412. 'You give it a function name and an expression in the brackets after it
  413. 'as 2 separate strings, and it calculates
  414. 'ADD ANY of the Functions you like
  415. '(E.G. it's interesting to add some 'acting' functions, like, say, MsgBox :)
  416. 'Then there are only several steps towards your own Script-Language
  417. Private Function CalcFunction(ByVal FunctionID As String, ByVal FuncExpr As String) As Double
  418.     On Error GoTo ErrCalc
  419.     If m_Error <> ERR_NONE Then Exit Function
  420.     Dim Arg As Double
  421.     Arg = Eval(FuncExpr)
  422.     Select Case FunctionID
  423.         Case "ABS"
  424.             CalcFunction = Abs(Arg)
  425.         Case "ATN"
  426.             CalcFunction = Atn(Arg)
  427.         Case "COS"
  428.             CalcFunction = Cos(Arg)
  429.         Case "EXP"
  430.             CalcFunction = Exp(Arg)
  431.         Case "FIX"
  432.             CalcFunction = Fix(Arg)
  433.         Case "INT"
  434.             CalcFunction = Int(Arg)
  435.         Case "LOG"
  436.             CalcFunction = Log(Arg)
  437.         Case "RND"
  438.             CalcFunction = Rnd(Arg)
  439.         Case "SGN"
  440.             CalcFunction = Sgn(Arg)
  441.         Case "SIN"
  442.             CalcFunction = Sin(Arg)
  443.         Case "SQR"
  444.             CalcFunction = Sqr(Arg)
  445.         Case "TAN"
  446.             CalcFunction = Tan(Arg)
  447.     'Derived
  448.         Case "SEC"
  449.             CalcFunction = 1 / Cos(Arg)
  450.         Case "COSEC"
  451.             CalcFunction = 1 / Sin(Arg)
  452.         Case "COTAN"
  453.             CalcFunction = 1 / Tan(Arg)
  454.         Case "ARCSIN"
  455.             CalcFunction = Atn(Arg / Sqr(-Arg * Arg + 1))
  456.         Case "ARCCOS"
  457.             CalcFunction = Atn(-Arg / Sqr(-Arg * Arg + 1)) + 2 * Atn(1)
  458.         Case "ARCSEC"
  459.             CalcFunction = Atn(Arg / Sqr(Arg * Arg - 1)) + Sgn(Arg - 1) * (2 * Atn(1))
  460.         Case "ARCCOSEC"
  461.             CalcFunction = Atn(Arg / Sqr(Arg * Arg - 1)) + (Sgn(Arg) - 1) * (2 * Atn(1))
  462.         Case "ARCCOTAN"
  463.             CalcFunction = Atn(Arg) + 2 * Atn(1)
  464.         Case "HSIN"
  465.             CalcFunction = (Exp(Arg) - Exp(-Arg)) / 2
  466.         Case "HCOS"
  467.             CalcFunction = (Exp(Arg) + Exp(-Arg)) / 2
  468.         Case "HTAN"
  469.             CalcFunction = (Exp(Arg) - Exp(-Arg)) / (Exp(Arg) + Exp(-Arg))
  470.         Case "HSEC"
  471.             CalcFunction = 2 / (Exp(Arg) + Exp(-Arg))
  472.         Case "HCOSEC"
  473.             CalcFunction = 2 / (Exp(Arg) - Exp(-Arg))
  474.         Case "HCOTAN"
  475.             CalcFunction = (Exp(Arg) + Exp(-Arg)) / (Exp(Arg) - Exp(-Arg))
  476.         Case "HARCSIN"
  477.             CalcFunction = Log(Arg + Sqr(Arg * Arg + 1))
  478.         Case "HARCCOS"
  479.             CalcFunction = Log(Arg + Sqr(Arg * Arg - 1))
  480.         Case "HARCTAN"
  481.             CalcFunction = Log((1 + Arg) / (1 - Arg)) / 2
  482.         Case "HARCSEC"
  483.             CalcFunction = Log((Sqr(-Arg * Arg + 1) + 1) / Arg)
  484.         Case "HARCCOSEC"
  485.             CalcFunction = Log((Sgn(Arg) * Sqr(Arg * Arg + 1) + 1) / Arg)
  486.         Case "HARCCOTAN"
  487.             CalcFunction = Log((Arg + 1) / (Arg - 1)) / 2
  488. 'Not Math functions, but also useful
  489.         Case "TIMER"
  490.             CalcFunction = Timer
  491.         Case "YEAR"
  492.             CalcFunction = Year(Now)
  493.         Case "MONTH"
  494.             CalcFunction = Month(Now)
  495.         Case "DAY"
  496.             CalcFunction = Day(Now)
  497.         Case "WEEKDAY"
  498.             CalcFunction = Weekday(Now)
  499.         Case "HOUR"
  500.             CalcFunction = Hour(Time)
  501.         Case "MINUTE"
  502.             CalcFunction = Minute(Time)
  503.         Case "SECOND"
  504.             CalcFunction = Second(Time)
  505. 'These should be constants, but here you must use them as functions
  506. '(i.e. with an argument, no matter what)
  507.         Case "PI"
  508.             CalcFunction = 3.14159265358979
  509.         Case "E"
  510.             CalcFunction = 2.71828182845905
  511.         Case "ZERO"
  512.             CalcFunction = 0
  513.         Case Else
  514.             m_Error = ERR_WRONG_SYNTAX
  515.     End Select
  516.  Exit Function
  517. ErrCalc:
  518.  m_Error = ERR_WRONG_FUNCTION
  519. End Function
  520.  
  521.