Code: Select all
Macro EnableClass(ClassName)
Global NewList ClassName#.c#ClassName#()
EndMacro
Macro DisableClass(ClassName)
;Flush ClassName#.c#ClassName#() ; <- Pity PB doesn't allow to flush a previously created variable :-|
EndMacro
Macro New_Obj(Object,ClassName)
AddElement(ClassName#())
ClassName#()\VTable=?c#ClassName#_VT
Object#.i#ClassName#=@ClassName#()
EndMacro
Macro Free_Obj(Object,ClassName)
If ClassName#()=Object
DeleteElement(ClassName#())
Else
PokeL(?c#ClassName#_VT+SizeOf(i#ClassName#),@ClassName#())
ChangeCurrentElement(ClassName#(),Object#)
DeleteElement(ClassName#())
ChangeCurrentElement(ClassName#(),PeekL(?c#ClassName#_VT+SizeOf(i#ClassName#)))
EndIf
;Flush Object ; <- Pity PB doesn't allow to flush a previously created variable :-|
EndMacro
;_____________________________
;****************************** Create Class PBSC (by remi meier):
; http://www.purebasic.fr/english/viewtopic.php?t=22116
Enumeration
#PBSC_Identifier
#PBSC_Number
#PBSC_String
#PBSC_Comment
#PBSC_NewLine
#PBSC_Other
EndEnumeration
Interface iPBSC
SetFile.l(FileName.s)
ResetFilePos()
IsNextToken.l()
GetNextToken.s()
GetCurrentLineNb.l()
GetCurrentType.l()
CloseFile()
EndInterface
Structure cPBSC
*VTable
FileID.l
Format.l
CurrentLine.l
CurrentType.l
LastToken.s
PreLastToken.s
PrePreLastToken.s
EndStructure
Procedure _PBSC_SetLastToken(*this.cPBSC,s.s)
;Static PreLastToken.s = #LF$
If *this\PreLastToken = "" : *this\PreLastToken=#LF$:EndIf
*this\PrePreLastToken = *this\PreLastToken
*this\PreLastToken = *this\LastToken
*this\LastToken = s
EndProcedure
Procedure.l PBSC_SetFile(*this.cPBSC, FileName.s)
If IsFile(*this\FileID)
CloseFile(*this\FileID)
EndIf
*this\FileID = ReadFile(#PB_Any, FileName)
If Not IsFile(*this\FileID)
ProcedureReturn #False
EndIf
_PBSC_SetLastToken(*this, #LF$)
*this\Format = ReadStringFormat(*this\FileID)
Select *this\Format
Case #PB_Ascii, #PB_UTF8, #PB_Unicode
*this\CurrentLine = 1
ProcedureReturn #True
Default
CloseFile(*this\FileID)
ProcedureReturn #False
EndSelect
EndProcedure
Procedure PBSC_ResetFilePos(*this.cPBSC)
If IsFile(*this\FileID)
FileSeek(*this\FileID,0)
*this\CurrentLine = 1
_PBSC_SetLastToken(*this, #LF$)
EndIf
EndProcedure
Procedure.l PBSC_IsNextToken(*this.cPBSC)
If IsFile(*this\FileID) And Eof(*this\FileID) = #False
ProcedureReturn #True
Else
ProcedureReturn #False
EndIf
EndProcedure
Procedure.s _PBSC_Trim(*this.cPBSC, s.s)
Protected *p.CHARACTER, *n.CHARACTER
*p = @s
While (*p\c = ' ' Or *p\c = 9) And *p\c
*p + SizeOf(CHARACTER)
Wend
; *p zeigt auf Start des Textes
; suche Ende
*n = *p
While *n\c
*n + SizeOf(CHARACTER)
Wend
*n - SizeOf(CHARACTER)
While (*n\c = ' ' Or *n\c = 9) And *n > *p
*n - SizeOf(CHARACTER)
Wend
ProcedureReturn PeekS(*p, (*n + SizeOf(CHARACTER) - *p)/SizeOf(CHARACTER))
EndProcedure
Procedure.l _PBSC_GetIdentifier(*this.cPBSC, s.s)
Protected z.l, Len.l, ToLen.l = 0, Const.l = 0, PseudoType.l = 0, Temp.s
Protected LastToken.s
If *this\LastToken = "." And (PeekC(@s) = 'p' Or PeekC(@s) = 'P') And PeekC(@s+SizeOf(CHARACTER)) = '-'
PseudoType = 1
ToLen = 2
EndIf
If PseudoType = 0
If PeekC(@s) = '#'
Select PeekC(@*this\LastToken)
Case '_', 'a' To 'z', 'A' To 'Z', '#'
Temp = LCase(*this\LastToken)
Select Temp
Case "to", "procedurereturn", "select", "case", "if", "elseif", "compilerselect"
Const = 1 : ToLen = 1
Case "compilercase", "compilerif", "compilerelseif", "break", "while", "until"
Const = 1 : ToLen = 1
Case "debug", "end"
Const = 1 : ToLen = 1
Default
ProcedureReturn 0
EndSelect
Case '*'
If PeekC(@*this\LastToken) = '*' And Len(*this\LastToken) > 1
ProcedureReturn 0
Else
Const = 1
ToLen = 1
EndIf
Default
Const = 1
ToLen = 1
EndSelect
ElseIf PeekC(@s) = '*'
For z = 1 To 2
If z = 1 : LastToken = *this\LastToken
ElseIf z = 2 : LastToken = *this\PrePreLastToken
EndIf
Select PeekC(@LastToken)
Case '_', 'a' To 'z', 'A' To 'Z', '#'
Temp = LCase(LastToken)
Select Temp
Case "protected", "define", "global", "shared", "static"
Const = 1
ToLen = 1
Break
EndSelect
Case '*'
If PeekC(@LastToken) = '*' And Len(LastToken) > 1
Else
Const = 1
ToLen = 1
Break
EndIf
Default
Const = 1
ToLen = 1
Break
EndSelect
Next
If Const <> 1
ProcedureReturn 0
EndIf
EndIf
If Const
z = 1
While (PeekC(@s+z*SizeOf(CHARACTER)) = ' ' Or PeekC(@s+z*SizeOf(CHARACTER)) = 9)
Const + 1
z + 1
ToLen + 1
Wend
EndIf
Select PeekC(@s + Const*SizeOf(CHARACTER))
Case '_', 'a' To 'z', 'A' To 'Z'
ToLen + 1
Default
ProcedureReturn 0
EndSelect
EndIf
Len = Len(s)
For z = 2+Const+PseudoType To Len
Select Asc(Mid(s, z, 1))
Case '_', 'a' To 'z', 'A' To 'Z', '0' To '9', '$'
ToLen + 1
Default
*this\CurrentType = #PBSC_Identifier
ProcedureReturn ToLen
EndSelect
Next
*this\CurrentType = #PBSC_Identifier
ProcedureReturn ToLen
EndProcedure
Procedure.l _PBSC_GetString(*this.cPBSC, s.s)
Protected z.l, Len.l, ToLen.l = 0, SearchString.l
If PeekC(@s) = '"'
SearchString = #True
ToLen = 1
ElseIf PeekC(@s) = Asc("'")
SearchString = #False
ToLen = 1
Else
ProcedureReturn 0
EndIf
Len = Len(s)
For z = 2 To Len
If SearchString
Select Asc(Mid(s, z, 1))
Case '"'
*this\CurrentType = #PBSC_String
ProcedureReturn ToLen + 1
Default
ToLen + 1
EndSelect
Else
Select Asc(Mid(s, z, 1))
Case Asc("'")
*this\CurrentType = #PBSC_Number
ProcedureReturn ToLen + 1
Default
ToLen + 1
EndSelect
EndIf
Next
*this\CurrentType = #PBSC_String
ProcedureReturn ToLen
EndProcedure
Procedure.l _PBSC_GetNumber(*this.cPBSC, s.s)
Protected z.l, Len.l, ToLen.l = 0, Digit.l = #False, Hex.l = #False, Spec.l = 0
If PeekC(@s) = '$'
Hex = #True
ToLen = 1
Spec = 1
ElseIf PeekC(@s) = '%'
ToLen = 1
Spec = 1
EndIf
Len = Len(s)
For z = (1+Spec) To Len
If Hex
Select Asc(Mid(s, z, 1))
Case '0' To '9', 'a' To 'f', 'A' To 'F'
ToLen + 1
Digit = #True
Default
If Digit
*this\CurrentType = #PBSC_Number
ProcedureReturn ToLen
Else
ProcedureReturn 0
EndIf
EndSelect
Else
Select Asc(Mid(s, z, 1))
Case '0' To '9', '.', 'e'
If Digit = #False And (Asc(Mid(s, z, 1)) = '.' Or Asc(Mid(s, z, 1)) = 'e')
ProcedureReturn 0
EndIf
ToLen + 1
Digit = #True
Case '+', '-'
If Digit
If Asc(Mid(s, z-1, 1)) = 'e'
ToLen + 1
Else
*this\CurrentType = #PBSC_Number
ProcedureReturn ToLen
EndIf
Else
ProcedureReturn 0
EndIf
Default
If Digit
*this\CurrentType = #PBSC_Number
ProcedureReturn ToLen
Else
ProcedureReturn 0
EndIf
EndSelect
EndIf
Next
*this\CurrentType = #PBSC_Number
ProcedureReturn ToLen
EndProcedure
Procedure.l _PBSC_GetDOperator(*this.cPBSC, s.s)
Select PeekC(@s)
Case '<', '>'
Select PeekC(@s+SizeOf(CHARACTER))
Case '>', '<', '='
*this\CurrentType = #PBSC_Other
ProcedureReturn 2
EndSelect
EndSelect
ProcedureReturn 0
EndProcedure
Procedure.l _PBSC_FindToken(*this.cPBSC, s.s)
; ok: Kommentare als Ganzes
; ok: Strings als Ganzes (auch mit ' umklammerte)
; ok: Bezeichner als Ganzes (auch #KONST, String$, *Ptr)
; ok: Pseudotypen als Ganzes
; ok: Zahlen: 2001, $5461, %454
; ok: Doppeloperatoren
Static RetVal.l = 0
If PeekC(@s) = ';'
_PBSC_SetLastToken(*this, s)
*this\CurrentType = #PBSC_Comment
ProcedureReturn Len(s)
EndIf
RetVal = _PBSC_GetIdentifier(*this, s)
If RetVal
_PBSC_SetLastToken(*this, Left(s, RetVal))
ProcedureReturn RetVal
EndIf
RetVal = _PBSC_GetString(*this, s)
If RetVal
_PBSC_SetLastToken(*this, Left(s, RetVal))
ProcedureReturn RetVal
EndIf
RetVal = _PBSC_GetNumber(*this, s)
If RetVal
_PBSC_SetLastToken(*this, Left(s, RetVal))
ProcedureReturn RetVal
EndIf
RetVal = _PBSC_GetDOperator(*this, s)
If RetVal
_PBSC_SetLastToken(*this, Left(s, RetVal))
ProcedureReturn RetVal
EndIf
_PBSC_SetLastToken(*this, Mid(s, 1, 1))
*this\CurrentType = #PBSC_Other
ProcedureReturn 1
EndProcedure
Procedure.s PBSC_GetNextToken(*this.cPBSC)
Protected s0.s, s.s, Token.s, Len.l, StartPos.l
Static NextIsNewLine.l = #False
If IsFile(*this\FileID) And Eof(*this\FileID) = #False
If NextIsNewLine
NextIsNewLine = #False
*this\CurrentLine + 1
*this\CurrentType = #PBSC_NewLine
_PBSC_SetLastToken(*this, #LF$)
ProcedureReturn #LF$
EndIf
StartPos = Loc(*this\FileID)
s0 = ReadString(*this\FileID, *this\Format)
s = _PBSC_Trim(*this, s0)
If s = ""
*this\CurrentLine + 1
*this\CurrentType = #PBSC_NewLine
_PBSC_SetLastToken(*this, #LF$)
ProcedureReturn #LF$
EndIf
Len = _PBSC_FindToken(*this.cPBSC, s)
Token = Left(s, Len)
If Len = Len(s)
NextIsNewLine = #True
Else
FileSeek(*this\FileID, StartPos + FindString(s0, Token, 1) + Len(Token) - 1)
EndIf
ProcedureReturn Token
Else
ProcedureReturn ""
EndIf
EndProcedure
Procedure.l PBSC_GetCurrentLineNb(*this.cPBSC)
ProcedureReturn *this\CurrentLine
EndProcedure
Procedure.l PBSC_GetCurrentType(*this.cPBSC)
ProcedureReturn *this\CurrentType
EndProcedure
Procedure PBSC_CloseFile(*this.cPBSC)
If IsFile(*this\FileID)
CloseFile(*this\FileID)
EndIf
EndProcedure
DataSection
cPBSC_VT:
Data.l @PBSC_SetFile(), @PBSC_ResetFilePos(), @PBSC_IsNextToken(), @PBSC_GetNextToken()
Data.l @PBSC_GetCurrentLineNb(), @PBSC_GetCurrentType(), @PBSC_CloseFile()
Data.l 0
EndDataSection
EnableClass(PBSC) ; <- Create and define PBSC() Class (set ready a class to add objects of it).
;******************************* End Create Class PBSC
;________________________Example of use:
New_Obj(test,PBSC)
New_Obj(test2,PBSC)
New_Obj(test3,PBSC)
New_Obj(test4,PBSC)
New_Obj(test5,PBSC)
If test4\SetFile("test.pb")
While test4\IsNextToken()
Debug test4\GetNextToken()
Wend
test4\CloseFile()
EndIf