VARIABLE
This commit is contained in:
		
							
								
								
									
										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
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user