commit e03f70485c92db5ba1f9b6fe8cf0660108838dad
parent c7f76583840bb1d7870cba5a4f22c8e500e4091f
Author: prenev <an2qzavok@gmail.com>
Date: Sun, 10 Oct 2021 21:38:17 +0300
touch up code after looking at the original implementation, rename fortum.go to first.go
Diffstat:
A | first.go | | | 284 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 284 insertions(+), 0 deletions(-)
diff --git a/first.go b/first.go
@@ -0,0 +1,284 @@
+package main
+
+import (
+ "fmt"
+ "bufio"
+ "os"
+ "io"
+ "strconv"
+ "strings"
+)
+
+const (
+ rsp int = 1
+ dep int = 0
+
+ rstacksize = 512
+ rstackstart = 32
+)
+
+var laswor string
+
+type Mem struct {
+ data []int
+}
+
+func NewMem() *Mem {
+ var mem = new(Mem)
+ mem.data = make([]int, 0)
+ return mem
+}
+
+func (m *Mem) Fetch(addr int) (int, error) {
+ if (addr >= len(m.data)) || (addr < 0) {
+ return 0, fmt.Errorf("memfetch: addr %d out of bonds", addr)
+ }
+ return m.data[addr], nil
+}
+
+func (m *Mem) Store(addr, val int) {
+ if addr >= len(m.data) {
+ buf := make([]int, addr - len(m.data) + 1)
+ m.data = append(m.data, buf...)
+ }
+ m.data[addr] = val
+}
+
+type Stack struct {
+ data []int
+}
+
+func NewStack() *Stack {
+ stack := new(Stack)
+ stack.data = make([]int, 1)
+ return stack
+}
+
+func (s *Stack) Push(val int) {
+ s.data = append(s.data, val)
+}
+
+func (s *Stack) Pop() (int, error) {
+ if s.data == nil {
+ return 0, fmt.Errorf("stack is empty")
+ }
+ x := s.data[len(s.data) - 1]
+ s.data = s.data[:len(s.data) - 1]
+ return x, nil
+}
+
+func (s *Stack) TOS() *int {
+ return &s.data[len(s.data) - 1]
+}
+
+type First struct {
+ stack *Stack
+ mem *Mem
+ strings []string
+ pc, lwp int
+ run bool
+ in *bufio.Reader
+}
+
+func NewFirst() (*First, error) {
+ const builtins string = ": immediate _read @ ! - * / <0 exit echo key _pick"
+ first := new(First)
+ *first = First{
+ NewStack(),
+ NewMem(),
+ make([]string, 0),
+ 0, 0,
+ true,
+ nil,
+ }
+ first.mem.Store(dep, rstackstart + rstacksize)
+ first.mem.Store(rsp, rstackstart)
+ first.in = bufio.NewReader(strings.NewReader(builtins))
+
+ first.define(3)
+ first.define(4)
+ first.define(1)
+ loopword := first.mem.data[dep]
+ first.Compile(5, 2)
+ first.pc = first.mem.data[dep]
+ first.Compile(loopword, first.pc - 1)
+ for i := 6; i < 16; i++ {
+ first.define(1)
+ first.Compile(i)
+ }
+ return first, nil
+}
+
+func (F *First) findWord(s string) int {
+ var err error
+ for wp := F.lwp; wp != 0; wp, err = F.mem.Fetch(wp) {
+ if err != nil {
+ return 0
+ }
+ id, err := F.mem.Fetch(wp + 1)
+ if err != nil {
+ return 0
+ }
+ if F.strings[id] == s {
+ return wp
+ }
+ }
+ return 0
+}
+
+func (F *First) rpush(val int) (error) {
+ if F.mem.data[rsp] >= rstacksize + rstackstart {
+ return fmt.Errorf("rstack is full")
+ }
+ F.mem.data[rsp]++
+ F.mem.Store(F.mem.data[rsp], val)
+ return nil
+}
+
+func (F *First) rpop() (int, error) {
+ if F.mem.data[rsp] <= rstackstart {
+ return 0, fmt.Errorf("rstack is empty")
+ }
+ x, err := F.mem.Fetch(F.mem.data[rsp])
+ F.mem.data[rsp]--
+ return x, err
+}
+
+func (F *First) Compile(vals ...int) {
+ for _, val := range vals {
+ F.mem.Store(F.mem.data[dep], val)
+ F.mem.data[dep]++
+ }
+}
+
+func (F *First) define(code int) error {
+ var s string
+ F.Compile(F.lwp)
+ F.lwp = F.mem.data[dep] - 1
+ F.Compile(len(F.strings), code)
+ if _, err := fmt.Fscan(F.in, &s); err != nil {
+ return err
+ }
+ F.strings = append(F.strings, s)
+ return nil
+}
+
+func (F *First) _read() error {
+ var (
+ s string
+ num, wp int
+ err error
+ )
+ if _, err = fmt.Fscan(F.in, &s); err != nil {
+ return err
+ }
+ wp = F.findWord(s)
+ if wp != 0 {
+ return F.Step(wp + 2)
+ }
+ if num, err = strconv.Atoi(s); err != nil {
+ return err
+ }
+ F.Compile(2, num)
+ return nil
+}
+
+func (F *First) Run(input *bufio.Reader) error {
+ F.in = input
+ var (
+ addr int
+ err error
+ )
+ for err == nil {
+ addr, err = F.mem.Fetch(F.pc)
+ F.pc++
+ if err != nil {
+ break
+ }
+ err = F.Step(addr)
+ }
+ if err == io.EOF {
+ return nil
+ }
+ return err
+}
+
+func (F *First) Step(addr int) error {
+ var x, y int
+ inst, err := F.mem.Fetch(addr)
+ addr++
+ switch inst {
+ case 0: // internal builtin "pushint"
+ x, err = F.mem.Fetch(F.pc)
+ F.pc++
+ F.stack.Push(x)
+ case 1: // compile
+ F.Compile(addr)
+ case 2: // run
+ F.rpush(F.pc)
+ F.pc = addr
+ case 3: // builtin "define", ":"
+ err = F.define(1)
+ F.Compile(2)
+ case 4: // builtin "immediate"
+ F.mem.data[dep] -= 2
+ F.Compile(2)
+ case 5: // builtin "_read"
+ err = F._read()
+ case 6: // builtin "fetch", "@"
+ x, err = F.stack.Pop()
+ y, err = F.mem.Fetch(x)
+ F.stack.Push(y)
+ case 7: // builtin "store", "!"
+ x, err = F.stack.Pop()
+ y, err = F.stack.Pop()
+ F.mem.Store(x, y)
+ case 8: // builtin "minus", "-"
+ x, err = F.stack.Pop()
+ y, err = F.stack.Pop()
+ F.stack.Push(y - x)
+ case 9: // builtin "mulitply", "*"
+ x, err = F.stack.Pop()
+ y, err = F.stack.Pop()
+ F.stack.Push(y * x)
+ case 10: // builtin "divide", "/"
+ x, err = F.stack.Pop()
+ y, err = F.stack.Pop()
+ F.stack.Push(y / x)
+ case 11: // builtin "less than 0", "<0"
+ x, err = F.stack.Pop()
+ if (x < 0) {
+ F.stack.Push(1)
+ } else {
+ F.stack.Push(0)
+ }
+ case 12: // builtin "exit"
+ F.pc, err = F.rpop()
+ case 13: // builtin "echo"
+ x, err = F.stack.Pop()
+ if err == nil {
+ fmt.Printf("%c", x)
+ }
+ case 14: // builtin "key"
+ var r rune
+ r, _, err = F.in.ReadRune()
+ F.stack.Push(int(r))
+ case 15: // builtin "_pick"
+ x, err = F.stack.Pop()
+ y = F.stack.data[len(F.stack.data) - x - 1]
+ F.stack.Push(y)
+ default:
+ err = fmt.Errorf("unexpected instruction %d", inst)
+ }
+ return err
+}
+
+func main() {
+ first, err := NewFirst()
+ if err != nil {
+ fmt.Println(err)
+ } else if err = first.Run(bufio.NewReader(os.Stdin));
+ err != nil {
+ fmt.Println(err)
+ }
+}