I've been using OPP to evaluate expressions. It works fine but I'm not sure how to treat the combintions invoked by And/Or/Not/Greater Than/Less Than/Equal.
Does anyone know how? Someone here pointed me in the direction of opp so I'm hoping you're reading, and have already solved it.
Here's the code. Just type an expression and it will give you the result. Left and right () are allowed like normal blitz expressions.
Strict
Global toke_id=0
Type deli
Field id
Global cur:TList
Field tag
Function deliTag( deli$,ntag )
Local del = deli[0]
For Local d:deli = EachIn cur
If d.id = del
d.tag=ntag
End If
Next
End Function
Function setcurrent( d:TList )
cur = d
End Function
Function isDel( in )
For Local de:Deli = EachIn cur
If de.id = in Return True
Next
Return False
End Function
Function hastag( in )
For Local de:Deli = EachIn cur
If de.id = in
If de.tag<>0 Return True
End If
Next
Return False
End Function
Function Create:Deli( word )
Local out:deli = New deli
out.id = word
Return out
End Function
Method debug()
Print "Delimiter Debug spool:"
Print "Actual id:"+id
Print "Textural referece "+Chr(id)
End Method
Function CreateDelis:TList( words$ )
Local dli:TList = CreateList()
Local wl = Len(words)
For Local j=1 To wl
Local d:Deli = deli.create( words[j] )
dli.addlast( d )
Next
cur = dli
Return dli
End Function
Function debugList( in:TList )
For Local v:Object = EachIn in
Local d:Deli = Deli(v)
d.debug()
Next
End Function
End Type
Type tokens
Field tokes:TList
Field toke:Object[]
Field ctoke
Method set( tok:TList )
tokes = tok
toke = tok.toarray()
End Method
Method NextToken:Token()
ctoke:+1
If ctoke>tokes.count()
ctoke=tokes.count()
Return Null
End If
Return Token(tokes.valueatindex(ctoke-1))
End Method
Function create:Tokens()
Return New tokens
End Function
Method New()
tokes = CreateList()
End Method
Method add( itoke:Token )
tokes.addlast( itoke )
toke = tokes.toarray()
End Method
Method debug()
For Local t:Token = EachIn tokes
Print t.id
Next
End Method
End Type
Type token
Field id$
Function Create:Token( toke$ )
Local out:token = New token
out.id = toke
Return out
End Function
Method getlut()
Select id
Case "+"
Return plus
Case "-"
Return minus
Case "*"
Return times
Case "/"
Return devide
Case "("
Return scope_entry
Case "}"
Return scope_exit
End Select
Return 0
End Method
Function CreateTokens:TList( tokes$ )
Local out:TList = CreateList()
Local tc = Len(tokes)
For Local j=1 To tc
Local nt:token = token.create( tokes[j] )
out.addlast( nt )
nt.debug()
Next
'Print "Approx " + CountList(out)+"Tokens were defined'
Return out
End Function
Method debug()
Print "Token symbolic info"
Print id
End Method
End Type
Type tokenizer
Function create:tokenizer()
Return New tokenizer
End Function
Method Tokenize:Tokens( text:String )
text = " "+text+" "
Local tk:Tokens = tokens.create()
Local lvc,fvc
lvc=-1
fvc=-1
Local tl= Len(text)
Local snc=0,igdot=0
For Local j=0 To tl-1
Local li = text[j]
If li = 39
If snc=0
fvc=j+1
snc=1
Else
lvc=j-1
snc=0
EndIf
EndIf
If li>47 And li<58
igdot = True
End If
Local skpdel=0
If snc=0
If deli.isdel( li )
If igdot = True
If li = 46
skpdel=True
End If
EndIf
If Not skpdel
If lvc<>fvc And fvc<>-1
If lvc<fvc lvc=fvc
Local tst$ = text[fvc..lvc+1]
' Print "Token:"+tst
tk.add( token.create( tst ) )
fvc=-1
lvc=-1
EndIf
If deli.hastag( li )
tk.add( token.create( Chr(li) ) )
Print "deli "+li+" Had a tag"
EndIf
igdot=False
End If
Else
If fvc=-1
fvc=j
Else
lvc=j
EndIf
EndIf
EndIf
Next
Return tk
End Method
End Type
Const Scope_Entry=1,Scope_Exit=2
Const Assign = 3,Minus=4,Plus=5,Times=7,Devide=8
Const classentry=9,numeric=10,value=11,tend=12
Const reduce=1,shift=2
Global act:Int[,] = New Int[20,20]
act[Plus,plus] = reduce
act[plus,minus] = reduce
act[plus,times] = shift
act[plus,devide] = shift
act[plus,scope_entry] = shift
act[plus,scope_Exit] = reduce
act[plus,tend] = reduce
act[minus,plus] = reduce
act[minus,minus] = reduce
act[minus,times] = shift
act[minus,devide] = shift
act[minus,scope_entry] = shift
act[minus,scope_exit] = reduce
act[minus,tend] = reduce
act[times,plus] = reduce
act[times,minus] = reduce
act[times,times] = reduce
act[times,devide] = reduce
act[times,scope_entry] = shift
act[times,scope_Exit] = reduce
act[times,tend] = reduce
act[devide,plus] = reduce
act[devide,minus] = reduce
act[devide,Times] = reduce
act[devide,devide] = reduce
act[devide,scope_entry] = shift
act[devide,scope_exit] = reduce
act[devide,tend ] = reduce
act[scope_entry,plus] = shift
act[scope_entry,minus] = shift
act[scope_entry,times] = shift
act[scope_entry,devide] = shift
act[scope_entry,scope_Entry] = shift
act[scope_Entry,scope_exit] = shift
act[scope_Exit,plus] = reduce
act[scope_exit,minus] = reduce
act[scope_exit,devide] = reduce
act[scope_exit,times] = reduce
act[scope_Exit,scope_entry] = reduce
act[scope_exit,scope_exit] = reduce
act[scope_exit,tend] = reduce
act[tend,plus] = shift
act[tend,minus] = shift
act[tend,times] = shift
act[tend,devide] = shift
act[tend,scope_entry] = shift
act[tend,tend] = tend
Const delimiters:String = "{}[]';;!@#$%^&*()_+=-/.,?{><\|<> ` "
Global maindel:TList = deli.createdelis( delimiters )
deli.delitag( "(",Scope_Entry )
deli.delitag( ")",Scope_Exit )
deli.delitag( "=",Assign )
deli.delitag( "-",Minus)
deli.delitag( "+",Plus)
deli.delitag( "*",Times)
deli.delitag( "/",Devide)
deli.delitag( ".",ClassEntry)
deli.delitag( "#",Numeric)
deli.delitag( ";",TEnd)
Type Stack
Field Val:Object[5000]
Field at
Method Push(obj:Object)
val[at]=obj
at:+1
End Method
Method Pop:Object()
at:-1
If at<0 at=0
Return val[at]
End Method
Method Get:Object()
If at>0 Return val[at-1]
End Method
Method size()
Return at
End Method
End Type
Type ExpressionParser
Field Val:Double[2000],valTop
Field Opr:String[2000],oprTop
Field tokes:Tokens
Method New()
End Method
Method Parse!( Expr:String )
Local tk:Tokenizer = New Tokenizer
tokes:Tokens = tk.tokenize( expr+";" )
valtop=-1
oprtop=0
opr[oprtop]=tend
If nxttok() Return 1
Repeat
If tok = value
If shiftstack() Return 1
Continue
End If
Select act[Int(opr[oprtop]),tok]
Case reduce
If reducestack() Return 1
Case shift
If shiftstack() Return 1
Case tend
If valtop<>0
Print "Syntax error"
End If
Return val[valtop]
Default
Print "Unknown combo:"
Print opr[oprtop]+":"+tok
End
End Select
Forever
End Method
Field debug1:String,debug2:String
Method nxtTok()
Local tokey:Token = tokes.nextToken()
If tokey=Null Return 1
debug1 = tokey.id
getTok( tokey.id )
End Method
Field tokval!,tok
Method GetTok(Toke:String)
Select toke
Case "+"
tok=plus
Case "-"
tok=minus
Case "*"
tok=times
Case "/"
tok=devide
Case "("
tok=scope_entry
Case ")"
tok=scope_exit
Case ";"
tok=tend
Default
tok=value
tokval=Double(toke)
End Select
End Method
Method shiftstack()
If tok = value
valTop:+1
val[valTop]=tokval
Else
oprTop:+1
opr[oprtop]=String(tok)
EndIf
If nxtTok() Return 1
End Method
Method Reducestack()
Select Int(opr[oprtop])
Case plus
val[valtop-1]:+val[valtop]
valtop:-1
Case minus
val[valtop-1]:-val[valtop]
valtop:-1
Case times
val[valtop-1]:*val[valtop]
valtop:-1
Case devide
val[valtop-1]:/val[valtop]
valtop:-1
Case scope_exit
oprtop:-1
End Select
oprtop:-1
End Method
End Type
Print "Running."
While True
Local ep:ExpressionParser = New ExpressionParser
Print "Answer:"+ep.Parse(Input())
Wend
|