mirror of
https://codeberg.org/scip/rpnc.git
synced 2025-12-17 12:31:04 +01:00
started work on porting it to golang
This commit is contained in:
155
go/calc.go
Normal file
155
go/calc.go
Normal file
@@ -0,0 +1,155 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/chzyer/readline"
|
||||
)
|
||||
|
||||
type Calc struct {
|
||||
debug bool
|
||||
batch bool
|
||||
stdin bool
|
||||
stack *Stack
|
||||
completer readline.AutoCompleter
|
||||
}
|
||||
|
||||
const Help string = `Available commands:
|
||||
batch enable batch mode
|
||||
debug enable debug output
|
||||
dump display the stack contents
|
||||
clear clear the whole stack
|
||||
shift remove the last element of the stack
|
||||
help show this message
|
||||
|
||||
Available operators:
|
||||
basic operators: + - * /
|
||||
`
|
||||
|
||||
func NewCalc() *Calc {
|
||||
c := Calc{stack: NewStack(), debug: false}
|
||||
|
||||
c.completer = readline.NewPrefixCompleter(
|
||||
readline.PcItem("dump"),
|
||||
readline.PcItem("debug"),
|
||||
readline.PcItem("clear"),
|
||||
readline.PcItem("batch"),
|
||||
readline.PcItem("shift"),
|
||||
readline.PcItem("undo"),
|
||||
readline.PcItem("help"),
|
||||
readline.PcItem("+"),
|
||||
readline.PcItem("-"),
|
||||
readline.PcItem("*"),
|
||||
readline.PcItem("/"),
|
||||
)
|
||||
|
||||
return &c
|
||||
}
|
||||
|
||||
func (c *Calc) ToggleDebug() {
|
||||
c.debug = !c.debug
|
||||
c.stack.ToggleDebug()
|
||||
}
|
||||
|
||||
func (c *Calc) ToggleBatch() {
|
||||
c.batch = !c.batch
|
||||
}
|
||||
|
||||
func (c *Calc) ToggleStdin() {
|
||||
c.stdin = !c.stdin
|
||||
}
|
||||
|
||||
func (c *Calc) Eval(line string) {
|
||||
line = strings.TrimSpace(line)
|
||||
space := regexp.MustCompile(`\s+`)
|
||||
simple := regexp.MustCompile(`[\+\-\*\/]`)
|
||||
|
||||
if line == "" {
|
||||
return
|
||||
}
|
||||
|
||||
for _, item := range space.Split(line, -1) {
|
||||
num, err := strconv.ParseFloat(item, 64)
|
||||
|
||||
if err == nil {
|
||||
c.stack.Backup()
|
||||
c.stack.Push(num)
|
||||
} else {
|
||||
if simple.MatchString(line) {
|
||||
c.simple(item[0])
|
||||
continue
|
||||
}
|
||||
|
||||
switch item {
|
||||
case "help":
|
||||
fmt.Println(Help)
|
||||
case "dump":
|
||||
c.stack.Dump()
|
||||
case "debug":
|
||||
c.ToggleDebug()
|
||||
case "batch":
|
||||
c.ToggleBatch()
|
||||
case "clear":
|
||||
c.stack.Backup()
|
||||
c.stack.Clear()
|
||||
case "shift":
|
||||
c.stack.Backup()
|
||||
c.stack.Shift()
|
||||
case "undo":
|
||||
c.stack.Restore()
|
||||
default:
|
||||
fmt.Println("unknown command or operator!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Calc) Result() {
|
||||
if !c.stdin {
|
||||
fmt.Print("= ")
|
||||
}
|
||||
|
||||
fmt.Println(c.stack.Last())
|
||||
}
|
||||
|
||||
func (c *Calc) simple(op byte) {
|
||||
c.stack.Backup()
|
||||
|
||||
for c.stack.Len() > 1 {
|
||||
b := c.stack.Pop()
|
||||
a := c.stack.Pop()
|
||||
var x float64
|
||||
|
||||
if c.debug {
|
||||
fmt.Printf("DEBUG: evaluating: %.2f %c %.2f\n", a, op, b)
|
||||
}
|
||||
|
||||
switch op {
|
||||
case '+':
|
||||
x = a + b
|
||||
case '-':
|
||||
x = a - b
|
||||
case '*':
|
||||
x = a * b
|
||||
case '/':
|
||||
if b == 0 {
|
||||
fmt.Println("error: division by null!")
|
||||
return
|
||||
}
|
||||
x = a / b
|
||||
default:
|
||||
panic("invalid operator!")
|
||||
}
|
||||
|
||||
c.stack.Push(x)
|
||||
|
||||
if !c.batch {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
c.Result()
|
||||
}
|
||||
Reference in New Issue
Block a user