Imported Upstream version 21
[debian/pforth] / docs / pf_tut.htm
1 <HTML>\r
2 <HEAD>\r
3    <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">\r
4    <META NAME="GENERATOR" CONTENT="Mozilla/4.05 [en] (Win95; I) [Netscape]">\r
5    <META NAME="Author" CONTENT="Phil Burk">\r
6    <META NAME="Description" CONTENT="Tutorial for pForth language.">\r
7    <META NAME="KeyWords" CONTENT="Forth, tutorial, pForth">\r
8    <TITLE>pForth Tutorial</TITLE>\r
9 </HEAD>\r
10 <BODY BACKGROUND="r2harch.gif">\r
11 \r
12 <HR size=4>\r
13 <CENTER>\r
14 <H1>\r
15 Forth Tutorial</H1></CENTER>\r
16 \r
17 <HR WIDTH="100%">\r
18 \r
19 <P>by <A HREF="http://www.softsynth.com/philburk.html">Phil Burk</A>\r
20 \r
21 <P>To <A HREF="pforth.html">pForth Home Page</A>\r
22 <H2>\r
23 Table of Contents</H2>\r
24 \r
25 <UL>\r
26 <LI>\r
27 <A HREF="#Forth Syntax">Forth Syntax</A></LI>\r
28 \r
29 <LI>\r
30 <A HREF="#The Stack">Stack Manipulation</A></LI>\r
31 \r
32 <LI>\r
33 <A HREF="#Arithmetic">Arithmetic</A></LI>\r
34 \r
35 <LI>\r
36 <A HREF="#Defining a New Word">Defining a New Word</A></LI>\r
37 \r
38 <LI>\r
39 <A HREF="#More Arithmetic">More Arithmetic</A></LI>\r
40 \r
41 <UL>\r
42 <LI>\r
43 <A HREF="#Arithmetic Overflow">Arithmetic Overflow</A></LI>\r
44 \r
45 <LI>\r
46 <A HREF="#Convert Algebraic Expressions to Forth">Convert Algebraic Expressions\r
47 to Forth</A></LI>\r
48 </UL>\r
49 \r
50 <LI>\r
51 <A HREF="#Character Input and Output">Character Input and Output</A></LI>\r
52 \r
53 <LI>\r
54 <A HREF="#Compiling from Files">Compiling from Files</A></LI>\r
55 \r
56 <LI>\r
57 <A HREF="#Variables">Variables</A></LI>\r
58 \r
59 <LI>\r
60 <A HREF="#Constants">Constants</A></LI>\r
61 \r
62 <LI>\r
63 <A HREF="#Logical Operators">Logical Operators</A></LI>\r
64 \r
65 <LI>\r
66 <A HREF="#Conditionals - IF ELSE THEN CASE">Conditionals - IF ELSE THEN\r
67 CASE</A></LI>\r
68 \r
69 <LI>\r
70 <A HREF="#Loops">Loops</A></LI>\r
71 \r
72 <LI>\r
73 <A HREF="#Text Input and Output">Text Input and Output</A></LI>\r
74 \r
75 <LI>\r
76 <A HREF="#Changing Numeric Base">Changing Numeric Base</A></LI>\r
77 \r
78 <LI>\r
79 <A HREF="#Answers to Problems">Answers to Problems</A></LI>\r
80 </UL>\r
81 The intent of this tutorial is to provide a series of experiments that\r
82 will introduce you to the major concepts of Forth. It is only a starting\r
83 point. Feel free to deviate from the sequences I provide. A free form investigation\r
84 that is based on your curiosity is probably the best way to learn any language.\r
85 Forth is especially well adapted to this type of learning.\r
86 \r
87 <P>This tutorial is written for the PForth implementation of the ANS Forth\r
88 standard. I have tried to restrict this tutorial to words that are part\r
89 of the ANS standard but some PForth specific words may have crept in.\r
90 \r
91 <P>In the tutorials, I will print the things you need to type in upper\r
92 case, and indent them. You can enter them in upper or lower case. At the\r
93 end of each line, press the RETURN (or ENTER) key; this causes Forth to\r
94 interpret what you've entered.\r
95 <H2>\r
96 <A NAME="Forth Syntax"></A>Forth Syntax</H2>\r
97 Forth has one of the simplest syntaxes of any computer language. The syntax\r
98 can be stated as follows, "<B>Forth code is a bunch of words with spaces\r
99 between them.</B>" This is even simpler than English! Each <I>word</I>\r
100 is equivalent to a function or subroutine in a language like 'C'. They\r
101 are executed in the order they appear in the code. The following statement,\r
102 for example, could appear in a Forth program:\r
103 <UL>\r
104 <PRE>&nbsp;<TT>WAKE.UP EAT.BREAKFAST WORK EAT.DINNER PLAY SLEEP</TT></PRE>\r
105 </UL>\r
106 Notice that WAKE.UP has a dot between the WAKE and UP. The dot has no particular\r
107 meaning to the Forth compiler. I simply used a dot to connect the two words\r
108 together to make one word. Forth word names can have any combination of\r
109 letters, numbers, or punctuation. We will encounter words with names like:\r
110 <UL>\r
111 <PRE>&nbsp;." #S SWAP ! @ ACCEPT . *</PRE>\r
112 </UL>\r
113 They are all called <I>words</I>. The word <B>$%%-GL7OP</B> is a legal\r
114 Forth name, although not a very good one. It is up to the programmer to\r
115 name words in a sensible manner.\r
116 \r
117 <P>Now it is time to run your Forth and begin experimenting. Please consult\r
118 the manual for your Forth for instructions on how to run it.\r
119 <H2>\r
120 <A NAME="The Stack"></A>Stack Manipulation</H2>\r
121 The Forth language is based on the concept of a <I>stack</I>. Imagine a\r
122 stack of blocks with numbers on them. You can add or remove numbers from\r
123 the top of the stack. You can also rearrange the order of the numbers.\r
124 Forth uses several stacks. The <I>DataStack </I>is the one used for passing\r
125 data between Forth words so we will concentrate our attention there. The\r
126 <I>Return Stack</I> is another Forth stack that is primarily for internal\r
127 system use. In this tutorial, when we refer to the "stack," we will be\r
128 referring to the Data Stack.\r
129 \r
130 <P>The stack is initially empty. To put some numbers on the stack, enter:\r
131 <UL>\r
132 <PRE><TT>23 7 9182</TT></PRE>\r
133 </UL>\r
134 Let's now print the number on top of the stack using the Forth word ' <B>.</B>\r
135 ', which is pronounced " dot ". This is a hard word to write about in a\r
136 manual because it is a single period.\r
137 \r
138 <P>Enter: <B>.&nbsp;</B>\r
139 \r
140 <P>You should see the last number you entered, 9182 , printed. Forth has\r
141 a very handy word for showing you what's on the stack. It is <B>.S</B>\r
142 , which is pronounced "dot S". The name was constructed from "dot" for\r
143 print, and "S" for stack. (PForth will automatically print the stack after\r
144 every line if the TRACE-STACK variable is set to TRUE.) If you enter:\r
145 <UL>\r
146 <PRE><TT>.S</TT></PRE>\r
147 </UL>\r
148 you will see your numbers in a list. The number at the far right is the\r
149 one on top of the stack.\r
150 \r
151 <P>You will notice that the 9182 is not on the stack. The word ' . ' removes\r
152 the number on top of the stack before printing it. In contrast, ' .S '\r
153 leaves the stack untouched.\r
154 \r
155 <P>We have a way of documenting the effect of words on the stack with a\r
156 <I>stack diagram</I>. A stack diagram is contained in parentheses. In Forth,\r
157 the parentheses indicate a comment. In the examples that follow, you do\r
158 not need to type in the comments. When you are programming, of course,\r
159 we encourage the use of comments and stack diagrams to make your code more\r
160 readable. In this manual, we often indicate stack diagrams in <B>bold text</B>\r
161 like the one that follows. Do not type these in. The stack diagram for\r
162 a word like ' . ' would be:\r
163 <PRE><B><TT>. ( N -- , print number on top of stack )</TT></B></PRE>\r
164 The symbols to the left of -- describe the parameters that a word expects\r
165 to process. In this example, N stands for any integer number. To the right\r
166 of --, up to the comma, is a description of the stack parameters when the\r
167 word is finished, in this case there are none because 'dot' "eats" the\r
168 N that was passed in. (Note that the stack descriptions are not necessary,\r
169 but they are a great help when learning other peoples programs.)\r
170 \r
171 <P>The text following the comma is an English description of the word.\r
172 You will note that after the -- , N is gone. You may be concerned about\r
173 the fact that there were other numbers on the stack, namely 23 and 7 .\r
174 The stack diagram, however, only describes the portion of the stack that\r
175 is affected by the word. For a more detailed description of the stack diagrams,\r
176 there is a special section on them in this manual right before the main\r
177 glossary section.\r
178 \r
179 <P>Between examples, you will probably want to clear the stack. If you\r
180 enter <B>0SP</B>, pronounced "zero S P", then the stack will be cleared.\r
181 \r
182 <P>Since the stack is central to Forth, it is important to be able to alter\r
183 the stack easily. Let's look at some more words that manipulate the stack.\r
184 Enter:\r
185 <UL>\r
186 <PRE><TT>0SP .S \ That's a 'zero' 0, not an 'oh' O.\r
187 777 DUP .S</TT></PRE>\r
188 </UL>\r
189 You will notice that there are two copies of 777 on the stack. The word\r
190 <B>DUP</B> duplicates the top item on the stack. This is useful when you\r
191 want to use the number on top of the stack and still have a copy. The stack\r
192 diagram for DUP would be:\r
193 <PRE><B><TT>DUP ( n -- n n , DUPlicate top of stack )</TT></B></PRE>\r
194 Another useful word, is <B>SWAP</B>. Enter:\r
195 <UL>\r
196 <PRE><TT>0SP&nbsp;\r
197 23 7 .S&nbsp;\r
198 SWAP .S&nbsp;\r
199 SWAP .S</TT></PRE>\r
200 </UL>\r
201 The stack diagram for SWAP would be:\r
202 <PRE><B><TT>SWAP ( a b -- b a , swap top two items on stack )</TT></B></PRE>\r
203 Now enter:\r
204 <UL>\r
205 <PRE><TT>OVER .S\r
206 OVER .S</TT></PRE>\r
207 </UL>\r
208 The word <B>OVER</B> causes a copy of the second item on the stack to leapfrog\r
209 over the first. It's stack diagram would be:\r
210 \r
211 <P><B><TT>OVER ( a b -- a b a , copy second item on stack )</TT></B>\r
212 \r
213 <P>Here is another commonly used Forth word:\r
214 \r
215 <P><B><TT>DROP ( a -- , remove item from the stack )</TT></B>\r
216 \r
217 <P>Can you guess what we will see if we enter:\r
218 <UL>\r
219 <PRE><TT>0SP 11 22 .S\r
220 DROP .S</TT></PRE>\r
221 </UL>\r
222 Another handy word for manipulating the stack is <B>ROT</B>. Enter:\r
223 <UL>\r
224 <PRE><TT>0SP\r
225 11 22 33 44 .S\r
226 ROT .S</TT></PRE>\r
227 </UL>\r
228 The stack diagram for ROT is, therefore:\r
229 \r
230 <P><B><TT>ROT ( a b c -- b c a , ROTate third item to top )&nbsp;</TT></B>\r
231 \r
232 <P>You have now learned the more important stack manipulation words. You\r
233 will see these in almost every Forth program. I should caution you that\r
234 if you see too many stack manipulation words being used in your code then\r
235 you may want to reexamine and perhaps reorganize your code. You will often\r
236 find that you can avoid excessive stack manipulations by using <I>local\r
237 or global VARIABLES</I> which will be discussed later.\r
238 \r
239 <P>If you want to grab any arbitrary item on the stack, use <B>PICK</B>\r
240 . Try entering:\r
241 <UL>\r
242 <PRE><TT>0SP\r
243 14 13 12 11 10\r
244 3 PICK . ( prints 13 )\r
245 0 PICK . ( prints 10 )\r
246 4 PICK .</TT></PRE>\r
247 </UL>\r
248 PICK makes a copy of the Nth item on the stack. The numbering starts with\r
249 zero, therefore:\r
250 <UL><TT>0 PICK is equivalent to DUP</TT>\r
251 <BR><TT>1 PICK is equivalent to OVER&nbsp;</TT></UL>\r
252 <B><TT>PICK ( ... v3 v2 v1 v0 N -- ... v3 v2 v1 v0 vN )&nbsp;</TT></B>\r
253 \r
254 <P>(Warning. The Forth-79 and FIG Forth standards differ from the ANS and\r
255 Forth '83 standard in that their PICK numbering starts with one, not zero.)\r
256 \r
257 <P>I have included the stack diagrams for some other useful stack manipulation\r
258 words. Try experimenting with them by putting numbers on the stack and\r
259 calling them to get a feel for what they do. Again, the text in parentheses\r
260 is just a comment and need not be entered.\r
261 \r
262 <P><B><TT>DROP ( n -- , remove top of stack )&nbsp;</TT></B>\r
263 \r
264 <P><B><TT>?DUP ( n -- n n | 0 , duplicate only if non-zero, '|' means OR\r
265 )&nbsp;</TT></B>\r
266 \r
267 <P><B><TT>-ROT ( a b c -- c a b , rotate top to third position )&nbsp;</TT></B>\r
268 \r
269 <P><B><TT>2SWAP ( a b c d -- c d a b , swap pairs )&nbsp;</TT></B>\r
270 \r
271 <P><B><TT>2OVER ( a b c d -- a b c d a b , leapfrog pair )&nbsp;</TT></B>\r
272 \r
273 <P><B><TT>2DUP ( a b -- a b a b , duplicate pair )&nbsp;</TT></B>\r
274 \r
275 <P><B><TT>2DROP ( a b -- , remove pair )&nbsp;</TT></B>\r
276 \r
277 <P><B><TT>NIP ( a b -- b , remove second item from stack )&nbsp;</TT></B>\r
278 \r
279 <P><B><TT>TUCK ( a b -- b a b , copy top item to third position )&nbsp;</TT></B>\r
280 <H3>\r
281 <A NAME="Problems - Stack"></A>Problems:</H3>\r
282 Start each problem by entering:\r
283 <UL>\r
284 <PRE><TT>0SP 11 22 33</TT></PRE>\r
285 </UL>\r
286 Then use the stack manipulation words you have learned to end up with the\r
287 following numbers on the stack:\r
288 <UL>\r
289 <PRE><TT>1) 11 33 22 22</TT></PRE>\r
290 \r
291 <PRE><TT>2) 22 33</TT></PRE>\r
292 \r
293 <PRE><TT>3) 22 33 11 11 22</TT></PRE>\r
294 \r
295 <PRE><TT>4) 11 33 22 33 11</TT></PRE>\r
296 \r
297 <PRE><TT>5) 33 11 22 11 22</TT></PRE>\r
298 </UL>\r
299 <A HREF="#Answers to Problems">Answers to the problems</A> can be found\r
300 at the end of this tutorial.\r
301 <H2>\r
302 <A NAME="Arithmetic"></A>Arithmetic</H2>\r
303 Great joy can be derived from simply moving numbers around on a stack.\r
304 Eventually, however, you'll want to do something useful with them. This\r
305 section describes how to perform arithmetic operations in Forth.\r
306 \r
307 <P>The Forth arithmetic operators work on the numbers currently on top\r
308 of the stack. If you want to add the top two numbers together, use the\r
309 Forth word <B>+</B> , pronounced "plus". Enter:\r
310 <UL>\r
311 <PRE><TT>2 3 + .\r
312 2 3 + 10 + .</TT></PRE>\r
313 </UL>\r
314 This style of expressing arithmetic operations is called <I>Reverse Polish\r
315 Notation,</I> or<I> RPN</I>. It will already be familiar to those of you\r
316 with HP calculators. In the following examples, I have put the algebraic\r
317 equivalent representation in a comment.\r
318 \r
319 <P>Some other arithmetic operators are <B>- * /</B> . Enter:\r
320 <UL>\r
321 <PRE><TT>30 5 - . ( 25=30-5 )\r
322 30 5 / . ( 6=30/5 )\r
323 30 5 * . ( 150=30*5 )\r
324 30 5 + 7 / . \ 5=(30+5)/7</TT></PRE>\r
325 </UL>\r
326 Some combinations of operations are very common and have been coded in\r
327 assembly language for speed. For example, <B>2*</B> is short for 2 * .\r
328 You should use these whenever possible to increase the speed of your program.\r
329 These include:\r
330 <UL>\r
331 <PRE><TT>1+ 1- 2+ 2- 2* 2/</TT></PRE>\r
332 </UL>\r
333 Try entering:\r
334 <UL>\r
335 <PRE><TT>10 1- .\r
336 7 2* 1+ . ( 15=7*2+1 )</TT></PRE>\r
337 </UL>\r
338 One thing that you should be aware of is that when you are doing division\r
339 with integers using / , the remainder is lost. Enter:\r
340 <UL>\r
341 <PRE><TT>15 5 / .\r
342 17 5 / .</TT></PRE>\r
343 </UL>\r
344 This is true in all languages on all computers. Later we will examine <B>/MOD</B>\r
345 and <B>MOD</B> which do give the remainder.\r
346 <H2>\r
347 <A NAME="Defining a New Word"></A>Defining a New Word</H2>\r
348 It's now time to write a <I>small program</I> in Forth. You can do this\r
349 by defining a new word that is a combination of words we have already learned.\r
350 Let's define and test a new word that takes the average of two numbers.\r
351 <DT>\r
352 We will make use of two new words, <B>:</B> ( "colon"), and <B>;</B> (\r
353 "semicolon") . These words start and end a typical <I>Forth definition</I>.\r
354 Enter:</DT>\r
355 \r
356 <UL>\r
357 <PRE><TT>: AVERAGE ( a b -- avg ) + 2/ ;</TT></PRE>\r
358 </UL>\r
359 Congratulations. You have just written a Forth program. Let's look more\r
360 closely at what just happened. The colon told Forth to add a new word to\r
361 its list of words. This list is called the Forth dictionary. The name of\r
362 the new word will be whatever name follows the colon. Any Forth words entered\r
363 after the name will be compiled into the new word. This continues until\r
364 the semicolon is reached which finishes the definition.\r
365 \r
366 <P>Let's test this word by entering:\r
367 <UL>\r
368 <PRE><TT>10 20 AVERAGE . ( should print 15 )</TT></PRE>\r
369 </UL>\r
370 Once a word has been defined, it can be used to define more words. Let's\r
371 write a word that tests our word.. Enter:\r
372 <UL>\r
373 <PRE><TT>: TEST ( --) 50 60 AVERAGE . ;\r
374 TEST</TT></PRE>\r
375 </UL>\r
376 Try combining some of the words you have learned into new Forth definitions\r
377 of your choice. If you promise not to be overwhelmed, you can get a list\r
378 of the words that are available for programming by entering:\r
379 <UL>\r
380 <PRE><TT>WORDS</TT></PRE>\r
381 </UL>\r
382 Don't worry, only a small fraction of these will be used directly in your\r
383 programs.\r
384 <H2>\r
385 <A NAME="More Arithmetic"></A>More Arithmetic</H2>\r
386 When you need to know the remainder of a divide operation. /MOD will return\r
387 the remainder as well as the quotient. the word MOD will only return the\r
388 remainder. Enter:\r
389 <UL>\r
390 <PRE><TT>0SP\r
391 53 10 /MOD .S\r
392 0SP\r
393 7 5 MOD .S</TT></PRE>\r
394 </UL>\r
395 Two other handy words are <B>MIN</B> and <B>MAX</B> . They accept two numbers\r
396 and return the MINimum or MAXimum value respectively. Try entering the\r
397 following:\r
398 <UL>\r
399 <PRE><TT>56 34 MAX .\r
400 56 34 MIN .\r
401 -17 0 MIN .</TT></PRE>\r
402 </UL>\r
403 Some other useful words are:\r
404 \r
405 <P><B><TT>ABS ( n -- abs(n) , absolute value of n )&nbsp;</TT></B>\r
406 \r
407 <P><B><TT>NEGATE ( n -- -n , negate value, faster then -1 * )&nbsp;</TT></B>\r
408 \r
409 <P><B><TT>LSHIFT ( n c -- n&lt;&lt;c , left shift of n )&nbsp;</TT></B>\r
410 \r
411 <P><B><TT>RSHIFT ( n c -- n>>c , logical right shift of n )&nbsp;</TT></B>\r
412 \r
413 <P><B><TT>ARSHIFT ( n c -- n>>c ) , arithmetic right shift of n )&nbsp;</TT></B>\r
414 \r
415 <P>ARSHIFT or LSHIFT can be used if you have to multiply quickly by a power\r
416 of 2 . A right shift is like doing a divide by 2. This is often faster\r
417 than doing a regular multiply or divide. Try entering:\r
418 <UL>\r
419 <PRE><TT>: 256* 8 LSHIFT ;\r
420 3 256* .</TT></PRE>\r
421 </UL>\r
422 \r
423 <H3>\r
424 <A NAME="Arithmetic Overflow"></A>Arithmetic Overflow</H3>\r
425 If you are having problems with your calculation overflowing the 32-bit\r
426 precision of the stack, then you can use <B>*/</B> . This produces an intermediate\r
427 result that is 64 bits long. Try the following three methods of doing the\r
428 same calculation. Only the one using */ will yield the correct answer,\r
429 5197799.\r
430 <UL>\r
431 <PRE><TT>34867312 99154 * 665134 / .\r
432 34867312 665134 / 99154 * .\r
433 34867312 99154 665134 */ .</TT></PRE>\r
434 </UL>\r
435 \r
436 <H4>\r
437 <A NAME="Convert Algebraic Expressions to Forth"></A>Convert Algebraic\r
438 Expressions to Forth</H4>\r
439 How do we express complex algebraic expressions in Forth? For example:\r
440 20 + (3 * 4)\r
441 \r
442 <P>To convert this to Forth you must order the operations in the order\r
443 of evaluation. In Forth, therefore, this would look like:\r
444 <UL>\r
445 <PRE><TT>3 4 * 20 +</TT></PRE>\r
446 </UL>\r
447 Evaluation proceeds from left to right in Forth so there is no ambiguity.\r
448 Compare the following algebraic expressions and their Forth equivalents:\r
449 (Do <B>not</B> enter these!)\r
450 <UL>\r
451 <PRE>(100+50)/2 ==> 100 50 + 2/\r
452 ((2*7) + (13*5)) ==> 2 7 * 13 5 * +</PRE>\r
453 </UL>\r
454 If any of these expressions puzzle you, try entering them one word at a\r
455 time, while viewing the stack with .S .\r
456 <H3>\r
457 <A NAME="Problems - Square"></A>Problems:</H3>\r
458 Convert the following algebraic expressions to their equivalent Forth expressions.\r
459 (Do <B>not</B> enter these because they are not Forth code!)\r
460 <UL>\r
461 <PRE>(12 * ( 20 - 17 ))</PRE>\r
462 \r
463 <PRE>(1 - ( 4 * (-18) / 6) )</PRE>\r
464 \r
465 <PRE>( 6 * 13 ) - ( 4 * 2 * 7 )</PRE>\r
466 </UL>\r
467 Use the words you have learned to write these new words:\r
468 <UL>\r
469 <PRE><TT>SQUARE ( N -- N*N , calculate square )</TT></PRE>\r
470 \r
471 <PRE><TT>DIFF.SQUARES ( A B -- A*A-B*B , difference of squares )</TT></PRE>\r
472 \r
473 <PRE><TT>AVERAGE4 ( A B C D -- [A+B+C+D]/4 )</TT></PRE>\r
474 \r
475 <PRE>HMS>SECONDS ( HOURS MINUTES SECONDS -- TOTAL-SECONDS , convert )</PRE>\r
476 </UL>\r
477 <A HREF="#Answers to Problems">Answers to the problems</A> can be found\r
478 at the end of this tutorial.\r
479 <H2>\r
480 <A NAME="Character Input and Output"></A>Character Input and Output</H2>\r
481 The numbers on top of the stack can represent anything. The top number\r
482 might be how many blue whales are left on Earth or your weight in kilograms.\r
483 It can also be an ASCII character. Try entering the following:\r
484 <UL>\r
485 <PRE><TT>72 EMIT 105 EMIT</TT></PRE>\r
486 </UL>\r
487 You should see the word "Hi" appear before the OK. The 72 is an ASCII 'H'\r
488 and 105 is an 'i'. EMIT takes the number on the stack and outputs it as\r
489 a character. If you want to find the ASCII value for any character, you\r
490 can use the word ASCII . Enter:\r
491 <UL>\r
492 <PRE><TT>CHAR W .\r
493 CHAR % DUP . EMIT\r
494 CHAR A DUP .\r
495 32 + EMIT</TT></PRE>\r
496 </UL>\r
497 There is an ASCII chart in the back of this manual for a complete character\r
498 list.\r
499 \r
500 <P>Notice that the word CHAR is a bit unusual because its input comes not\r
501 from the stack, but from the following text. In a stack diagram, we represent\r
502 that by putting the input in angle brackets, &lt;input>. Here is the stack\r
503 diagram for CHAR.\r
504 \r
505 <P><B><TT>CHAR ( &lt;char> -- char , get ASCII value of a character )&nbsp;</TT></B>\r
506 \r
507 <P>Using EMIT to output character strings would be very tedious. Luckily\r
508 there is a better way. Enter:\r
509 <UL>\r
510 <PRE><TT>: TOFU ." Yummy bean curd!" ;\r
511 TOFU</TT></PRE>\r
512 </UL>\r
513 The word <B>."</B> , pronounced "dot quote", will take everything up to\r
514 the next quotation mark and print it to the screen. Make sure you leave\r
515 a space after the first quotation mark. When you want to have text begin\r
516 on a new line, you can issue a carriage return using the word <B>CR</B>\r
517 . Enter:\r
518 <UL>\r
519 <PRE><TT>: SPROUTS ." Miniature vegetables." ;\r
520 : MENU\r
521 &nbsp;&nbsp;&nbsp; CR TOFU CR SPROUTS CR\r
522 ;\r
523 MENU</TT></PRE>\r
524 </UL>\r
525 You can emit a blank space with <B>SPACE</B> . A number of spaces can be\r
526 output with SPACES . Enter:\r
527 <UL>\r
528 <PRE><TT>CR TOFU SPROUTS\r
529 CR TOFU SPACE SPROUTS\r
530 CR 10 SPACES TOFU CR 20 SPACES SPROUTS</TT></PRE>\r
531 </UL>\r
532 For character input, Forth uses the word <B>KEY</B> which corresponds to\r
533 the word EMIT for output. KEY waits for the user to press a key then leaves\r
534 its value on the stack. Try the following.\r
535 <UL>\r
536 <PRE><TT>: TESTKEY ( -- )\r
537 &nbsp;&nbsp;&nbsp; ." Hit a key: " KEY CR\r
538 &nbsp;&nbsp;&nbsp; ." That = " . CR\r
539 ;\r
540 TESTKEY</TT></PRE>\r
541 </UL>\r
542 [Note: On some computers, the input if buffered so you will need to hit\r
543 the ENTER key after typing your character.]\r
544 \r
545 <P><B><TT>EMIT ( char -- , output character )&nbsp;</TT></B>\r
546 \r
547 <P><B><TT>KEY ( -- char , input character )&nbsp;</TT></B>\r
548 \r
549 <P><B><TT>SPACE ( -- , output a space )&nbsp;</TT></B>\r
550 \r
551 <P><B><TT>SPACES ( n -- , output n spaces )&nbsp;</TT></B>\r
552 \r
553 <P><B><TT>CHAR ( &lt;char> -- char , convert to ASCII )&nbsp;</TT></B>\r
554 \r
555 <P><B><TT>CR ( -- , start new line , carriage return )&nbsp;</TT></B>\r
556 \r
557 <P><B><TT>." ( -- , output " delimited text )&nbsp;</TT></B>\r
558 <H2>\r
559 <BR>\r
560 <BR>\r
561 <A NAME="Compiling from Files"></A>Compiling from Files</H2>\r
562 PForth can read read from ordinary text files so you can use any editor\r
563 that you wish to write your programs.\r
564 <H3>\r
565 Sample Program</H3>\r
566 Enter into your file, the following code.\r
567 <UL>\r
568 <PRE><TT>\ Sample Forth Code\r
569 \ Author: <I>your name</I></TT></PRE>\r
570 \r
571 <PRE><TT>: SQUARE ( n -- n*n , square number )\r
572 &nbsp;&nbsp;&nbsp; DUP *\r
573 ;</TT></PRE>\r
574 \r
575 <PRE><TT>: TEST.SQUARE ( -- )\r
576 &nbsp;&nbsp;&nbsp; CR ." 7 squared = "\r
577 &nbsp;&nbsp;&nbsp; 7 SQUARE . CR\r
578 ;</TT></PRE>\r
579 </UL>\r
580 Now save the file to disk.\r
581 \r
582 <P>The text following the <B>\</B> character is treated as a comment. This\r
583 would be a REM statement in BASIC or a /*---*/ in 'C'. The text in parentheses\r
584 is also a comment.\r
585 <H3>\r
586 Using INCLUDE</H3>\r
587 "INCLUDE" in Forth means to compile from a file.\r
588 \r
589 <P>You can compile this file using the INCLUDE command. If you saved your\r
590 file as WORK:SAMPLE, then compile it by entering:\r
591 <UL>\r
592 <PRE><TT>INCLUDE SAMPLE.FTH</TT></PRE>\r
593 </UL>\r
594 Forth will compile your file and tell you how many bytes it has added to\r
595 the dictionary. To test your word, enter:\r
596 <UL>\r
597 <PRE><TT>TEST.SQUARE</TT></PRE>\r
598 </UL>\r
599 Your two words, SQUARE and TEST.SQUARE are now in the Forth dictionary.\r
600 We can now do something that is very unusual in a programming language.\r
601 We can "uncompile" the code by telling Forth to <B>FORGET</B> it. Enter:\r
602 <UL>\r
603 <PRE><TT>FORGET SQUARE</TT></PRE>\r
604 </UL>\r
605 This removes SQUARE and everything that follows it, ie. TEST.SQUARE, from\r
606 the dictionary. If you now try to execute TEST.SQUARE it won't be found.\r
607 \r
608 <P>Now let's make some changes to our file and reload it. Go back into\r
609 the editor and make the following changes: (1) Change TEST.SQUARE to use\r
610 15 instead of 7 then (2) Add this line right before the definition of SQUARE:\r
611 <UL>\r
612 <PRE><TT>ANEW TASK-SAMPLE.FTH</TT></PRE>\r
613 </UL>\r
614 Now Save your changes and go back to the Forth window.\r
615 \r
616 <P>You're probably wondering what the line starting with <B>ANEW</B> was\r
617 for. ANEW is always used at the beginning of a file. It defines a special\r
618 marker word in the dictionary before the code. The word typically has "TASK-"\r
619 as a prefix followed by the name of the file. When you ReInclude a file,\r
620 ANEW will automatically FORGET the old code starting after the ANEW statement.\r
621 This allows you to Include a file over and over again without having to\r
622 manually FORGET the first word. If the code was not forgotten, the dictionary\r
623 would eventually fill up.\r
624 \r
625 <P>If you have a big project that needs lots of files, you can have a file\r
626 that will load all the files you need. Sometimes you need some code to\r
627 be loaded that may already be loaded. The word <B>INCLUDE?</B> will only\r
628 load code if it isn't already in the dictionary. In this next example,\r
629 I assume the file is on the volume WORK: and called SAMPLE. If not, please\r
630 substitute the actual name. Enter:\r
631 <UL>\r
632 <PRE><TT>FORGET TASK-SAMPLE.FTH\r
633 INCLUDE? SQUARE WORK:SAMPLE\r
634 INCLUDE? SQUARE WORK:SAMPLE</TT></PRE>\r
635 </UL>\r
636 Only the first INCLUDE? will result in the file being loaded.\r
637 <H2>\r
638 <A NAME="Variables"></A>Variables</H2>\r
639 Forth does not rely as heavily on the use of variables as other compiled\r
640 languages. This is because values normally reside on the stack. There are\r
641 situations, of course, where variables are required. To create a variable,\r
642 use the word <B>VARIABLE</B> as follows:\r
643 <UL>\r
644 <PRE><TT>VARIABLE MY-VAR</TT></PRE>\r
645 </UL>\r
646 This created a variable named MY-VAR . A space in memory is now reserved\r
647 to hold its 32-bit value. The word VARIABLE is what's known as a "defining\r
648 word" since it creates new words in the dictionary. Now enter:\r
649 <UL>\r
650 <PRE><TT>MY-VAR .</TT></PRE>\r
651 </UL>\r
652 The number you see is the address, or location, of the memory that was\r
653 reserved for MY-VAR. To store data into memory you use the word <B>!</B>\r
654 , pronounced "store". It looks like an exclamation point, but to a Forth\r
655 programmer it is the way to write 32-bit data to memory. To read the value\r
656 contained in memory at a given address, use the Forth word <B>@</B> , pronounced\r
657 "fetch". Try entering the following:\r
658 <UL>\r
659 <PRE><TT>513 MY-VAR !\r
660 MY-VAR @ .</TT></PRE>\r
661 </UL>\r
662 This sets the variable MY-VAR to 513 , then reads the value back and prints\r
663 it. The stack diagrams for these words follows:\r
664 \r
665 <P><B><TT>@ ( address -- value , FETCH value FROM address in memory )&nbsp;</TT></B>\r
666 \r
667 <P><B><TT>! ( value address -- , STORE value TO address in memory )</TT></B>\r
668 \r
669 <P><B><TT>VARIABLE ( &lt;name> -- , define a 4 byte memory storage location)</TT></B>\r
670 \r
671 <P>A handy word for checking the value of a variable is <B>? </B>, pronounced\r
672 "question". Try entering:\r
673 <UL>\r
674 <PRE><TT>MY-VAR ?</TT></PRE>\r
675 </UL>\r
676 If ? wasn't defined, we could define it as:\r
677 <UL>\r
678 <PRE><TT>: ? ( address -- , look at variable )\r
679 &nbsp;&nbsp;&nbsp; @ .\r
680 ;</TT></PRE>\r
681 </UL>\r
682 Imagine you are writing a game and you want to keep track of the highest\r
683 score. You could keep the highest score in a variable. When you reported\r
684 a new score, you could check it aginst the highest score. Try entering\r
685 this code in a file as described in the previous section:\r
686 <UL>\r
687 <PRE><TT>VARIABLE HIGH-SCORE</TT></PRE>\r
688 \r
689 <PRE><TT>: REPORT.SCORE ( score -- , print out score )\r
690 &nbsp;&nbsp;&nbsp; DUP CR ." Your Score = " . CR\r
691 &nbsp;&nbsp;&nbsp; HIGH-SCORE @ MAX ( calculate new high )\r
692 &nbsp;&nbsp;&nbsp; DUP ." Highest Score = " . CR\r
693 &nbsp;&nbsp;&nbsp; HIGH-SCORE ! ( update variable )\r
694 ;</TT></PRE>\r
695 </UL>\r
696 Save the file to disk, then compile this code using the INCLUDE word. Test\r
697 your word as follows:\r
698 <UL>\r
699 <PRE><TT>123 REPORT.SCORE\r
700 9845 REPORT.SCORE\r
701 534 REPORT.SCORE</TT></PRE>\r
702 </UL>\r
703 The Forth words @ and ! work on 32-bit quantities. Some Forths are "16-bit"\r
704 Forths. They fetch and store 16-bit quantities. Forth has some words that\r
705 will work on 8 and 16-bit values. C@ and C! work characters which are usually\r
706 for 8-bit bytes. The 'C' stands for "Character" since ASCII characters\r
707 are 8-bit numbers. Use W@ and W! for 16-bit "Words."\r
708 \r
709 <P>Another useful word is <B>+!</B> , pronounced "plus store." It adds\r
710 a value to a 32-bit value in memory. Try:\r
711 <UL>\r
712 <PRE><TT>20 MY-VAR !\r
713 5 MY-VAR +!\r
714 MY-VAR @ .</TT></PRE>\r
715 </UL>\r
716 Forth also provides some other words that are similar to VARIABLE. Look\r
717 in the glossary for VALUE and ARRAY. Also look at the section on "<A HREF="pf_ref.htm#Local Variables { foo --}?">local\r
718 variables</A>" which are variables which only exist on the stack while\r
719 a Forth word is executing.\r
720 \r
721 <P><I>A word of warning about fetching and storing to memory</I>: You have\r
722 now learned enough about Forth to be dangerous. The operation of a computer\r
723 is based on having the right numbers in the right place in memory. You\r
724 now know how to write new numbers to any place in memory. Since an address\r
725 is just a number, you could, but shouldn't, enter:\r
726 <UL>\r
727 <PRE><TT>73 253000 ! ( Do NOT do this. )</TT></PRE>\r
728 </UL>\r
729 The 253000 would be treated as an address and you would set that memory\r
730 location to 73. I have no idea what will happen after that, maybe nothing.\r
731 This would be like firing a rifle through the walls of your apartment building.\r
732 You don't know who or what you are going to hit. Since you share memory\r
733 with other programs including the operating system, you could easily cause\r
734 the computer to behave strangely, even crash. Don't let this bother you\r
735 too much, however. Crashing a computer, unlike crashing a car, does not\r
736 hurt the computer. You just have to reboot. The worst that could happen\r
737 is that if you crash while the computer is writing to a disk, you could\r
738 lose a file. That's why we make backups. This same potential problem exists\r
739 in any powerful language, not just Forth. This might be less likely in\r
740 BASIC, however, because BASIC protects you from a lot of things, including\r
741 the danger of writing powerful programs.\r
742 \r
743 <P>Another way to get into trouble is to do what's called an "odd address\r
744 memory access." The 68000 processor arranges words and longwords, 16 and\r
745 32 bit numbers, on even addresses. If you do a <B>@</B> or <B>!</B> , or\r
746 <B>W@</B> or <B>W!</B> , to an odd address, the 68000 processor will take\r
747 exception to this and try to abort.\r
748 \r
749 <P>Forth gives you some protection from this by trapping this exception\r
750 and returning you to the OK prompt. If you really need to access data on\r
751 an odd address, check out the words <B>ODD@</B> and <B>ODD!</B> in the\r
752 glossary. <B>C@</B> and <B>C!</B> work fine on both odd and even addresses.\r
753 <H2>\r
754 <A NAME="Constants"></A>Constants</H2>\r
755 If you have a number that is appearing often in your program, we recommend\r
756 that you define it as a "constant." Enter:\r
757 <UL>\r
758 <PRE><TT>128 CONSTANT MAX_CHARS\r
759 MAX_CHARS .</TT></PRE>\r
760 </UL>\r
761 We just defined a word called MAX_CHARS that returns the value on the stack\r
762 when it was defined. It cannot be changed unless you edit the program and\r
763 recompile. Using <B>CONSTANT</B> can improve the readability of your programs\r
764 and reduce some bugs. Imagine if you refer to the number 128 very often\r
765 in your program, say 8 times. Then you decide to change this number to\r
766 256. If you globally change 128 to 256 you might change something you didn't\r
767 intend to. If you change it by hand you might miss one, especially if your\r
768 program occupies more than one file. Using CONSTANT will make it easy to\r
769 change. The code that results is equally as fast and small as putting the\r
770 numbers in directly. I recommend defining a constant for almost any number.\r
771 <H2>\r
772 <A NAME="Logical Operators"></A>Logical Operators</H2>\r
773 These next two sections are concerned with decision making. This first\r
774 section deals with answering questions like "Is this value too large?"\r
775 or "Does the guess match the answer?". The answers to questions like these\r
776 are either TRUE or FALSE. Forth uses a 0 to represent <B>FALSE</B> and\r
777 a -1 to represent <B>TRUE</B>. TRUE and FALSE have been capitalized because\r
778 they have been defined as Forth constants. Try entering:\r
779 <UL>\r
780 <PRE><TT>23 71 = .\r
781 18 18 = .</TT></PRE>\r
782 </UL>\r
783 You will notice that the first line printed a 0, or FALSE, and the second\r
784 line a -1, or TRUE. The equal sign in Forth is used as a question, not\r
785 a statement. It asks whether the top two items on the stack are equal.\r
786 It does not set them equal. There are other questions that you can ask.\r
787 Enter:\r
788 <UL>\r
789 <PRE><TT>23 198 &lt; .\r
790 23 198 > .\r
791 254 15 > .</TT></PRE>\r
792 </UL>\r
793 In California, the drinking age for alcohol is 21. You could write a simple\r
794 word now to help bartenders. Enter:\r
795 <UL>\r
796 <PRE><TT>: DRINK? ( age -- flag , can this person drink? )\r
797 &nbsp;&nbsp;&nbsp; 20 >\r
798 ;</TT></PRE>\r
799 \r
800 <PRE><TT>20 DRINK? .\r
801 21 DRINK? .\r
802 43 DRINK? .</TT></PRE>\r
803 </UL>\r
804 The word FLAG in the stack diagram above refers to a logical value.\r
805 \r
806 <P>Forth provides special words for comparing a number to 0. They are <B>0=</B>\r
807 <B>0></B> and <B>0&lt;</B> . Using 0> is faster than calling 0 and > separately.\r
808 Enter:\r
809 <UL><TT>23 0> . ( print -1 )</TT>\r
810 <BR><TT>-23 0> . ( print 0 )</TT>\r
811 <BR><TT>23 0= . ( print 0 )</TT></UL>\r
812 For more complex decisions, you can use the <I>Boolean</I> operators <B>OR</B>\r
813 , <B>AND</B> , and <B>NOT</B> . OR returns a TRUE if either one or both\r
814 of the top two stack items are true.\r
815 <UL>\r
816 <PRE><TT>TRUE TRUE OR .\r
817 TRUE FALSE OR .\r
818 FALSE FALSE OR .</TT></PRE>\r
819 </UL>\r
820 AND only returns a TRUE if both of them are true.\r
821 <UL>\r
822 <PRE><TT>TRUE TRUE AND .\r
823 TRUE FALSE AND .</TT></PRE>\r
824 </UL>\r
825 NOT reverses the value of the flag on the stack. Enter:\r
826 <UL>\r
827 <PRE><TT>TRUE .\r
828 TRUE NOT .</TT></PRE>\r
829 </UL>\r
830 Logical operators can be combined.\r
831 <UL>\r
832 <PRE><TT>56 3 > 56 123 &lt; AND .\r
833 23 45 = 23 23 = OR .</TT></PRE>\r
834 </UL>\r
835 Here are stack diagrams for some of these words. See the glossary for a\r
836 more complete list.\r
837 \r
838 <P><B><TT>&lt; ( a b -- flag , flag is true if A is less than B )</TT></B>\r
839 \r
840 <P><B><TT>> ( a b -- flag , flag is true if A is greater than B )</TT></B>\r
841 \r
842 <P><B><TT>= ( a b -- flag , flag is true if A is equal to B )</TT></B>\r
843 \r
844 <P><B><TT>0= ( a -- flag , true if a equals zero )</TT></B>\r
845 \r
846 <P><B><TT>OR ( a b -- a||b , perform logical OR of bits in A and B )</TT></B>\r
847 \r
848 <P><B><TT>AND ( a b -- a&amp;b , perform logical AND of bits in A and B\r
849 )</TT></B>\r
850 \r
851 <P><B><TT>NOT ( flag -- opposite-flag , true if false, false if true )</TT></B>\r
852 <H3>\r
853 <A NAME="Problems - Logical"></A>Problems:</H3>\r
854 1) Write a word called LOWERCASE? that returns TRUE if the number on top\r
855 of the stack is an ASCII lowercase character. An ASCII 'a' is 97 . An ASCII\r
856 'z' is 122 . Test using the characters " A ` a q z { ".\r
857 <UL>\r
858 <PRE><TT>CHAR A LOWERCASE? . ( should print 0 )\r
859 CHAR a LOWERCASE? . ( should print -1 )</TT></PRE>\r
860 </UL>\r
861 <A HREF="#Answers to Problems">Answers to the problems</A> can be found\r
862 at the end of this tutorial.\r
863 <H2>\r
864 <A NAME="Conditionals - IF ELSE THEN CASE"></A>Conditionals - IF ELSE THEN\r
865 CASE</H2>\r
866 You will now use the TRUE and FALSE flags you learned to generate in the\r
867 last section. The "flow of control" words accept flags from the stack,\r
868 and then possibly "branch" depending on the value. Enter the following\r
869 code.\r
870 <UL>\r
871 <PRE><TT>: .L ( flag -- , print logical value )\r
872 &nbsp;&nbsp;&nbsp; IF ." True value on stack!"\r
873 &nbsp;&nbsp;&nbsp; ELSE ." False value on stack!"\r
874 &nbsp;&nbsp;&nbsp; THEN\r
875 ;</TT></PRE>\r
876 \r
877 <PRE><TT>0 .L\r
878 FALSE .L\r
879 TRUE .L\r
880 23 7 &lt; .L</TT></PRE>\r
881 </UL>\r
882 You can see that when a TRUE was on the stack, the first part got executed.\r
883 If a FALSE was on the stack, then the first part was skipped, and the second\r
884 part was executed. One thing you will find interesting is that if you enter:\r
885 <UL>\r
886 <PRE><TT>23 .L</TT></PRE>\r
887 </UL>\r
888 the value on the stack will be treated as true. The flow of control words\r
889 consider any value that does not equal zero to be TRUE.\r
890 \r
891 <P>The <B>ELSE</B> word is optional in the <B>IF...THEN</B> construct.\r
892 Try the following:\r
893 <UL>\r
894 <PRE><TT>: BIGBUCKS? ( ammount -- )\r
895 &nbsp;&nbsp;&nbsp; 1000 >\r
896 &nbsp;&nbsp;&nbsp; IF ." That's TOO expensive!"\r
897 &nbsp;&nbsp;&nbsp; THEN\r
898 ;</TT></PRE>\r
899 \r
900 <PRE><TT>531 BIGBUCKS?\r
901 1021 BIGBUCKS?</TT></PRE>\r
902 </UL>\r
903 Many Forths also support a <B>CASE</B> statement similar to switch() in\r
904 'C'. Enter:\r
905 <UL>\r
906 <PRE><TT>: TESTCASE ( N -- , respond appropriately )\r
907 &nbsp;&nbsp;&nbsp; CASE\r
908 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0 OF ." Just a zero!" ENDOF\r
909 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 OF ." All is ONE!" ENDOF\r
910 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2 OF WORDS ENDOF\r
911 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DUP . ." Invalid Input!"\r
912 &nbsp;&nbsp;&nbsp; ENDCASE CR\r
913 ;</TT></PRE>\r
914 \r
915 <PRE><TT>0 TESTCASE\r
916 1 TESTCASE\r
917 </TT>5 TESTCASE</PRE>\r
918 </UL>\r
919 See CASE in the glossary for more information.\r
920 <H3>\r
921 <A NAME="Problems - Conditionals"></A>Problems:</H3>\r
922 1) Write a word called DEDUCT that subtracts a value from a variable containing\r
923 your checking account balance. Assume the balance is in dollars. Print\r
924 the balance. Print a warning if the balance is negative.\r
925 <UL>\r
926 <PRE><TT>VARIABLE ACCOUNT</TT></PRE>\r
927 \r
928 <PRE><TT>: DEDUCT ( n -- , subtract N from balance )\r
929 &nbsp;&nbsp;&nbsp; ????????????????????????????????? ( you fill this in )\r
930 ;</TT></PRE>\r
931 \r
932 <PRE><TT>300 ACCOUNT ! ( initial funds )\r
933 40 DEDUCT ( prints 260 )\r
934 200 DEDUCT ( print 60 )\r
935 100 DEDUCT ( print -40 and give warning! )</TT></PRE>\r
936 </UL>\r
937 <A HREF="#Answers to Problems">Answers to the problems</A> can be found\r
938 at the end of this tutorial.\r
939 <H2>\r
940 <A NAME="Loops"></A>Loops</H2>\r
941 Another useful pair of words is <B>BEGIN...UNTIL</B> . These are used to\r
942 loop until a given condition is true. Try this:\r
943 <UL>\r
944 <PRE><TT>: COUNTDOWN&nbsp; ( N -- )\r
945 &nbsp;&nbsp;&nbsp; BEGIN\r
946 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DUP . CR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( print number on top of stack )\r
947 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1-&nbsp; DUP&nbsp; 0&lt;&nbsp;&nbsp;&nbsp; ( loop until we go negative )\r
948 &nbsp;&nbsp;&nbsp; UNTIL\r
949 ;</TT></PRE>\r
950 \r
951 <PRE><TT>16 COUNTDOWN</TT></PRE>\r
952 </UL>\r
953 This word will count down from N to zero.\r
954 \r
955 <P>If you know how many times you want a loop to execute, you can use the\r
956 <B>DO...LOOP</B> construct. Enter:\r
957 <UL>\r
958 <PRE><TT>: SPELL\r
959 &nbsp;&nbsp;&nbsp; ." ba"\r
960 &nbsp;&nbsp;&nbsp; 4 0 DO\r
961 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ." na"\r
962 &nbsp;&nbsp;&nbsp; LOOP\r
963 ;</TT></PRE>\r
964 </UL>\r
965 This will print "ba" followed by four occurrences of "na". The ending value\r
966 is placed on the stack before the beginning value. Be careful that you\r
967 don't pass the values in reverse. Forth will go "the long way around" which\r
968 could take awhile. The reason for this order is to make it easier to pass\r
969 the loop count into a word on the stack. Consider the following word for\r
970 doing character graphics. Enter:\r
971 <UL>\r
972 <PRE><TT>: PLOT# ( n -- )\r
973 &nbsp;&nbsp;&nbsp; 0 DO\r
974 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [CHAR] - EMIT\r
975 &nbsp;&nbsp;&nbsp; LOOP CR\r
976 ;</TT></PRE>\r
977 \r
978 <PRE><TT>CR 9 PLOT# 37 PLOT#</TT></PRE>\r
979 </UL>\r
980 If you want to access the loop counter you can use the word I . Here is\r
981 a simple word that dumps numbers and their associated ASCII characters.\r
982 <UL>\r
983 <PRE><TT>: .ASCII ( end start -- , dump characters )\r
984 &nbsp;&nbsp;&nbsp; DO\r
985 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CR I . I EMIT\r
986 &nbsp;&nbsp;&nbsp; LOOP CR\r
987 ;</TT></PRE>\r
988 \r
989 <PRE><TT>80 64 .ASCII</TT></PRE>\r
990 </UL>\r
991 If you want to leave a DO LOOP before it finishes, you can use the word\r
992 <B>LEAVE</B>. Enter:\r
993 <UL>\r
994 <PRE><TT>: TEST.LEAVE&nbsp; ( -- , show use of leave )\r
995 &nbsp;&nbsp;&nbsp; 100 0\r
996 &nbsp;&nbsp;&nbsp; DO\r
997 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; I . CR&nbsp; \ print loop index\r
998 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; I 20 >&nbsp; \ is I over 20\r
999 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IF\r
1000 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LEAVE\r
1001 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; THEN\r
1002 &nbsp;&nbsp;&nbsp; LOOP\r
1003 ;\r
1004 TEST.LEAVE&nbsp; \ will print 0 to 20</TT></PRE>\r
1005 </UL>\r
1006 Please consult the manual to learn about the following words <B>+LOOP</B>\r
1007 and <B>RETURN</B> . FIXME\r
1008 \r
1009 <P>Another useful looping construct is the <B>BEGIN WHILE REPEAT</B> loop.\r
1010 This allows you to make a test each time through the loop before you actually\r
1011 do something. The word WHILE will continue looping if the flag on the stack\r
1012 is True. Enter:\r
1013 <UL>\r
1014 <PRE><TT>: SUM.OF.N ( N -- SUM[N] , calculate sum of N integers )\r
1015 &nbsp;&nbsp;&nbsp; 0&nbsp; \ starting value of SUM\r
1016 &nbsp;&nbsp;&nbsp; BEGIN\r
1017 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OVER 0>&nbsp;&nbsp; \ Is N greater than zero?\r
1018 &nbsp;&nbsp;&nbsp; WHILE\r
1019 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OVER +&nbsp; \ add N to sum\r
1020 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SWAP 1- SWAP&nbsp; \ decrement N\r
1021 &nbsp;&nbsp;&nbsp; REPEAT\r
1022 &nbsp;&nbsp;&nbsp; SWAP DROP&nbsp; \ get rid on N\r
1023 ;</TT></PRE>\r
1024 \r
1025 <PRE><TT>4 SUM.OF.N&nbsp;&nbsp;&nbsp; \ prints 10&nbsp;&nbsp; ( 1+2+3+4 )</TT></PRE>\r
1026 </UL>\r
1027 \r
1028 <H3>\r
1029 <A NAME="Problems - Loops"></A>Problems:</H3>\r
1030 1) Rewrite SUM.OF.N using a DO LOOP.\r
1031 \r
1032 <P>2) Rewrite SUM.OF.N using BEGIN UNTIL.\r
1033 \r
1034 <P>3) For bonus points, write SUM.OF.N without using any looping or conditional\r
1035 construct!\r
1036 \r
1037 <P><A HREF="#Answers to Problems">Answers to the problems</A> can be found\r
1038 at the end of this tutorial.\r
1039 <H2>\r
1040 <A NAME="Text Input and Output"></A>Text Input and Output</H2>\r
1041 You learned earlier how to do single character I/O. This section concentrates\r
1042 on using strings of characters. You can embed a text string in your program\r
1043 using S". Note that you must follow the S" by one space. The text string\r
1044 is terminated by an ending " .Enter:\r
1045 <UL>\r
1046 <PRE>: TEST S" Hello world!" ;\r
1047 TEST .S</PRE>\r
1048 </UL>\r
1049 Note that TEST leaves two numbers on the stack. The first number is the\r
1050 address of the first character. The second number is the number of characters\r
1051 in the string. You can print the characters of the string as follows.\r
1052 <UL>\r
1053 <PRE>TEST DROP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \ get rid of number of characters\r
1054 DUP C@ EMIT&nbsp;&nbsp;&nbsp;&nbsp; \ prints first character, 'H'\r
1055 CHAR+ DUP C@ EMIT&nbsp; \ prints second character, 'e'\r
1056 \ and so on</PRE>\r
1057 </UL>\r
1058 CHAR+ advances the address to the next character. You can print the entire\r
1059 string using TYPE.\r
1060 <UL>\r
1061 <PRE>TEST&nbsp; TYPE\r
1062 TEST&nbsp; 2/&nbsp; TYPE&nbsp;&nbsp; \ print half of string</PRE>\r
1063 </UL>\r
1064 It would be nice if we could simply use a single address to describe a\r
1065 string and not have to pass the number of characters around. 'C' does this\r
1066 by putting a zero at the end of the string to show when it ends. Forth\r
1067 has a different solution. A text string in Forth consists of a character\r
1068 count in the first byte, followed immediately by the characters themselves.\r
1069 This type of character string can be created using the Forth word C" ,\r
1070 pronounced 'c quote'. Enter:\r
1071 <UL>\r
1072 <PRE><TT>: T2 C" Greetings Fred" ;\r
1073 T2 .</TT></PRE>\r
1074 </UL>\r
1075 The number that was printed was the address of the start of the string.\r
1076 It should be a byte that contains the number of characters. Now enter:\r
1077 <UL>\r
1078 <PRE><TT>T2 C@ .</TT></PRE>\r
1079 </UL>\r
1080 You should see a 14 printed. Remember that C@ fetches one character/byte\r
1081 at the address on the stack. You can convert a counted Forth string to\r
1082 an address and count using COUNT.\r
1083 <UL>\r
1084 <PRE><TT>T2 COUNT .S\r
1085 TYPE</TT></PRE>\r
1086 </UL>\r
1087 The word <B>COUNT</B> extracts the number of characters and their starting\r
1088 address. COUNT will only work with strings of less than 256 characters,\r
1089 since 255 is the largest number that can be stored in the count byte. TYPE\r
1090 will, however, work with longer strings since the length is on the stack.\r
1091 Their stack diagrams follow:\r
1092 \r
1093 <P><B><TT>CHAR+ ( address -- address' , add the size of one character )</TT></B>\r
1094 \r
1095 <P><B><TT>COUNT ( $addr -- addr #bytes , extract string information )&nbsp;</TT></B>\r
1096 \r
1097 <P><B><TT>TYPE ( addr #bytes -- , output characters at addr )</TT></B>\r
1098 \r
1099 <P>The $addr is the address of a count byte. The dollar sign is often used\r
1100 to mark words that relate to strings.\r
1101 \r
1102 <P>You can easily input a string using the word <B>ACCEPT</B>. (You may\r
1103 want to put these upcoming examples in a file since they are very handy.)\r
1104 The word <B>ACCEPT </B>receives characters from the keyboard and places\r
1105 them at any specified address. <B>ACCEPT </B>takes input characters until\r
1106 a maximum is reached or an end of line character is entered. <B>ACCEPT\r
1107 </B>returns the number of characters entered. You can write a word for\r
1108 entering text. Enter:\r
1109 <UL>\r
1110 <PRE><TT>: INPUT$ ( -- $addr )\r
1111 &nbsp;&nbsp;&nbsp; PAD&nbsp; 1+ ( leave room for byte count )\r
1112 &nbsp;&nbsp;&nbsp; 127 ACCEPT ( recieve a maximum of 127 chars )\r
1113 &nbsp;&nbsp;&nbsp; PAD C! ( set byte count )\r
1114 &nbsp;&nbsp;&nbsp; PAD ( return address of string )\r
1115 ;</TT></PRE>\r
1116 \r
1117 <PRE><TT>INPUT$ COUNT TYPE</TT></PRE>\r
1118 </UL>\r
1119 Enter a string which should then be echoed. You could use this in a program\r
1120 that writes form letters.\r
1121 <UL>\r
1122 <PRE><TT>: FORM.LETTER ( -- )\r
1123 &nbsp;&nbsp;&nbsp; ." Enter customer's name." CR\r
1124 &nbsp;&nbsp;&nbsp; INPUT$\r
1125 &nbsp;&nbsp;&nbsp; CR ." Dear " DUP COUNT TYPE CR\r
1126 &nbsp;&nbsp;&nbsp; ." Your cup that says " COUNT TYPE\r
1127 &nbsp;&nbsp;&nbsp; ." is in the mail!" CR\r
1128 ;</TT></PRE>\r
1129 </UL>\r
1130 <B><TT>ACCEPT ( addr maxbytes -- numbytes , input text, save at address\r
1131 )&nbsp;</TT></B>\r
1132 \r
1133 <P>You can use your word INPUT$ to write a word that will read a number\r
1134 from the keyboard. Enter:\r
1135 <UL>\r
1136 <PRE><TT>: INPUT# ( -- N true | false )\r
1137 &nbsp;&nbsp;&nbsp; INPUT$ ( get string )\r
1138 &nbsp;&nbsp;&nbsp; NUMBER? ( convert to a string if valid )\r
1139 &nbsp;&nbsp;&nbsp; IF DROP TRUE ( get rid of high cell )\r
1140 &nbsp;&nbsp;&nbsp; ELSE FALSE\r
1141 &nbsp;&nbsp;&nbsp; THEN\r
1142 ;</TT></PRE>\r
1143 </UL>\r
1144 This word will return a single-precision number and a TRUE, or it will\r
1145 just return FALSE. The word <B>NUMBER?</B> returns a double precision number\r
1146 if the input string contains a valid number. Double precision numbers are\r
1147 64-bit so we DROP the top 32 bits to get a single-precision 32 bit number.\r
1148 <H2>\r
1149 <A NAME="Changing Numeric Base"></A>Changing Numeric Base</H2>\r
1150 Our numbering system is decimal, or "base 10." This means that a number\r
1151 like 527 is equal to (5*100 + 2*10 + 7*1). The use of 10 for the numeric\r
1152 base is a completely arbitrary decision. It no doubt has something to do\r
1153 with the fact that most people have 10 fingers (including thumbs). The\r
1154 Babylonians used base 60, which is where we got saddled with the concept\r
1155 of 60 minutes in an hour. Computer hardware uses base 2, or "binary". A\r
1156 computer number like 1101 is equal to (1*8 + 1*4 + 0*2 + 1*1). If you add\r
1157 these up, you get 8+4+1=13 . A 10 in binary is (1*2 + 0*1), or 2. Likewise\r
1158 10 in any base N is N .\r
1159 \r
1160 <P>Forth makes it very easy to explore different numeric bases because\r
1161 it can work in any base. Try entering the following:\r
1162 <UL>\r
1163 <PRE><TT>DECIMAL 6 BINARY .\r
1164 1 1 + .\r
1165 1101 DECIMAL .</TT></PRE>\r
1166 </UL>\r
1167 Another useful numeric base is <I>hexadecimal</I>. which is base 16. One\r
1168 problem with bases over 10 is that our normal numbering system only has\r
1169 digits 0 to 9. For hex numbers we use the letters A to F for the digits\r
1170 10 to 15. Thus the hex number 3E7 is equal to (3*256 + 14*16 + 7*1). Try\r
1171 entering:\r
1172 <UL>\r
1173 <PRE><TT>DECIMAL 12 HEX .&nbsp; \ print C\r
1174 DECIMAL 12 256 *&nbsp;&nbsp; 7 16 * +&nbsp; 10 + .S\r
1175 DUP BINARY .\r
1176 HEX .</TT></PRE>\r
1177 </UL>\r
1178 A variable called <B>BASE</B> is used to keep track of the current numeric\r
1179 base. The words HEX , <B>DECIMAL</B> , and <B>BINARY</B> work by changing\r
1180 this variable. You can change the base to anything you want. Try:\r
1181 <UL>\r
1182 <PRE><TT>7 BASE !\r
1183 6 1 + .\r
1184 BASE @ . \ surprise!</TT></PRE>\r
1185 </UL>\r
1186 You are now in base 7 . When you fetched and printed the value of BASE,\r
1187 it said 10 because 7, in base 7, is 10.\r
1188 \r
1189 <P>PForth defines a word called .HEX that prints a number as hexadecimal\r
1190 regardless of the current base.\r
1191 <UL>\r
1192 <PRE>DECIMAL 14 .HEX</PRE>\r
1193 </UL>\r
1194 You could define a word like .HEX for any base. What is needed is a way\r
1195 to temporarily set the base while a number is printed, then restore it\r
1196 when we are through. Try the following word:\r
1197 <UL>\r
1198 <PRE><TT>: .BIN ( N -- , print N in Binary )\r
1199 &nbsp;&nbsp;&nbsp; BASE @ ( save current base )\r
1200 &nbsp;&nbsp;&nbsp; 2 BASE ! ( set to binary )\r
1201 &nbsp;&nbsp;&nbsp; SWAP . ( print number )\r
1202 &nbsp;&nbsp;&nbsp; BASE ! ( restore base )\r
1203 ;</TT></PRE>\r
1204 \r
1205 <PRE><TT>DECIMAL\r
1206 22 .BIN\r
1207 22 .</TT></PRE>\r
1208 </UL>\r
1209 \r
1210 <H2>\r
1211 <A NAME="Answers to Problems"></A>Answers to Problems</H2>\r
1212 If your answer doesn't exactly match these but it works, don't fret. In\r
1213 Forth, there are usually many ways to the same thing.\r
1214 <H3>\r
1215 <A HREF="#Problems - Stack">Stack Manipulations</A></H3>\r
1216 \r
1217 <UL>\r
1218 <PRE><TT>1) SWAP DUP\r
1219 2) ROT DROP\r
1220 3) ROT DUP 3 PICK\r
1221 4) SWAP OVER 3 PICK\r
1222 5) -ROT 2DUP</TT></PRE>\r
1223 </UL>\r
1224 \r
1225 <H3>\r
1226 <A HREF="#Problems - Square">Arithmetic</A></H3>\r
1227 \r
1228 <UL>\r
1229 <PRE>(12 * (20 - 17)) ==> <TT>20 17 - 12 *\r
1230 </TT>(1 - (4 * (-18) / 6)) ==> <TT>1 4 -18 * 6 / -\r
1231 </TT>(6 * 13) - (4 * 2 * 7) ==> <TT>6 13 * 4 2 * 7 * -</TT></PRE>\r
1232 \r
1233 <PRE><TT>: SQUARE ( N -- N*N )&nbsp;\r
1234 &nbsp;&nbsp;&nbsp; DUP *\r
1235 ;</TT></PRE>\r
1236 \r
1237 <PRE><TT>: DIFF.SQUARES ( A B -- A*A-B*B )\r
1238 SWAP SQUARE&nbsp;\r
1239 SWAP SQUARE -&nbsp;\r
1240 ;</TT></PRE>\r
1241 \r
1242 <PRE><TT>: AVERAGE4 ( A B C D -- [A+B+C+D]/4 )\r
1243 &nbsp;&nbsp;&nbsp; + + + ( add'em up )\r
1244 &nbsp;&nbsp;&nbsp; -2 ashift ( divide by four the fast way, or 4 / )\r
1245 ;</TT></PRE>\r
1246 \r
1247 <DT>\r
1248 <TT>: HMS>SECONDS ( HOURS MINUTES SECONDS -- TOTAL-SECONDS )</TT></DT>\r
1249 \r
1250 <BR><TT>&nbsp;&nbsp;&nbsp; -ROT SWAP ( -- seconds minutes hours )</TT>\r
1251 <BR><TT>&nbsp;&nbsp;&nbsp; 60 * + ( -- seconds total-minutes )</TT>\r
1252 <BR><TT>&nbsp;&nbsp;&nbsp; 60 * + ( -- seconds )</TT>\r
1253 <BR><TT>;&nbsp;</TT></UL>\r
1254 \r
1255 <H3>\r
1256 <A HREF="#Problems - Logical">Logical Operators</A></H3>\r
1257 \r
1258 <UL>\r
1259 <PRE><TT>: LOWERCASE? ( CHAR -- FLAG , true if lowercase )\r
1260 &nbsp;&nbsp;&nbsp; DUP 123 &lt;\r
1261 &nbsp;&nbsp;&nbsp; SWAP 96 > AND\r
1262 ;</TT></PRE>\r
1263 </UL>\r
1264 \r
1265 <H3>\r
1266 <A HREF="#Problems - Conditionals">Conditionals</A></H3>\r
1267 \r
1268 <UL>\r
1269 <PRE><TT>: DEDUCT ( n -- , subtract from account )\r
1270 &nbsp;&nbsp;&nbsp; ACCOUNT @ ( -- n acc&nbsp;\r
1271 &nbsp;&nbsp;&nbsp; SWAP - DUP ACCOUNT ! ( -- acc' , update variable )\r
1272 &nbsp;&nbsp;&nbsp; ." Balance = $" DUP . CR ( -- acc' )\r
1273 &nbsp;&nbsp;&nbsp; 0&lt; ( are we broke? )\r
1274 &nbsp;&nbsp;&nbsp; IF ." Warning!! Your account is overdrawn!" CR\r
1275 &nbsp;&nbsp;&nbsp; THEN\r
1276 ;</TT></PRE>\r
1277 </UL>\r
1278 \r
1279 <H3>\r
1280 <TT><A HREF="#Problems - Loops">Loops</A></TT></H3>\r
1281 \r
1282 <UL>\r
1283 <PRE><TT>: SUM.OF.N.1 ( N -- SUM[N] )\r
1284 &nbsp;&nbsp;&nbsp; 0 SWAP \ starting value of SUM\r
1285 &nbsp;&nbsp;&nbsp; 1+ 0 \ set indices for DO LOOP\r
1286 &nbsp;&nbsp;&nbsp; ?DO \ safer than DO if N=0\r
1287 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; I +\r
1288 &nbsp;&nbsp;&nbsp; LOOP\r
1289 ;</TT></PRE>\r
1290 \r
1291 <PRE><TT>: SUM.OF.N.2 ( N -- SUM[N] )\r
1292 &nbsp;&nbsp;&nbsp; 0 \ starting value of SUM\r
1293 &nbsp;&nbsp;&nbsp; BEGIN ( -- N' SUM )\r
1294 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OVER +\r
1295 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SWAP 1- SWAP\r
1296 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OVER 0&lt;\r
1297 &nbsp;&nbsp;&nbsp; UNTIL\r
1298 &nbsp;&nbsp;&nbsp; SWAP DROP\r
1299 ;</TT></PRE>\r
1300 \r
1301 <PRE><TT>: SUM.OF.N.3 ( NUM -- SUM[N] , Gauss' method )\r
1302 &nbsp;&nbsp;&nbsp; DUP 1+&nbsp;&nbsp; \ SUM(N) = N*(N+1)/2\r
1303 &nbsp;&nbsp;&nbsp; * 2/\r
1304 ;</TT></PRE>\r
1305 </UL>\r
1306 Back to <A HREF="pforth.html">pForth Home Page</A>\r
1307 </BODY>\r
1308 </HTML>\r