Skip to content

Instantly share code, notes, and snippets.

@jordanorelli
Last active December 20, 2015 16:59
Show Gist options
  • Save jordanorelli/6165753 to your computer and use it in GitHub Desktop.
Save jordanorelli/6165753 to your computer and use it in GitHub Desktop.
stack-based rpn accumulator
package main
import (
"bufio"
"errors"
"fmt"
"os"
"strconv"
"strings"
)
var operators = map[string]func(int, int) int{
"+": func(x, y int) int { return x + y },
"-": func(x, y int) int { return x - y },
"*": func(x, y int) int { return x * y },
"/": func(x, y int) int { return x / y },
"%": func(x, y int) int { return x % y },
}
var (
stack = make([]int, 0, 8)
errStackEmpty = errors.New("stack is empty")
errStackNotClear = errors.New("stack not clear")
)
func getLine() string {
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
return scanner.Text()
}
func pop() (int, error) {
if len(stack) < 1 {
return 0, errStackEmpty
}
i := stack[len(stack)-1]
stack = stack[:len(stack)-1]
return i, nil
}
func push(i int) {
stack = append(stack, i)
}
func apply(op func(int, int) int) error {
right, err := pop()
left, err := pop()
if err != nil {
return err
}
push(op(left, right))
return nil
}
func clear() {
stack = stack[0:0]
}
func runLine(line string) (int, error) {
defer clear()
tokens := strings.Split(line, " ")
for _, s := range tokens {
if op, ok := operators[s]; ok {
if err := apply(op); err != nil {
return 0, err
}
continue
}
if i, err := strconv.ParseInt(s, 10, 64); err != nil {
return 0, err
} else {
push(int(i))
}
}
if len(stack) != 1 {
return 0, errStackNotClear
}
return pop()
}
func main() {
for {
line := getLine()
i, err := runLine(line)
if err != nil {
fmt.Fprintln(os.Stderr, "error: "+err.Error())
continue
}
fmt.Println(i)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment