dForth.go (6926B)
1 package main 2 3 import ( 4 "io" 5 "fmt" 6 "os" 7 "strconv" 8 "encoding/binary" 9 ) 10 11 var le = binary.LittleEndian 12 13 const ( 14 pcpt = 0 15 stpt = 4 16 rspt = 8 17 lwpt = 12 18 dtpt = 16 19 stackstart = 64 20 rstackstart = 512 21 dictstart = 1024 22 initmemsize = 4096 23 ) 24 25 type Word struct { 26 Name string 27 Builtin func() error 28 Addr int32 29 Immediate bool 30 } 31 32 func NewWord(name string, builtin func() error) *Word { 33 word := new(Word) 34 word.Name = name 35 word.Builtin = builtin 36 word.Immediate = false 37 return word 38 } 39 40 type Forth struct { 41 in io.Reader 42 out io.Writer 43 Dict []*Word 44 Mem []byte 45 } 46 47 func NewForth() *Forth { 48 forth := new(Forth) 49 forth.Dict = make([]*Word, 0) 50 forth.Dict = append(forth.Dict, 51 NewWord("_read", forth.biRead), 52 NewWord("_call", forth.biCall), 53 NewWord("_lit", forth.biLit), 54 NewWord("_jump", forth.biJump), 55 NewWord("_ret", forth.biRet), 56 NewWord(".", forth.biDot), 57 NewWord("@", forth.biFetch), 58 NewWord("!", forth.biStore), 59 NewWord("+", forth.biAdd), 60 NewWord("-", forth.biSub), 61 NewWord("_nwd", forth.biNewWord), 62 NewWord("immediate", forth.biImmediate), 63 NewWord("_cmpl", forth.biCompile), 64 ) 65 forth.Mem = make([]byte, initmemsize) 66 _ = forth.memStore(stpt, stackstart) 67 _ = forth.memStore(rspt, rstackstart) 68 _ = forth.memStore(dtpt, dictstart) 69 _ = forth.memStore(lwpt, 0) 70 _ = forth.memStore(pcpt, dictstart) 71 forth.memCompile( 72 0, /* _read */ 73 2, dictstart, /* _lit dictstart */ 74 2, 0, /* _lit 0 */ 75 3, /* _jump */ 76 ) 77 return forth 78 } 79 80 func (forth *Forth) memFetch(pt int32) (int32, error) { 81 if (pt < 0) && (int(pt) > len(forth.Mem) - 4) { 82 return 0, fmt.Errorf("memFetch: pt out of bonds") 83 } 84 val := int32(binary.LittleEndian.Uint32(forth.Mem[pt:])) 85 return val, nil 86 } 87 88 func (forth *Forth) memStore(pt, val int32) error { 89 if (pt < 0) { 90 return fmt.Errorf("memStore: pt out of bonds") 91 } 92 if int(pt) > len(forth.Mem) - 4 { 93 forth.Mem = append(forth.Mem, 94 make([]byte, int(pt) - len(forth.Mem) + 4)...) 95 } 96 binary.LittleEndian.PutUint32(forth.Mem[pt:], uint32(val)) 97 return nil 98 } 99 100 func (forth *Forth) memCompile(codes ...int32) { 101 dt, _ := forth.memFetch(dtpt) 102 for i, code := range codes { 103 _ = forth.memStore(int32(int(dt) + i * 4), code) 104 } 105 forth.memStore(dtpt, int32(int(dt) + len(codes) * 4)) 106 } 107 108 func (forth *Forth) Step() error { 109 pc, err := forth.memFetch(pcpt); 110 inst, _ := forth.memFetch(pc); 111 _ = forth.memStore(pcpt, pc + 4) 112 if (inst < 0) || (int(inst) > len(forth.Dict)) { 113 return fmt.Errorf("invalid inst %d, pc %d", 114 inst, pc) 115 } 116 w := forth.Dict[inst] 117 if w.Builtin != nil { 118 err = w.Builtin() 119 } else { 120 forth.Push(rspt, pc + 4) 121 pc = w.Addr 122 } 123 return err 124 } 125 126 func (forth *Forth) Push(pt, val int32) { 127 tos, err := forth.memFetch(pt) 128 if err != nil { 129 panic(err) 130 } 131 if err = forth.memStore(tos, val); err != nil { 132 panic(err) 133 } 134 if err = forth.memStore(pt, tos + 4); err != nil { 135 panic(err) 136 } 137 } 138 139 func (forth *Forth) Pop(pt int32) int32 { 140 tos, err := forth.memFetch(pt) 141 if err != nil { 142 panic(err) 143 } 144 tos -= 4 145 val, err := forth.memFetch(tos) 146 if err != nil { 147 panic(err) 148 } 149 if err = forth.memStore(pt, tos); err != nil { 150 panic(err) 151 } 152 return val 153 } 154 155 func (forth *Forth) Exec(w *Word) error { 156 if w.Builtin != nil { 157 return w.Builtin() 158 } else { 159 pc, _ := forth.memFetch(pcpt) 160 forth.Push(rspt, pc) 161 _ = forth.memStore(pcpt, w.Addr) 162 } 163 return nil 164 } 165 166 func (forth *Forth) biDot() error { 167 val := forth.Pop(stpt) 168 fmt.Fprint(forth.out, val, " ") 169 return nil 170 } 171 172 func (forth *Forth) biFetch() error { 173 addr := forth.Pop(stpt) 174 val, err := forth.memFetch(addr) 175 if err == nil { 176 forth.Push(stpt, val) 177 } 178 return err 179 } 180 181 func (forth *Forth) biStore() error { 182 addr := forth.Pop(stpt) 183 val := forth.Pop(stpt) 184 err := forth.memStore(addr, val) 185 return err 186 } 187 188 func (forth *Forth) biRead() error { 189 var ( 190 err, nerr error 191 s string 192 i, id, num int 193 w *Word 194 ) 195 if _, err = fmt.Fscan(forth.in, &s); err != nil { 196 return err 197 } 198 /* We shouldn't get empty reads, but on 9front 199 * we somehow do. (as of 18.10.2021) 200 * Let's filter them out. 201 */ 202 if s == "" { 203 forth.memCompile(4) /* 4 is _ret */ 204 return nil 205 } 206 id = -1 207 for i = len(forth.Dict); i > 0; i-- { 208 w = forth.Dict[i - 1] 209 if (s == w.Name) { 210 id = i - 1 211 break; 212 } 213 } 214 if id >= 0 { 215 return forth.Exec(w) 216 } else { 217 if num, nerr = strconv.Atoi(s); nerr != nil { 218 fmt.Fprintln(forth.out, "?") 219 } else { 220 forth.Push(stpt, int32(num)) 221 } 222 } 223 return nil 224 } 225 226 func (forth *Forth) biCall() error { 227 /* do we need _call? 228 * can we just treat opcode as call 229 * if it's >= dictstart ? 230 */ 231 pc, err := forth.memFetch(pcpt) 232 if err != nil { 233 return err 234 } 235 forth.Push(rspt, pc + 4) 236 jmp := forth.Pop(stpt) 237 err = forth.memStore(pcpt, jmp) 238 return err 239 } 240 241 func (forth *Forth) biRet() error { 242 jmp := forth.Pop(rspt) 243 err := forth.memStore(pcpt, jmp) 244 return err 245 } 246 247 func (forth *Forth) biLit() error { 248 pc, err := forth.memFetch(pcpt) 249 if err != nil { 250 return err 251 } 252 val, err := forth.memFetch(pc) 253 _ = forth.memStore(pcpt, pc + 4) 254 forth.Push(stpt, val) 255 return err 256 } 257 258 func (forth *Forth) biJump() error { 259 var err error 260 cond := forth.Pop(stpt) 261 addr := forth.Pop(stpt) 262 if cond == 0 { 263 err = forth.memStore(pcpt, addr) 264 } 265 return err 266 } 267 268 func (forth *Forth) biAdd() error { 269 x := forth.Pop(stpt) 270 y := forth.Pop(stpt) 271 forth.Push(stpt, x + y) 272 return nil 273 } 274 275 func (forth *Forth) biSub() error { 276 x := forth.Pop(stpt) 277 y := forth.Pop(stpt) 278 forth.Push(stpt, y - x) 279 return nil 280 } 281 282 func (forth *Forth) biNewWord() error { 283 var ( 284 err error 285 s string 286 w *Word 287 ) 288 if _, err = fmt.Fscan(forth.in, &s); err != nil { 289 return err 290 } 291 w = NewWord(s, nil) 292 w.Addr, _ = forth.memFetch(dtpt) 293 forth.Dict = append(forth.Dict, w) 294 forth.Push(stpt, w.Addr) 295 return nil 296 } 297 298 func (forth *Forth) biImmediate() error { 299 forth.Dict[len(forth.Dict) - 1].Immediate = true 300 return nil 301 } 302 303 func (forth *Forth) biCompile() error { 304 var ( 305 i int 306 s string 307 w *Word 308 ) 309 s = "" 310 for ;; { 311 if _, err := fmt.Fscan(forth.in, &s); err != nil { 312 return err 313 } 314 if s == ";" { 315 break 316 } 317 w = nil 318 for i = len(forth.Dict); i > 0; i-- { 319 if s == forth.Dict[i-1].Name { 320 w = forth.Dict[i-1] 321 break 322 } 323 } 324 if w != nil { 325 if w.Immediate { 326 forth.Exec(w) 327 } else { 328 forth.memCompile(int32(i - 1)) 329 } 330 } else { 331 if num, err := strconv.Atoi(s); err != nil { 332 fmt.Fprintln(forth.out, "?") 333 /* TODO: we should revert changes to before compilation start */ 334 return nil 335 } else { 336 forth.memCompile(2 , int32(num)) /* 2 is _lit */ 337 } 338 } 339 } 340 forth.memCompile(4) /* 4 is _ret */ 341 return nil 342 } 343 344 func (forth *Forth) Run(in io.Reader, out io.Writer) error { 345 var err error 346 forth.in = in 347 forth.out = out 348 for err == nil { 349 err = forth.Step() 350 } 351 return err 352 } 353 354 func main() { 355 fmt.Println("Welcome to dForth.") 356 forth := NewForth() 357 err := forth.Run(os.Stdin, os.Stdout) 358 fmt.Println("done: ", err) 359 }