@@ -147,6 +147,7 @@ Private Const d_rParenthesis As String = ")"
147147Private Const d_lSquareB As String = " ["
148148Private Const d_rSquareB As String = " ]"
149149Private Const d_Apostrophe As String = "'"
150+ Private Const d_Underscore As String = " _"
150151Private Const d_Space As String = " "
151152Private Const e_ValueError As String = " #VALUE!"
152153Private Const Tiny As Double = 1E-20
@@ -3759,6 +3760,8 @@ End Function
37593760''' < summary>
37603761''' Finds a zero of a univariate function ussing a modified bisection method.
37613762''' aFunction must be a continuous function f(x) for the interval a < = x < = b.
3763+ ''' The function zeroing will be performed on the unassigned variable. If more
3764+ ''' than one variables are unassigned, an error will be returned.
37623765''' < /summary>
37633766''' < param name=" aFunction"> Inline function.< /param>
37643767''' < param name=" a"> Leftmost interval value.< /param>
@@ -3792,13 +3795,16 @@ Private Function fZeroMBM(ByRef aFunction As String, ByVal A As Double, _
37923795 aZero = 10 * epsilon
37933796 With fEvalHelper
37943797 .Create aFunction
3798+ Set .EvalScope = .EvalScope.CopyScope(P_SCOPE)
37953799 tmpVar() = Split(.CurrentVariables, " ; " )
37963800 varLB = LBound(tmpVar)
3797- If UBound(tmpVar) - varLB > 0 Then ' Reject multivariate functions
3801+ If UBound(tmpVar) - varLB > 0 Then ' Check multivariate functions
37983802 For i = varLB To UBound(tmpVar)
37993803 If Not IsConstant(tmpVar(i)) Then
3800- varCounter = varCounter + 1
3801- varIdx = i
3804+ If Not IsAssigned(tmpVar(i)) Then
3805+ varCounter = varCounter + 1
3806+ varIdx = i
3807+ End If
38023808 End If
38033809 Next i
38043810 If varCounter > 1 Then
@@ -3859,13 +3865,16 @@ Private Function fZeroMBM(ByRef aFunction As String, ByVal A As Double, _
38593865 .LetVarValue(tmpVar(varIdx), tmpResult)
38603866 If Round(tmpFzeroEval, Len(CStr(1 / aZero)) - 1) = 0 Then
38613867 If includeVarNames Then
3862- fZeroMBM = ToLiteralString(.CurrentVarValues)
3868+ fZeroMBM = ToLiteralString( _
3869+ tmpVar(varIdx) & d_Space & op_equal _
3870+ & d_Space & tmpResult)
38633871 Else
38643872 fZeroMBM = tmpResult
38653873 End If
38663874 Else
38673875 fZeroMBM = e_ValueError
38683876 End If
3877+ Set P_SCOPE = .EvalScope.CopyToScope
38693878 End With
38703879fZeroMBM_terminate:
38713880 Set fEvalHelper = Nothing
@@ -4528,13 +4537,24 @@ End Function
45284537
45294538Private Function GetLiteralStringGap(startPos As Long, ByRef expression As String) As Variant
45304539 Dim literalStrGap() As Long
4540+ Dim tmpPos1 As Long
4541+ Dim tmpPos2 As Long
45314542 Dim tmpPos As Long
4543+ Dim markerChr As String
45324544 ReDim literalStrGap(0 To 1)
45334545
4534- tmpPos = InStr(startPos, expression, d_Apostrophe)
4546+ tmpPos1 = InStr(startPos, expression, d_Apostrophe)
4547+ tmpPos2 = InStr(startPos, expression, d_Underscore)
4548+ If tmpPos1 < = tmpPos2 Then ' Leftmost one
4549+ tmpPos = tmpPos1
4550+ markerChr = d_Apostrophe
4551+ Else
4552+ tmpPos = tmpPos2
4553+ markerChr = d_Underscore
4554+ End If
45354555 If tmpPos Then
45364556 literalStrGap(0) = tmpPos
4537- literalStrGap(1) = InStr(tmpPos + 1, expression, d_Apostrophe )
4557+ literalStrGap(1) = InStr(tmpPos + 1, expression, markerChr )
45384558 End If
45394559 GetLiteralStringGap = literalStrGap
45404560End Function
@@ -4651,7 +4671,7 @@ Private Function GetOPeratorSymbolPos(ByRef expression As String, _
46514671 Dim tmpResult As Long
46524672
46534673 tmpResult = strVBA.InStrB(StartPosition, expression, OperatorSymbol)
4654- Do While IsSymbolInLiteralString(expression, tmpResult)
4674+ Do While IsSymbolInLiteralString(expression, tmpResult) And tmpResult
46554675 tmpResult = strVBA.InStrB(tmpResult + strVBA.LenB2(OperatorSymbol), expression, OperatorSymbol)
46564676 Loop
46574677 GetOPeratorSymbolPos = tmpResult
@@ -5049,11 +5069,11 @@ Private Sub GetTokenEnd(ByRef expression As String, ByRef startIndex As Long, By
50495069 curChar = strVBA.MidB(expression, outLng, 2)
50505070 ' @--------------------------------------------------------------------
50515071 ' Skip literal strings
5052- If curChar = d_Apostrophe Then
5072+ If curChar = d_Apostrophe Or curChar = d_Underscore Then
50535073 Do
50545074 outLng = outLng + 2
50555075 curChar = strVBA.MidB(expression, outLng, 2)
5056- Loop While curChar <> d_Apostrophe And outLng < lenExpr
5076+ Loop While (( curChar <> d_Apostrophe) Or (curChar <> d_Underscore)) And outLng < lenExpr
50575077 If outLng > = lenExpr Then Exit Sub
50585078 End If
50595079 Do
@@ -5136,11 +5156,11 @@ Private Sub GetTokenStart(ByRef expression As String, ByRef startIndex As Long,
51365156 curChar = strVBA.MidB(expression, outLng, 2)
51375157 ' @--------------------------------------------------------------------
51385158 ' Skip literal strings
5139- If curChar = d_Apostrophe Then
5159+ If curChar = d_Apostrophe Or curChar = d_Underscore Then
51405160 Do
51415161 outLng = outLng - 2
51425162 curChar = strVBA.MidB(expression, outLng, 2)
5143- Loop While curChar <> d_Apostrophe And outLng > 1
5163+ Loop While (( curChar <> d_Apostrophe) Or (curChar <> d_Underscore)) And outLng > 1
51445164 If outLng = 1 Then Exit Sub
51455165 End If
51465166 Do While (strVBA.InStrB(1, op_AllItems, curChar) = 0) And outLng > 1
@@ -5747,6 +5767,10 @@ err_Handler:
57475767 IsArrayAllocated = False
57485768End Function
57495769
5770+ Private Function IsAssigned(aVarName As String) As Boolean
5771+ IsAssigned = (strVBA.LenB(P_SCOPE.VarValue(aVarName)) > 0)
5772+ End Function
5773+
57505774Private Function IsBoolean(ByRef expression As String) As Boolean
57515775 IsBoolean = (expression = " true" )
57525776 If Not IsBoolean Then
@@ -5831,6 +5855,19 @@ Private Function IsExtAlphaNumeric(ByRef Char As String) As Boolean
58315855 End If
58325856End Function
58335857
5858+ Private Function IsInList(ByRef aList As Variant, aValue As String) As Boolean
5859+ Dim i As Long, j As Long
5860+ Dim tmpResult As Boolean
5861+
5862+ i = LBound(aList)
5863+ j = UBound(aList)
5864+ Do
5865+ tmpResult = (FormatLiteralString(CStr(aList(i)), True) = aValue)
5866+ i = i + 1
5867+ Loop While i < = j And Not tmpResult
5868+ IsInList = tmpResult
5869+ End Function
5870+
58345871Private Function IsLetter(ByRef Char As String) As Boolean
58355872 If strVBA.LenB2(Char) Then
58365873 Select Case AscW(Char)
@@ -5858,6 +5895,8 @@ Private Function IsLiteralString(ByRef aString As String) As Boolean
58585895 If aString <> vbNullString Then
58595896 If AscW(aString) = 39 Then ' Apostrophe
58605897 IsLiteralString = (strVBA.InStrB(3, aString, d_Apostrophe) = strVBA.LenB2(aString) - 1)
5898+ ElseIf AscW(aString) = 95 Then ' Underscore
5899+ IsLiteralString = (strVBA.InStrB(3, aString, d_Underscore) = strVBA.LenB2(aString) - 1)
58615900 Else
58625901 IsLiteralString = False
58635902 End If
@@ -5890,17 +5929,14 @@ Private Function IsSavedPredictorName(ByRef aName As String, ByRef aNamesList()
58905929End Function
58915930
58925931Private Function IsSymbolInLiteralString(ByRef expression As String, SymbolPos As Long) As Boolean
5893- Dim flagCounter As Long
58945932 Dim tmpPos As Long
5933+ Dim literalGap() As Long
58955934
5896- tmpPos = strVBA.InStrB(1, expression, d_Apostrophe)
5897- If tmpPos Then
5898- Do While tmpPos < SymbolPos And tmpPos > 0
5899- flagCounter = flagCounter + 1
5900- tmpPos = strVBA.InStrB(tmpPos + 2, expression, d_Apostrophe)
5901- Loop
5902- End If
5903- IsSymbolInLiteralString = flagCounter And 1
5935+ literalGap() = GetLiteralStringGap(1, expression)
5936+ Do While (literalGap(1) < SymbolPos) And (literalGap(1) > 0)
5937+ literalGap() = GetLiteralStringGap(literalGap(1) + 1, expression)
5938+ Loop
5939+ IsSymbolInLiteralString = ((SymbolPos > literalGap(0)) And (SymbolPos < literalGap(1)))
59045940End Function
59055941
59065942Private Function IsTwiceJaggedArr(ByRef arr As Variant, elIdx As Long) As Boolean
@@ -7765,16 +7801,20 @@ Private Sub ParseVariables(ByRef expression As String)
77657801 Do
77667802 tmpChr = strVBA.MidB(expression, curPos, 2)
77677803 varLen = 0
7768- If IsLetter(tmpChr) Or tmpChr = d_Apostrophe Then
7804+ If IsLetter(tmpChr) Or tmpChr = d_Apostrophe Or tmpChr = d_Underscore Then
77697805 varInitPos = curPos
7770- If tmpChr <> d_Apostrophe Then
7806+ If tmpChr <> d_Apostrophe And tmpChr <> d_Underscore Then
77717807 Do
77727808 varLen = varLen + 2
77737809 curPos = curPos + 2
77747810 tmpChr = strVBA.MidB(expression, curPos, 2)
77757811 Loop While IsExtAlphaNumeric(tmpChr) And curPos < lenExpr
77767812 Else
7777- curPos = strVBA.InStrB(varInitPos + 2, expression, d_Apostrophe)
7813+ If tmpChr = d_Apostrophe Then
7814+ curPos = strVBA.InStrB(varInitPos + 2, expression, d_Apostrophe)
7815+ Else
7816+ curPos = strVBA.InStrB(varInitPos + 2, expression, d_Underscore)
7817+ End If
77787818 varLen = curPos - varInitPos + 2
77797819 End If
77807820 If varInitPos > 2 Then
@@ -8626,10 +8666,14 @@ Private Function ReplaceImpliedMult(expression As String) As String
86268666 Dim prevChar As String
86278667 Dim reservedChar As Boolean
86288668 Dim tmpChar As String
8669+ Dim literalGap() As Long
86298670
86308671 LookupPos = 1
86318672 tmpStr = expression
86328673 tmpPos = strVBA.InStrB(LookupPos, tmpStr, d_lParenthesis)
8674+ Do While InLiteralGap(tmpStr, tmpPos) And tmpPos
8675+ tmpPos = strVBA.InStrB(tmpPos + 2, tmpStr, d_lParenthesis)
8676+ Loop
86338677 Do While tmpPos
86348678 If tmpPos > 2 Then
86358679 If strVBA.InStrB(1, op_AllItems, strVBA.MidB(tmpStr, tmpPos - 2, 2)) = 0 Then
@@ -8653,9 +8697,15 @@ Private Function ReplaceImpliedMult(expression As String) As String
86538697 End If
86548698 LookupPos = tmpPos + 4
86558699 tmpPos = strVBA.InStrB(LookupPos, tmpStr, d_lParenthesis)
8700+ Do While InLiteralGap(tmpStr, tmpPos) And tmpPos
8701+ tmpPos = strVBA.InStrB(tmpPos + 2, tmpStr, d_lParenthesis)
8702+ Loop
86568703 Else
86578704 LookupPos = tmpPos + 2
86588705 tmpPos = strVBA.InStrB(LookupPos, tmpStr, d_lParenthesis)
8706+ Do While InLiteralGap(tmpStr, tmpPos) And tmpPos
8707+ tmpPos = strVBA.InStrB(tmpPos + 2, tmpStr, d_lParenthesis)
8708+ Loop
86598709 End If
86608710 Loop
86618711 ReplaceImpliedMult = tmpStr
0 commit comments