Code archives/User Input/Parser
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
| simple, minimalistic, but handy parser | |||||
'Strict
Type Parser
Rem
A very basic command/value parser, but often sufficient.
A single string holds the script, and that script can be as ugly as uglyness can be, it could
come from textareas, files etc. The idea is that everything can be parsed, without bugging the
user with (runtime-)errors, caused by a bad script. If you create a texture-generator, the
result would be that the texture would look wrong, but never (runtime-)errors, or annoying popups
you need to click away.
The syntax for the script is always:
<command><value> <command><value> <command><value> .. ..
<Command>
- A single char, anyone of these: QWERTYUIOPASDFGHJKLZXCVBNM`!@#$%^&*()_+[]:;'\|,/<>?"
- Exluded are the tilde ~ and both braces { }
- Any other character (including spaces) is wiped out.
- az will become uppercase
<Value>
- is any double.
- ugly written values will be souped-up
- if no value is given, value=0
an example:
a0b100c-3d9.9
These are 4 commands (a b c and d), and 4 values (1 100 -3 and 9.9).
(values intentially rounded for readablity)
The same script could also've been written as:
ab1 00c -----3... d9.9----
Groundrules for Double souping-up:
- the most right dot will be the decimal dot
- the amount of minus-signs defines whether it's positive or negative
So, 10000.00 could be written as 10.000.00, and 3-3 -..-..- 3-3 means -33.33
{} are used for commenting .. but very basic again. When the parser sees a { it'll ignore
the next characters until there's a } again.. no support for nesting. Advantage is that with no
further use of commenting in a large script, a single { comments the rest without the need of a
closing }.
usage:
MyParser = CreateParser()
MyParser.Parse(MyScript$)
AmountOfCommands:Int = MyParser.Commands()
MyCommand$ = MyParser.GetCommand(commandnumber)
MyValue:Double = MyParser.GetValue(commandnumber)
made by:
CS_TBL, 2nd xmas-day 2005 :P
EndRem
Field bank:TBank
Method Prepare$(s$)
Local n$
Local c$
Local t:Short
Local comment:Byte
' allow ASCIIs 33..125
For t=0 To Len(s$)-1
c$=Mid$(s$,t+1,1)
If Asc(c$)>32 And Asc(c$)<126 n$=n$+Upper$(c$)
Next
s$=n$
n$=""
t=0
For t=0 To Len(s$)-1
c$=Mid$(s$,1+t,1)
If c$="{" comment=True
If c$="}" comment=False
If Not comment
If c$<>"}" n$=n$+c$
EndIf
Next
Return n$
End Method
Method Text2Double:Double(a$)
If a$="" Return 0
Local l:Short
Local az$
Local m:Short
Local negative:Byte
Local found:Byte
Local foundpos:Short
Local t:Short
l=Len(a$)
' do we have an odd amount of '-' ?
az$=Replace$(a$,"-","")
m=l-Len(az$)
' yes? it's a negative number!
If m Mod 2 negative=True
' scan the value (without - ) For dots
For t=Len(az$)-1 To 0 Step -1
If Not found
If Mid$(az$,t+1,1)="."
found=True
foundpos=(Len(az$)-1)-t
EndIf
EndIf
Next
' so we found the most-Right dot, If any..
' get rid of all the dots Then
az$=Replace$(az$,".","")
l=Len(az$)
If found ' place 1 dot back
az$=Left$(az$,l-foundpos)+"."+Right$(az$,foundpos)
EndIf
If negative
az$="-"+az$
EndIf
Return az$.todouble()
End Method
Method Parse(a$)
Local t:Short
Local valuefound:Byte
Local number$
Local ch$
Local parselen:Short
Local bs:Int
Local char$
a$=Prepare$(a$)
If a$="" Return
ResizeBank bank,0
parselen=Len(a$)
Repeat
char$=Mid$(a$,t+1,1)
If Instr("QWERTYUIOPASDFGHJKLZXCVBNM`!@#$%^&*()_+[]:;'\|,/<>?"+Chr$(34),char$)
t:+1
valuefound=0
number$=""
Repeat
ch$=Mid$(a$,t+1,1)
If Instr("1234567890-.",ch$)
number$=number$+ch$
t:+1
Else
valuefound=True
t:-1
EndIf
If t>=parselen valuefound=True
Until valuefound
bs=BankSize(bank)
ResizeBank bank,bs+9
bs:+9
PokeByte bank,bs-9,Asc(char$)
PokeDouble bank,bs-8,Text2Double(number$)
EndIf
t:+1
Until t>=parselen
End Method
Method Commands:Int()
Return BankSize(bank)/9
End Method
Method GetCommand$(which:Short)
Local t:Short
If which<0 which=0
t=Commands()
If which=>t which=t-1
Return Chr$(PeekByte(bank,which*9))
End Method
Method GetValue:Double(which:Short)
Local t:Short
If which<0 which=0
t=Commands()
If which=>t which=t-1
Return PeekDouble(bank,which*9+1)
End Method
End Type
Function CreateParser:Parser()
Local a:Parser=New Parser
a.bank=CreateBank(0)
Return a
End Function
Rem ' example..
Local a:Parser=CreateParser()
a.Parse " a 34.1 1 b 9 4 c4d5.3 e-99. 3f 30.0 00. 76"
For Local t:Byte=0 Until a.Commands()
DebugLog a.GetCommand(t)
DebugLog " "+a.GetValue(t)
Next
Notify "^_^"
' and again..
a.Parse "3{1373}}}Blitz{GUI} rules { b()()bs!"
For Local t:Byte=0 Until a.Commands()
DebugLog a.GetCommand(t)
DebugLog " "+a.GetValue(t)
Next
Notify "^_^"
End
EndRem |
Comments
None.
Code Archives Forum