This repository was archived by the owner on Aug 8, 2026. It is now read-only.
Repository navigation
Expand file tree
/
Copy patheval.go
More file actions
112 lines (94 loc) · 2.55 KB
/
Copy patheval.go
File metadata and controls
112 lines (94 loc) · 2.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// part2 - allow defining words in terms of others
package main
import (
"fmt"
"strconv"
"strings"
)
// Word is the structure for a single word
type Word struct {
// Name is the name of the function "+", "print", etc.
Name string
// Function is the function-pointer to call to invoke it.
//
// If this is nil then instead we interpret the known-codes
// from previously defined words.
Function func()
// Words holds the words we execute if the function-pointer
// is empty.
//
// The indexes here are relative to the Dictionary our evaluator
// holds/maintains
Words []int
}
// Eval is our evaluation structure
type Eval struct {
// Internal stack
Stack Stack
// Dictionary entries
Dictionary []Word
}
// NewEval returns a simple evaluator
func NewEval() *Eval {
// Empty structure
e := &Eval{}
// Populate the dictionary of words we have implemented
// which are hard-coded.
//
// All of these are coded in go, except for the new function
// square - which is implemented as just "dup *". The implementation
// just has the offsets in this array of the words used to invoke.
e.Dictionary = []Word{
{Name: "+", Function: e.add}, // 0
{Name: "-", Function: e.sub}, // 1
{Name: "*", Function: e.mul}, // 2
{Name: "/", Function: e.div}, // 3
{Name: "print", Function: e.print}, // 4
{Name: ".", Function: e.print}, // 5
{Name: "dup", Function: e.dup}, // 6
{Name: "square", Function: nil, Words: []int{6, 2}}, // 7
}
return e
}
// Eval processes a list of tokens.
//
// This is invoked by our repl with a line of input at the time.
func (e *Eval) Eval(args []string) {
for _, tok := range args {
// Trim the leading/trailing spaces,
// and skip any empty tokens
tok = strings.TrimSpace(tok)
if tok == "" {
continue
}
// Did we handle this as a dictionary item?
handled := false
for index, word := range e.Dictionary {
if tok == word.Name {
e.evalWord(index)
handled = true
}
}
// If we didn't handle this as a word, then
// assume it is a number.
if !handled {
i, err := strconv.ParseFloat(tok, 64)
if err != nil {
fmt.Printf("%s: %s\n", tok, err.Error())
return
}
e.Stack.Push(i)
}
}
}
// evalWord evaluates a word, by index from the dictionary
func (e *Eval) evalWord(index int) {
word := e.Dictionary[index]
if word.Function != nil {
word.Function()
} else {
for _, offset := range word.Words {
e.evalWord(offset)
}
}
}