started work on porting it to golang

This commit is contained in:
2023-10-30 14:22:43 +01:00
parent 76a1ada486
commit 3b48674f2b
5 changed files with 397 additions and 0 deletions

155
go/calc.go Normal file
View 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()
}