2021-03-06 22:30:32 +03:00
|
|
|
package main
|
|
|
|
|
|
|
|
// Helper functions to convert infix notation to RPN and calculates expression result.
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"strconv"
|
|
|
|
|
2024-04-28 02:33:13 +03:00
|
|
|
"go.neonxp.ru/unilex"
|
2021-03-06 22:30:32 +03:00
|
|
|
)
|
|
|
|
|
2021-03-06 22:38:08 +03:00
|
|
|
var opPriority = map[string]int{
|
|
|
|
"^": 3,
|
|
|
|
"!": 3,
|
|
|
|
"*": 2,
|
|
|
|
"/": 2,
|
|
|
|
"+": 1,
|
|
|
|
"-": 1,
|
|
|
|
}
|
|
|
|
|
2021-03-06 22:30:32 +03:00
|
|
|
func infixToRPNotation(l *unilex.Lexer) []unilex.Lexem {
|
|
|
|
output := []unilex.Lexem{}
|
|
|
|
stack := lexemStack{}
|
|
|
|
parseLoop:
|
|
|
|
for ll := range l.Output { // Read lexems from Lexer output channel, convert starts as soon as first lexems scanned!
|
|
|
|
fmt.Printf("Lexem: %+v\n", ll)
|
|
|
|
|
|
|
|
switch {
|
2022-02-02 22:17:30 +03:00
|
|
|
case ll.Type == NUMBER, ll.Type == OPERATOR && ll.Value == "!":
|
2021-03-06 22:30:32 +03:00
|
|
|
output = append(output, ll)
|
2022-02-02 22:17:30 +03:00
|
|
|
case ll.Type == LP:
|
2021-03-06 22:30:32 +03:00
|
|
|
stack.Push(ll)
|
2022-02-02 22:17:30 +03:00
|
|
|
case ll.Type == RP:
|
2021-03-06 22:30:32 +03:00
|
|
|
for {
|
|
|
|
cl := stack.Pop()
|
2022-02-02 22:17:30 +03:00
|
|
|
if cl.Type == LP {
|
2021-03-06 22:30:32 +03:00
|
|
|
break
|
|
|
|
}
|
2022-02-02 22:17:30 +03:00
|
|
|
if cl.Type == unilex.LexEOF {
|
2021-03-06 22:30:32 +03:00
|
|
|
log.Fatalf("No pair for parenthesis at %d", ll.Start)
|
|
|
|
}
|
|
|
|
output = append(output, cl)
|
|
|
|
}
|
2022-02-02 22:17:30 +03:00
|
|
|
case ll.Type == OPERATOR:
|
2021-03-06 22:30:32 +03:00
|
|
|
for {
|
2022-02-02 22:17:30 +03:00
|
|
|
if stack.Head().Type == OPERATOR && (opPriority[stack.Head().Value] > opPriority[ll.Value]) {
|
2021-03-06 22:30:32 +03:00
|
|
|
output = append(output, stack.Pop())
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
stack.Push(ll)
|
2022-02-02 22:17:30 +03:00
|
|
|
case ll.Type == unilex.LexEOF:
|
2021-03-06 22:30:32 +03:00
|
|
|
break parseLoop
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-02 22:17:30 +03:00
|
|
|
for stack.Head().Type != unilex.LexEOF {
|
2021-03-06 22:30:32 +03:00
|
|
|
output = append(output, stack.Pop())
|
|
|
|
}
|
|
|
|
|
|
|
|
return output
|
|
|
|
}
|
|
|
|
|
|
|
|
func calculateRPN(rpnLexems []unilex.Lexem) string {
|
|
|
|
stack := lexemStack{}
|
|
|
|
for _, op := range rpnLexems {
|
2022-02-02 22:17:30 +03:00
|
|
|
if op.Type == NUMBER {
|
2021-03-06 22:30:32 +03:00
|
|
|
stack.Push(op)
|
|
|
|
} else {
|
|
|
|
switch op.Value {
|
|
|
|
case "+":
|
|
|
|
a1, _ := strconv.ParseFloat(stack.Pop().Value, 64)
|
|
|
|
a2, _ := strconv.ParseFloat(stack.Pop().Value, 64)
|
2022-02-02 22:17:30 +03:00
|
|
|
stack.Push(unilex.Lexem{Type: NUMBER, Value: strconv.FormatFloat(a2+a1, 'f', -1, 64)})
|
2021-03-06 22:30:32 +03:00
|
|
|
case "-":
|
|
|
|
a1, _ := strconv.ParseFloat(stack.Pop().Value, 64)
|
|
|
|
a2, _ := strconv.ParseFloat(stack.Pop().Value, 64)
|
2022-02-02 22:17:30 +03:00
|
|
|
stack.Push(unilex.Lexem{Type: NUMBER, Value: strconv.FormatFloat(a2-a1, 'f', -1, 64)})
|
2021-03-06 22:30:32 +03:00
|
|
|
case "*":
|
|
|
|
a1, _ := strconv.ParseFloat(stack.Pop().Value, 64)
|
|
|
|
a2, _ := strconv.ParseFloat(stack.Pop().Value, 64)
|
2022-02-02 22:17:30 +03:00
|
|
|
stack.Push(unilex.Lexem{Type: NUMBER, Value: strconv.FormatFloat(a2*a1, 'f', -1, 64)})
|
2021-03-06 22:30:32 +03:00
|
|
|
case "/":
|
|
|
|
a1, _ := strconv.ParseFloat(stack.Pop().Value, 64)
|
|
|
|
a2, _ := strconv.ParseFloat(stack.Pop().Value, 64)
|
2022-02-02 22:17:30 +03:00
|
|
|
stack.Push(unilex.Lexem{Type: NUMBER, Value: strconv.FormatFloat(a2/a1, 'f', -1, 64)})
|
2021-03-06 22:30:32 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return stack.Head().Value
|
|
|
|
}
|