commit 9a8b5b76d96e039c3f47cb12131647125ce8c6c2
parent ab098c9b15348758bff4f9874acb175f4ab6efb7
Author: Pavel Renev <an2qzavok@gmail.com>
Date: Mon, 4 Oct 2021 01:39:08 +0300
implement FIRST probably
Diffstat:
M | fortum.go | | | 329 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------- |
1 file changed, 244 insertions(+), 85 deletions(-)
diff --git a/fortum.go b/fortum.go
@@ -2,127 +2,286 @@ package main
import (
"fmt"
+ "bufio"
"os"
+ "io"
+ "strconv"
+ "strings"
)
-type Word struct {
- name string
- builtin func()
- code []int
+const rsp int = 0
+const dep int = 1
+
+type Mem struct {
+ data []int
}
-var stack = make([]int, 0)
-var mem = make([]int, 4096)
-var dict = make([]Word, 0)
+func NewMem() *Mem {
+ var mem = new(Mem)
+ mem.data = make([]int, 0)
+ return mem
+}
-const rsp = 0
+func (m *Mem) Fetch(addr int) int {
+ if addr >= len(m.data) {
+ return 0
+ }
+ return m.data[addr]
+}
-func builtin(dict []Word, name string, f func()) []Word {
- word := Word{name, f, nil}
- dict = append(dict, word)
- return dict
+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
}
-func TOS(stack []int) int {
- return stack[len(stack) - 1]
+type Stack struct {
+ data []int
}
-func pop(stack *[]int) int {
- x := TOS(*stack)
- s := *stack
- *stack = s[:len(s) - 1]
- return x
+func NewStack() *Stack {
+ stack := new(Stack)
+ stack.data = make([]int, 0)
+ return stack
}
-func noop() {
+func (s *Stack) Push(val int) {
+ s.data = append(s.data, val)
}
-func minus() {
- stack[len(stack) - 2] -= TOS(stack)
- pop(&stack)
+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 multiply() {
- stack[len(stack) - 2] *= TOS(stack)
- pop(&stack)
+func (s *Stack) TOS() *int {
+ return &s.data[len(s.data) - 1]
}
-func divide() {
- stack[len(stack) - 2] /= TOS(stack)
- pop(&stack)
+type First struct {
+ stack *Stack
+ mem *Mem
+ strings []string
+ pc, lwp int
+ run bool
+ in io.Reader
}
-func lessthan0() {
- x := TOS(stack)
- if (x < 0) {
- stack[len(stack) - 1] = 1
- } else {
- stack[len(stack) - 1] = 0
+func NewFirst() (*First, error) {
+ var first = new(First)
+ *first = First{
+ NewStack(),
+ NewMem(),
+ make([]string, 0),
+ 0, 0,
+ true,
+ nil,
+ }
+ first.mem.Store(dep, 4096)
+ first.mem.Store(rsp, 4)
+ first.in = strings.NewReader(
+ "halt : immediate")
+ for i := 0; i < 3; i++ {
+ first.define()
+ first.mem.Store(first.mem.Fetch(dep) - 1, -3)
+ first.Compile(i, 4149)
+ }
+ first.in = strings.NewReader(
+ "_read @ ! - * / <0 exit echo key _pick _loop")
+ for i:=3 ; i < 14; i++ {
+ first.define()
+ first.Compile(i, 4149)
}
+
+ // 4149 should be a pointer to exit as it is defined here
+
+ first.define();
+ first.mem.Store(first.mem.Fetch(dep) -1, -3)
+ first.Compile(3, first.lwp + 3)
+ return first, nil
}
-func echo() {
- x := pop(&stack)
- fmt.Printf("%c", x)
+func (F *First) findWord(s string) int {
+ for wp := F.lwp; wp != 0; wp = F.mem.Fetch(wp) {
+ id := F.mem.Fetch(wp + 1)
+ if F.strings[id] == s {
+ return wp
+ }
+ }
+ return 0
}
-func key() {
- mem[rsp]++
- mem[mem[rsp]] = os.Stdin.ReadRune()
+func (F *First) rpush(val int) (error) {
+ if F.mem.Fetch(rsp) >= 4096 {
+ return fmt.Errorf("rstack is full")
+ }
+ F.mem.Store(F.mem.Fetch(rsp), val)
+ F.mem.data[rsp]++
+ return nil
}
-func execword() {
- word := dict[mem[mem[rsp]]]
- if (word.builtin != nil) {
- word.builtin()
- } else {
- for w := range word.code {
- mem[rsp]++
- mem[mem[rsp]] = w
- execword()
- }
+func (F *First) rpop() (int, error) {
+ if F.mem.Fetch(rsp) <= 4 {
+ return 0, fmt.Errorf("rstack is empty")
}
- mem[rsp]--
+ F.mem.data[rsp]--
+ x := F.mem.Fetch(F.mem.Fetch(rsp))
+ return x, nil
}
-func store() {
- addr := TOS(stack)
- pop(&stack)
- if len(mem) < addr {
- bump := make([]int, addr - len(mem) + 1)
- mem = append(mem, bump...)
+func (F *First) Compile(vals ...int) {
+ for _, val := range vals {
+ F.mem.Store(F.mem.Fetch(dep), val)
+ F.mem.data[dep]++
}
- mem[addr] = TOS(stack)
}
-func fetch() {
- addr := TOS(stack)
- if addr > len(mem) {
- stack[len(stack)-1] = 0
- } else {
- stack[len(stack)-1] = mem[addr]
+func (F *First) define() error {
+ var s string
+ nwp := F.mem.Fetch(dep)
+ _, err := fmt.Fscan(F.in, &s)
+ if err != nil {
+ return err
+ }
+ F.strings = append(F.strings, s)
+ id := len(F.strings) - 1
+ F.Compile(F.lwp, id, -2)
+ F.lwp = nwp
+ return nil
+}
+
+func (F *First) _read() error {
+ var s string
+ _, err := fmt.Fscan(F.in, &s)
+ if err != nil {
+ return err
}
+ wp := F.findWord(s)
+ if wp != 0 {
+ err = F.rpush(F.pc)
+ F.pc = wp + 2
+ return err
+ }
+ num, err := strconv.Atoi(s)
+ if err != nil {
+ return err
+ }
+ F.Compile(-1, num)
+ return nil
+}
+
+func (F *First) Run(input io.Reader) error {
+ var err error
+ F.in = input
+ F.pc = F.findWord("_loop") + 3
+ for err == nil {
+ var x, y int
+ inst := F.mem.Fetch(F.pc)
+ F.pc++
+ switch inst {
+ case -1: // internal builtin "pushint"
+ F.stack.Push(F.mem.Fetch(F.pc))
+ F.pc++
+ case -2: // internal builtin "compile me"
+ /* "a pointer to the word's data field is
+ * appended to the dictionary" ????
+ */
+ F.Compile(F.pc)
+ F.pc, err = F.rpop();
+ case -3: // internal builtin "run me"
+ /* "the word's data field is taken to be
+ * a stream of pointers to words, and is
+ * executed" ????
+ */
+ case 0: // builtin "halt"
+ fmt.Println(F.pc - 1, "halt")
+ return nil
+ case 1: // builtin "define", ":"
+ err = F.define()
+ case 2: // builtin "immediate"
+ F.mem.Store(F.mem.Fetch(dep) - 1, -3)
+ case 3: // builtin "_read"
+ err = F._read()
+ case 4: // builtin "fetch", "@"
+ x, err = F.stack.Pop()
+ y = F.mem.Fetch(x)
+ F.stack.Push(y)
+ case 5: // builtin "store", "!"
+ x, err = F.stack.Pop()
+ y, err = F.stack.Pop()
+ F.mem.Store(x, y)
+ case 6: // builtin "minus", "-"
+ x, err = F.stack.Pop()
+ y, err = F.stack.Pop()
+ F.stack.Push(y - x)
+ case 7: // builtin "mulitply", "*"
+ x, err = F.stack.Pop()
+ y, err = F.stack.Pop()
+ F.stack.Push(y * x)
+ case 8: // builtin "divide", "/"
+ x, err = F.stack.Pop()
+ y, err = F.stack.Pop()
+ F.stack.Push(y / x)
+ case 9: // builtin "less than 0", "<0"
+ x, err = F.stack.Pop()
+ if (x < 0) {
+ F.stack.Push(1)
+ } else {
+ F.stack.Push(0)
+ }
+ case 10: // builtin "exit"
+ /* We rpop twice because we need
+ * to exit "exit" as well
+ */
+ _, err = F.rpop()
+ F.pc, err = F.rpop()
+ case 11: // builtin "echo"
+ x, err = F.stack.Pop()
+ if err == nil {
+ fmt.Printf("%c", x)
+ }
+ case 12: // builtin "key"
+ var r rune
+ k := bufio.NewReader(F.in)
+ r, _, err = k.ReadRune()
+ F.stack.Push(int(r))
+ case 13: // builtin "_pick"
+ x, err = F.stack.Pop()
+ y = F.stack.data[x]
+ F.stack.Push(y)
+ default:
+ err = F.rpush(F.pc)
+ F.pc = inst
+ }
+ }
+ if err == io.EOF {
+ return nil
+ }
+ return err
}
func main() {
- dict = builtin(dict, "noop", noop)
- dict = builtin(dict, "execword", execword)
- dict = builtin(dict, "-", minus)
- dict = builtin(dict, "*", multiply)
- dict = builtin(dict, "/", divide)
- dict = builtin(dict, "echo", echo)
- dict = builtin(dict, "key", key)
- dict = builtin(dict, "@", fetch)
- dict = builtin(dict, "!", store)
-
- stack = append(stack, 10, 79, 76, 76, 69, 72)
- mem[rsp] = 1
- execword()
- echo()
- echo()
- echo()
- echo()
- echo()
- echo()
- fmt.Println(stack)
+ first, err := NewFirst()
+ if err != nil {
+ fmt.Println(err)
+ }
+ var code string = ": L immediate exit L"
+ err = first.Run(strings.NewReader(code))
+ if err != nil {
+ fmt.Println(err)
+ } else {
+ err = first.Run(os.Stdin)
+ if err != nil {
+ fmt.Println(err)
+ }
+ }
+// fmt.Println("Words:", first.strings)
+// fmt.Println("Stack:", first.stack.data)
+// fmt.Println(first.mem.data[4096:])
}