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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
package main
import "strconv"
type AngleMode bool
const (
degrees AngleMode = false
radians AngleMode = true
)
func (a AngleMode) String() string {
if a == degrees {
return "deg"
}
return "rad"
}
type Calculator struct {
stack Stack
buf string
angleMode AngleMode
}
// swap swaps the values of the buffer and the bottom element of the stack. If
// the buffer is empty this simply pops from the stack. If the stack is empty,
// this simply pushes to the stack.
func (c *Calculator) swap() {
stackVal, err := c.stack.pop()
stackIsEmpty := err != nil
if v, err := c.parseBuffer(); err == nil {
c.stack.push(v)
}
if stackIsEmpty {
c.buf = ""
} else {
c.buf = printNum(stackVal)
}
}
// dup duplicates the value at the bottom of the stack.
func (c *Calculator) dup() {
v, err := c.stack.pop()
if err != nil {
// empty
return
}
c.stack.push(v)
c.stack.push(v)
}
// negate negates the number in the buffer, if any; or the bottom number on the
// stack, if any.
func (c *Calculator) negate() {
if v, err := c.parseBuffer(); err == nil {
c.buf = printNum(-v)
} else if len(c.buf) == 0 && len(c.stack) > 0 {
c.stack[len(c.stack)-1] = -c.stack[len(c.stack)-1]
}
}
// operate performs a binary arithmetic operation on the stored values.
func (c *Calculator) operate(op Op) {
lhs, rhs, err := c.operands()
if err != nil {
return
}
c.stack.push(op(lhs, rhs))
c.buf = ""
}
// operands returns the left and right operands, or error if there are not enough.
func (c *Calculator) operands() (lhs, rhs float64, err error) {
if rhs, err = c.parseBuffer(); err == nil {
lhs, err = c.stack.pop()
return
} else if rhs, err = c.stack.pop(); err == nil {
lhs, err = c.stack.pop()
if err != nil { // missing lhs
c.stack.push(rhs)
}
return
}
return 0, 0, OperandErr{}
}
// parseBuffer returns the numerical value of the contents of the buffer.
func (c Calculator) parseBuffer() (float64, error) {
if con, err := parseConstant(c.buf); err == nil {
return con, nil
} else if fl, err := strconv.ParseFloat(c.buf, 64); err == nil {
return fl, nil
}
return 0, InvalidBufferContentErr{c.buf}
}
type InvalidBufferContentErr struct {
buf string
}
func (e InvalidBufferContentErr) Error() string {
return "invalid buffer contents: " + e.buf
}
type OperandErr struct{}
func (e OperandErr) Error() string {
return "not enough operands"
}
|