-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathappendixb.tex
More file actions
263 lines (234 loc) · 9.75 KB
/
appendixb.tex
File metadata and controls
263 lines (234 loc) · 9.75 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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
%% Thinking Forth
%% Copyright (C) 2004 Leo Brodie
%% Initial transcription by Ed Beroset
%%
%% Chapter: Appendix B, Defining DOER/MAKE
\Chapmark{B}
\chapter{Defining
DOER/MAKE}
\index{D!DOER/MAKE|(}
\initial If your system doesn't have \forth{DOER} and \forth{MAKE}
already defined, this appendix is meant to help you install them and,
if necessary, understand how they work. Because by its nature this
construct is system dependent, I've included several different
implementations at the end of this appendix in the hope that one of
them will work for you. If no, and if this section doesn't give you
enough information to get them running, you probably have an unusual
system. Please don't ask me for help; ask your \Forth{} vendor.
Here's how it works. \forthb{DOER} is a defining word that creates an
entry with one cell in its parameter field. That cell contains the vector
address, and is initialized to point to a no-op word called
\forthb{NOTHING}.
Children of \forthb{DOER} will execute that \forthb{DOES>} code of
\forthb{DOER}, which does only two things: fetch the vector address and
place it on the return stack. That's all. \Forth{} execution then
continues with this address on the return stack, which will cause the
vectored function to be performed. It's like saying (in '83-Standard)
\begin{Code}
' nothing >body >r <return>
\end{Code}
which executes \forth{NOTHING}. (This trick only works with colon
definitions.)
Here's an illustration of the dictionary entry created when we enter
{\sf
\bigskip
\begin{tabular}{|l|l|}
\multicolumn{1}{l}{DOER JOE} & \multicolumn{1}{l}{}\\
\hline
JOE & pfa of NOTHING \\
\hline
\multicolumn{1}{l}{header} & \multicolumn{1}{l}{parameter field}
\end{tabular}
\bigskip
}
\noindent Now suppose we define:
\begin{Code}
: test make joe cr ;
\end{Code}
that is, we define a word that can vector \forth{JOE} to do a carriage
return.
Here's a picture of the compiled definition of \forth{TEST}:
%! This is supposed to be the cell diagram on p. 277, but I just
%! couldn't figure out how to do it.
{\sf\bigskip\begin{tabular}{|c|c|c|c|c|c|}\hline
& adr of & & adr of & adr of & adr of \\
TEST & (MAKE) & 0 & JOE & CR & EXIT \\ \hline\noalign{\vspace{2pt}}
\multicolumn{1}{c}{header} & \multicolumn{1}{c}{} & \multicolumn{1}{c}{\boxto{adr}{MARKER}} & \multicolumn{3}{c}{} \\
\end{tabular}
\bigskip}
\noindent Let's look at the code for \forthb{MAKE}. Since we're using
\forthb{MAKE} inside a colon definition, \forthb{STATE} will be true, and
we'll execute the phrase:
\begin{Code}
postpone (make) here marker ! 0 ,
\end{Code}
We can see how \forthb{MAKE} has compiled the address of the run-time
routine, \forthb{(MAKE)}, followed by a zero. (We'll explain what the
zero is for, and why we save its address in the variable
\forthb{MARKER}, later).
% should probably be "save its address in the variable..."
Now let's look at what \forthb{(MAKE)} does when we execute our new
definition \forthb{TEST}:
\bigskip{
\begin{tabular}{l@{\hspace{4ex}}>{\parindent-2ex}p{.5\textwidth}}
\verb%r>% & Gets an address from the return stack.
This address points to the cell just
past \forthb{(MAKE)}, where the zero is.\\
\verb%dup cell+% & Gets the address of the second cell after
\forthb{(MAKE)}, where the address of \forthb{JOE} is.\\
\verb%dup cell+% & Gets the address of the third cell after
\forthb{(MAKE)}, where the code we want to
execute begins. The stack now has:
\parindent2ex (~'marker,~'joe,~'code~--{}--~)\\
\verb%swap @ >body% & Fetches the contents of the address
pointing to \forth{JOE} (i.e., gets the address
of \forth{JOE}) and computes \forth{JOE}'s pfa, where
the vector address goes.\\
\verb%!% & Stores the address where the new code
begins (\forthb{CR}, etc.) into the vector
address of \forth{JOE}. \\
& Now \forth{JOE} points inside the definition of
\forth{TEST}. When we type \forth{JOE}, we'll do a
carriage return.\\
\verb%@ ?dup IF >r THEN%& Fetches the contents of the cell
containing zero. Since the cell does
contain zero, the \forth{IF THEN} statement is
not performed.\\
\end{tabular}}
\bigskip
That's the basic idea. But what about that cell containing zero? That's
for the use of \forthb{;AND}. Suppose we changed \forth{TEST} to read:
\begin{Code}
: test make joe cr ;and space ;
\end{Code}
That is, when we invoke \forth{TEST} we'll vector \forth{JOE} to do a
\forthb{CR}, and we'll do a \forthb{SPACE} right now. Here's what this
new version of \forth{TEST} will look like:
%! The diagram from page 278 is supposed to be here -- I didn't have a
%! clue, so I just omitted it.
\begin{center}\vspace{10pt}\sf\begin{tabular}{|c|c|c|c|c|c|c|c|}\hline
& adr of & \smash{\rnode{M1}{~\large\strut}} & adr of & adr of & adr of & \rnode{M2}{adr of\large\strut} & adr of \\
TEST & (MAKE) & adr & JOE & CR & EXIT & SPACE & EXIT \\ \hline\noalign{\vspace{2pt}}
\multicolumn{1}{c}{header} & \multicolumn{1}{c}{} & \multicolumn{1}{c}{\boxto{adr}{MARKER}} & \multicolumn{5}{c}{} \\
\end{tabular}
\psset{arrows=->,arrowinset=0,arrowsize=5pt,armA=0,angleA=90,angleB=90}
\ncangle{M1}{M2}
\end{center}
Here's the definition of \forthb{;AND}:
\begin{Code}
: ;and postpone EXIT here marker @ ! ; immediate
\end{Code}
We can see that \forthb{;AND} has compiled an \forthb{EXIT}\index{E!EXIT},
just as semicolon would.
Next, recall that \forthb{MAKE} saved the address of that cell in a
variable called \forthb{MARKER}. Now \forthb{;AND} stores \forthb{HERE}
(the location of the second string of code beginning with \forthb{SPACE})
into the cell previously containing zero. Now \forthb{(MAKE)} has a
pointer to the place to resume execution. The phrase
\begin{Code}
IF >r THEN
\end{Code}
will leave on the return stack the address of the code beginning with
\forthb{SPACE}. Thus execution will skip over the code between
\forthb{MAKE} and \forthb{;AND} and continue with the remainder of the
definition up to semicolon.
The word \forthb{UNDO} ticks the name of a \forthb{DOER} word, and stores the
address of \forthb{NOTHING} into it.
One final note: on some systems you may encounter a problem. If you use
\forthb{MAKE} outside of a colon definition to create a forward reference,
you may not be able to find the most recently defined word. For instance,
if you have:
\begin{Code}
: refrain do-dah do-dah ;
make song chorus refrain ;
\end{Code}
your system might think that refrain has not been defined. The problem is
due to the placement of \forth{SMUDGE}. As a solution, try rearranging
the order of definitions or, if necessary, put \forth{MAKE} code inside a
definition which you then execute:
\begin{Code}
: setup make song chorus refrain ; setup
\end{Code}
In Laboratory Microsystems PC/FORTH 2.0, the \forth{UNSMUDGE} on line 9
handles the problem. This problem does not arise with the
Laxen/Perry/Harris model.
The final screen is an example of using \forthb{DOER/MAKE}. After loading
the block, enter
\begin{Code}
recital
\end{Code}
then enter
\begin{Code}
why?
\end{Code}
followed by return, as many times as you like (you'll get a different
reason each time).
\vfill
\setcounter{screen}{21}
\begin{Screen}
( DOER/MAKE Shadow screen LPB 12/05/83 )
NOTHING A no-opp
DOER Defines a word whose behavior is vectorable.
marker Saves adr for optional continuation pointer.
(MAKE) Stuffs the address of further code into the
parameter field of a doer word.
MAKE Used interpretively: MAKE doer-name forth-code ;
or inside a definition:
: def MAKE doer-name forth-code ;
Vectors the doer-name word to the forth-code.
;AND Allows continuation of the "making" definition
UNDO Usage: UNDO doer-name ; makes it safe to execute
\end{Screen}
\vfill
\begin{Screen}
\ DOER/MAKE ANS Forth with real return-stack BP 22/04/06
: nothing ;
: Doer Create ['] nothing >body , DOES> @ >r ;
Variable marker
: (make) r> dup cell+ dup cell+ swap @ >body !
@ ?dup IF >r THEN ;
: make state @ IF ( compiling)
postpone (make) here marker ! 0 , ' ,
ELSE here ' >body !
] THEN ; immediate
: ;and postpone EXIT here marker @ ! ; immediate
: undo ['] nothing >body ' >body ! ;
\ The code in this screen is in the public domain.
\end{Screen}
\vfill
\begin{Screen}
\ DOER/MAKE NC ANS Forth with real return-stack BP 22/04/06
: nothing ;
: Doer Create ['] nothing , DOES> @ >r ;
Variable marker
: (make) r> dup cell+ dup cell+ swap @ >body !
@ ?dup IF >r THEN ;
: make state @ IF ( compiling)
postpone (make) here marker ! 0 , ' ,
ELSE here ' >body !
] THEN ; immediate
: ;and postpone EXIT here marker @ ! ; immediate
: undo ['] nothing ' >body ! ;
\ The code in this screen is in the public domain.
\end{Screen}
\vfill
\begin{Screen}
\ toddler: Example of DOER/MAKE 12/01/83 )
Doer answer
: recital
cr ." Your daddy is standing on the table. Ask him 'WHY?' "
make answer ." To change the light bulb."
BEGIN
make answer ." Because it's burned out."
make answer ." Because it was old."
make answer ." Because we put it in there a long time ago."
make answer ." Because it was dark!"
make answer ." Because it was night time!!"
make answer ." Stop saying WHY?"
make answer ." Because it's driving me crazy."
make answer ." Just let me change this light bulb!"
AGAIN ;
: why? cr answer quit ;
\end{Screen}
\index{D!DOER/MAKE|)}
\vfill