From 7c76bc49af8b6805488ffdffec94829b29c88428 Mon Sep 17 00:00:00 2001 From: David Ashby Date: Mon, 15 Feb 2021 15:35:40 -0500 Subject: [PATCH] remove special-case : ; from parser --- builtins.go | 17 +++++++++++++++++ eval.go | 24 ++++++------------------ main.go | 31 ++++++++++++++++++++++--------- 3 files changed, 45 insertions(+), 27 deletions(-) diff --git a/builtins.go b/builtins.go index 560e8b8..30b4cb3 100644 --- a/builtins.go +++ b/builtins.go @@ -8,6 +8,23 @@ type Builtins struct{} // ErrExit is a special sentinel value to cease computation and quit var ErrExit = fmt.Errorf("exit requested") +// Colon sets the COMPILE/IMMEDIATE flag to COMPILE +func (b *Builtins) Colon(f *bool) func() error { + return func() error { + *f = false + return nil + } +} + +// Semicolon sets the COMPILE/IMMEDIATE flag back to IMMEDIATE and adds the defintion to the dictionary +func (b *Builtins) Semicolon(c *Context) func() error { + return func() error { + c.Dictionary.AddWord(c.Words[0], nil, c.Words[1:], false) + c.Immediate = true + return nil + } +} + // Eq compares TOS and NOS and puts -1 on the stack if they're equal, 0 otherwise. func (b *Builtins) Eq(s *Stack) func() error { return func() error { diff --git a/eval.go b/eval.go index aa70682..ede9315 100644 --- a/eval.go +++ b/eval.go @@ -11,15 +11,15 @@ type Context struct { Dictionary Dictionary Stack *Stack RStack *Stack + Immediate bool + Words []string } // Eval evaulates a given line, recursively descending into given words as needed func (c *Context) Eval(line string) error { // state var word []byte - var words []string var comment bool - immediate := true for i := 0; i < len(line); i = i + 1 { switch line[i] { @@ -34,28 +34,16 @@ func (c *Context) Eval(line string) error { } else { word = append(word, line[i]) } - case ':', ';': // COMPILE/IMMEDIATE mode swapping - if len(word) == 0 { - if line[i] == ':' { - immediate = false - } else if line[i-1] == ' ' && line[i] == ';' { - c.Dictionary.AddWord(words[0], nil, words[1:], false) - word = []byte{} - immediate = true - } - } else { - word = append(word, line[i]) - } case ' ': sword := strings.TrimSpace(string(word)) - if !immediate { // continue building our subroutine if we're not in immediate mode... + if !c.Immediate { // continue building our subroutine if we're not in immediate mode... if len(word) != 0 { // don't add empty words to our list // Was that a word we know? w, _ := c.Dictionary.GetWord(sword) // check if it's an IMMEDIATE mode toggle word - immediate = w.Immediate - if !immediate { - words = append(words, sword) + c.Immediate = w.Immediate + if !c.Immediate { + c.Words = append(c.Words, sword) word = []byte{} continue } diff --git a/main.go b/main.go index 7ba8868..ed7808a 100644 --- a/main.go +++ b/main.go @@ -13,12 +13,29 @@ func main() { rstack := Stack{values: []int{}} dict := Dictionary{} + + c := Context{ + Dictionary: dict, + Stack: &stack, + RStack: &rstack, + Immediate: true, + Words: []string{}, + } + b := &Builtins{} + // word definitions + dict.AddWord(":", b.Colon(&c.Immediate), nil, false) + dict.AddWord(";", b.Semicolon(&c), nil, true) + // math dict.AddWord("+", b.Add(&stack), nil, false) dict.AddWord("-", b.Sub(&stack), nil, false) dict.AddWord("*", b.Mul(&stack), nil, false) dict.AddWord("/", b.Div(&stack), nil, false) + // output dict.AddWord(".", b.Print(&stack), nil, false) + dict.AddWord("EMIT", b.Emit(&stack), nil, false) + dict.AddWord("CR", b.CR(), nil, false) + // logic dict.AddWord("=", b.Eq(&stack), nil, false) dict.AddWord("0=", nil, []string{"0", "="}, false) dict.AddWord("<>", b.NEq(&stack), nil, false) @@ -28,29 +45,25 @@ func main() { dict.AddWord("<=", b.LtEq(&stack), nil, false) dict.AddWord("0<", nil, []string{"0", "<"}, false) dict.AddWord("0>", nil, []string{"0", ">"}, false) + // stack manipulation dict.AddWord("DUP", b.Dup(&stack), nil, false) dict.AddWord("SWAP", b.Swap(&stack), nil, false) dict.AddWord("OVER", b.Over(&stack), nil, false) dict.AddWord("DROP", b.Drop(&stack), nil, false) dict.AddWord("ROT", b.Rot(&stack), nil, false) + // debugging dict.AddWord("WORDS", b.Words(dict), nil, false) dict.AddWord(".S", b.Debug(&stack), nil, false) dict.AddWord(".R", b.Debug(&rstack), nil, false) - dict.AddWord("EMIT", b.Emit(&stack), nil, false) dict.AddWord("R>", b.RFrom(&stack, &rstack), nil, false) dict.AddWord(">R", b.ToR(&stack, &rstack), nil, false) dict.AddWord("R@", b.RFetch(&stack, &rstack), nil, false) + // branching dict.AddWord("DO", b.Do(&stack, &rstack), nil, false) dict.AddWord("LOOP", b.Loop(&stack, &rstack), nil, false) dict.AddWord("I", b.I(&stack, &rstack), nil, false) - dict.AddWord("CR", b.CR(), nil, false) - dict.AddWord("QUIT", b.Quit(), nil, false) - - c := Context{ - Dictionary: dict, - Stack: &stack, - RStack: &rstack, - } + // exit + dict.AddWord("BYE", b.Quit(), nil, false) reader := bufio.NewReader(os.Stdin) fmt.Print("prosper")