@JimBrown: Reading again your post, I think you need a decent tokenizer.
This is the tokenizer for my blitzmax-like script system:
(This code
is not public domain, use it if you wish in your own project, but don't distribute it outside this forum, please. I'll distribute the whole script package once I feel it is stable.)
'This BMX file was edited with BLIde ( <a href="http://www.blide.org" target="_blank">http://www.blide.org</a> )
Type TTokenizer
'There's another single line comment
Field Tokens:TToken[]
rem
bbdoc: Reads a string containing source code and fills the tokens collection.
end rem
Method Tokenize:String(Text:String)
Local Cur:String
Local Literal:Int = False
Local Line:Int = 0
Local SingleComment:Int = False
For Local i:Int = 1 To Text.Length
Local a:String = Mid(Text, I, 1)
If Not literal Then
If singleComment = True Then
If a = Chr(13) Or a = Chr(10) Then
cur = ""
singlecomment = False
End If
ElseIf (a >= "a" And a <= "z") Or (a >= "A" And a <= "Z") Or (a >= "0" And a <= "9") Or a = "_"
Cur = cur + a
ElseIf a = "'" Then
If cur.Length > 0 Then
If tokens = Null Then
tokens = New TToken[1]
Else
tokens = tokens[..tokens.length + 1]
End If
tokens[tokens.Length - 1] = New TToken
tokens[tokens.Length - 1].Text = cur
tokens[tokens.Length - 1].Line = Line
EndIf
cur = ""
SingleComment = True
ElseIf a = Chr(34) Then
If cur.Length > 0 Then
If tokens = Null Then
tokens = New TToken[1]
Else
tokens = tokens[..tokens.length + 1]
End If
tokens[tokens.Length - 1] = New TToken
tokens[tokens.Length - 1].Text = cur
tokens[tokens.Length - 1].Line = Line
'Print "TOKEN: " + cur
EndIf
cur = a
literal = True
Else
If cur.Length > 0 Then
If tokens = Null Then
tokens = New TToken[1]
Else
tokens = tokens[..tokens.length + 1]
End If
tokens[tokens.Length - 1] = New TToken
tokens[tokens.Length - 1].Text = cur
tokens[tokens.Length - 1].Line = Line
'Print "TOKEN: " + cur
EndIf
If a <> Chr(10) Then
If tokens = Null Then
tokens = New TToken[1]
Else
tokens = tokens[..tokens.length + 1]
End If
tokens[tokens.Length - 1] = New TToken
tokens[tokens.Length - 1].Text = A
tokens[tokens.Length - 1].Line = Line
If a <> Chr(13) Then
'Print "TOKEN: " + A
Else
'Print "<BR>"
Line:+1
EndIf
EndIf
CUR = ""
End If
Else
Cur = cur + a
If a = Chr(34) Then
literal = False
ElseIf a = Chr(13) Or a = Chr(10) Then
Return "Missing " + Chr(34) + " at string literal termination."
End If
EndIf
Next
'Get last:
If cur <> "" Then
If tokens = Null Then
tokens = New TToken[1]
Else
tokens = tokens[..tokens.length + 1]
End If
tokens[tokens.Length - 1] = New TToken
tokens[tokens.Length - 1].Text = cur
tokens[tokens.Length - 1].Line = Line
'Print "TOKEN: " + cur
End If
CleanTokens(Self)
End Method
rem
bbdoc: Gets a token from the collection by idex
endrem
Method Item:Ttoken(I:Int)
Return Self.Tokens[i]
End Method
rem
bbdoc: Gets the number of tokens in the collection
endrem
Method Count:Int()
Return Self.Tokens.Length
End Method
rem
bbdoc: Gets the number of the latest index in the collection
endrem
Method LastIndex:Int()
Return Self.Tokens.Length - 1
End Method
rem
bbdoc: Removes an index from the collection at a given index
endrem
Method RemoveTokenAt(I:Int)
Self.Tokens = Self.tokens[0..i] + Self.tokens[i + 1..]
End Method
rem
bbdoc: Inserts an item on the collection at a given index
endrem
Method AddTokenAt(I:Int, T:Ttoken)
Local Ar:TToken[] = New TToken[1]
Ar[0] = T
Self.Tokens = Self.tokens[0..i] + Ar + Self.tokens[i + 1..]
End Method
End Type
Private
rem
bbdoc: This function removes the void and false separator tokens from the collection
endrem
Function CleanTokens(Tokenizer:TTokenizer)
'DebugStop
Local DeleteToken:Int[] = New Int[1]
Local InsideRem:Int = False
Local LastEnter:Int = False
For Local i:Int = 0 To tokenizer.Tokens.Length - 1
If tokenizer.tokens[i].Text = " " Or tokenizer.tokens[i].Text = Chr(9) Then
DeleteToken = DeleteToken[..deletetoken.length + 1]
DeleteToken[deleteToken.length - 1] = i
ElseIf i > 0 And tokenizer.tokens[i - 1].Text = "<" And tokenizer.tokens[i].Text = ">" Then
DeleteToken = DeleteToken[..deletetoken.length + 1]
DeleteToken[deleteToken.length - 1] = i - 1
tokenizer.Tokens[i].text = "<>"
ElseIf i > 0 And tokenizer.tokens[i - 1].Text = ">" And tokenizer.tokens[i].Text = "=" Then
DeleteToken = DeleteToken[..deletetoken.length + 1]
DeleteToken[deleteToken.length - 1] = i - 1
tokenizer.Tokens[i].text = ">="
ElseIf i > 0 And tokenizer.tokens[i - 1].Text = "<" And tokenizer.tokens[i].Text = "=" Then
DeleteToken = DeleteToken[..deletetoken.length + 1]
DeleteToken[deleteToken.length - 1] = i - 1
tokenizer.Tokens[i].text = "<="
ElseIf i > 0 And tokenizer.tokens[i - 1].Text = "=" And tokenizer.tokens[i].Text = "<" Then
DeleteToken = DeleteToken[..deletetoken.length + 1]
DeleteToken[deleteToken.length - 1] = i - 1
tokenizer.Tokens[i].text = "<="
ElseIf i > 0 And tokenizer.tokens[i - 1].Text = "=" And tokenizer.tokens[i].Text = ">" Then
DeleteToken = DeleteToken[..deletetoken.length + 1]
DeleteToken[deleteToken.length - 1] = i - 1
tokenizer.Tokens[i].text = ">="
ElseIf i > 0 And tokenizer.tokens[i - 1].Text = ":" And tokenizer.tokens[i].Text = "+" Then
DeleteToken = DeleteToken[..deletetoken.length + 1]
DeleteToken[deleteToken.length - 1] = i - 1
tokenizer.Tokens[i].text = ":+"
ElseIf i > 0 And tokenizer.tokens[i - 1].Text = ":" And tokenizer.tokens[i].Text = "-" Then
DeleteToken = DeleteToken[..deletetoken.length + 1]
DeleteToken[deleteToken.length - 1] = i - 1
tokenizer.Tokens[i].text = ":-"
ElseIf i > 0 And tokenizer.tokens[i - 1].Text = ":" And tokenizer.tokens[i].Text = "*" Then
DeleteToken = DeleteToken[..deletetoken.length + 1]
DeleteToken[deleteToken.length - 1] = i - 1
tokenizer.Tokens[i].text = ":*"
ElseIf i > 0 And tokenizer.tokens[i - 1].Text = ":" And tokenizer.tokens[i].Text = "/" Then
DeleteToken = DeleteToken[..deletetoken.length + 1]
DeleteToken[deleteToken.length - 1] = i - 1
tokenizer.Tokens[i].text = ":/"
ElseIf i > 0 And tokenizer.tokens[i - 1].Text = ":" And tokenizer.tokens[i].Text = "^" Then
DeleteToken = DeleteToken[..deletetoken.length + 1]
DeleteToken[deleteToken.length - 1] = i - 1
tokenizer.Tokens[i].text = ":^"
ElseIf (i > 0 And i < tokenizer.Tokens.Length - 1) And ..
tokenizer.tokens[i].text = "." And ..
IsOperator (tokenizer.tokens[i - 1]) And ..
IsIntNumber(tokenizer.tokens[i + 1])
DeleteToken = DeleteToken[..deletetoken.length + 1]
DeleteToken[deleteToken.length - 1] = i + 1
tokenizer.Tokens[i].text = "." + tokenizer.tokens[i + 1].text
ElseIf (i > 0 And i < tokenizer.Tokens.Length - 1) And ..
tokenizer.tokens[i].text = "." And ..
IsIntNumber(tokenizer.tokens[i - 1]) And ..
IsIntNumber(tokenizer.tokens[i + 1])
DeleteToken = DeleteToken[..deletetoken.length + 1]
DeleteToken[deleteToken.length - 1] = i - 1
DeleteToken = DeleteToken[..deletetoken.length + 1]
DeleteToken[deleteToken.length - 1] = i + 1
tokenizer.Tokens[i].text = tokenizer.tokens[i - 1].Text + "." + tokenizer.tokens[i + 1].text
ElseIf (tokenizer.tokens[i].Text.ToLower() = "rem") And (insiderem = False) Then
DeleteToken = DeleteToken[..deletetoken.length + 1]
DeleteToken[deleteToken.length - 1] = i
InsideRem = True
ElseIf tokenizer.tokens[i].Text.ToLower() = "endrem" Then
DeleteToken = DeleteToken[..deletetoken.length + 1]
DeleteToken[deleteToken.length - 1] = i
InsideRem = False
ElseIf (i > 1) And (tokenizer.tokens[i].Text.ToLower() = "rem") And (insiderem = True) And (tokenizer.tokens[i - 1].Text.ToLower() = " ") And ((tokenizer.tokens[i - 2].Text.ToLower() = "end")) Then
DeleteToken = DeleteToken[..deletetoken.length + 1]
DeleteToken[deleteToken.length - 1] = i - 2
DeleteToken = DeleteToken[..deletetoken.length + 1]
DeleteToken[deleteToken.length - 1] = i - 1
DeleteToken = DeleteToken[..deletetoken.length + 1]
DeleteToken[deleteToken.length - 1] = i
insiderem = False
ElseIf insiderem = True Then
DeleteToken = DeleteToken[..deletetoken.length + 1]
DeleteToken[deleteToken.length - 1] = i
tokenizer.tokens[i].Text = ";" 'Deletion on anex pass!!
End If
If tokenizer.tokens[i].Text = Chr(13) Or tokenizer.tokens[i].Text = ";" Then
If lastenter = True Then
DeleteToken = DeleteToken[..deletetoken.length + 1]
DeleteToken[deleteToken.length - 1] = i
End If
tokenizer.tokens[i].Text = ";"
lastenter = True
Else
lastenter = False
EndIf
Next
deletetoken.sort()
Local LastIndex:Int = -1 'Ensure not to delete the same index twice!
Print "Disposable tokens: " + deletetoken.Length
For Local i:Int = deletetoken.length - 1 To 1 Step - 1
'tokenizer.Tokens = Tokenizer.tokens[0..deletetoken[i] ] + tokenizer.tokens[deletetoken[i] + 1..]
If lastindex <> deletetoken[i] Then
Tokenizer.RemoveTokenAt(deletetoken[i])
lastindex = deletetoken[i]
EndIf
Next
End Function
Public
'This BMX file was edited with BLIde ( <a href="http://www.blide.org" target="_blank">http://www.blide.org</a> )
rem
bbdoc: Base token class
endrem
Type TToken
rem
bbdoc: Text represented by the token
endrem
Field Text:String
rem
bbdoc: line in the original source code where the token belongs
endrem
Field Line:Int = -1 '-1 means no line
End Type
rem
bbdoc:Returns TRUE if a token is an operator. Otherwise return false.
end rem
Function IsOperator:Int(Token:TToken)
Select Token.Text.ToLower()
Case "+", "-", "*", "/", "^", "[", "]", "(", ")", "=", ":+", ":-", ":*", ":/", ":^", ..
"and", "or", "xor", "|", "&", "<>", ">=", "<=", ".", "{", "}", ";"
Return True
Default
Return False
End Select
End Function
Function IsIntNumber:Int(Token:TToken)
For Local i:Int = 1 To token.Text.Length
Local Char:String = Mid(token.Text, i, 1)
Select char
Case "-"
If i <> 1 Then Return False
Case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
Default
Return False
End Select
Next
Return True
End Function
'This BMX file was edited with BLIde ( <a href="http://www.blide.org" target="_blank">http://www.blide.org</a> )
Function LoadStreamText:TTextStream(url:Object)
Local format:Int, Size:Int = 0, c:Int, d:Int, e:Int
Local stream:TStream = ReadStream(url)
If stream = Null Then Return Null
If Not stream.Eof()
c = stream.ReadByte()
Size:+1
If Not stream.Eof()
d = stream.ReadByte()
Size:+1
If c = $fe And d = $ff
format = TTextStream.UTF16BE
Else If c = $ff And d = $fe
format = TTextStream.UTF16LE
Else If c = $ef And d = $bb
If Not stream.Eof() Then
e = stream.ReadByte()
Size:+1
If e = $bf format = TTextStream.UTF8
EndIf
EndIf
EndIf
EndIf
If Not format
Local Stream2:TTextStream = TTextStream.Create(ReadStream(url), TTextStream.LATIN1)
Return Stream2
EndIf
stream:TStream = ReadStream(url)
Local TStream:TTextStream = TTextStream.Create(stream, format)
Return TStream
End Function
(This code
is not public domain, use it if you wish in your own project, but don't distribute it outside this forum, please. I'll distribute the whole script package once I feel it is stable.)
By the way, forgot to mention that the code is superstrict. It won't compile as not-strict code.