home *** CD-ROM | disk | FTP | other *** search
/ APDL Public Domain 1 / APDL_PD1A.iso / program / language / forthmacs / !Forthmacs / docs / ascii / tutorial < prev    next >
Encoding:
Text File  |  1994-07-29  |  30.1 KB  |  752 lines

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