diff options
author | Joop Kiefte <ikojba@gmail.com> | 2020-10-17 13:09:16 +0300 |
---|---|---|
committer | Joop Kiefte <ikojba@gmail.com> | 2020-10-17 13:09:16 +0300 |
commit | f13c785ad79cc993582b61c7b84260bbf91e9fe3 (patch) | |
tree | b007c9c6118e030af05fd46ddaa6053c26b4cb2e |
Initial commit
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | go.mod | 3 | ||||
-rw-r--r-- | main.go | 135 |
3 files changed, 139 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..134751d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +buforth @@ -0,0 +1,3 @@ +module git.kiefte.eu/lapingvino/buforth + +go 1.15 @@ -0,0 +1,135 @@ +package main + +import ( + "bufio" + "os" + "strings" + "strconv" +) + +type operation func(*[]int, *int) string +type numberError string +type bufferError string + +func (n numberError) Error() string { return string(n) } +func (n bufferError) Error() string { return string(n) } + +var stack []int +var stackpointer int +var dictionary = map[string]operation{ + "base" : func(st *[]int, stp *int) string { + base, _ := getvalue(st, stp) + r, err := getvalue(st, stp) + if err != nil { + return err.Error() + } + return strconv.FormatInt(int64(r), base) + }, + "+" : func(st *[]int, stp *int) string { + n1, _ := getvalue(st, stp) + n2, err := getvalue(st, stp) + if err != nil { + return err.Error() + } + err = putvalue(st, stp, n1+n2) + if err != nil { + return err.Error() + } + return "*" + }, + "quit": func(_ *[]int, _ *int) string { + os.Exit(0) + return "should have quit" + }, +} + +func getvalue(st *[]int, stp *int) (int, error) { + if *stp < 1 { + return 0, bufferError("buffer underflow") + } + r := (*st)[*stp-1] + *st = (*st)[:len(*st)-1] + *stp-- + return r, nil +} + +func putvalue(st *[]int, stp *int, n int) error { + if *stp == int(^uint(0) >> 1) { // check for maxint + return bufferError("buffer overflow") + } + *st = append(*st, n) + *stp++ + return nil +} + +func read(r *bufio.Reader) (string, error) { + s, err := r.ReadString('\n') + if err != nil { + return "", err + } + return s[:len(s)-1], err +} + +func pow(n, p int) int { + r := 1 + for i := 0; i < p; i++ { + r *= n + } + return r +} + +func number(st *[]int, stp *int, cmd string) error { + base := 6 + if len(cmd) < 1 { + return numberError("tried parsing empty value") + } + switch { + case cmd[0] == 'd': + base = 10 + case cmd[0] == 'x': + base = 16 + case cmd[0] == '0': + base = 8 + case cmd[0] == 'b': + base = 2 + case cmd[0] == '#': + base = 36 + } + if base != 6 { + cmd = cmd[1:] + } + val, err := strconv.ParseInt(cmd, base, 0) + if err != nil { + return err + } + return putvalue(st, stp, int(val)) +} + +func eval(code string, inerr error) string { + if inerr != nil { + return "Error before evaluating code: " + inerr.Error() + } + var value string + for _, cmd := range strings.Split(code, " ") { + op, ok := dictionary[cmd] + if ok { + value = op(&stack, &stackpointer) + continue + } + err := number(&stack, &stackpointer, cmd) + if err != nil { + return "Error reading value: " + err.Error() + } + } + return value +} + +func main() { + stdin := bufio.NewReader(os.Stdin) + dictionary["."] = func(st *[]int, stp *int) string { + return eval("10 base", nil) + } + for { + println(eval(read(stdin))) + } +} |