You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
135 lines
2.4 KiB
Go
135 lines
2.4 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type forthfunc func(*[]int, *int, []string) string
|
|
type operation struct {
|
|
op forthfunc
|
|
readuntil 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 = make(map[string]operation)
|
|
|
|
func forth(code string) forthfunc {
|
|
op := func(st *[]int, stp *int, _ []string) string {
|
|
return eval(code, nil)
|
|
}
|
|
return forthfunc(op)
|
|
}
|
|
|
|
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 {
|
|
if code == "" {
|
|
os.Exit(0)
|
|
}
|
|
return "Error before evaluating code: " + inerr.Error()
|
|
}
|
|
var value string
|
|
cmds := strings.Split(code, " ")
|
|
for i := 0; i < len(cmds); i++ {
|
|
cmd := cmds[i]
|
|
op, ok := dictionary[cmd]
|
|
if ok {
|
|
var read []string
|
|
if op.readuntil != "" {
|
|
for j, c := range cmds[i+1:] {
|
|
if c == op.readuntil {
|
|
read = cmds[i+1 : i+j+1]
|
|
i += j + 1
|
|
break
|
|
}
|
|
}
|
|
}
|
|
value = op.op(&stack, &stackpointer, read)
|
|
continue
|
|
}
|
|
err := number(&stack, &stackpointer, cmd)
|
|
if err != nil {
|
|
return "Error reading value: " + err.Error()
|
|
}
|
|
}
|
|
return value
|
|
}
|
|
|
|
func main() {
|
|
stdin := bufio.NewReader(os.Stdin)
|
|
prelude()
|
|
for {
|
|
println(eval(read(stdin)))
|
|
}
|
|
}
|