Parent directory

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}