rpn.go
1969 bytes
1package rpn
2
3import (
4 "fmt"
5 "math"
6)
7
8type RPN struct {
9 stack *Stack
10 lexer *Lexer
11}
12
13type Event int
14
15const (
16 EventNone Event = iota
17 EventHelp
18 EventExit
19)
20
21const HelpText = `RPN Calculator
22==============
23Commands:
24 +, -, *, /, %, ^, sqrt
25 pop, swap
26 help
27 exit (or Ctrl-D)
28Examples:
29 1 2 + == 3
30 2 3 4 + *
31 2 3 4 + * 5 /
32 9 sqrt
33 2 3 swap -
34 exit`
35
36func NewRPN() *RPN {
37 return &RPN{
38 stack: &Stack{},
39 lexer: &Lexer{},
40 }
41}
42
43func (r *RPN) Eval(input string) (Event, error) {
44 tokens, err := r.lexer.Parse(input)
45 if err != nil {
46 return EventNone, err
47 }
48
49 event := EventNone
50 for _, token := range tokens {
51 switch token.Type {
52 case number:
53 r.stack.Push(token.Value)
54 case binaryOp:
55 a, b, err := r.stack.Pop2()
56 if err != nil {
57 return EventNone, err
58 }
59 switch token.Operator {
60 case plus:
61 r.stack.Push(b + a)
62 case minus:
63 r.stack.Push(b - a)
64 case multiply:
65 r.stack.Push(b * a)
66 case divide:
67 if a == 0 {
68 r.stack.Push(b)
69 r.stack.Push(a)
70 return EventNone, fmt.Errorf("can't divide by zero")
71 }
72 r.stack.Push(b / a)
73 case mod:
74 if a == 0 {
75 r.stack.Push(b)
76 r.stack.Push(a)
77 return EventNone, fmt.Errorf("can't divide by zero")
78 }
79 r.stack.Push(float64(int64(b) % int64(a)))
80 case power:
81 r.stack.Push(math.Pow(b, a))
82 }
83 case unaryOp:
84 a, err := r.stack.Pop()
85 if err != nil {
86 return EventNone, err
87 }
88 switch token.Operator {
89 case sqrt:
90 r.stack.Push(math.Sqrt(a))
91 }
92 case pop:
93 _, err := r.stack.Pop()
94 if err != nil {
95 return EventNone, err
96 }
97 case swap:
98 err := r.stack.Swap()
99 if err != nil {
100 return EventNone, err
101 }
102 case clr:
103 r.stack.Clear()
104 case help:
105 event = EventHelp
106 case exit:
107 return EventExit, nil
108 default:
109 return EventNone, fmt.Errorf("operation not implemented: %s", token.Original)
110 }
111 }
112
113 return event, nil
114}
115
116func (r *RPN) Values() []float64 {
117 return r.stack.Values()
118}