You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
2.4 KiB
134 lines
2.4 KiB
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))) |
|
} |
|
}
|
|
|