summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoop Kiefte <ikojba@gmail.com>2020-10-17 13:09:16 +0300
committerJoop Kiefte <ikojba@gmail.com>2020-10-17 13:09:16 +0300
commitf13c785ad79cc993582b61c7b84260bbf91e9fe3 (patch)
treeb007c9c6118e030af05fd46ddaa6053c26b4cb2e
Initial commit
-rw-r--r--.gitignore1
-rw-r--r--go.mod3
-rw-r--r--main.go135
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
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..e4e97c1
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,3 @@
+module git.kiefte.eu/lapingvino/buforth
+
+go 1.15
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..c6d1268
--- /dev/null
+++ b/main.go
@@ -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)))
+ }
+}