Variable/Maths system implementation

Blitz3D Forums/Blitz3D Programming/Variable/Maths system implementation

Hey peeps..
I posted this a while ago but cocked up the Topic title....
Heres what i had to say:

Just need to get some ideas on how to implement Maths and Variables into my script engine?

Ive got the command set in, and got a script system very similar to that of the God Mode in Die Hard Trilogy for those who played it...

Now, ive tried getting maths in but i couldnt get any results;- ive since stripped the maths and variable system out to start again..

So, What techniques/routines would i use to implement these? any code snippets?





Im posting again in case the whole "hey peeps" topic title did peoples head in and they ignored it.
If of course you ignored it for another reason, feel free to ignore this too!

Cheers....

I would suggest having a type:
Type ScriptVar
Field Name
Field Value
End Type

Then in your script engine:
Peanut = 10

Would create a ScriptVar with Name of Peanut and a Value of 10.

You'd create a function called GetScriptVarValue that returns the value of a VarName and a SetScriptVarValue that checks to see if it already exists, if not create it.

All this code is off the top of my head and totally untested! Expand on this general theme to end up with all the stuff you need.
Function GetScriptVarValue(Name$)
for v.scriptvar = each scriptvar
if v\name = name then return v\value
next
end function

Function SetScriptVarValue(Name$,value)
for v.scriptvar = each scriptvar
if v\name = name then v\value = value:return true
next
v.scriptvar = new scriptvar
v\name = name
v\value = value
end function


I've done a math thingie in blitz... This is an old ver. newere ones included stuff like if print, vars, etc but i redesigned since it started getting unwieldy, and ive stopped blitzen:

Type Stack
	Field Dat,typ,el
End Type

Global Vars=CreateVirtual()

Const Debug=0

Function CreateS.Stack()
	s.stack=New stack
	s\dat=CreateBank(0)
	s\typ=CreateBank(0)
	Return s
End Function

Function ClearStack(s.stack)
	For i=0 To BankSize(s\typ)-1
		PokeByte s\typ,i,0
	Next
	s\el=0
End Function

Function Push(s.stack,Num#)
	If (Num Mod 1)=0 Then PushI s,num Else PushF s,num
End Function 

Function PushI(s.stack,Num%)
	If s\el>BankSize(s\dat)-1 Then
		ResizeBank s\dat,BankSize(s\dat)+4
		ResizeBank s\typ,BankSize(s\typ)+1
	EndIf
	PokeInt s\dat,s\el,num
	PokeByte s\typ,s\el/4,1
	s\el=s\el+4
End Function

Function PushF(s.stack,Num#)
	If s\el>BankSize(s\dat)-1 Then
		ResizeBank s\dat,BankSize(s\dat)+4
		ResizeBank s\typ,BankSize(s\typ)+1
	EndIf
	PokeFloat s\dat,s\el,num#
	PokeByte s\typ,s\el/4,2
	s\el=s\el+4
End Function

Function Pop#(s.stack)
	s\el=s\el-4
	;If s\el<0 Then RuntimeError "Attempted to Pop more than there was pushed"
	Select PeekByte(s\typ,s\el/4)
	Case 0:
		;RuntimeError "Attempted to Pop i non-number"
	Case 1:
		Return PeekInt(s\dat,s\el)
	Case 2:
		Return PeekFloat#(s\dat,s\el)
	End Select
End Function

Const C_P=-2
Const C_None=-1
Const C_Add=0
Const C_Subtract=1
Const C_Multiply=2
Const C_Divide=3
Const C_Sin=4
Const C_Cos=5
Const C_Sqr=6
Const C_Pi=7
Const C_Int=8
Const C_Floor=9
Const C_Ceil=10
Const C_Sgn=11
Const C_Abs=12
Const C_Mod=13
Const C_Tan=14
Const C_Asin=15
Const C_Atan=16
Const C_Exp=17
Const C_Log=18
Const C_Log10=19
Const C_Xor=20
Const C_Shl=21
Const C_Shr=22
Const C_Sar=23
Const C_Equal=24
Const C_Greater=25
Const C_Less=26
Const C_GreaterEqual=27
Const C_LessEqual=28
Const C_NotEqual=29
Const C_Or=30
Const C_And=31
Const C_Not=32
Const C_Complement=33
Const C_Power=34
Const C_Acos=35
Const C_Print=36
Const C_Rnd=37
Const C_Rand=38

Function OperatorID(Expression$)
	Select Lower$(Expression$)
	Case "+"
		Return C_Add
	Case "-"
		Return C_Subtract
	Case "*"
		Return C_Multiply
	Case "/"
		Return C_Divide
	Case "sin"
		Return C_Sin
	Case "cos"
		Return C_Cos
	Case "sqr"
		Return C_Sqr
	Case "pi"
		Return C_Pi
	Case "int"
		Return C_Int
	Case "floor"
		Return C_Floor
	Case "ceil"
		Return C_Ceil
	Case "sgn"
		Return C_Sgn
	Case "abs"
		Return C_Abs
	Case "mod"
		Return C_Mod
	Case "tan"
		Return C_Tan
	Case "asin"
		Return C_Asin
	Case "atan"
		Return C_Atan
	Case "acos"
		Return C_Acos
	Case "exp"
		Return C_Exp
	Case "log"
		Return C_Log
	Case "logt"
		Return C_Log10
	Case "xor"
		Return C_Xor
	Case "shl"
		Return C_Shl
	Case "shr"
		Return C_Shr
	Case "sar"
		Return C_Sar
	Case "="
		Return C_Equal
	Case ">"
		Return C_Greater
	Case "<"
		Return C_Less
	Case ">="
		Return C_GreaterEqual
	Case "<="
		Return C_LessEqual
	Case "<>"
		Return C_NotEqual
	Case "or"
		Return C_Or
	Case "and"
		Return C_And
	Case "not"
		Return C_Not
	Case "~"
		Return C_Complement
	Case "^"
		Return C_Power
	Case "print"
		Return C_Print
	Case "rnd"
		Return C_Rnd
	Case "rand"
		Return C_Rand
	Default
		Return C_None
	End Select
End Function

Function DoOperator(s.stack,Num)
	Select Num
	Case C_Add
		Push s,Pop(s)+Pop(s)
	Case C_Subtract
		v#=Pop(s)
		Push s,Pop(s)-v#
	Case C_Multiply
		Push s,Pop(s)*Pop(s)
	Case C_Divide
		v#=pop(s)
		Push s,Pop(s)/v#
	Case C_Sin
		Push s,Sin(Pop(s))
	Case C_Cos
		Push s,Cos(Pop(s))
	Case C_Sqr
		Push s,Sqr(Pop(s))
	Case C_Pi
		Push s,Pi
	Case C_Int
		PushI s,Int(Pop(s))
	Case C_Floor
		PushI s,Floor(Pop(s))
	Case C_Ceil
		PushI s,Ceil(Pop(s))
	Case C_Sgn
		PushI s,Sgn(Pop(s))
	Case C_Abs
		Push s,Abs(Pop(s))
	Case C_Mod
		v#=Pop(s)
		Push s,Pop(s) Mod v#
	Case C_Tan
		Push s,Tan(Pop(s))
	Case C_Asin
		Push s,ASin(Pop(s))
	Case C_Atan
		Push s,ATan(Pop(s))
	Case C_Exp
		Push s,Exp(Pop(s))
	Case C_Log
		Push s,Log(Pop(s))
	Case C_Log10
		Push s,Log10(Pop(s))
	Case C_Xor
		v#=Pop(s)
		PushI s,Pop(s) Xor v 
	Case C_Shl
		v#=Pop(s)
		PushI s,Pop(s) Shl v
	Case C_Shr
		v#=Pop(s)
		PushI s,Pop(s) Shr v
	Case C_Sar
		v#=Pop(s)
		PushI s,Pop(s) Sar v
	Case C_Equal
		PushI s,Pop(s)=Pop(s)
	Case C_Greater
		PushI s,Pop(s)<Pop(s)
	Case C_Less
		PushI s,Pop(s)>Pop(s)
	Case C_GreaterEqual
		PushI s,Pop(s)<=Pop(s)
	Case C_LessEqual
		PushI s,Pop(s)>=Pop(s)
	Case C_NotEqual
		PushI s,Pop(s)<>Pop(s)
	Case C_Or
		PushI s,Pop(s) Or Pop(s)
	Case C_And
		PushI s,Pop(s) And Pop(s)
	Case C_Not
		PushI s,Not Pop(s)
	Case C_Complement
		Push s,~Pop(s)
	Case C_Power
		v#=Pop(s)
		PushI s,Pop(s)^v#
	Case C_Acos
		Push s,ACos(Pop(s))
	Case C_Print
		Print Pop(s)
	Case C_Rnd
		PushF s,Rnd(Pop(s))
	Case C_Rand
		PushI s,Rand(Pop(s))	
	End Select
End Function

Function Precedence(Num)
	Select Num
	Case C_Add
		Return 4
	Case C_Subtract
		Return 4
	Case C_Multiply
		Return 6
	Case C_Divide
		Return 6
	Case C_Sin
		Return 10
	Case C_Cos
		Return 10
	Case C_Sqr
		Return 10
	Case C_Pi
		Return 10
	Case C_Int
		Return 9
	Case C_Floor
		Return 9
	Case C_Ceil
		Return 9
	Case C_Sgn
		Return 10
	Case C_Abs
		Return 10
	Case C_Rnd
		Return 10
	Case C_Rand
		Return 10
	Case C_Mod
		Return 6
	Case C_Tan
		Return 10
	Case C_Asin
		Return 10
	Case C_Atan
		Return 10
	Case C_Exp
		Return 10
	Case C_Log
		Return 10
	Case C_Log10
		Return 10
	Case C_Xor
		Return 2
	Case C_Shl
		Return 5
	Case C_Shr
		Return 5
	Case C_Sar
		Return 5
	Case C_Equal
		Return 3
	Case C_Greater
		Return 3
	Case C_Less
		Return 3
	Case C_GreaterEqual
		Return 3
	Case C_LessEqual
		Return 3
	Case C_NotEqual
		Return 3
	Case C_Or
		Return 2
	Case C_And
		Return 2
	Case C_Not
		Return 1
	Case C_Complement
		Return 8
	Case C_Power
		Return 7
	Case C_Acos
		Return 10
	End Select
End Function

Function ExpressionToBank(Expression$)
	Expression$=pre$(Lower$(Expression$+" "))
	DebugLog expression$
	b=CreateBank(0)
	s.stack=CreateS.stack()

	For i=1 To Len(Expression$)
		char$=Mid$(expression$,i,1)
		nes=0
		nev=0
		Select char$
		Case "("
			bo=EndString(Current_Text$,b,EndValue(Current_Value#,b,bo,s,1),s)
			If i=Len(expression$) Then Exit	;5
			Push s,C_P
			nes=1
			nev=1
			Current_Value=0
			Current_Text$=""
		Case ")"
			bo=EndString(Current_Text$,b,EndValue(Current_Value#,b,bo,s),s)
			Current_Value=0
			Current_Text$=""
			.strt
			If s\el<4 Then Exit				;5
			temp=Pop(s)
			If temp<>C_P Then		;3
				ResizeBank b,BankSize(b)+3
				PokeByte b,bo,3
				PokeShort b,bo+1,temp			;2
				bo=bo+3
				Goto strt			
			EndIf		
		Case "."
			dec=-1
			nev=1
		Default
			cha=Asc(Char$)
			If cha>47 Then
				If cha<58 Then
					If current_Text$="" Then nes=1
					nev=1
					If Dec<0 Then
						Current_Value#=Current_Value#+(cha-48)*10^Dec
						Dec=Dec-1
					Else
						Current_Value#=cha-48+Current_Value#*10
					EndIf
				EndIf
			EndIf
			If (cha>96 And cha<123) Or cha=42 Or cha=43 Or cha=47 Or cha=33 Or cha=38 Or (cha>59 And cha<63) Or cha=94 Or cha=124 Or cha=126 Or cha=45 Then
				If current_Value=0 Then nev=1
				nes=1
				Current_Text$=Current_Text$+Char$
			EndIf
			If char$="*" Or char$="/" Or char$="-" Or char$="+" Or char$="~" Then nes=0
		End Select
		If nev=0 Then
			bo=EndValue(Current_Value,b,bo,s)
			Current_Value=0
			dec=0
		EndIf
		If nes=0 Then
			bo=EndString(Current_Text,b,bo,s)
			Current_Text$=""
		EndIf
		If debug Then
			DebugLog "Step "+char$+":"
			DebugState b,s
			DebugLog ""
		EndIf
	Next	;4
	While s\el>3
		ID=pop(s)
		If ID<>C_P Then
			ResizeBank b,BankSize(b)+3
			PokeByte b,bo,3
			PokeShort b,bo+1,ID
			bo=bo+3
		EndIf
	Wend
	If debug Then
		DebugLog "End:"
		DebugState b,s
	EndIf 
	Return b
End Function

Function Pre$(expression$)
	For a=1 To Len(expression$)
		If Mid$(expression$,a,1)="(" And Mid$(expression$,a+1,1)="-" Then expression$=Left$(expression$,a-1)+"(0.0000001"+Right$(expression$,Len(expression$)-a)
	Next
	If Left$(expression$,1)="-" Then Return "0.0000001"+expression$ Else Return expression$
End Function

Function DebugState(ba,s.stack)
	i=0
	bnks=BankSize(ba)
	If bnks Then
		Repeat
			Select PeekByte(ba,i)
			Case 0
				DebugLog "Value:"+PeekInt(ba,i+1)
				i=i+5
			Case 1
				DebugLog "Value:"+PeekFloat(ba,i+1)
				i=i+5
			Case 3
				DebugLog "Operator:"+PeekShort(ba,i+1)
				i=i+3
			Default
				i=i+1
			End Select
			If i>bnks-1 Then Exit
		Forever
	EndIf
	DebugLog "Stack:"
	s2.stack=CreateS.stack()
	While s\el>0
		t#=pop(s)
		DebugLog t#
		Push s2,t
	Wend
	While s2\el>0
		Push s,Pop(s2)
	Wend
End Function

Function EndValue(current_value#,b,bo,s.stack,p=0)
	If current_value>0 Then
		If p Then							;Multiplication on Parenthesis
			.strt
			If s\el<4 Then
				Push s,C_Multiply								;1
			Else
				temp=Pop(s)
				If Precedence(C_Multiply)>Precedence(temp) Then
					Push s,temp								;1
					Push s,C_Multiply
				Else
					ResizeBank b,BankSize(b)+3
					PokeByte b,bo,3							;2
					PokeShort b,bo+1,temp
					bo=bo+3
					Goto strt
				EndIf
			EndIf
		EndIf 
		If current_value# Mod 1=0 Then 
			ResizeBank b,BankSize(b)+5
			PokeByte b,bo,0
			PokeInt b,bo+1,current_value
			bo=bo+5
		Else
			ResizeBank b,BankSize(b)+5
			PokeByte b,bo,1
			PokeFloat b,bo+1,current_value#
			bo=bo+5
		EndIf
		current_value=0
	EndIf
	Return bo
End Function

Function EndString(Current_Text$,b,bo,s.stack)
	If Current_Text$<>"" Then
		Current_text$=Trim(current_text$)
		ID=OperatorID(Current_Text$)
		If ID=C_None Then
			ResizeBank b,BankSize(b)+3
			PokeByte b,bo,2
			PokeShort b,bo+1,RegVar(Current_Text$)
			bo=bo+3
		Else
			.strt
			If s\el<4 Then
				Push s,ID								;1
			Else
				temp=Pop(s)
				If Precedence(ID)>Precedence(temp) Then
					Push s,temp								;1
					Push s,ID
				Else
					ResizeBank b,BankSize(b)+3
					PokeByte b,bo,3							;2
					PokeShort b,bo+1,temp
					bo=bo+3
					Goto strt
				EndIf
			EndIf
		EndIf
	EndIf
	Return bo
End Function

Function RegVar(Expression$)
	For a=0 To VirtualElements(Vars)-1
		If Virtual$(Vars,a)=Expression$ Then Return a
	Next
	Return Addvirtual(Vars,Expression$)
End Function

Function EvaluateBank.stack(Bank)
	s.stack=createS.stack()
	bnks=BankSize(bank)
	If bnks=0 Then pushI(s,-100000):Return
	Repeat
		Select PeekByte(bank,i)
		Case 0
			PushI s,PeekInt(bank,i+1)
			i=i+5
		Case 1
			PushF s,PeekFloat(bank,i+1)
			i=i+5
		Case 3
			DoOperator(s,PeekShort(bank,i+1))
			i=i+3
		Default
			pushI(s,-100000)
			Return s
		End Select
		If i>bnks-1 Then Exit
	Forever
	Return s.stack
End Function

Repeat
	Print Pop(EvaluateBank.stack(ExpressionToBank(Input("Expression?"))))
Forever

Function CreateVirtual()	 ;My own dynamic string array system !LOL! Rather simple, but effective for my uses.
 main=CreateBank(16)
 PokeInt main,0,CreateBank(0)
 PokeInt main,4,CreateBank(0)
 Return main
End Function

Function AddVirtual(main,txt$)
 toc=PeekInt(main,0)
 arr=PeekInt(main,4)
 pos=PeekInt(main,8)
 tocpos=PeekInt(main,12)

 ResizeBank arr,pos+4+Len(txt$)
 PokeString arr,pos,txt$
 ResizeBank toc,tocpos+4
 PokeInt toc,tocpos,pos

 PokeInt main,8,pos+4+Len(txt$)
 PokeInt main,12,tocpos+4

 Return tocpos/4
End Function

Function Virtual$(main,index)
 Return PeekString$(PeekInt(main,4),PeekInt(PeekInt(main,0),index*4))
End Function

Function VirtualElements(main)
 Return PeekInt(main,12)/4
End Function

Function PokeString(bank,offset,value$)
	PokeInt bank,Offset,Len(value$)
	For i=1 To Len(value$)
		PokeByte bank,Offset+i+3,Asc(Mid$(value$,i,1))
	Next
End Function

Function PeekString$(bank,offset)
	l=PeekInt(bank,Offset)
	For i=1 To l
		ttl$=ttl$+Chr$(PeekByte(bank,Offset+i+3))
	Next
	Return ttl$
End Function


Rather hard to follow since i was doing everything in banks without using text since it was designed as the beginning of a tokenizer for an interpreter. Actually, this isnt too far off from a full interpreter.

As far as variables, i had an array for each variable type stored, each with as many elements as required by the program. Then, in the tokenized form of the program, the index and type of variable is given.

Oh, and my method for tokenizing math expressions with order of operations and parenthesis is explained in the "Converting from infix notation" section I added to a wikipedia article.

cheers for posting...i could and have before easily done varibale implementation via types- is there no quicker way?

BotBuilder; how would i implement this? im not on my coding machine just yet- looks simple enough to put in. Im not loking to have to understand it, just put it in and know it works... or an idea as to where i could start writing one...

Il give that one a go later on. Would you mind me using it?