summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitri Sokolyuk <demon@dim13.org>2018-09-22 20:25:41 +0200
committerDimitri Sokolyuk <demon@dim13.org>2018-09-22 20:25:41 +0200
commited154369ee1e9de3b43ce6a5be77d42b873175c7 (patch)
tree19a3771dfbc606c31cbc9048d0f7d4c5a14ddd2d
parent389aaf8f88f565d6983765f529905d4799e7a031 (diff)
refactor lexer
-rw-r--r--go/forth/forth.go83
1 files changed, 51 insertions, 32 deletions
diff --git a/go/forth/forth.go b/go/forth/forth.go
index 8675941..9059168 100644
--- a/go/forth/forth.go
+++ b/go/forth/forth.go
@@ -2,7 +2,7 @@ package forth
import (
"errors"
- "log"
+ "io"
"strconv"
"strings"
)
@@ -35,11 +35,11 @@ func (s *stack) values() []int {
}
func pop2(s stacker) (int, int, error) {
- tos, err := s.pop()
+ tos, err := s.pop() // top on stack
if err != nil {
return 0, 0, err
}
- nos, err := s.pop()
+ nos, err := s.pop() // next on stack
if err != nil {
return 0, 0, err
}
@@ -141,41 +141,42 @@ func number(word string) (int, bool) {
return n, err == nil
}
-func index(s []string, r string) int {
- for i, v := range s {
- if v == r {
- return i
- }
+func colon(dict dictionary, l *lexer) error {
+ name, err := l.Next()
+ if err != nil {
+ return err
+ }
+ if _, ok := number(name); ok {
+ return errors.New("name cannot be a number")
+ }
+ w, err := compile(dict, l)
+ if err != nil {
+ return err
}
- return -1
+ dict.add(name, w...)
+ return nil
}
-func compile(dict dictionary, s []string) ([]func(stacker) error, error) {
- log.Println("compile", s)
+func compile(dict dictionary, l *lexer) ([]func(stacker) error, error) {
var words []func(stacker) error
- for i := 0; i < len(s); i++ {
- v := s[i]
- // lookup dictionary first
- if w, ok := dict.find(v); ok {
- words = append(words, w...)
- continue
+ for {
+ v, err := l.Next()
+ if err == io.EOF {
+ return words, nil
}
+ // colon operator
if v == ":" {
- next := index(s[i+1:], ";")
- if next == -1 {
- return nil, errors.New("unterminated colon operator")
- }
- name := s[i+1]
- if _, ok := number(name); ok {
- return nil, errors.New("name cannot be a number")
- }
- w, err := compile(dict, s[i+2:i+next+1])
- if err != nil {
+ if err := colon(dict, l); err != nil {
return nil, err
}
- log.Println("add", name)
- dict.add(name, w...)
- i += next + 1
+ continue
+ }
+ if v == ";" {
+ return words, nil
+ }
+ // lookup dictionary first
+ if w, ok := dict.find(v); ok {
+ words = append(words, w...)
continue
}
// try to parse literal
@@ -185,7 +186,24 @@ func compile(dict dictionary, s []string) ([]func(stacker) error, error) {
}
return nil, errors.New("unknown word")
}
- return words, nil
+}
+
+type lexer struct {
+ fields []string
+ pos int
+}
+
+func NewLexer(line string) *lexer {
+ return &lexer{fields: strings.Fields(line)}
+}
+
+func (l *lexer) Next() (string, error) {
+ if l.pos >= len(l.fields) {
+ return "", io.EOF
+ }
+ s := l.fields[l.pos]
+ l.pos++
+ return s, nil
}
func Forth(v []string) ([]int, error) {
@@ -202,7 +220,8 @@ func Forth(v []string) ([]int, error) {
var words []func(stacker) error
for _, line := range v {
- w, err := compile(dict, strings.Split(line, " "))
+ l := NewLexer(line)
+ w, err := compile(dict, l)
if err != nil {
return nil, err
}