VARIABLE
This commit is contained in:
parent
241470248b
commit
762b6c870c
14
README.md
14
README.md
@ -54,6 +54,18 @@ ok
|
|||||||
55 ok
|
55 ok
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Propser also has a basic off-stack memory model using variables and pointers:
|
||||||
|
```
|
||||||
|
> VARIABLE FOO
|
||||||
|
ok
|
||||||
|
> 10 FOO !
|
||||||
|
ok
|
||||||
|
> FOO @
|
||||||
|
ok
|
||||||
|
> .
|
||||||
|
10 ok
|
||||||
|
```
|
||||||
|
|
||||||
And, of course, it knows how to quit:
|
And, of course, it knows how to quit:
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -63,6 +75,6 @@ bye
|
|||||||
|
|
||||||
## Future Plans
|
## Future Plans
|
||||||
|
|
||||||
* Implement `VARIABLE` and `CONSTANT` and the various `? ! @` related words
|
* Implement `CONSTANT`
|
||||||
* Implement loading libraries of pre-written functions both from the command-line and at run-time
|
* Implement loading libraries of pre-written functions both from the command-line and at run-time
|
||||||
* Add much better readline behaviors in the interactive console (up-arrow for history, cursor movement...)
|
* Add much better readline behaviors in the interactive console (up-arrow for history, cursor movement...)
|
||||||
|
53
builtins.go
53
builtins.go
@ -663,3 +663,56 @@ func (b *Builtins) Depth(s *Stack) func(string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Variable adds a new word to the dictionary that returns a pointer to memory
|
||||||
|
func (b *Builtins) Variable(c *Context) func(string) error {
|
||||||
|
return func(next string) error {
|
||||||
|
w := []byte{}
|
||||||
|
for i := 1; i < len(next); i = i + 1 {
|
||||||
|
switch next[i] {
|
||||||
|
case ' ':
|
||||||
|
next := c.Memory.NextFreeAddress()
|
||||||
|
if next == 0 {
|
||||||
|
// don't use the 0 cell, since we can't distinguish that from the uninitialized field
|
||||||
|
next = 1
|
||||||
|
}
|
||||||
|
c.Dictionary.AddWord(string(w), Word{Name: string(w), Variable: next})
|
||||||
|
j, _ := c.RStack.Pop()
|
||||||
|
c.RStack.Push(j + i - 1) // push the end-point onto the stack
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
w = append(w, next[i])
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store places a value in memory
|
||||||
|
func (b *Builtins) Store(c *Context) func(string) error {
|
||||||
|
return func(_ string) error {
|
||||||
|
addr, err := c.Stack.Pop()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
val, err := c.Stack.Pop()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.Memory.Write(addr, []int{val})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch returns a value from memory and puts it on the stack
|
||||||
|
func (b *Builtins) Fetch(c *Context) func(string) error {
|
||||||
|
return func(_ string) error {
|
||||||
|
addr, err := c.Stack.Pop()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
res := c.Memory.Read(addr, 1)
|
||||||
|
c.Stack.Push(res[0])
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
4
eval.go
4
eval.go
@ -14,6 +14,7 @@ type Context struct {
|
|||||||
IfStack *Stack // tracks nested branches
|
IfStack *Stack // tracks nested branches
|
||||||
Flags Flags
|
Flags Flags
|
||||||
Words []string
|
Words []string
|
||||||
|
Memory Memory
|
||||||
}
|
}
|
||||||
|
|
||||||
// Eval evaulates a given line, recursively descending into given words as needed
|
// Eval evaulates a given line, recursively descending into given words as needed
|
||||||
@ -78,6 +79,9 @@ func (c *Context) Exec(w Word, s string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error during nested evaluation of word %+v: %w", w, err)
|
return fmt.Errorf("error during nested evaluation of word %+v: %w", w, err)
|
||||||
}
|
}
|
||||||
|
} else if w.Variable > 0 {
|
||||||
|
// it's a variable, let's get that address and put it on the stack
|
||||||
|
c.Stack.Push(w.Variable)
|
||||||
} else {
|
} else {
|
||||||
it, err := strconv.Atoi(w.Name)
|
it, err := strconv.Atoi(w.Name)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
8
main.go
8
main.go
@ -24,6 +24,10 @@ func main() {
|
|||||||
"Immediate": true,
|
"Immediate": true,
|
||||||
},
|
},
|
||||||
Words: []string{},
|
Words: []string{},
|
||||||
|
Memory: Memory{
|
||||||
|
intern: map[int]int{},
|
||||||
|
nextFree: 1,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
b := &Builtins{}
|
b := &Builtins{}
|
||||||
@ -78,6 +82,10 @@ func main() {
|
|||||||
dict.AddWord("2DROP", Word{Name: "2DROP", Source: []string{"DROP", "DROP"}})
|
dict.AddWord("2DROP", Word{Name: "2DROP", Source: []string{"DROP", "DROP"}})
|
||||||
dict.AddWord("2DUP", Word{Name: "2DUP", Source: []string{"OVER", "OVER"}})
|
dict.AddWord("2DUP", Word{Name: "2DUP", Source: []string{"OVER", "OVER"}})
|
||||||
dict.AddWord("2OVER", Word{Name: "2OVER", Source: []string{"3", "PICK", "3", "PICK"}})
|
dict.AddWord("2OVER", Word{Name: "2OVER", Source: []string{"3", "PICK", "3", "PICK"}})
|
||||||
|
// memory access with variables
|
||||||
|
dict.AddWord("VARIABLE", Word{Name: "VARIABLE", Impl: b.Variable(&c)})
|
||||||
|
dict.AddWord("!", Word{Name: "!", Impl: b.Store(&c)})
|
||||||
|
dict.AddWord("@", Word{Name: "@", Impl: b.Fetch(&c)})
|
||||||
// debugging
|
// debugging
|
||||||
dict.AddWord("WORDS", Word{Name: "WORDS", Impl: b.Words(os.Stdout, dict)})
|
dict.AddWord("WORDS", Word{Name: "WORDS", Impl: b.Words(os.Stdout, dict)})
|
||||||
dict.AddWord("SEE", Word{Name: "SEE", Impl: b.See(os.Stdout, &rstack, dict)})
|
dict.AddWord("SEE", Word{Name: "SEE", Impl: b.See(os.Stdout, &rstack, dict)})
|
||||||
|
11
words.go
11
words.go
@ -10,11 +10,12 @@ type Dictionary map[string]Word
|
|||||||
|
|
||||||
// A Word defines a subroutine
|
// A Word defines a subroutine
|
||||||
type Word struct {
|
type Word struct {
|
||||||
Name string
|
Name string // Name of our word/variable
|
||||||
Impl func(string) error
|
Impl func(string) error // built-in implementation of the word
|
||||||
Source []string
|
Source []string // source, if user-defined
|
||||||
Immediate bool
|
Variable int // if this is a variable, the memory address
|
||||||
BranchCheck bool
|
Immediate bool // is this word immediate?
|
||||||
|
BranchCheck bool // is this word part of IF/ELSE/THEN?
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddWord inserts a new word into the dictonary, overwriting any existing word by that name
|
// AddWord inserts a new word into the dictonary, overwriting any existing word by that name
|
||||||
|
Loading…
Reference in New Issue
Block a user