the rpn parser was moved to it's own repo and already imported in go.modpull/5/head
parent
d9e1efbaf0
commit
e2f25eaab4
@ -1,156 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Operator struct {
|
|
||||||
Token string
|
|
||||||
Precedence int
|
|
||||||
Association string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o Operator) HasHigherPrecedence(t Operator) bool {
|
|
||||||
return o.Precedence < t.Precedence // lower number is higher precedence
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o Operator) HasEqualPrecedence(t Operator) bool {
|
|
||||||
return o.Precedence == t.Precedence
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o Operator) IsLeftAssociative() bool {
|
|
||||||
return o.Association == "left"
|
|
||||||
}
|
|
||||||
|
|
||||||
var operators = map[string]Operator{
|
|
||||||
"+": Operator{
|
|
||||||
Token: "+",
|
|
||||||
Precedence: 4,
|
|
||||||
Association: "left",
|
|
||||||
},
|
|
||||||
"-": Operator{
|
|
||||||
Token: "-",
|
|
||||||
Precedence: 4,
|
|
||||||
Association: "left",
|
|
||||||
},
|
|
||||||
"*": Operator{
|
|
||||||
Token: "*",
|
|
||||||
Precedence: 3,
|
|
||||||
Association: "left",
|
|
||||||
},
|
|
||||||
"/": Operator{
|
|
||||||
Token: "/",
|
|
||||||
Precedence: 3,
|
|
||||||
Association: "left",
|
|
||||||
},
|
|
||||||
"%": Operator{
|
|
||||||
Token: "%",
|
|
||||||
Precedence: 3,
|
|
||||||
Association: "left",
|
|
||||||
},
|
|
||||||
"(": Operator{
|
|
||||||
Token: "(",
|
|
||||||
Precedence: 1,
|
|
||||||
Association: "left",
|
|
||||||
},
|
|
||||||
")": Operator{
|
|
||||||
Token: ")",
|
|
||||||
Precedence: 1,
|
|
||||||
Association: "left",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
type Stack []Operator
|
|
||||||
|
|
||||||
func (s *Stack) IsEmpty() bool {
|
|
||||||
return len(*s) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stack) Push(op Operator) {
|
|
||||||
*s = append(*s, op)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stack) Pop() (Operator, bool) {
|
|
||||||
if s.IsEmpty() {
|
|
||||||
return Operator{}, false
|
|
||||||
}
|
|
||||||
index := len(*s) - 1
|
|
||||||
element := (*s)[index]
|
|
||||||
*s = (*s)[:index]
|
|
||||||
return element, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stack) Top() Operator {
|
|
||||||
if s.IsEmpty() {
|
|
||||||
return Operator{}
|
|
||||||
}
|
|
||||||
return (*s)[len(*s)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
func GenerateRPN(tokens []string) (string, error) {
|
|
||||||
output := ""
|
|
||||||
s := Stack{}
|
|
||||||
for _, token := range tokens {
|
|
||||||
err := processToken(token, &s, &output)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for !s.IsEmpty() {
|
|
||||||
ele, _ := s.Pop()
|
|
||||||
output += " " + ele.Token
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.TrimSpace(output), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func processToken(t string, s *Stack, o *string) error {
|
|
||||||
if _, err := strconv.Atoi(t); err == nil {
|
|
||||||
*o += " " + t
|
|
||||||
return nil
|
|
||||||
} else if op, ok := operators[t]; ok {
|
|
||||||
if op.Token == "(" {
|
|
||||||
s.Push(op)
|
|
||||||
} else if op.Token == ")" {
|
|
||||||
if s.IsEmpty() {
|
|
||||||
return fmt.Errorf("mismatched parentheses")
|
|
||||||
}
|
|
||||||
for s.Top().Token != "(" {
|
|
||||||
if ele, ok := s.Pop(); ok {
|
|
||||||
*o += " " + ele.Token
|
|
||||||
} else {
|
|
||||||
return fmt.Errorf("mismatched parentheses")
|
|
||||||
}
|
|
||||||
if s.IsEmpty() {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s.Pop() // Pop and discard the (
|
|
||||||
} else if !s.IsEmpty() {
|
|
||||||
for {
|
|
||||||
if (s.Top().HasHigherPrecedence(op) ||
|
|
||||||
(s.Top().HasEqualPrecedence(op) &&
|
|
||||||
op.IsLeftAssociative())) &&
|
|
||||||
s.Top().Token != "(" {
|
|
||||||
if ele, ok := s.Pop(); ok {
|
|
||||||
*o += " " + ele.Token
|
|
||||||
if s.IsEmpty() {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
s.Push(op)
|
|
||||||
} else {
|
|
||||||
s.Push(op)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return fmt.Errorf("invalid character %s", t)
|
|
||||||
}
|
|
||||||
@ -1,95 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"math"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FStack []float64
|
|
||||||
|
|
||||||
func (s *FStack) IsEmpty() bool {
|
|
||||||
return len(*s) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FStack) Push(op float64) {
|
|
||||||
*s = append(*s, op)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FStack) Pop() (float64, bool) {
|
|
||||||
if s.IsEmpty() {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
index := len(*s) - 1
|
|
||||||
element := (*s)[index]
|
|
||||||
*s = (*s)[:index]
|
|
||||||
return element, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FStack) PopTwo() (float64, float64, bool) {
|
|
||||||
if s.IsEmpty() || len(*s) < 2 {
|
|
||||||
return 0, 0, false
|
|
||||||
}
|
|
||||||
index := len(*s) - 1
|
|
||||||
b := (*s)[index]
|
|
||||||
a := (*s)[index-1]
|
|
||||||
*s = (*s)[:index-1]
|
|
||||||
return a, b, true
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *FStack) Top() float64 {
|
|
||||||
if s.IsEmpty() {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return (*s)[len(*s)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseRPN(args []string) (float64, error) {
|
|
||||||
s := FStack{}
|
|
||||||
for _, token := range args {
|
|
||||||
switch token {
|
|
||||||
case "+":
|
|
||||||
if a, b, ok := s.PopTwo(); ok {
|
|
||||||
s.Push(a + b)
|
|
||||||
} else {
|
|
||||||
return 0, fmt.Errorf("not enough operands on stack for +: %v", s)
|
|
||||||
}
|
|
||||||
case "-":
|
|
||||||
if a, b, ok := s.PopTwo(); ok {
|
|
||||||
s.Push(a - b)
|
|
||||||
} else {
|
|
||||||
return 0, fmt.Errorf("not enough operands on stack for -: %v", s)
|
|
||||||
}
|
|
||||||
case "*":
|
|
||||||
if a, b, ok := s.PopTwo(); ok {
|
|
||||||
s.Push(a * b)
|
|
||||||
} else {
|
|
||||||
return 0, fmt.Errorf("not enough operands on stack for *: %v", s)
|
|
||||||
}
|
|
||||||
case "/":
|
|
||||||
if a, b, ok := s.PopTwo(); ok {
|
|
||||||
s.Push(a / b)
|
|
||||||
} else {
|
|
||||||
return 0, fmt.Errorf("not enough operands on stack for /: %v", s)
|
|
||||||
}
|
|
||||||
case "%":
|
|
||||||
if a, b, ok := s.PopTwo(); ok {
|
|
||||||
s.Push(math.Mod(a, b))
|
|
||||||
} else {
|
|
||||||
return 0, fmt.Errorf("not enough operands on stack for %: %v", s)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
f, err := strconv.ParseFloat(token, 64)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
s.Push(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if res, ok := s.Pop(); ok {
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
return 0, errors.New("no result")
|
|
||||||
}
|
|
||||||
Loading…
Reference in new issue