-
Notifications
You must be signed in to change notification settings - Fork 0
/
07_interpreter.fth
126 lines (114 loc) · 2.38 KB
/
07_interpreter.fth
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
\ case-insensitive name equality
\ assume that c-addr2 is capitalized,
\ and that hidden words have a non-ASCII first character
: name= ( c-addr1 u1 c-addr2 u2 -- ? )
rot over <> if
drop 2drop false exit
then ( c-addr1 c-addr2 len )
0 ?do ( c-addr1 c-addr2 )
over c@ upchar over c@ <> if
2drop false unloop exit
then
swap 1+ swap 1+
loop
2drop true
;
: find-name ( c-addr u -- nt | 0 )
latest @ ( c-addr u nt )
begin dup
while
>r 2dup r@ -rot r> \ clone the stack
name>string name= =0
while name>backword
repeat then
nip nip
;
: ' ( -- xt )
parse-name find-name
dup =0 if -2 throw then
name>xt
;
: ['] ( -- xt )
' [ ' literal , ]
; immediate
: postpone ( -- )
parse-name find-name
dup =0 if -2 throw then
dup name>immediate?
if name>xt ,
else ['] lit , name>xt , ['] , ,
then
; immediate
: interpret
begin
parse-name \ get the next word
dup =0 if
2drop exit \ if it's 0-length, we're done!
then
2dup find-name
?dup if \ if we found the word in the dictionary,
nip nip \ get rid of the name
compiling? if
dup name>xt
swap name>immediate?
if execute
else ,
then
else
name>xt execute
then
else
\ TODO: double-width numbers
2dup s>number? nip if \ if it's a number, either bake it in or leave it on the stack
nip nip
compiling?
if postpone literal
then \ no else branch, just leave the number on the stack
else
drop
." Unrecognized word: " type cr
-14 throw
then
then
again
;
: include-named-file ( name name# fid -- )
add-file-source
begin refill
while
['] interpret catch ?dup
if drop-source throw
then
repeat
drop-source
;
: include-file ( fid -- )
0 0 rot include-named-file
;
: save-filename ( c-addr u -- c-addr u )
tuck here >r
dup allot align
r@ swap move
r> swap
;
: included ( c-addr u -- )
resolve-relative-path \ make sure the path we save is absolute
2dup save-filename 2swap
r/o open-file throw
include-named-file
;
: include ( -- ) parse-name included ;
: quit
begin r-depth while r> drop repeat
reset-source
postpone [
begin refill
while
['] interpret catch ?dup if
." Threw exception " . cr
else
state @ =0 if space ." ok" cr then
then
repeat
bye
;