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 FunctionRather 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.