doubles.. but:
MaGetzUb wrote:Miten sitten voisi tehdä laskukoneen jossa olisi perus +, -, /, * toiminnot ja algoritmina olisi Käänteinen Puolalainen Notaatio?
Pinolla kenties?
Ei vaan siis oikeasti, RPN-notaatiossa luet "2 3 1 2 + / ^" syötteen vasemalta oikealle, työntäen arvot pinoon.
Kun törmät "2 3 1 2" jälkeen lasku operaatioon "+" poppaat pinosta operaattorin haluaman määrän tavaraa ("2" ja "1" siis) ja suoritat laskun. Tuloksen lykkäät
takaisin pinoon. Tätä sitten toistetaan kunnes pinossa on jäljellä enää vastaus. Jos joltain laskuoperaattorilta loppuivat operandit kesken, kyseessä on virhe.
Note: " x y *" -> "y * x", tai en muista meneekö se sitenkin näin päin: "x y *" -> "x * y". Jompi kumpi, wikissä on hyvä artikkeli.
Bonuksena pakastuneesta kääntäjästä pätkä Infix -> RPN koodia:
Code: Select all
'Lausekkeen Tokenisaattori
Function TokenizeString(txt$)
For i = 0 To SM_TotalKeywords
MaxLen% = Max(MaxLen, Len( SM_Keyword(i) ) )
Next i
'Lisätään välimerkkejä avain sanojen ympärille
processed_text$ = ""
i = 1
k = 1
While i <= Len(txt)
keyLen% = 1
keyStr$ = ""
For j = 0 To SM_TotalKeywords
For k = 1 To MaxLen
If Mid(txt, i, k) = SM_Keyword(j) And k => keyLen
keyLen = k
keyStr$ = SM_Keyword(j)
EndIf
Next k
Next j
If keyStr <> ""
processed_text = processed_text + " " + keyStr + " "
Else
processed_text = processed_text + Mid(txt, i, 1)
EndIf
i = i + keyLen
Wend
'Poistetaan ylimääräiset välimerkit
For i = 0 To SM_TotalKeywords
processed_text = Replace(processed_text, " "+SM_Keyword(i), " "+SM_Keyword(i))
processed_text = Replace(processed_text, SM_Keyword(i)+" ", SM_Keyword(i)+" ")
processed_text = Replace(processed_text, " ", " ")
Next i
Return processed_text
EndFunction
'Apufunktio: Lisää ulostuloon kunnes pinossa päällimäisenä olevan operaation prioriteetti
' on pienempi kuin annettu tai operaatio on arvo/muuttuja.
Function PopUntil(PRIORITY)
iCS.ConvertStack = Last(ConvertStack)
While iCS <> NULL
If iCS\Priority => PRIORITY Or iCS\ID = OPR_VALUE Or iCS\ID = OPR_VARIABLE
nOperand.OperatorStack = New(OperatorStack)
nOperand\ID = iCS\ID
nOperand\Value = iCS\Value
Delete iCS
Else
Exit
EndIf
iCS = Last(ConvertStack)
Wend
EndFunction
'Parsii lausekkeen (ja kaikki muut prioriteetin omaavat toimitukset)
Function ParseStatement(statement$)
For i = 1 To CountWords(statement)
operand$ = GetWord(statement, i)
If Float(operand) <> 0.0 Or operand = "0" Or operand = "0.0"
'Tarkistetaan negaatio: (joko suoritetaan negaatio tässä,
' tai muutetaan miinus negaatio operaatioksi)
peek1.OperatorStack = Last(OperatorStack)
If peek1 <> NULL
peek2.OperatorStack = Before(peek1)
If peek2 <> NULL
peek3.OperatorStack = Before(peek2)
If peek3 <> NULL
If peek1\ID = OPR_MINUS And peek2\ID <> OPR_VALUE And peek3\ID <> OPR_VALUE
'kyseessä ON negaatio, muutetaan.
peek1\ID = OPR_NEGATE
EndIf
EndIf
EndIf
EndIf
'Lisätään luku pinoon.
nCS.ConvertStack = New(ConvertStack)
nCS\Priority = PRI_MIN
nCS\ID = OPR_VALUE
nCS\Value = Float(operand)
Else
'Käsitellään operaattorit niiden prioriteetin mukaan.
Select operand
Case "&&", "||", "!", "!|"
PopUntil(PRI_LOGIC)
Select operand
Case "&&": ID% = OPR_AND
Case "||": ID = OPR_OR
Case "!": ID = OPR_NOT
Case "!|": ID = OPR_XOR
EndSelect
nCS.ConvertStack = New(ConvertStack)
nCS\Priority = PRI_LOGIC
nCS\ID = ID
Case "==", "!=", "<", "=>", ">", "=<"
PopUntil(PRI_COMPARE)
Select operand
Case "==": ID% = OPR_EQUAL
Case "!=": ID = OPR_INEQUAL
Case "<": ID = OPR_LESS
Case "=>": ID = OPR_LESS_OR_EQUAL
Case ">": ID = OPR_GREATER
Case "=<": ID = OPR_GREATER_OR_EQUAL
EndSelect
nCS.ConvertStack = New(ConvertStack)
nCS\Priority = PRI_COMPARE
nCS\ID = ID
Case "-", "+"
'Poistetaan pinosta mahdolliset suuremman prioriteetin omaavat operaatiot,
'ja lisätään ne ulostulo pinoon.
PopUntil(PRI_MINUS_PLUS_NEGATE)
'Lisätään operaatio "muunto"-pinoon
If operand = "-" Then ID% = OPR_MINUS
If operand = "+" Then ID% = OPR_PLUS
nCS.ConvertStack = New(ConvertStack)
nCS\Priority = PRI_MINUS_PLUS_NEGATE
nCS\ID = ID
Case "*", "/"
PopUntil(PRI_MULTIPLY_DIVISION)
'Lisätään operaatio "muunto"-pinoon
If operand = "*" Then ID% = OPR_MULTIPLY
If operand = "/" Then ID% = OPR_DIVISION
nCS.ConvertStack = New(ConvertStack)
nCS\Priority = PRI_MULTIPLY_DIVISION
nCS\ID = ID
Case "^"
PopUntil(PRI_POWER)
'Lisätään operaatio "muunto"-pinoon
nCS.ConvertStack = New(ConvertStack)
nCS\Priority = PRI_POWER
nCS\ID = OPR_POWER
Case "("
'Lisätään suoraan pinoon
nCS.ConvertStack = New(ConvertStack)
nCS\Priority = PRI_MIN
nCS\ID = OPR_BRACKET
Case ")"
'Lisätään "muunto" pinosta ulostuloon kunnes saavutetaan "(" merkki
iCS.ConvertStack = Last(ConvertStack)
While iCS <> NULL
If iCS\ID <> OPR_BRACKET
nOperand.OperatorStack = New(OperatorStack)
nOperand\ID = iCS\ID
nOperand\Value = iCS\Value
Delete iCS
Else
Exit
EndIf
iCS.ConvertStack = Last(ConvertStack)
Wend
If iCS <> NULL Then Delete iCS Else MakeError "Non equal Brackets!" 'poistetaan vielä "("
Case "="
PopUntil(PRI_MIN)
nCS.ConvertStack = New(ConvertStack)
nCS\Priority = PRI_MIN
nCS\ID = OPR_SETVARIABLE
Default
'Sana ei ollut operaattori eikä numero, joten tarkistetaan onko se muuttuja.
For iVar.Variable = Each Variable
If Lower(operand) = iVar\NameID
'Muuttuja nimi ON olemassa, lisätään pinoon.
nCS.ConvertStack = New(ConvertStack)
nCS\ID = OPR_VARIABLE
nCS\Priority = PRI_MIN
nCS\Value = ConvertToInteger(iVar)
Exit
EndIf
Next iVar
EndSelect
EndIf
Next i
'Popataan loput.
iCS.ConvertStack = Last(ConvertStack)
While iCS <> NULL
'Thyjennetään muuntopino ja tarkistetaan virheet.
If iCS\ID = OPR_BRACKET Then MakeError "Non equal Brackets!"
nOperand.OperatorStack = New(OperatorStack)
nOperand\ID = iCS\ID
nOperand\Value = iCS\Value
Delete iCS
iCS.ConvertStack = Last(ConvertStack)
Wend
EndFunction