unilex/example/math_expression/rpn.go

94 lines
2.3 KiB
Go
Raw Normal View History

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
}