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