dForth

Forth-like interpreter in go
Log | Files | Refs

commit 5cd10237dd040262673cba8660a9a113a8be292a
parent c9837e147e17f77130ae633e2d322888c3290272
Author: Pavel Renev <an2qzavok@gmail.com>
Date:   Sun, 17 Oct 2021 21:22:23 +0000

add more builtins

Diffstat:
MdForth.go | 141++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
1 file changed, 96 insertions(+), 45 deletions(-)

diff --git a/dForth.go b/dForth.go @@ -9,11 +9,15 @@ import ( var le = binary.LittleEndian const ( - stpt = 0 - rspt = 4 + pcpt = 0 + stpt = 4 + rspt = 8 + lwpt = 12 + dtpt = 16 stackstart = 64 rstackstart = 512 - initmemsize = 1024 + dictstart = 1024 + initmemsize = 4096 ) type Word struct { @@ -41,9 +45,21 @@ type Forth struct { func NewForth() *Forth { forth := new(Forth) forth.Dict = make([]*Word, 0) + forth.Dict = append(forth.Dict, + NewWord("_read", forth.biRead), + NewWord("_call", forth.biCall), + NewWord("_lit", forth.biLit), + NewWord("_jump", forth.BiJump), + NewWord(".", forth.biDot), + NewWord("@", forth.biFetch), + NewWord("!", forth.biStore), + ) forth.Mem = make([]byte, initmemsize) _ = forth.memStore(stpt, stackstart) _ = forth.memStore(rspt, rstackstart) + _ = forth.memStore(dtpt, dictstart) + _ = forth.memStore(lwpt, 0) + _ = forth.memStore(pcpt, dictstart) return forth } @@ -96,70 +112,105 @@ func (forth *Forth) Pop(pt int32) int32 { return val } -func (forth *Forth) Run() { +func (forth *Forth) biDot() error { + val := forth.Pop(stpt) + fmt.Print(val, " ") + return nil +} + +func (forth *Forth) biFetch() error { + addr := forth.Pop(stpt) + val, err := forth.memFetch(addr) + if err == nil { + forth.Push(stpt, val) + } + return err +} + +func (forth *Forth) biStore() error { + addr := forth.Pop(stpt) + val := forth.Pop(stpt) + err := forth.memStore(addr, val) + return err +} + +func (forth *Forth) biRead() error { var ( err, nerr error s string i, id, num int w *Word ) - for err = nil; err == nil; _, err = fmt.Scan(&s) { - /* We shouldn't get empty reads, but on 9front - * we somehow do. (as of 18.10.2012) - * Let's filter them out. - */ - if s == "" { - continue + if _, err = fmt.Scan(&s); err != nil { + return err + } + /* We shouldn't get empty reads, but on 9front + * we somehow do. (as of 18.10.2021) + * Let's filter them out. + */ + if s == "" { + return nil + } + id = -1 + for i, w = range forth.Dict { + if (s == w.Name) { + id = i + break; } - id = -1 - for i, w = range forth.Dict { - if (s == w.Name) { - id = i - break; - } + } + if id >= 0 { + if w.Builtin != nil { + w.Builtin() } - if id >= 0 { - if w.Builtin != nil { - w.Builtin() - } - // else exec code + // else exec code + } else { + if num, nerr = strconv.Atoi(s); nerr != nil { + fmt.Println("?") } else { - if num, nerr = strconv.Atoi(s); nerr != nil { - fmt.Println("?") - } else { - forth.Push(stpt, int32(num)) - } + forth.Push(stpt, int32(num)) } } + return nil } -func (forth *Forth) biDot() error { - val := forth.Pop(stpt) - fmt.Print(val) - return nil +func (forth *Forth) biCall() error { + /* do we need call? + * can we just treat opcode as call + * if it's >= dictstart ? + */ + pc, err := forth.memFetch(pcpt) + if err != nil { + return err + } + forth.Push(rspt, pc + 1) + jmp := forth.Pop(stpt) + err = forth.memStore(pcpt, jmp) + return err } -func (forth *Forth) biFetch() error { - addr := forth.Pop(stpt) - val, err := forth.memFetch(addr) - if err == nil { - forth.Push(stpt, val) +func (forth *Forth) biLit() error { + pc, err := forth.memFetch(pcpt) + if err != nil { + return err } + val, err := forth.memFetch(pc) + forth.Push(val) return err } -func (forth *Forth) biStore() error { - addr := forth.Pop(stpt) - val := forth.Pop(stpt) - err := forth.memStore(addr, val) +func (forth *Forth) biJump() error { + var err error + cond := forth.Pop() + addr := forth.Pop() + if cond == 0 { + err = forth.memStore(pcpt, addr) + } return err } func main() { - fmt.Println("Welcome to dForth") + fmt.Println("Welcome to dForth.") forth := NewForth() - forth.Dict = append(forth.Dict, NewWord(".", forth.biDot)) - forth.Dict = append(forth.Dict, NewWord("@", forth.biFetch)) - forth.Dict = append(forth.Dict, NewWord("!", forth.biStore)) - forth.Run() + for forth.biRead() == nil { + } }