Systeemin toiminta periaate selviää Wikipediasta: http://en.wikipedia.org/wiki/Shunting_yard_algorithm ja http://en.wikipedia.org/wiki/Stack_(data_structure)
Koodin lopussa on esimerkki lasku, jonka oikeaa vastausta en ole jaksanut laskea käsin.
Pistäkää tähän topiikiin kommentien lisäksi omia laskin systeemejäne.
Code: Select all
///////////////////////////////////////////
// Konversio funktio infix -> postfix //
// "reverse polish notation" //
///////////////////////////////////////////
Const STACK_BLOCK = 5 'pinon "blockin" koko. esim: "( " eli yhteensä 5 merkkiä
Function InfixToPostfix(statement$)
//siistitään lauseke
statement = Replace(Trim(statement), "+", " + ")
statement = Replace(Trim(statement), "-", " - ")
statement = Replace(Trim(statement), "*", " * ")
statement = Replace(Trim(statement), "/", " / ")
statement = Replace(Trim(statement), "^", " ^ ")
statement = Replace(Trim(statement), "(", " ( ")
statement = Replace(Trim(statement), ")", " ) ")
statement = Replace(Trim(statement), " ", " ")
rpn$ = ""
opr_stack$ = ""
prev_opr2 = False
prev_opr1 = False
For i = 1 To CountWords(statement)
token$ = GetWord(statement, i)
Select token
Case "("
opr_stack = opr_stack + "( "
prev_opr2 = prev_opr1
prev_opr1 = 1
Case ")"
opr$ = ""
While Len(opr_stack)>0 And opr <> "("
opr$ = Trim(Right(opr_stack, STACK_BLOCK))
opr_stack = StrRemove(opr_stack, Int(Max(1,Len(opr_stack)-STACK_BLOCK)), STACK_BLOCK)
If opr <> "(" Then rpn = rpn + " " + opr
Wend
Case "+", "-"
opr$ = ""
While Len(opr_stack)>0 And opr <> "("
opr$ = Trim(Right(opr_stack, 5))
opr_stack = StrRemove(opr_stack, Int(Max(1,Len(opr_stack)-STACK_BLOCK)), STACK_BLOCK)
If opr <> "(" Then rpn = rpn + " " + opr
Wend
opr_stack = opr_stack + token + " "
If token = "-" Then
prev_opr2 = prev_opr1
prev_opr1 = 2
Else
prev_opr2 = prev_opr1
prev_opr1 = 1
EndIf
Case "*", "/"
opr$ = ""
While Len(opr_stack)>0 And opr <> "(" And (opr = "*" Or opr = "/" Or opr = "^")
opr$ = Trim(Right(opr_stack, 5))
opr_stack = StrRemove(opr_stack, Int(Max(1,Len(opr_stack)-STACK_BLOCK)), STACK_BLOCK)
If opr <> "(" Then rpn = rpn + " " + opr
Wend
opr_stack = opr_stack + token + " "
prev_opr2 = prev_opr1
prev_opr1 = 1
Case "^"
opr$ = ""
While Len(opr_stack)>0 And opr <> "(" And opr = "^"
opr$ = Trim(Right(opr_stack, 5))
opr_stack = StrRemove(opr_stack, Int(Max(1,Len(opr_stack)-STACK_BLOCK)), STACK_BLOCK)
If opr <> "(" Then rpn = rpn + " " + opr
Wend
opr_stack = opr_stack + token + " "
prev_opr2 = prev_opr1
prev_opr1 = 1
Default
If Float(token)<>0 Or token = "0" Or token = "0.0" Then
rpn = rpn + " "
If prev_opr2 = 1 And prev_opr1 = 2 Then rpn = rpn + "-" + token Else rpn = rpn + token
prev_opr2 = prev_opr1
rev_opr1 = 0
EndIf
EndSelect
Next i
opr$ = ""
While Len(opr_stack)>0
opr$ = Trim(Right(opr_stack, 5))
opr_stack = StrRemove(opr_stack, Int(Max(1,Len(opr_stack)-STACK_BLOCK)), STACK_BLOCK)
rpn = rpn + " " + opr
Wend
Return Trim(rpn)
EndFunction
//laskee muunnetun lausekkeen arvon.
Function Calculate(math$)
stack$ = ""
Repeat
opr$ = GetWord(math$, 1)
math$ = Trim(Mid(math$, Len(opr$)+1))
If Float(opr$)<>0 Or opr$ = "0" Or opr$ = "0.0" Then stack$ = stack$ +" "+ opr$
offset% = CountWords(stack)
If offset=1
'Return Float(GetWord(stack$, offset%))
Else
num1$ = GetWord(stack$, offset%)
num2$ = GetWord(stack$, offset%-1)
EndIf
Select opr
Case "+"
val1# = Float(num1$)
val2# = Float(num2$)
pos% = Max(1,Len(stack$)-Len(" "+num1$+num2$))
stack$ = StrRemove(stack$, pos, Len(" "+num1$+num2$))
stack$ = Trim(stack$+" "+(val1# + val2#))
Case "-"
val1# = Float(num2$)
val2# = Float(num1$)
pos% = Max(1,Len(stack$)-Len(" "+num1$+num2$))
stack$ = StrRemove(stack$, pos, Len(" "+num1$+num2$))
stack$ = Trim(stack$+" "+(val1# - val2#))
Case "*"
val1# = Float(num1$)
val2# = Float(num2$)
pos% = Max(1,Len(stack$)-Len(" "+num1$+num2$))
stack$ = StrRemove(stack$, pos, Len(" "+num1$+num2$))
stack$ = Trim(stack$+" "+(val1# * val2#))
Case "/"
val1# = Float(num2$)
val2# = Float(num1$)
pos% = Max(1,Len(stack$)-Len(" "+num1$+num2$))
stack$ = StrRemove(stack$, pos, Len(" "+num1$+num2$))
stack$ = Trim(stack$+" "+(val1# / val2#))
Case "^"
val1# = Float(num2$)
val2# = Float(num1$)
pos% = Max(1,Len(stack$)-Len(" "+num1$+num2$))
stack$ = StrRemove(stack$, pos, Len(" "+num1$+num2$))
stack$ = Trim(stack$+" "+(val1# ^ val2#))
EndSelect
Until Len(math$)=0 And CountWords(stack$)=1
Return Float(Trim(stack$))
EndFunction
SCREEN 800,300
Const math = "(100+123*0.1)/-13.0+(2.0+(6+(-7-2)+8.0)*(34/2)-3^(-2+1))^0.5"
repeat
Text 0,0,math
ticks%=Timer()
convert$ = InfixToPostfix(math)
Text 0,12, convert
Text 0,24, "answer is: "+Calculate(convert)
Text 0,36, "time went to conversion and calulation: "+(Timer()-ticks)+" ms"
DrawScreen
Forever