home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 5 / DATAFILE_PDCD5.iso / utilities / f / forthmac / !Forthmacs / docs / ascii / tutorial < prev    next >
Encoding:
Text File  |  1997-05-01  |  29.7 KB  |  723 lines

  1.  
  2. Forth Tutorial
  3. **************
  4.  
  5.  
  6. This chapter is a brief tutorial about the Forth language.  It will get you 
  7. started with Forth, but you should probably buy a Forth book to learn more.  
  8.  
  9. If you already know how to program in Forth, you may skip this chapter.  You 
  10. may want to look at the chapter "Glossary Functional Index".  
  11.  
  12.  
  13. Forth is a complete programming language with some unique features.  In fact, 
  14. it is probably unlike any other language you have ever used.  Please don't let 
  15. it's "strangeness" cause you to immediately reject it --- once you get used to 
  16. it, you may find that you can use Forth to write working programs faster than 
  17. you ever dreamed possible.  
  18.  
  19. Forth is often described as an assembler, compiler, operating system, editor, 
  20. and command language all rolled into one.  In addition, most of the Forth 
  21. system is written in Forth.  
  22.  
  23. To find out more about your RISC OS Forthmacs system try 
  24.     words
  25.     see words
  26.     whatis words
  27. or others.  
  28.  
  29.  
  30. Getting Started
  31. ===============
  32.  
  33. If you sit down to a computer running Forth, you'll probably see the word ok 
  34. right before the cursor.  ok is the "prompt".  It means that Forth is ready 
  35. for you to type something.  Suppose you type 
  36.  
  37. 1 2 + .
  38.  
  39. Always type the cr, Return, lf, Linefeed, or whatever equivalent key your 
  40. terminal has, at the end of the line.  Forth will respond with 
  41.  
  42. 3
  43.  
  44. You have just added 1 and 2, and printed the result.  
  45.  
  46. I am going to assume at this point that you understand the concept of a stack.  
  47. Forth uses stacks heavily.  In fact, the consistent stack orientation is the 
  48. key to Forth's ability to pack a lot of capability in a small amount of 
  49. memory.  
  50.  
  51. Going back to our example, typing "1" caused the number 1 to be pushed onto 
  52. Forth's main stack, which is called the data stack.  Typing "2" caused the 
  53. number 2 to be pushed onto the same stack, on top of the 1.  The "+" caused 
  54. two numbers to be popped off the stack, in this case 1 and 2.  The numbers 
  55. were added together and the result was put back on the stack.  The "." caused 
  56. a number to be popped off the stack, in this case 3, and printed on the 
  57. terminal.  
  58.  
  59. If you have an HP calculator, no doubt this sounds very familiar to you.  An 
  60. important differences is that HP calculators have a stack that is 4 numbers 
  61. deep, whereas Forth's stack is much larger, typically more than 64 numbers.  
  62. In RISC OS Forthmacs this is ps-size divided by the cell size.  
  63.  
  64. Other arithmetic operators that Forth knows about are - (minus), * (times), 
  65. and / (divide), as well a some others that we'll worry about later.  The 
  66. arithmetic is performed as 32-bit integer arithmetic, although there are 
  67. operators which will cope with other kinds of numbers.  
  68.  
  69.  
  70. Defining your own words
  71. =======================
  72.  
  73. A Forth system understands a number of "words", each of which causes something 
  74. to happen, usually to the stack.  In our example, "+" and "." were both words.  
  75. You can define your own words in terms of words the system already knows.  
  76. Once defined, your words may be used just as though they they were system 
  77. words.  Another example: 
  78.  
  79. : addprint   + .   ;
  80.  
  81. Here, the ":", which is a system word, causes a new word to be defined, in 
  82. this case addprint.  The definition of addprint is (B + .  ), which means that 
  83. when you execute addprint, two numbers will be taken from the stack and the 
  84. sum printed.  The ;, another system word, terminates the definition.  If you 
  85. were to later type 
  86.  
  87. 23 45 addprint
  88.  
  89. Forth would respond with 
  90.  
  91. 68
  92.  
  93. A definition of this sort is called a "colon definition".  A distinguishing 
  94. characteristic is that the new word is defined in terms of other Forth words.  
  95. It is also possible to define a word in terms of the assembly language of the 
  96. machine you are actually running on.  This kind of definition is called a 
  97. "code definition", and is not used nearly as often as colon definitions.  
  98.  
  99. If you wished to later use addprint in the definition of another word, you 
  100. could do so just as though addprint were a system-supplied word.  
  101.  
  102. : addprint2 addprint addprint ;
  103. 1 2 3 4  addprint2
  104.  
  105. would result in 
  106.  
  107. 7 3
  108.  
  109. Note the order in which the numbers were added.  The reason is that, when 
  110. addprint2 is executed, 4 is on top of the stack, with 3 underneath it.  The 
  111. first addition will thus be 3+4.  
  112.  
  113. It is important to keep track of what is on the stack when you are writing 
  114. Forth programs.  An essential part of the documentation of a Forth word is a 
  115. stack diagram.  A stack diagram shows what the word expects to be on the stack 
  116. when it starts executing, and what it leaves on the stack after it is 
  117. finished.  The stack diagram for addprint would be 
  118.  
  119. ( n1 n2 -- sum )
  120.  
  121. showing that two numbers ( n1 and n2 ) are expected to be on the stack at the 
  122. start, and that addprint leaves one number on the stack ( sum ) when it is 
  123. finished.  The "--" shows where the word executes, or, in other words, it 
  124. separates the input parameters from the output parameters.  
  125.  
  126. Stack diagrams are enclosed in parentheses, because parentheses are used in 
  127. Forth to enclose comments.  The Forth system will ignore everything between 
  128. "(" and the next ")".  The space between "(" and "n1" is necessary.  The space 
  129. between "sum" and ")" is optional in most Forth's, but it is a good idea to 
  130. include it anyway.  
  131.  
  132. By convention, the rightmost number (n2) is the one that is on top of the 
  133. stack.  Thus ( a b c -- d e f ) would signify a word which expected c on top 
  134. of the stack, b under c, and a under b.  After execution, f would be on top, 
  135. with e under f, and d under e.  
  136.  
  137.  
  138. Variables, @, !
  139. ===============
  140.  
  141.  
  142. variable  john ( -- adr )
  143.  
  144. defines a variable called john and allocates one 32-bit machines word for it.  
  145. The stack diagram shows that when john is executed, an address will be left on 
  146. the stack.  The address is the address of the word that was allocated for 
  147. john.  Right now we don't know what value is contained in the variable, so 
  148. let's put something in it.  
  149.  
  150. 123 john !
  151.  
  152. will put the number 123 in the variable.  ! , pronounced 'store' , is the 
  153. store operator.  Its stack diagram looks like ( value adr -- ), meaning that 
  154. it expects an address on the top of the stack and a value underneath the 
  155. address.  The value will be put in the machine word at the indicated address, 
  156. and both arguments will be removed from the stack.  
  157.  
  158. Note in this example that the address was left by the word john.  It is an 
  159. important point that variables leave their addresses, rather than their 
  160. values.  If the value of a variable is needed, the @ (fetch) operator is used.  
  161.  
  162. john @
  163.  
  164. will leave the value contained in the variable, in this case 123, on the 
  165. stack.  The stack diagram for @ is ( adr -- value ).  
  166.  
  167. It is reasonable to ask why it works this way, rather than having a variable 
  168. return its value.  In fact, a scheme to do this was discussed in the Forth 
  169. community for awhile, and the final consensus was that the the consistency and 
  170. regularity of the @ and ! operators was too powerful to give up.  Forth is not 
  171. the only language to do it is this way.  BLISS is another language which 
  172. requires an explicit operator to return the value of a variable.  
  173.  
  174. Similar operators, c! and c@, are provided for storing and fetching bytes 
  175. instead of 32-bit quantities.  The stack only holds 32-bit quantities, so the 
  176. bytes are stored in the least-significant part of the 32-bit number on the 
  177. stack.  
  178.  
  179. w!  ( w adr -- )        stores the least-significant 16 bits of the number
  180.                         on the stack into the 16-bit memory location at addr
  181. w@  ( adr -- w )        fetches the 16-bit word at addr, leaving it on the
  182.                         stack.  The high-order bits of the stack item are
  183.                         zeroed.
  184. c!  ( byte adr -- )     stores the least-significant byte of the stack
  185.                         item into the 8-bit memory location at adr 
  186. c@  ( adr -- byte )     fetches the byte at addr
  187. +!  ( n adr -- )        adds n to the contents of the 32-bit word at addr
  188.  
  189.  
  190. Constants
  191. =========
  192.  
  193.  
  194. 32 constant buflen
  195.  
  196. defines a constant whose value is 32.  When buflen is executed, it leaves its 
  197. value, in contrast to a variable, which leaves its address.  There is no 
  198. explicit mechanism provided for changing the value of a constant.  Many Forth 
  199. systems may be tricked into telling you the address where the value of a 
  200. constant is actually stored, so it may be possible to change the value.  
  201. However, this is non-standard and implementation dependent.  Use a variable if 
  202. you want to change the value.  
  203.  
  204. buflen buflen + .
  205.  
  206. results in 
  207.  
  208. 64
  209.  
  210. buflen john @ + .
  211.  
  212. results in 
  213.  
  214. 155
  215.  
  216. assuming that john was defined and initialised as before to 123.  you should 
  217. make sure you understand why the @ is needed after john but not after buflen.  
  218.  
  219. The stack diagram for a constant is ( -- value ).  Remember that this is what 
  220. happens to the stack when the constant is executed, not when it is defined.  
  221.  
  222. More generally, the word constant need not be explicitly preceded by a number.  
  223. constant takes the initial value off of the stack.  The stack diagram is 
  224.  
  225. constant  \ name  ( initial_value -- )
  226.  
  227. "\ name" means that when the defining word constant executes, it takes a name 
  228. ( a sequence of non-blank characters ) out of the input stream and uses that 
  229. name for something.  In this case, the name is used as the name of the new 
  230. constant.  Notice that distinction between arguments that are taken from the 
  231. stack and names that are taken from the input stream ( the input stream is 
  232. what you type at the terminal ).  
  233.  
  234. Since typing a number puts that number on the stack, our example works fine.  
  235. It is also possible to use Forth to calculate the value of the constant, as in 
  236.  
  237. buflen 10 * constant bigbufsize
  238.  
  239. which defines a constant whose value is 10 times buflen, or 320.  This is 
  240. completely general; if you can get a number on the stack by any means 
  241. whatsoever, you can define a constant which returns that value.  
  242.  
  243.  
  244. Stack Manipulation
  245. ==================
  246.  
  247. The following words rearrange numbers on the stack.  
  248.  
  249. dup  ( n -- n n )   duplicates the number on top of the stack.  This is a
  250.                     real workhorse - dup is used a lot when you want to
  251.                     make a copy because you want to remember a number but
  252.                     the word you want to use next will "eat" it.
  253. drop  ( n -- )      discards the number on top of the stack.
  254. swap  ( n1 n2 -- n2 n1 )    exchanges the positions of the number on top
  255.                             of the stack and the number underneath it.  
  256.                             Suppose you had 3 4 on the stack and you
  257.                             wanted to compute 4-3.  You could do SWAP -
  258.                             and you would get what you wanted.
  259. over ( n1 n2 -- n1 n2 n1 )  copies the number which is directly
  260.                             underneath the top of the stack so that a copy
  261.                             of it on top.
  262. rot ( n1 n2 n3 -- n2 n3 n1 ) pulls the third stack element to the top
  263.                             and moves the two which were above it
  264.                             down to fill its vacancy.
  265. pick  (  np np-1 np-2 ... n0 p -- np np-1 np-2 np-2 ... n0 np )
  266.                       copies the p-th stack element to the top of the
  267.                       stack; 0 pick is equivalent to dup
  268.                              1 pick is equivalent to over
  269. roll  ( np np-1 np-2 ... n0 p -- np-1 np-2 ... n0 np )
  270.                       moves the p-th stack element to the top and moves
  271.                       the others down to fill the vacancy.  3 roll is
  272.                       equivalent to rot
  273. depth  ( -- n )       leaves the number of items that were on the stack
  274.                       before depth executed.  The number that depth leaves
  275.                       on the stack is not included in the count.
  276.  
  277.  
  278. Conditionals
  279. ============
  280.  
  281. Of course Forth lets you make tests and do different things based on the 
  282. results of those tests.  
  283.  
  284. Here are some words which are useful for comparisons.  
  285.  
  286. <     ( n1 n2 -- flag )   Flag is true if n1 < n2
  287. =     ( n1 n2 -- flag )   Flag is true if n1 = n2
  288. >     ( n1 n2 -- flag )   Flag is true if n1 > n2
  289. 0<    ( n1 -- flag )      Flag is true if n1 < 0
  290. 0=    ( n1 -- flag )      Flag is true if n1 = 0
  291. <>    ( n1 n2 --  flag )  Flag is true if n1 not equal to n2
  292. 0>    ( n1 -- flag )      Flag is true if n1 > 0
  293. u<    ( un1 un2 -- flag)  "<" for unsigned integers, such as addresses
  294. ?dup  (n-- [n] n )        duplicate the top of the stack only if it is not
  295.                           zero
  296.  
  297. The brackets mean that the number in brackets is present only if the number on 
  298. top of it is nonzero.  This convention is useful because some words leave a 
  299. flag on top of the stack to indicate whether or not a particular operation 
  300. succeeded.  If it did succeed, the flag is true and the word has left some 
  301. results on the stack underneath the flag.  If the operation failed, the flag 
  302. is false (zero) and the results were not put on the stack.  
  303.  
  304. The basic conditional in Forth is if .  It's stack diagram is ( n -- ), and it 
  305. is used like: 
  306.  
  307. if  stuff_to_do_if_n_was_not_0  else  stuff_to_do_if_n_was_0  then
  308.  
  309. The else part is optional.  The use of the English word "then" to terminate 
  310. the conditional is misleading, but that is the way it is.  
  311.  
  312. : absval  ( n -- absolute_value_of_n )  dup 0 < if 0 swap - then  ;
  313.  
  314. Let's analyze this definition carefully.  First of all, when this word 
  315. executes, it expects a number to be on top of the stack.  Call the number n.  
  316. The first thing that happens is that dup is executed, putting another copy of 
  317. n on top of the stack.  The stack now looks like ( n n ).  Next we have "0", 
  318. which puts a zero on top of the stack, so that stack looks like ( n n 0 ).  
  319. Then we execute "<", which compares to see whether or not n is less than 0.  
  320. The two numbers that "<" compares are removed from the stack and a flag is 
  321. left instead.  
  322.  
  323. Suppose that n was -5, so that n really was less than 0.  "<" would then leave 
  324. a -1 on top of the stack.  Any nonzero number is considered to mean true, 
  325. whereas zero means false. So the stack is ( n 1 ).  if takes the number off 
  326. the top of the stack, sees that it is -1, and proceeds to execute 0 SWAP - .  
  327. This has the effect of negating n.  The complete sequence of stack states is 
  328.  
  329. ( n )  dup  ( n n )  0  ( n n 0 )  <  ( n 1 )  if  ( n )
  330.  0  ( n 0 )  swap  ( 0 n )  -  ( -n )  then  ( -n )
  331.  
  332. The then terminates the conditional.  
  333.  
  334. If n had been positive, "<" would have left a zero, because 0 is not greater 
  335. than a positive number.  if would have taken the zero off of the stack and 
  336. then skipped the stuff between if and then. If there had been an else clause, 
  337. it would have been executed.  
  338.  
  339. Instead of DUP 0 < , we could have used DUP 0< .  
  340.  
  341. As a matter of fact there is an easier way to negate a number than 0 SWAP - .  
  342. You can just use negate ( n -- n ).  In fact, absval duplicates the function 
  343. provided by system-supplied Forth word abs ( n -- |n| ).  
  344.  
  345. if ...  else ...  then may be nested to any depth, provided of course that 
  346. there is a then for every if. if may only be used within colon definitions, 
  347. which means that you can't just type in if blah-blah-blah then unless you are 
  348. in the middle of defining some other word.  
  349.  
  350.  
  351. Loops
  352. =====
  353.  
  354. The basic looping construct is the do loop. The stack diagram is (end+1 start 
  355. -- ).  Examples are necessary.  
  356.  
  357. : printlots ( n9 n8 ... n1 n0 -- ) 10 0 do . loop ;
  358.  
  359. will print ten numbers from off of the stack.  The loop will start at 0 and 
  360. end after 9.  
  361.  
  362. You can get at the loop index by using I .  It leaves the loop index on the 
  363. stack (where else?).  
  364.  
  365. : sumit010 ( -- sum ) 0 11 1 do i + loop ;
  366.  
  367. will add up the numbers from 1 to 10 inclusive.  The "0" is there because the 
  368. current running sum is kept on the stack, and the sum needs to be initialised 
  369. to 0.  
  370.  
  371. loop limits don't have to be positive.  Try out various limits and see what 
  372. happens.  
  373.  
  374. : bigjumps ( -- n ) 0   1000 0 do i +  10  +loop ;
  375.  
  376. will sum the multiples of 10 less than 1000.  +loop increments the loop index 
  377. by a number that it takes from the stack, in this case 10.  You can run loops 
  378. backwards if you wish, by using +loop with a negative increment.  
  379.  
  380. You may prematurely exit from a do loop by executing leave within the loop.  
  381. You probably want to enclose the leave in an if ...  then structure, because 
  382. it doesn't make sense to construct a loop which always exits after the first 
  383. times through.  
  384.  
  385. More general loops may be constructed with 
  386.  
  387. begin ... until       or
  388. begin ... while ... repeat
  389.  
  390. In the case of begin ...  until, the stack is checked by until. If if is zero, 
  391. looping continues at begin. If it is one, execution continues after until. 
  392.  
  393. For begin ...  while ...  repeat, while checks the stack.  If it is 1, looping 
  394. proceeds, first executing the stuff between while and repeat, then starting 
  395. over at begin. If while found a zero on the stack, the stuff between while and 
  396. repeat is skipped and execution continues after "repeat".  
  397.  
  398. Well, campers, it's example time again.  This time we'll assume that there is 
  399. a table somewhere in memory.  This table consists of 8-word entries, and the 
  400. end of the table is flagged by a -1 in the first word of the last entry.  We 
  401. would like to scan through the table and add a number to the third word in 
  402. each entry.  This third word represents the age of an employee, so we'll call 
  403. it AGE .  Our operation will make everybody older.  Study this example 
  404. carefully.  It shows how Forth programs should be constructed with simple 
  405. words.  
  406.  
  407. : age  ( entry_adr -- age_adr )  \ converts entry adr to age adr
  408.    12 +
  409. ;
  410. : addin  ( n adr -- n adr )  \ adds n to the number at adr
  411.    over over                   \ copy both n and adr
  412.    age +!                      \ increase age by n
  413. ;
  414. : more?  ( adr -- adr flag )  \ flag is false iff adr points to a -1
  415.    dup @ -1 <>
  416. ;
  417. : +entry  ( adr1 -- adr2 )  \ advances to the next entry
  418.    32 +
  419. ;
  420. : older  ( n adr -- )  \ adds n to each age in table at adr
  421.    begin  more?  while  addin +entry  repeat  drop drop
  422. ;
  423.  
  424.  
  425. Supposing that there is a word EMPLOYEES which returns the address of such a 
  426. table, we could make a everybody 100 years older by typing 
  427.  
  428. 100 employees older
  429.  
  430. Notice that I was careful to define each word before I used it inside another 
  431. word.  This is a requirement with typical Forth systems.  There is no "forward 
  432. referencing", so everything must be defined before it is used.  This may seem 
  433. archaic, but in fact it is seldom ever missed.  The payoff is great, in terms 
  434. of reduced compiler complexity and conceptual simplicity.  There are Forth 
  435. "cross-compiler" and "meta-compiler" programs which allow forward references 
  436. to varying degree, but they are generally used to build entire Forth kernels 
  437. from scratch.  
  438.  
  439. Now suppose we want to print out multiples of 2 until the user types a key on 
  440. his keyboard, at which time we want to stop.  There is a word key? which 
  441. returns true if the user has typed something since the last time we checked, 0 
  442. otherwise.  
  443.  
  444. : mults-of-2  ( -- )  0  begin  dup . 2 +  key?  until  drop  ;
  445.  
  446. Of course, this could have been done as 
  447.  
  448. : mults-of-2  ( -- )  32766 0  do  i .  key?  if leave then  2 +loop  ;
  449.  
  450. but the real point here was to illustrate the begin ...  until .  
  451.  
  452. key?  ( -- flag )      input and output
  453.                        flag is true if a key has been typed.
  454. key  ( -- char )       key waits until the user types a character, then
  455.                        returns the character
  456. emit  ( char -- )      emit displays the char on the terminal
  457. space  ( -- )          displays a space character.
  458. cr  ( -- )             displays a carriage return, line feed
  459. spaces  ( n -- )       displays n spaces
  460. type  ( adr n -- )     displays n characters, beginning at adr
  461. ." string of characters to display"
  462.                        here you actually have to type the
  463.                        double-quote characters.  The string starts 
  464.                        after the space following the first quote, 
  465.                        and continues up to but not including the 
  466.                        last quote.
  467. expect  ( adr n -- )   accepts n characters from the terminal,
  468.                        storing them at addr.  If a carriage return is
  469.                        typed before n characters have been
  470.                        accumulated, expect fills out the rest of the
  471.                        n locations with nulls
  472. -trailing  ( adr nl -- adr n2 )
  473.                        reduces the character count n1 so that
  474.                        trailing blanks are omitted 
  475. count  ( adr -- adr+1 n )
  476.                        converts a packed string to an address and
  477.                        character count
  478.  
  479. A word about count is in order.  Forth stores strings as a length byte 
  480. followed by a number of characters.  The length byte contains the number of 
  481. characters in the string, not including the length byte.  count takes the 
  482. address of a packed string, which is the address of its length byte, and 
  483. returns the address of the actual characters in the string, which is 1 more 
  484. than the address of the length byte.  On top of that, it returns the value of 
  485. the length byte.  
  486.  
  487. Note that Forth addresses are byte addresses.  If you add 1 to a Forth 
  488. address, you get the next byte.  To get the next word, you have to add 2.  
  489.  
  490. Normally, when you are typing Forth words for it to execute, they are being 
  491. stored in a buffer called the "terminal input buffer".  To execute the next 
  492. word, it first has to be fetched from the terminal input buffer.  To do this, 
  493. a word called word is executed.  word takes the next word from the terminal 
  494. input buffer and stores it as a packed string, then returns the address of the 
  495. packed string.  The boundary between one word and the next is denoted by a 
  496. space character.  Actually, word accepts an argument which tells it what to 
  497. use as the separator character.  Normally, space is used, but if you want to 
  498. use word yourself, you are free to chose your own delimiter.  
  499.  
  500. word  \ word  ( delimiter_char -- adr )
  501.                 accepts the next word, or sequence of characters not
  502.                 including the delimiter_char, from the input stream.
  503.                 Stores it as a packed string and returns its address
  504.                 (the address of the length byte).
  505.  
  506.  
  507. Numeric I/O
  508. ===========
  509.  
  510. We have already seen how to use "." Also, we have seen that numbers may be put 
  511. on the stack simply by typing the number.  More options are available, such as 
  512. accepting or typing hexadecimal numbers.  
  513.  
  514. base  ( -- adr )     a variable which contains the value of the current
  515.                      numeric input and output base.
  516. hex  ( -- )          sets base to 16 ( default when running stand alone )
  517. decimal  ( -- )      sets base to 10 ( the default when running under unix )
  518. .  ( n -- )          displays n according to the current BASE
  519. u.  ( u -- )         displays u as an unsigned number
  520. .r  ( n r -- )       displays n right-justified in a field of width r
  521. u.r  ( u r -- )      like ".r", but unsigned
  522. ?  ( adr -- )        displays the contents of the memory location at address
  523.                      adr. Equivalent to "@ ."
  524. .s  ( -- )           displays the entire stack contents without removing
  525.                      anything from the stack
  526.  
  527.  
  528. Note that executing BASE @ . is useless as a way to find out what the current 
  529. value of base is.  You will always get 10 as the answer because whatever base 
  530. is, it will be typed as "10" according to its own base.  If you want to find 
  531. out what the base is according to the decimal numbering system, this will 
  532. work: 
  533.  
  534. : decbase  ( -- )  base @ dup decimal .  base !  ;
  535.  
  536. Can you figure out why this works? 
  537.  
  538.  
  539. Arrays
  540. ======
  541.  
  542. Forth doesn't have very many explicit data structures, but it provides good 
  543. primitives for efficiently creating whatever kind of data structures you want.  
  544. Let's build an array.  
  545.  
  546. We need to know a couple more words first.  
  547.  
  548. create  \ name ( -- adr )  defines a new word which will return its address
  549.                            when executed.  The name of the new word is taken
  550.                            from the input stream.
  551. allot  ( n -- )            allocates n bytes of storage for the most recently
  552.                            defined word.
  553.  
  554. create is the like variable, except that variable automatically allocates /N 
  555. bytes of storage.  variable xxx is like the CREATE xxx /cell allot).  Okay, 
  556. here we go.  
  557.  
  558. : arrayvar  \ name  ( size-in-words -- )
  559.    cells create allot
  560. ;
  561. : a@  ( index adr -- value )  swap cells + @  ;
  562. : a!  ( value index adr -- )  swap cells + !  ;
  563.  
  564. ARRAYVAR will allow us to create an array to hold size words.  a@ and a! will 
  565. allow us to fetch and store elements of an array we have created.  Let's make 
  566. an array and initialise it to all zeroes.  
  567.  
  568. 50 arrayvar ourarray
  569. : init  ( n adr -- )  swap   0 do  0 over i a!  loop  ;
  570. 50 ourarray init
  571.  
  572.  
  573. Now let's put a 5 in the 23rd element.  
  574.  
  575. \d 5 23 ourarray a! 
  576.  
  577. Is it there? 
  578.  
  579. 23 ourarray a@  .
  580.  
  581. Of course it is.  Would I lie to you? Data structures in Forth can be as 
  582. sophisticated as you can imagine.  It's up to you; the primitives are all 
  583. present.  
  584.  
  585.  
  586. Vocabularies
  587. ============
  588.  
  589. Note: This section is incomplete.  The stuff that is here is correct, but 
  590. there are some words that I don't list.  Read the "Vocabularies and Search 
  591. Order" chapter in the manual for more information.  
  592.  
  593. Forth words may be grouped together in sets called VOCABULARIES .  This is 
  594. somewhat analogous to directories in other operating systems, whereby files 
  595. are grouped together in different places.  
  596.  
  597. When Forth is looking for a word, it may search several vocabularies.  The 
  598. vocabulary where Forth looks first is called the "context" vocabulary, and 
  599. there is a system variable called context which keeps track of which 
  600. vocabulary is the "context".  All Forth systems have a vocabulary whose name 
  601. is forth. If the word that is sought is not found in "context", a list of 
  602. other vocabularies is searched.  
  603.  
  604. The "context" vocabulary specifies where to look for words.  It is also 
  605. necessary to know where to put the new words created by the user.  This 
  606. vocabulary is called the "current" vocabulary (also known as the "compilation 
  607. vocabulary), and again there is a system word current to keep track of which 
  608. vocabulary is selected as the "current" one.  
  609.  
  610. Typical vocabularies present in most systems include forth, and assembler. 
  611. Others may be present, and you can create your own if you wish.  After you 
  612. have created a vocabulary, you make make it the "context" vocabulary by typing 
  613. the vocabulary's name.  The only way to make a vocabulary "current" is to 
  614. first make it "context" (by typing its name).  Then you may use the word 
  615. "definitions" which sets the "current" vocabulary to be the same as the 
  616. "context" vocabulary.  
  617.  
  618. vocabulary  \ name ( -- )    creates a new vocabulary whose name is taken
  619.                              from the input stream.  Executing that
  620.                              name later will cause the new vocabulary
  621. definitions  ( -- )          makes the "CURRENT" vocabulary the same as
  622.                              "the "CONTEXT" one
  623. order  ( -- )                displays the list of vocabularies to be
  624.                              searched 
  625.  
  626.  
  627. So, if you want to make a new vocabulary named "myvoc", execute 
  628.  
  629. vocabulary myvoc
  630.  
  631. If you want your new vocabulary to be the one that is searched first (i.e.  
  632. the "context"), just type its name.  
  633.  
  634. myvoc
  635.  
  636. If you wished new word definitions to go into your new vocabulary (i.e.  make 
  637. it "current"), all you have to do is type 
  638.  
  639. definitions
  640.  
  641. assuming that you have already made "myvoc" the "context" by typing "myvoc".  
  642. If not, just execute 
  643.  
  644. myvoc definitions
  645.  
  646. It is possible to create vocabularies within vocabularies, but it is most of 
  647. the time you should create new vocabularies only within the "forth" 
  648. vocabulary.  To insure that this is the case, type 
  649.  
  650. forth definitions
  651.  
  652. before creating new vocabularies.  This way, you always know how to find your 
  653. vocabularies ( just type Forth then the vocabulary name).  
  654.  
  655.  
  656. Forgetting
  657. ==========
  658.  
  659. forget  \ name  ( -- )  forgets the named word from the dictionary.
  660.                         All words which have been defined after the
  661.                         named word are forgotten too.  This is necessary
  662.                         because the subsequent words may depend on the
  663.                         word you are forgetting.
  664. words  ( -- )           tells you what words the system knows
  665.  
  666.  
  667. Arithmetic Summary
  668. ==================
  669.  
  670. +  ( n1 n2 -- sum )           integer addition
  671. -  ( n1 n2 -- difference )    integer subtraction, n1-n2 
  672. 1+  ( n -- n+1 )              add 1.  This is provided as an alternative
  673.                               to "1 +" because it is such a frequent
  674.                               operation and should be optimized
  675. 1-  ( n -- n-1 )              subtract 1
  676. 2+  ( n -- n+2 )              add 2.
  677. 2-  ( n -- n-2 )              subtract 2
  678. *  ( n1 n2 -- product )       integer multiply
  679. 2*  ( n -- n*2 )              times 2.  Usually implemented by shifting
  680. /  ( n1 n2 -- quotient )      integer portion of quotient
  681. 2/  ( n -- n/2 )              halve.  Usually implemented by shifting
  682. mod  ( n1 n2 -- remainder )   integer remainder
  683. /mod  ( n1 n2 -- quotient remainder )
  684.                               quotient and remainder
  685. u*  ( un1 un2 -- ud )         like "*" but unsigned
  686. u/mod  ( u1 u2 -- uremainder uquotient )
  687.                               unsigned /mod
  688.  
  689. max  ( n1 n2 -- max )         maximum
  690. min  ( n1 n2 -- min )         minimum
  691. abs  ( n -- |n| )             absolute value 
  692. negate  ( n -- -n )           arithmetic negation 
  693. and  ( n1 n2 -- and )         bitwise logical and
  694. or  ( n1 n2 -- or )           bitwise logical or
  695. xor  ( n1 n2 -- xor )         bitwise logical exclusive-or
  696. not  ( n1 -- complement )     bitwise logical complement
  697.  
  698.  
  699. Further Topics and books
  700. ========================
  701.  
  702. There is a lot more to Forth than I have described here.  However, this should 
  703. be sufficient to get you a long way.  For a complete introduction to the 
  704. complete Forth language, I recommend the following books: 
  705.  
  706. Mastering Forth
  707. Anita Anderson and Martin Tracy
  708. Mountain View Press,
  709. P.O. Box 4656,
  710. Mountain  View, CA 94040
  711.     
  712. Starting Forth
  713. Leo Brodie of Forth,Inc.
  714. Prentice-Hall,Inc.
  715. Englewood Cliffs, NJ 07632
  716.    
  717. Thinking Forth
  718. Leo Brodie
  719. Prentice-Hall,Inc.
  720.    
  721. Dr. Dobbs Toolbook of Forth, Parts I+II
  722.  
  723.