Code archives/User Input/Parser

This code has been declared by its author to be Public Domain code.

Download source code

Parser by CS_TBL2005
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