-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrpn.go
91 lines (75 loc) · 1.58 KB
/
rpn.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// Package rpn provides a Reverse Polish Notation (RPN) evaluator
package rpn
import (
"errors"
"fmt"
"math"
"strconv"
"strings"
)
var operators = "+-*/^"
// Evalrpn is a Reverse Polish Notation calculator.
// It parses the tokens and returns the result.
func Evalrpn(tokens []string) (float64, error) {
if len(tokens) <= 0 {
return 0, errors.New("no tokens to evaluate")
}
var err error
var x, y float64
stack := newOperandStack()
for i, t := range tokens {
if strings.Contains(operators, t) {
x, err = stack.pop()
if err != nil {
return 0, fmt.Errorf("processing token %v: %v", i, err)
}
y, err = stack.pop()
if err != nil {
return 0, fmt.Errorf("processing token %v: %v", i, err)
}
}
switch t {
case "+":
stack.push(x + y)
case "-":
stack.push(y - x)
case "*":
stack.push(x * y)
case "/":
stack.push(y / x)
case "^":
stack.push(math.Pow(y, x))
default:
x, err = strconv.ParseFloat(t, 64)
if err != nil {
return 0, fmt.Errorf("processing token %v: %v", i, err)
}
stack.push(x)
}
}
return stack.pop()
}
type operandStack struct {
head *stacknode
}
type stacknode struct {
value float64
next *stacknode
}
func newOperandStack() *operandStack {
return &operandStack{}
}
func (s *operandStack) isEmpty() bool {
return (s.head == nil)
}
func (s *operandStack) push(v float64) {
s.head = &stacknode{v, s.head}
}
func (s *operandStack) pop() (float64, error) {
if s.isEmpty() {
return 0, errors.New("cannot pop, operand stack is empty")
}
popped := s.head
s.head = s.head.next
return popped.value, nil
}