why dont you use split function?
msg = "SPLIT" & vbCrLf
s = "X,14,Sin(12)*56/i,12"
s = Split(s, ",")
For i = 0 To UBound(s)
msg = msg & "s(" & i & ") = " & s(i) & vbCrLf
Next
msg = msg & vbCrLf & "ParseArguments()" & vbCrLf
s = "X,14,Sin(12)*56/i,12"
s = ParseArguments(s)
For i = 0 To UBound(s)
msg = msg & "s(" & i & ") = " & s(i) & vbCrLf
Next
MsgBox msg
i tested out and both return same result, or is it you are writing an optimized version of microsoft split?
I'm not using split because it doesn't work.
tell me what the string "34,Sin(1),RANDOM(1,4)" returns.
the desired output is {"34","Sin(1)","RANDOM(1,4)"}, but split decides otherwise.
the reason is of course that it cares not for brackets, so I keep track of the number of open brackets as I proceed through, and also the number of quotes (again- Split cares not for quotes)
As usual, I have no idea of what you are doing. I do better with 'top down' programming. Perhaps you are using queue/stack solution.
This item: "Sin(12)*56/i"
would suggest that yup need an expression evaluator and maybe a floating pint match kit. I will comment on the expression evaluator. This kind of expression is often called a left to right evaluation, but with FORTRAN rules. Which means that he parser is cgoing to to do some look ahead or even read the thing right to left.
But going going left to right, we parse SIM and determine that is a function we know, will put a token, perhaps a pointer, into a queue (read stack) to identify that item. Next we look inside the left _( and find a constant and next find the right_) Now can call SIM with the value. Next find an atom the denotes multiply, so will queue that with the value return by SIM. We find a constant and an atom for divide, lower precedence, so perform what we now have in the queue. Note that divide is coming. Queue it. Next is looks like a variable, go get its value... and so one.
Anyway. I would use an expression evaluator made by somebody else But this is not new stuff. Was that not done bu Egyptians on clay tablets?
Sorry.. I can not take anymore... I need a Tylenol.
My parser was originally a Stack-based solution but upon reflection it really ends up as a recursive descent parser.
Support for complex numbers and a number of interfaces one can implements plugins through (Ioperable objects that support operations/functions on their instances), and "IEvalEvents" implementors that can add new Functions/Operators to the evaluator as well. The Stack created initially to store the parsed expression is really just a list of tokens (functions, operators, literals) which have all the data they need. The Function and SubExpression types (IT_FUNCTION and IT_SUBEXPRESSION) are most interesting, because they perform no real parsing of the arguments/contents themselves. The SUBEXPRESSION type (with parentheses) simply creates another parser object, setting it's expression to the contents of the paretheses. Same for the Function parameters (Except the function parameters store a number of "CParser" objects in the Linked List that "RipFormula" creates.
Because of this, it can Optimize far better. The parser stores each Stack created into a global collection, keyed by the expression used to build it. It consults this collection to determine wether another parser object hasn't already parsed it. If it has, it simply retrieves the stack as stored; otherwise, it rips the formula itself, and then stores the resulting stack.
executing, for example:
"Sin(RANDOM(1,10*STORE(X,5))*{1,2,3}"
will end up in a grand total of 9 stacks being cached. This means that if, for example, a later execution of:
[code]
10*STORE(X,5)
is performed, anywhere- there will be no need to perform the expensive task of ripping the stack from the string, instead it will just grab it from the stack.
Of course, storing all these stacks can me hard on RAM with longer runs, so each "configuration set" (a name given to a set of Plugins and settings; useful for applications that always want to have the parser load plugins specific to the app) each one can specify the maximum number of Cached Parse Stacks. the Purges are performed by deleting old entries from the collection until the count is acceptable.
Additionally, it has intrinsic support for method calls on object-type variables. For example, the following would start word and display it, if it's installed:
STORE(Word,CREATEOBJECT("Word.Application");
Word@VISIBLE(True);
STORE(Word,Nothing);
the @ operator implements eventually) a set of queries to the objects type information and then performs InvokeHook with the appropriate parameters, after inspecting wether the member is a method or property.
In any case, I had to fix a few subtle issues with the previous incarnation:
Public Function ParseArguments(ByVal FromString As String, Optional ByVal BracketStart As String = DefaultBracketStart, _
Optional ByVal Bracketend As String = DefaultBracketEnd, Optional ByVal ARGUMENTSEP As String = ARGSEP, Optional ByRef startpos As Long = 1) As String()
'NOTE: this routine REALLY needs to be rewritten!
'full of hacks and kludges...
'ParseArguments Function:
'assumes the given string is a parameter lists.
'keeping track of parentheses and quotes, it finds the next ARGSEP that is not part of some other token.
'Added May 06 2008 10:50 PM:
'recognize the use of a "To" keyword between two arguments.
Dim CurrPos As Long
Dim SplMake() As String
Dim CurrArgument As Long, Char As String
Dim inquote As Boolean, BracketCount As Long
Dim ArgStart As Long
'If there isn't even a separator in the string, at all, return the string as the single argument
If InStr(FromString, ARGUMENTSEP) = 0 Then
ReDim SplMake(0)
SplMake(0) = FromString
ParseArguments = SplMake
Exit Function
End If
If Len(FromString) <= 0 Then
Erase SplMake()
ParseArguments = SplMake
Exit Function
End If
CurrArgument = 0
CurrPos = startpos
ArgStart = CurrPos
Do
Char = Mid$(FromString, CurrPos, 1)
Select Case True
Case Char = """"
inquote = Not inquote
Case inquote And CurrPos < Len(FromString)
'IGNORE!>
'ignore as long as we are in a string.
Case InStr(BracketStart, Char) <> 0 And Char <> ""
BracketCount = BracketCount + 1
Case InStr(Bracketend, Char) <> 0 And Char <> ""
BracketCount = BracketCount - 1
If BracketCount < 0 Then
'Sigh.
BracketCount = 0
End If
Case InStr(CurrPos, FromString, ARGUMENTSEP) = 0 And BracketCount = 0 And Trim$(Mid$(FromString, CurrPos)) <> ""
ReDim Preserve SplMake(CurrArgument)
SplMake(CurrArgument) = Mid$(FromString, CurrPos)
Exit Do
Case Char = ARGUMENTSEP, (CurrPos >= Len(FromString))
'Stop
'If ((Not Inquote) Or _
(CurrPos >= Len(FromString))) And BracketCount = 0 Then
If ((Not inquote) And BracketCount = 0) Or (CurrPos >= Len(FromString)) Then
'wow, that is very strange, heh?
'This will only be true when inquote=false (0) and bracketcount=0 as well.
ReDim Preserve SplMake(CurrArgument)
SplMake(CurrArgument) = Mid$(FromString, ArgStart, Abs(CurrPos - ArgStart))
If right$(SplMake(CurrArgument), 1) = ARGUMENTSEP Then
SplMake(CurrArgument) = Mid$(SplMake(CurrArgument), 1, Len(SplMake(CurrArgument)) - 1)
End If
CurrArgument = CurrArgument + 1
ArgStart = CurrPos + 1
If CurrPos >= Len(FromString) Then
' If InStr(1, Bracketend, right$(SplMake(CurrArgument - 1), 1), vbTextCompare) <> 0 And BracketCount <= 0 Then
' SplMake(CurrArgument - 1) = Mid$(SplMake(CurrArgument - 1), 1, Len(SplMake(CurrArgument - 1)) - 1)
' End If
Exit Do
End If
End If
End Select
CurrPos = CurrPos + 1
Loop
If UBound(SplMake) = 0 Then
If SplMake(0) = "" Then
'there weren't any arguments- return an actual "Empty" array to denote this to the caller.
Erase SplMake
End If
End If
startpos = CurrPos
ParseArguments = SplMake
End Function
The core itself implements support for Complex arithmetic, (heh, all I had to do was create an "IOperable" implementing object for Complex numbers, handle the appropriate interface functions and add a variable "i" to a complex number with it's imaginary part set to 1 and the realpart set to 0, and then set that variable as read-only.),Arrays (for example, {1,2,3}*{5,6,7} will work fine).
quite an interesting library.
[/code]