TABLE OF CONTENTS INTRODUCTION -------------------------------------------------- 2 GETTING STARTED ----------------------------------------------- 4 USING THIS MANUAL --------------------------------------------- 5 USING EXTERNAL MEMORY ----------------------------------------- 6 AFTER THE CRASH ----------------------------------------------- 7 TOUR OF THE 68HC11 Max-FORTH MEMORY MAP ----------------------- 8 DOWNLOADING SOURCE CODE -------------------------------------- 13 A BEGINING FORTH TUTORIAL ------------------------------------ 14 APPENDICES --------------------------------------------------- 43 WORDS LIST FOR Max-FORTH V1.0 6/86 ---------------------- 44 GUIDES IN USING APPENDICES C AND D ---------------------- 47 Max-FORTH WORDS DEFINITION ------------------------------ 51 DEFINITIONS BY GROUP ----------------------------------- 282 Max-FORTH 68HC11 MEMORY MAP ---------------------------- 298 Max-FORTH 68HC11 MACHINE CODE ROUTINES ----------------- 308 Max-FORTH 68HC11 SELECTED OPERATING SYSTEM SEGMENTS ---- 311 ERROR MESSAGES ----------------------------------------- 316 A PRIMER FOR BEGINNERS --------------------------------- 319 ASCII TABLE -------------------------------------------- 327 SELECTED REFERENCES ------------------------------------ 328 LIMITED USE SOFTWARE LICENSE AGREEMENT ----------------- 329 1 INTRODUCTION Max-FORTH for the 68HC11 is a ROM based operating system and lan- guage. When combined with a 68HC11, whether in internal or exter- nal ROM, Max-FORTH creates a complete development enviroment. Max-FORTH programs can be written, tested and run under its con- trol. Although usual development configurations would include external RAM and mass storage (either on the 68HC11 system or on the host terminal), short programs can actually be developed on a 68HC11 system using Max-FORTH with no extra support (beyond XTAL cir- cuit, pull ups, power and serial I/O connections). Max-FORTH produces compact code that is suitable for ROMing or EEPROMing. Both "Headed" and "Target Compiled" code applications can be created. While the compiled programs may not execute as fast as well-written assembly language programs, they do compare favorably with the results from other compiled languages. They are usually more compact, more quickly written, and more easily tested in Max-FORTH's interactive programming environment. Max-FORTH closely follows the FORTH-83 Standard in order to be compatible with other FORTH's, also, to be easily supported, learned and used. In addition to the FORTH-83 Required Word Set, Max-FORTH also contains all the FORTH-83 Extension Word Sets, all the Controlled Reference Words and some of the Uncontrolled Reference Words. It also has many single chip specific exten- sions and operating system words not found in the standard. Max-FORTH is available in several versions: Version 1.0 is supplied in an external ROM for use on systems such as Motorola's EVB system or the New Micros, Inc. NMIX-0021 and NMIX-0022 single board computers. This version does not have an autostart capability. It is otherwise "full featured". Version 2.0 is also supplied in external ROM for use on the same type systems. This version will autostart a user program at any 1K boundry, or in the EEPROM. This version is suitable for volume production use under a license agreement. The license agreement requirements to acquire the Version 2.0 ROM's are, therefore, stricter than for Version 1.0. Version 2.0 is essen- tially identical to Version 3.0 which is supplied in the NMI F68HC11 MCU. Version 3.0 is supplied in the internal ROM of the NMI F68HC11 MCU. These chips are manufactured by Motorola for sale by New Micros, Inc. These chips will autostart a user program at any 1K boundry, or in the EEPROM and are suitable for volume produc- tion use under license agreement. Version 4.0, not yet released, will allow the user to target com- pile up to 5K bytes of program on a 3K byte Max-FORTH kernel, which may be submitted to Motorola for production as an internal single chip ROM code in the MC68HC11A8, under license agreement for the kernel with New Micros, Inc.. 2 This manual is suitable for use with Versions 1.0, 2.0 and 3.0. 3 GETTING STARTED In order to run the 68HC11 version of Max-FORTH, a working 68HC11 based hardware system is required. With Versions 1.0 and 2.0, this system can be a Motorola EVB, a New Micros, Inc. NMIX-0021/22/23 or similar single board level computer system. The Max-FORTH ROM needs to be installed in the $E000 - $FFFF portion of the memory map. The MODA and MODB pins on the 68HC11 need to be strapped high (i.e.: to VDD, usually through pullups) to put the chip in the expanded multi- plexed mode. The internal ROM, if any, must be disabled (EEPROM bit 1 of the CONFIG Register = 0), which may need to be accomplished on a Motorola EVM if not so set by the factory. With Version 3.0, this system can be a Motorola EVB or New Micros, Inc. NMIX-0021 or similar single board level computer system. The Max-FORTH is resident in the NMI 68HC11 MCU, which must be installed as the microprocessor of the board. Internally, the ROM occupies the $E000 - $FFFF portion of the memory map. The MODA and MODB pins on the 68HC11 can be: both strapped high (i.e.: to VDD) to put the chip in the expanded multiplexed mode or MODA strapped low and MODB strapped high to put the chip in the single chip mode. The internal ROM, which contains the Max-FORTH code, must NOT be disabled (EEPROM bit 1 of the CONFIG Register = 1), which may need to be accomplished on a Motorola EVM if acci- dently changed from factory setting. When the Max-FORTH ROM is properly installed in the memory map of the 68HC11, a reset will cause the FORTH system to take control. If there is no user program in external memory or the internal EEPROM, the outer interpreter of Max-FORTH will be entered. The start-up message "Max-FORTH Vx.x" will be sent out to the system serial com- munications interface at 9600 baud (that assumes an 8 MHz XTAL, 2 MHz internal operation) with 1 start, 8 data, and 1 stop bit. The system is now ready for input on the serial communications inter- face. At this point, entering WORDS followed by a carriage return will display all the words in the language in tabular form. (It is psychologically very reassuring, for some reason, to type in a few letters and watch the computer respond with pages of information. The long listing of words can be interrupted by pressing the any key... ) At this point, the entire language is running out of the internal 256 bytes of 68HC11 RAM. Because of this limited amount of RAM available, the amount of room for the Terminal Input Buffer and the dictionary is small. The Terminal Input Buffer is set to 16 charac- ters. The dictionary has room for only a few short definitions. The Data Stack is limited to 39 entries and the Return Stack to 28 words. Any or all of these RAM based areas may be moved to external locations to allow expansion. After they have been arranged to satisfaction, programming can begin. 4 USING THIS MANUAL Read what ever you want to. You don't have to read it in order either. 5 USING EXTERNAL MEMORY The internal RAM and EEPROM of the 68HC11 is limited. Many ap- plications will require more RAM for program development. Using a Terminal Input Buffer longer than 16 characters is also desire- able. The following brief listing moves the internal pointers for TIB , and the dictionary to use external memory. The input line is also extended to 80 (decimal) characters. If the RAM is installed at 0100-1FFF (factory default for single 8K RAM in the NMIX-0023) the following will accomplish that. HEX 100 TIB ! 50 TIB 2+ ! 200 DP ! In the next example, the memory is located at $C000 (as in the case with the Motorola EVB, and as can be set on the NMIX-0023 boards as well). PAD is moved as well. Other addresses for RAM could be accomodated by changing the listed $Cxxx constants ac- cordingly. HEX C004 1C ! ( TIB MOVE ) 50 1E ! ( C/L CHANGE ) C060 22 ! ( PAD MOVE ) FORGET TASK C080 DP ! ( DICTIONARY MOVE ) Note that the first four locations at $C000 are left unassigned so that an autostart pattern can be placed there ($C000 is a 1K boundary) after the program is complete. If a Battery RAM were used in that socket, the program would be saved through power down. If autostarting is not done, the address of the main routine to be run can be EXECUTE'ed from the terminal, or it can be run by its name if the dictionary pointers are intact. To be able to use the Battery RAM words' heads, the USER area must be battery backed, otherwise, the dictionary pointers must be relinked. If the program is ROM'ed later, it should allow for the locations $C004 through $C080 to become "unwritable". Ofcourse applications that will have one RAM for variables and one RAM that will be later ROM'ed will probably assigned TIB to the low RAM with other variables (see Preparing a Program for ROM) and the Dictionary Pointer to the high RAM. The USER area can also be moved to give more room in the data stack, although, it is not normally necessary to do so. 6 AFTER THE CRASH You may occasionally experience a system crash, from which it is difficult to recover. A simple reset may give you a Max-FORTH Vx.x prompt and a carriage return may even give you an "OK", however, Max-FORTH doesn't seem to understand anything typed in that's over 1 character long. (A no Max-FORTH prompt condition probably means an autostart problem or hardware failure.) This is usually the result of a blown dictionary link. If the linked list of the dictionary is opened (ie: one of the link fields is erased, written over, badly manipulated, etc.), Max- FORTH will accept your input and then go on a wild goose chase looking for a match with your word all over memory until it finds a $0000 in a link field which indicates "end of dictionary" (which, coincidentally, may never be found). It will either lock up or echo the entry with a question mark. This can be simulated by doing: 0 LATEST PFAPTR LFA ! . You might want to wait a minute before you try this, however, until you know how to recover ... Another problem can be experienced when the dictionary pointer gets out of RAM if, for instance, you did a HEX E000 DP ! (which puts the dictionary pointer in ROM). The problem is that the outer interpreter takes your input line in TIB and parses a word at a time out of it. It moves the parsed word to HERE which is an exceptionally bad idea if DP is in ROM. ROM is funny that way, no matter what you write to it, it never takes it. When the dictionary search compares the dictionary list with the word at HERE , the result has nothing to do with the characters (and num- ber of them) of word you typed in. It prints junk and a question mark. A similar thing can happen if a word is moved to EEPROM with EEWORD and then forgotten. Guess where DP ends up? Putting a bad value in UP can be interesting. Changing UEMIT or UKEY to some erroneous values can have some extremely quiet results, too. If any of the above conditions occur, the only way to recover is to power down and re-power or to force a cold reset. A -G key combination in the Serial Communications Interface input register will force a cold reset. (-G is the ASCII "BELL" character, $07 hex.) By entering the -G and hitting reset again, one should recover from any badly modified variable, blown dictionary links, crashed processor, etc. problems. A bad autostart, however, can only be rectified by disabling the offending memory device. If the autostart pattern is in the part's EEPROM, it may be erased using a Motorola EVM for recovery. 7 TOUR OF THE 68HC11 Max-FORTH MEMORY MAP A first step in preparing to use a dedicated computer system is to learn the system's memory map. This is an easy task with the use of the Max-FORTH DUMP command. Remember that DUMP displays one or more lines each containing 16 memory locations (8 words) which are most easily read when in hex mode, so begin by entering HEX . Starting in low memory, examine the contents of the first three words (six memory locations --- one byte or two hex digits per location which means two locations per word) by entering 0 6 DUMP . (This displays a full dump-line of 16 memory locations --- 8 words, $0000-$000F. Leading zeros at each location are not displayed.) Examine the first three words ($0000-$0006), ignor- ing the others for the moment. From the manual's Appendix ???, it is seen that these locations contain the system variables of Max-FORTH, namely: W (Word Pointer, $0000-$0001) IP (Instruction Pointer, $0002-$0003); and UP (User Pointer, $0004-$0005). Any two bytes of memory reserved to hold only the address of a particular item (word, block, stack, etc.) is refered to as a pointer. Thus, W and IP are pointers whose contents change every time FORTH executes a new definition. Programmers rarely have need to use W or IP . Advanced programmers might use them in code level definitions when making multitaskers, etc.. UP points to the USER area. By modifying UP to point to another area, the values that user variables return will be a different set. This again is useful in multitaskers. Be sure that the new USER area is initialized with its set of values before changing UP to point to it, otherwise, the systems will crash and be dif- ficult to recover. It is worth mentioning that if you ex- perience a system crash from which it is difficult to recover with a simple reset, a -G key combination in the Serial Communications Interface input register will force a cold reset. (-G is the ASCII "BELL" character, $07 hex.) By entering -G and hitting reset again, you should recover from any badly modified variable, blown dictionary links, crashed processor, or similar problems. A bad autostart, however, can only be rectified by removing or disa- bling the offending memory device. Notice that UP points to the current USER memory area starting at $0006. To examine this area, enter 6 74 DUMP . The first four words ($0006, $0008, $000A and $000C) are zero'ed by the cold 8 download. They represent DNLINK , UPLINK , PRIORITY and RPSAVE which are user variables reserved for multitasking. These vari- ables are not used by the Version 1.0 Max-FORTH implementation. The following two words ($000E and $0010) are the default stack values, R0 and S0, assigned by ABORT . They can be modified to point into RAM if larger stack areas are desired. They will not be put into effect until ABORT is executed. Normally, the stacks should stay in internal RAM. TIB , PAD and the dictionary areas can be moved to external RAM which will allow room for 28 Return Stack words and 39 Data Stack words. The next two word locations ($0012 and $0014), KEY-CB-PTR and EMIT-CB-PTR, point to control blocks that determine how the built-in I/O routines work. Alternate control blocks can be con- structed to handle alternate I/O devices without modifying the I/O routines. Each control blocks are six bytes long and con- tains the following: 1) a two-byte address of the I/O device status register to be read, 2) a one-byte mask with which the status value read will be AND'ed to screen out extraneous bits, 3) a one-byte mask with which the AND'ed result will be XOR'ed to obtain a non-zero result when the device is ready for trans- fer, and 4) a two-byte address of the I/O device data register. These pointers (KEY-CB-PTR and the EMIT-CB-PTR) are initialized to point to the beginning of the default Serial Communications Interface control blocks. The pointer can be modified to point to control blocks that handle LCD displays and keypad controllers or alternate serial chips, etc. to redirect system I/O. The next three word locations ($0016, $0018 and $001A) are the actual machine level vectors to the I/O subroutines that provide the functions mentioned above. If a control block solution is not sufficient, you may write your own machine code subroutine. Its address is installed in UKEY , UEMIT or U?TERMINAL as ap- propriate. Following is the pointer (at $001C) to the Terminal Input Buffer, TIB, and normally contains an address pointing to the RAM just beyond the bottom of the Return Stack. It is limited by UC/L ($001E) to 16 characters. TIB can be moved to external RAM and made larger by modifying these USER variables. The USER variable which indicates that a COLD reset has been per- formed is called CLD/WRM ($0020). As long as it contains a $A55A pattern and there is no -R in the SCI, the system will not do a cold download of system variables at every reset. PAD in most FORTH systems is a fixed distance above the diction- ary pointer, but in Max-FORTH that would be impossible with the limited internal RAM, so PAD is restricted to be at a "fixed" location, which can be "moved" by changing UPAD ($0022). Since 9 the user may work "above" PAD with temporary variables and the system works "below" PAD when doing output number conversions, ensure that PAD has free RAM on both sides of its new setting. BASE , the current number base, is kept in the next location ($0024) and performs as per most other FORTH's. The next location ($0026) is used in conjunction with the Timer Output Capture 5 in EEPROM programming words to time the number of cycles to program the EEPROM. It is called C/10MS for "Cycles Per 10 Milliseconds delay". You should decrease this value from the default decimal value of 20000 if your system has a clock slower than 2 Mhz. The line termination character can be changed from a carriage return to any other character by modification of the next loca- tion ($0028). Similarly, the backspace character can be changed from a backspace to a delete by modifying the following location ($002A). The Dictionary Pointer, DP , and the heads dictionary pointer fol- low ($002C and $002E). The location after them ($0030) is the EEPROM dictionary usage pointer that is added to when a word is moved into EEPROM with EEWORD . The flag that controls header- less code generation follows ($0032). Additional standard FORTH USER definitions follow ($0034 through $0070). Following are four USER variable locations ($0072, $0074, $0076 and $0078) which are reserved for mass storage re- quirements. Only the first location ($0072) has any reference in the internal code. It is used to set the base address of the RAMDSK mass storage simulator. To use RAMDSK, which is pointed to by the default setting of UR/W ($0056), set the first location to the base address of free RAM (ie: C400 72 ! ) and clear the buffers (which are at default locations $D7FC through $E000 ) (ie: EMPTY-BUFFERS ). The RAM screens can then be listed, loaded and saved, etc.. This ends the USER area while the default location of the diction- ary begins at $007A. When a cold reset occurs, TASK is moved to the beginning of the dictionary. New entries in the dictionary will build up from TASK ($0083 and up). The Data Stack is above the dictionary. It grows down as more entries are added ($00C7 and down). There aren't many locations between the dictionary and the stack, so some care should be exer- cised. Needless to say, running the stack into the dictionary or vice versa is a very bad idea. The dictionary can be moved after a cold reset simply by forget- ing task and storing the address of the new dictionary RAM in DP (ie: FORGET TASK HEX C004 DP ! ). The area immediately above the data stack ($00C8 down from $00CF) is used by the system numeric output routines. The usage builds down from just below PAD until the number of output characters for a given print or "dot word" is reached. (Note: only 8 digit 10 numbers are provided for in the default setting.) (The two lowest locations are used as "secret" storage places for the set- tings of BLK ($00C8) and >IN ($00CA) after an error message is generated so you can look up the location of the error on mass storage after the crash. Better get them before you print any numbers after a crash... ) The beginning of TIB and PAD are both at the same location ($00D0), the idea is to prevent PAD from being used in internal RAM if TIB is in use. Sixteen bytes are reserved for TIB ($00D0 through $00DF). The Return Stack occupies the upper end of internal RAM ($00E0 through $00FF). The next location of interest in the 68HC11 map is the first loca- tion that an autostart pattern can be located ($0400). Versions 2.0 and greater do autostart pattern searches in EEPROM and then on every 1K boundary starting there and on. Since reset puts the register block of the 68HC11 at $1000 in the "middle of things", the Max-FORTH V1.0 operating system moves them to $9000. The Max-FORTH V2.3 and 3.3 operating system move them to $B000. (Originally, it was intended to put them at $B000, but the EVB has a special write latch from $A000 to $BFFF that precluded proper functioning there. References to the register block at $B000 often shut off the serial channel on the EVB. Later versions of the EVB were changed to correct the oversight.) The write that moves the register block will still affect external memory when the move is performed, so, always watch out for location $103D which will have $09 or $0B stored into it with every reset. The registers are moved into $9000 to $903F for version V1.0 and $B000 for versions V2.3 and V3.3. See the later section on programming the I/O or the appropriate Motorola documentation for their description. To look at them enter 9000 40 DUMP or B000 40 DUMP. The EEPROM is the next natural occurrence in the memory map ($B600 through $B7FF). The first word location ($B600) may hold the autostart pattern. This location is the first high level autostart location checked after power up. If the first location is the autostart pattern, the next ($B602) is the address of the CFA (code field address) of the word to be autostarted. If inter- rupts are not used, the next 247 bytes of EEPROM are unassigned. If interrupts are to be used, the particular interrupt enable must have a machine code program at its EEPROM target location. Starting at location $B7BF and thereafter for each interrupt vec- tor in ROM, three bytes are reserved. They will normally contain a jump instruction to another portion of memory which performs the appropriate interrupt function. It can return to the inter- rupted program by doing an RTI at its completion. At the very end of EEPROM, a word location ($B7FE) is checked by the reset routine for an autostart pattern which means that there is a machine code instruction in the previous three bytes ($B7FB) to be executed at power up before the write-once-only registers are modified. If that autostart pattern is present, the system jumps to subroutine to the code address. It will normally con- 11 tain a jump instruction to another portion of memory which sets the OPTIONS and INIT registers as desired. It can reenter the start up procedures by doing an RTS at it completion. To look at the EEPROM enter B600 200 DUMP . (On the Motorola EVB the area from $C000 to $DFFF is RAM. This can be used for mass storage buffers and screens, or program space or for TIB and PAD etc.) The Max-FORTH ROM runs from $E000 through $FFFF and contains the heads of Max-FORTH, followed by non-runtime words, followed by the runtime kernel. The DUMP command can be used to explore any portion of the ROM. It will be noted that the heads are made up mostly of ASCII characters and pointers. The non runtime codes are mostly pointers. The runtime codes are a mix of pointers, machine code and miscellaneous tables, etc.. 12 DOWNLOADING SOURCE CODE Development with the Max-FORTH system will normally be done using a host computer. (One alternative would be to add sufficient RAM and use the internal RAMDSK. Another alternative would be hook- ing up mass storage to the system and writing a user mass storage handler that would replace RAMDSK in the USER variable UR/W. Either method requires you to live with the limited FORTH line editors available or to write your own.) Source code text can be edited on a host PC with a familiar editor. The code can be down loaded and tested a portion at a time using a communications package. This can be continued until the program is complete. PC's are usually graced with printer, etc., so all in all, using a PC as a host can save development time. Any editor that produces an ASCII text file (ie: non-document mode) should be suitable. Communications packages should be able to handle 9600 baud transfers (or you have to run the XTAL slower) and should have file send and capture capabilities. The file send program should have a wait-for-echo'ed-character setting and a wait-at-end-of-line-for-return-character. The character to be waited for at the end of line should be a LINE FEED, ASCII $0A ( -J ). In Microstuff's Crosstalk these settings are the CWait Echo and LWait CHaracter '^J' . With those settings, a smooth down load of a code file by the SEnd command should be possible. Be sure to watch the down load as it occurs to spot any error mes- sages returned from the Max-FORTH system. 13 A BEGINNING FORTH TUTORIAL What Makes FORTH Different ? Most high level languages are very similar in nature. Since there were some applications where one programming language was inefficient, another language was written based on a new set of routines. Until FORTH, there was very little "new under the sun". There are two basic types of high level languages: compilers and interpreters. Although most languages are usually available as only one or the other type, there is no other reason a version of any language could be written as either. A compiler is a program that translates source code from a predefined file into its machine equivalent. Actually the output of a compiler may be machine code or assembly language to be further assembled to machine code. If a program had errors or did not work as desired, the programmer must re-edit the source file and again run the compilation process. An interpreter is usually more interactive, meaning it responds to the user. There are usually two distinct modes associated with an interpreter - the entry mode and run mode. In the entry mode, the programmer edits and prepares the program for execu- tion. When the run mode is entered, each line is translated into machine code routines and is executed as encountered. There is usually no intermediate step of compilation to machine code. Each line is translated and executed as a single action. The ad- vantage of an interpreter is that it is very user friendly, which makes it easy to use. The disadvantage is that it runs very slowly when compared to a compiled program. Despite the fact of whether a language is an interpreter or com- piler, most languages work in quite the same way. Their struc- ture is nearly identical in philosophy to that of straight line assembly code. The language allows for a fixed set of functions in the language just as the machine has a fixed number of instruc- tion in its instruction set. To solve this problem, the program- mer must list a sequence of these functions to be performed. The solution is defined in terms of the functions available. FORTH is a truly unique language. Programming in FORTH is quite conceptually different from using other languages. Making a long list of functions to be performed is not the usual programming method. Instead, new functions are defined based on other previ- ously defined functions. In turn, higher level functions can be defined using the new definitions just added. The language it- self is expanded and modified. In this way, the programming lan- guage FORTH might be more accurately called a programmable programing language. It is difficult to classify FORTH based on previous guidelines. Neither "interpreter" nor "compiler" can accurately describe the nature of FORTH. While FORTH has elements of being an inter- preter, it can also be argued that it's a compiler. It is often described as an interactive compiler or compiling interpreter, 14 the later probably being most accurate. FORTH has an interactive interpreter which acts like a conventional interpreter in entry mode. New definitions (called "words") can be entered in the same manner as code would be entered into an interpreter. These words can be directly entered at the system terminal and run as commands or be used in new definitions. It is difficult, there- fore, to distinguish between the entry mode and the run mode. FORTH's unique structure allows for some of the best of both worlds. FORTH runs fast during execution. It is therefore com- parable to compiled languages. On the other hand, FORTH is very user friendly and resembles an interpretive language. Because of FORTH's unique structure of programmability it is easier and, thereby, quicker to program and test applications in, than either type of previous category of languages. This new concept in programming gives FORTH an unusually wide range of applications as compared with conventional languages. The FORTH instruction set is open ended. The intent is to give the programmer not just a set of function to use but also the tools to create new functions, in fact any functions desired, in- stead. FORTH was developed by an individual (Charles Moore) in the early 70's. He found himself in the position of having a whole com- puter to his use to do a real time task. He found that conven- tional languages restricted his access to the machine to the point that they were unusable. Using a different set of base premises, he created a new language over the course of several years that was tailored to the new system requirement. How Does One Uses FORTH ? Like other user friendly interpreters FORTH is easy to get started with. You sit down at the terminal of a FORTH computer and use it as a calculator or type in a string of commands. When FORTH is done interpreting what was on the line you typed in, it says "OK" and waits for another line. FORTH is a very format free language with a minimum of restric- tion. Classification of what things can be typed in the input stream is fairly simple. Inputs can only be two things. The first are commands called "words" that have predefined meanings (a few words require inputs following them, which are strings). The other possible items entered are numbers. So with this limitation of using only words and numbers, all of FORTH can be used. The most pressing requirement in successfully typing in commands to be interpreted by FORTH is the correct use of delimiters. Most other languages have so few commands that the allowed com- mands can easily be picked out of the input stream, even in a long and run-together line of typed characters. They also often use special rules and conventions for naming words (ie: variables). The requirement that names begin with an alpha character and contain only alpha-numerics is almost a universal requirement for other high level languages. Some languages re- 15 quire even more difficult conventions, such as variables be in capital letters and constants in lower case, or special charac- ters, like "$" to indicate a string variable, etc.. FORTH re- quires each word or number entered to be separated from others around it by delimiting characters. At least one delimiting character must intervene between each unique entry and the next, but use of more than one is not prohibited. FORTH recognizes blanks as delimiting characters. (thisisratheraconvenientconventiontakenfromenglish.onemustwonder- whyotherlanguagesletallinputtoberuntogether.) By virtue of this unique, but very simple requirement, FORTH words can use any characters as part of their names. Only blanks, backspaces and null characters can not to be used in a words name. Extremely useful names can be given to words on this basis. The name of the subtraction function can be therefore be written as - and the operation that prints a title as ." and the operation that indicates the compiler should continue on the next screen of text as --> . Since FORTH allows you to define new words to those already in the language as you program, the same opportunities are yours. Very meaningful names can be assigned to newly defined functions. FORTH allows up to 31 characters to be used in naming words. Names such as CALCULATE-NET-PROFIT*%OF-RETURN are not only pos- sible, but add a great deal of meaning to the program to casual readers. Without forcing such liberal use of the keyboard, FORTH would equally as well deal with words named A, B or C. These simple rules suffice for all the syntax required by a FORTH system. Anything typed into FORTH to interpret must either be a word (a word may be followed by a string as required by its definition) or a number. Anything else will cause an error. Each item must be separated from another by at least one space. Names of words can be any character except a space, a backspace, a null character, and of course, a carriage return which is used to ter- minate (enter) a line typed into FORTH. How Much is There to FORTH ? As with any language, the most difficult part of using it is learning it. Unlike other computer languages such as BASIC, which has a few functions (or operators) and lots of syntax rules, there are many functions built into FORTH, and just a little syntax (which you just learned). These functions are the building blocks which you must use to solve your programming problem. With BASIC it is fairly easy to look at a list of valid commands, picking a few to start with, learn what are valid names for vari- ables, acquire a very basic understanding of syntax and how line numbers work, and then begin programming. The effective range of program solutions based on such a brief exposure is, to say the least, quite limited. The key how to do more in BASIC is by not only recognizing the command words and understanding their pur- pose, but also in understanding some very complex relational ef- fects and detailed syntactical rules. Learning the commands and their purpose is not extremely difficult because of their small 16 numbers (usually 15 to 40 depending on the level of implementa- tion or version). Learning a new syntactical set of rules for each command is difficult. For instance, the operator + (plus) in BASIC may be used to calculate the sum of two variables or terms in an equation giving a numerical result. This same operator may also be used to append one string of characters to another. Whether this operator has other uses and effects, using it to add a variable to a string can be quite another problem. The answer to these questions varies from BASIC to BASIC depend- ing on the attittudes of the programmer who implemented it. The more "powerful" the BASIC, the more "complex" the syntax. With the exception of the brief rules mentioned in the earlier section, FORTH is nearly syntax free. Inputs are words (and their strings) and numbers. There is no particular requirement that a word be on one line, or the next. Words are executed in their order of entry. Little else in the way of format is re- quired. So if syntax is not a great problem, what is necessary to learn FORTH? Although each word has a fairly distinct unique action, there are many words to learn, over 200 in most FORTH im- plementation. It is difficult to directly relate word count to language "power" but it is probably correct to say: the more "fully developed" the FORTH, the greater the number of words. Then the opposite of BASIC is true of FORTH, after a few basic principles are learned about the language you must learn more words rather than more syntax. This way, the learning of FORTH is much more akin to a language like French, a few basic words from the language must be known and a few rules learned about using them. This is enough to get by. More words must be under- stood to become fluent in the language. FORTH words can be likened to verbs. They represent the actions, the functions to be performed. Numbers and strings are similar to nouns. They usually indicate where the action of the words will be directed. There are, of course, words that you may never need to learn. The same is true of French. There are details of any language in which only scholars find interest. There are primitive words in FORTH which only those most curious about FORTH's structure bother to learn. Some areas of programming may be of no par- ticular applicability in another discipline. Output formatting may be of no use to a programmer doing real time process control. There would be no more use in a detailed study of formatting for him than would the French word for "polar bear" to someone who never speaks of animals. One of the largest differences between FORTH and conventional lan- guages is the handling of temporary data storage. Almost all con- temporary languages use variables. FORTH uses a data stack. Using the stack is simple and a major part of FORTH fundamentals. Unfortunately, many new students of FORTH, who have programmed in other high level languages before, decide that the stack hinders their efforts to ever successfully use FORTH. Beginning program- mers often adapt to stack based operations more quickly than ex- perienced programmers because they have not learned prejudices based on variable based languages. A brief look of the begin- nings of the two philosophies may be of benefit. 17 Many of the basic computing concepts came from the days of cal- culators. Most calculations are performed one step at a time. With standard four function calculators there are only two num- bers, the last result and the number now being entered. (More advanced calculators have a memory for temporary storage of results.) In this way, one result can be held while another is entered. Then the two can be operated on together. This is the point at which the two philosophies split. If more than one memory and one entry are to be maintained, there are two ways to handle it. Either each memory locations can be given names (i.e., 1, 2, 3, ... or A, B, C etc.) or the entire memory can be treated as a single sequential file. With the latter method, if two memory locations are in use and another is needed, the third location is automatically selected. If contents from two memory locations are to be taken, the contents of the third and then the second locations are retrieved. The second location is now available for use again. Both methods are widely used by calculator manufacturers today. The first method (widely used by Texas Instrument) is closest in format to the teaching of modern algebra. Unknown or temporary values are given names. By using mid-fix notation, calculations bear a strong resemblance to algebraic statements, i.e., to solve A = B + C the following entries would by made : B + C = . This result is displayed on the calculator (instead of being assigned to A). Assignments to B and C would already have been assigned values. The more complex equation A = (B + C) * (D + E) requires parenthesis to indicate the correct precedence of operation. The second method (extensively used by Hewlett-Packard) is more difficult to give examples for, since quantities go without names, but are ordered by time and level of entry. Although mid- fix operators and even prefix notation (called Reverse Polish Notation) are possible with this method, the most commonly used is post fix notation (sometimes called Reverse Polish Notation or RPN). To illustrate the first example given for the algebraic method, you will have to imagine that the results B and C are already in the first and second sequence memory locations. To add them only the entry of + is required, since + always adds the last two numbers entered, or "on the top of the stack". To il- lustrate the more complex example a method of entering numbers into memory locations is necessary. For the purpose of this ex- ample merely stating the number will enter it into the next avail- able memory location. Instead of using actual numbers, we will use substitute names. Remember these names are substitutes for the numbers, not the memory location that the numbers go in. En- tering B C + carriage return (ret for short) would put the number " B " in the first memory location. " C " would follow in the next. The + would add the top two numbers on the stack, " B " and " C " , and place the result in the now unused first location. Further entry of D E + ret 18 would store " D " in the open second location and " E " in the third with the " + " operator completing the addition. The result is stored in the once again vacant second location. Finally, entry of * would multiply the two temporary results together (again these are the top two on the stack) and leave the results in the first location. The total entry was B C + D E + * No parentheses were required because the stack of memory loca- tions itself provided for even the machines temporary results. This is the total complexity of the stack. If the previous ex- ample can be understood, FORTH stack operation can be under- stood. FORTH uses a data stack and RPN almost exclusively for all operations. Variables and constants are provided in FORTH for your use but are for storage of a more permanent nature. Tem- porary storage using the stack is much more efficient. By using post fixed notation (RPN) there is no ambiguity concerning priority of operations, without the use of cumbersome nested parenthesis. In summary, in learning FORTH you must first understand a little syntax, a little about stack operations and quite a few words. With over 200 words, there must be at least 2000 ways of grouping them into categories. In order to allow you to start learning FORTH quickly, the first group to be presented to you in this book will be the basic words. As they are mastered, later chap- ters will include more words until all have been presented. Beginning Words Almost all computer courses at one point or another list the major parts of a computer as being input, output, the central processor and memory. In previous discussion, the method of en- tering words and numbers in the input stream, separated by spaces, was explained. It is fitting, then, that the first word to be decribed is . (pronounced as "dot"). This word is an important FORTH word used to output a numerical value. When the dot word is executed by the interpreter, the last number entered or calculated will be output. Although the computer works only in binary, the number will be printed in the current number base. When your FORTH system is first turned on, the num- bering system will be base 10 or decimal. That means that the numbers will be accepted as inputs or printed as outputs like com- mon decimal numbers. Later you will learn how to change the base so input and output can be in other bases. It is possible to use binary, octal, hexadecimal and many other number based systems. Once the . is executed, the number that is printed is no longer in memory. It has been taken off the stack. To try an example of using . try the following. Enter 5 . ret 19 After the return is entered, FORTH begins interpreting the line looking for words and numbers. When the 5 is encountered, FORTH picks it out of the input buffer and puts it in a temporary loca- tion. There, it will be compared to all the names in FORTH's en- tire dictionary of names. When no match can be found for it, FORTH assumes it to be a number and tries to convert the current number base to binary. This is possible with the 5 entered. If the entry was not a valid entry, FORTH would give an error and wait for a new line of input. Once converted to binary, the 5 is placed on the top of the stack, the first available location in the temporary data file. No further action is required for num- bers. The interpreter continues to process the line. FORTH next picks up the . and searches the dictionary for a match. A match is found and the interpreter turns execution control over to the in- structions that make the . function. As described, this word finds the top value on the stack and converts that binary number into an output. The location on the stack is now free again for further use. The result of the example is as follows: 5 . 5 OK After the . returns control to the interpreter, the result of the carriage return will be processed. Since that indicates the end of the line of entry, FORTH puts up the message OK . The purpose of this message is to inform you that the previous com- mands have been completed successfully. FORTH is ready for another line of input. Now try a longer line of input. Enter the following: 5 . 6 . 7 . ret the interpreter will process this line by entering the 5 on the stack and then printing it. Then the 6 and printing it and finally the 7, likewise. The result looks like this: 5 . 6 . 7 . 5 6 7 OK Note that no more than one location is used on the stack. Each number is entered on the stack and immediately output before the next is added. Note also that no action is taken by the inter- preter until the ret is entered. Changing the order will change the action taken. To illustrate, try the following: 5 6 7 . . . ret The 5, 6 and 7 go on the stack in order. The 7 is on the top. When the first . is executed 7 is output since it is on top. The next . removes and prints the 6 . The last . prints the 5 and the stack is empty. If all three . had not been used, the numbers would have been left on the stack. For instance, 5 6 7 . ret 20 would show 5 6 7 . 7 OK As a result, a later entry of . ret would draw the 6 out of the stack and show . 6 OK The 5 will remain on the stack until used or an error clears the remaining numbers from the stack. Another word which would be useful to learn now is .S . This word not only outputs the value of the top number on the stack but all other numbers on the stack as well. Unlike . , it only copies the value on the stack which is not removed. This command is sometimes likened to a snapshot because a non-destructive print of the content of the stack is made. Entering .S ret will show .S 5 OK The 5 was left on the stack from the last example. Now enter a word that is not in the dictionary. If it is not a number, it will cause an error. QWERTY ret FORTH will respond with QWERTY QWERTY ? meaning that the word entered was neither a valid word nor num- ber. Now use the .S word. The stack was emptied when the error was encountered and the 5 typed earlier is now lost. The .S word is a very useful diagnostic tool. To try one more example with it, enter 5 6 .S ret and check the result: 5 6 .S 6 5 OK The 5 and 6 are still on the stack and can be further manipulated by other words or printed using . words. Now that you have learned how to input and output numbers, it is time to learn something to do with them. One of the nicer fea- tures of FORTH is the interactive way that computations can be done. In the last example, a 5 and a 6 were left on the stack. 21 We could cause the sum of those two numbers to be computed by en- tering the + word. The action taken by + when executed is to pick the top word from the stack and add it to the second number down. Like the . , when + word uses numbers from the stack, they are removed. The result of the addition after computation is put in temporary storage for further use. It is the new top number on the stack. The . word entered now will cause the result to be printed. The response should be like this: + . 11 OK To try another example, enter the following: 2 3 4 .S ret shows 2 3 4 .S 4 3 2 OK This action entered three numbers on the stack and then displayed them. These numbers are still on the stack since the .S does not remove them. It will take two + words to add the three numbers. + + . ret shows + + . 9 OK The execution of the first + adds the top number, 4, to the second number, 3, from the stack. Three numbers were on the stack. When the + returns its resulting value (7) to the stack there are two left. The second + causes the two values left on the stack (2 and 7) to be added and the result (9) returned to the stack. The result is the final remaining value, the only num- ber on the stack. It is, of course, the top number on the stack which the . caused to be printed. The stack is then empty. It is important to remember that FORTH can only recognize words if they are separated from other words and numbers by spaces (delimiters). If there are no spaces, FORTH will try to make a single word out of the entry. For instance, 5 6+ ret as an entry would give an error. FORTH look for a word named 6+ in the dictionary. When it cannot be found, FORTH will try to convert 6+ into a number which will also fail. The order in which numbers are entered on the stack makes no dif- ference in the result of an addition. This is because of commuta- tive property of addition. The operation of 6 2 + . will produce the same answer as 2 6 + . which is 8. The same is not true of all operations. The next word to be learned is logically, -. The word that al- lows subtraction operations to be performed. The commutative property does not apply to subtraction, therefore, 6 2 - . will give a result different from 2 6 - . . The function performed 22 by - is to subtract the top number on the stack from the second number on the stack. The process removes both numbers from the stack and returns the resulting value as the new top of stack. The result of 6 4 - . ret is 6 4 - . 2 OK written algebraically, the calculation would look like this: 6 - 4 = 2 An easy way to remember the order of operation is to visualize the two numbers to be operated on in relationship to the stack. Although they could have been computed or manipulated by earlier operation, imagine you just entered them by hand. Since we write left to right, imagine the stack contents displayed with the left side being the deepest or earliest entry and the right side the latest. To understand what the operator will do, imagine the two numbers (written as you would enter them) with the operator be- tween the two numbers. As an example, if the 6 is on the second number down (meaning it went on first, then became second) and the 4 is on the top of the stack, you should be able to envision the problem in algebraic format like this: 6 - 4 . This method of visualizing the numbers from the stack and the operator between them will help you to understand how - works as well as all other two number operators, all the math related words and relational operators that compare values. While multiplication is a function which is covered by the com- mutative law, division is not. The word to cause the the second number on the stack to be multiplied by the top number is * . The word / causes the second word on the stack to be divided by the top number on the stack. Just as with addition, there is no difference between the results of 2 3 * and 3 2 * . In algebraic notation, these two equations look like this 2 x 3 = 6 and 3 x 2 = 6 Again, to translate from RPN notation to algebraic, imagine the operator to be between the second and top value from the stack in that order. In the case of division, the order of the two numbers on the stack determines which number is the divisor and which is the dividend. There is indeed a difference in the result between 24 6 / and 6 24 / . The division word, / , will cause the top number to be divided into the second number on the stack. That is, the top number is the divisor. The two numbers are removed from the stack, the quotient is left on the top of the stack in their place. There will, of course, be occasions when numbers on the stack will be in the wrong order. For instance: in a lengthy calcula- tion, an intermediate value may already be on the stack. To find 23 the final value that result must be divided into 100 . Entering 100 / . will not give the correct answer. The value would be divided by 100 rather than into 100. A correct result can be ob- tained by printing the intermediate value and entering 100 and then reentering the printed value and doing the division. This, however, is not a very reasonable approach. Fortunately, there is a handy word available in FORTH to manage such problems. The word is SWAP . The execution of SWAP causes the top value n on the stack to be "swapped" with the second value on the stack. The old top value becomes the second value and vice versa. In the example, the solution to divide the inter- mediate value into 100 looks like this 100 SWAP / . ret Words such as SWAP are called stack management words because their entire functions deal with "grooming" the stack. Another important word in stack management is DUP . This word is used to duplicate the top of stack and places that value on the new top of the stack. The original value is the second number on the stack and its copy is the new top value. The two numbers are ex- actly identical. This is very useful when it is necessary to use a copy of a number to be printed, displayed or used in further calculation. The copy will be used for the operation rather than the original value which remains ready for further use on the stack. There are occasions when excess values are left on the stack by operations. These unwanted leftovers can be removed from the stack by the word DROP . To see how these stack management words work, try the following. Enter 2 3 4 .S ret which will display 2 3 4 .S 4 3 2 OK these numbers are still on the stack, now enter SWAP .S ret which displays SWAP .S 3 4 2 OK Note that the position of the top number and second number have changed. Now type DUP .S ret which displays DUP .S 3 3 4 2 OK The top value was duplicated and the copy added to the stack. Finally, try 24 DROP SWAP .S ret which shows DROP SWAP .S 4 3 2 OK The copied 3 was dropped from the stack leaving a 3 on top and a 4 then a 2 below it. The SWAP reversed the order of the 4 and 3 and coincidentally restored the numbers on the stack to their original order. A few more words should be introduced before leaving this chap- ter. You may sometimes want to put different numbers on separate lines. The word that will finish an existing line on the CRT or printer and starts a new one CR . This is short for "carriage return" and has the same meaning as if you hit the carriage return button on an electric typewritter. The printing head is returned to the left margin and the platten advanced to the next empty line of paper. If you are working on a CRT, the cursor will advance down the screen or cause a scroll to make room for a new line. Try the following entry 1 . CR 2 . CR CR Ret The FORTH interpreter will place the 1 on the stack and print it and encounter a CR . A new line will be used to print the follow- ing 2 which first goes on the stack and then is input by . . If there were no further entries on that line, the 2 would be immediately followed by FORTH's comment "OK". There are however two CR's to be processed. Two additional lines follow the 2 before the familiar "OK" is seen. The ability to title an output may be very handy. There are also times when you may just want to output a message to indicate how the program is doing or to prompt an operator for an input. The word .( is provided for this purpose. To use .( in a program you must have at least one space in front of . and one space fol- lowing the " just like the other words. This word is a special case, however, because it accepts a string following it (trailing by one space!) and outputs every character in the string until it finds a ) . The ) is not a word, therefore it does not have to be proceeded by a space. It is a special charac- ter, that .( looks for, to indicate that it is time to quit and turn control over to the interpreter again. The interpreter will begin looking for more words starting in the space after the en- ding ) . To illustrate try .( HELLO) ret which shows .( HELLO) HELLOOK Starting the output on another line will improve the readability, so try the following: CR .( HELLO) CR ret 25 which produces CR .( HELLO) CR HELLO OK More than one .( may be used to construct a line CR .( HELLO) .( THERE ) ret which produces CR .( HELLO) .( THERE ) HELLOTHERE OK Notice that there is no spare between the HELLO and THERE . This is because the first .( stopped outputting when the ) was found. The second .( started outputting again with the charac- ter following the next space after it. That space was necessary so that the interpreter could separate .( from the rest of the text and look for it in the dictionary. If you forgot the space in this case, the interpreter would try to find .(THERE in the dictionary. That of course would be unsuccessful and cause an error to output. There was a space after the end of the word THERE before the ending ) . This is what separated the THERE and the OK in the printout. If you want a space between HELLO and THERE , an extra space can be left after HELLO or before THERE , like CR .( HELLO ) .( THERE ) ret or CR .( HELLO) .( THERE ) ret If you want to separate two outputs by blanks, there is an easier way than typing. .( followed by a number of spaces and then an ending .( . The word SPACE outputs one blank space. Another similar word SPACES takes the top number from the stack and out- puts that many blank spaces. To see this, enter .( HELLO) SPACE .( THERE ) ret which outputs .( HELLO) SPACE .( THERE ) HELLO THERE OK and then CR .( HELLO) 10 SPACES .( THERE ) ret and see .( HELLO) 10 SPACES .( THERE ) ret HELLO THERE OK 26 With the words you have learned now, you can use FORTH to perform and function as a standard four function calculator can. You can also put titles and spaces in your result. Every time you wish to compute a result, though, the entire process must be typed again. You are only using the words provided in FORTH in se- quence. It is time you learned how to define your own words in- stead. Definitions To program in FORTH is to create new words. To learn the power of FORTH you must learn how to define your own words designed to perform the functions you want. So far you have only seen the first level of FORTH, using words already defined in the dictionary. The outer FORTH interpreter turned control over to a word only when found in the dictionary. After the word is complete it returns control back to the inter- preter which then looked for the next word. The second level of understanding in mastering FORTH is being able to use a special group of words, called "defining words". Defining words allow you to enter new words of your choosing into the language. When you first initialize the language FORTH, there are a fixed number of words defined in the dictionary. Most of those words can be used directly from the keyboard. In- cluded are the defining words. To see all of the words avail- able, enter the word WORDS . This word will cause the names of all the words in the language to be typed on the terminal. The name of this word WORDS is taken from its function which is to list all the names of words in FORTH's vocabulary. The vocabulary list will not only show the words that were originally provided in FORTH but also any words you may have added to the FORTH dictionary by using defining words. Notice the first word in the list. Remember the name. This is where FORTH starts looking for a match between a word you enter and the words of the entire vocabulary. This word is at the top of the dictionary. Any new words written into the language with defining words will go above it in the dictionary. To understand this concept you will now define a word. The ac- tual function for this word will be to turn control back to the controlling interpreter. Since when you enter the word, the outer interpreter finds and executes the word and this word will turn control right back to the outer interpreter the net result of using this word will essentially be of no effect on the out- come of anything (except a brief delay while the computer finds and runs the word). Therefore, an excellent name for this word will be NO-EFFECT . To define this word you must use the defin- ing word : (pronounced "colon") and the word used to terminate the effects of : which is called ; (pronounced "semi-colon"). More will be said about these new words in a bit, but first try this: : NO-EFFECT ; ret 27 FORTH should respond to your entry with a courteous "OK". The word NO-EFFECT is now a part of the FORTH language in the com- puter. To run this new word, type its name into input stream. FORTH will run the word and respond with "OK". Try using NO- EFFECT with this example 5 NO-EFFECT 4 NO-EFFECT + NO-EFFECT . ret After which FORTH will print 9 OK . The word NO-EFFECT was executed once per entry and had, of course, no effect on the final printed result of 9. Now type WORDS again. Notice the first word listed is NO- EFFECT . As you can see it is now part of this vocabulary just as + , - , and . are. The defining word : entered the name NO-EFFECT into the library for later use. (A brief note on the "NOT UNIQUE" warning message you may recieve when defining new words. FORTH allows redefinition of existing words using the same name. This allows all later references to the new definition with an old name. All previously defined references to the old word will remain unchanged. Sometimes the "NOT UNIQUE" message may be issued when there seems to be no match. For instance, : FLAGS ; , gives a not unique message. This is an anomolly of the shortened names in the internal ROM of Max-FORTH. A potential match has been found between FLAGS and FLUSH , since FLUSH is stord as "a count of 5 with first two let- ters FL___ . Do not worry about these occurances. The system is not harmed by the warning message. FLUSH can still be found in the dictionary, as can FLAGS .) It is useful to remember that the ultimate interpreter of your FORTH system is the computer itself executing machine code. There is nothing else the CPU can run directly but machine code. Any higher level program to be run must be translated into its machine code equivalents. Naturally, FORTH is written in machine code so that the computer can run it as a program. This is not as accurate a statement as might be supposed, though. It is true that the most primitive words in FORTH are written in machine code. These account for less than a quarter of the memory space used by FORTH language. That is because most of FORTH is written in FORTH. In other words, not every entry in the FORTH diction- ary is written in machine code. It may have instead been written in terms of other words already defined. Since the computer can not execute this instructions directly, each word defined in terms of other FORTH words or any structures other than machine code must have an interpreter. This interpreter will be used to "unscramble" the high level words and execute the appropriate machine code routines to accomplish the actions indicated. These interpreters are themselves machine code routines, called `inner interpreters'. Each defining word that enters the new words into the dictionary has its own inner interpreter routines associated with it. The defining word assigns its own inner interpreter to the word it creates in the dictionary. These inner interpreters are what the outer interpreter actually gives control to, in order to execute a word found in the dictionary. When the inner interpreter 28 finishes the functions indicated by the entered word, control is passed back to the calling routine. If a word is entered in machine code the CPU itself can translate the word directly. This type word must end by returning control back to the calling interpreter so the next word in line can be executed (there is a machine code defining word that allows machine code routine to be entered). All the defining words available in FORTH will be discussed in coming sections, however, you first should know that they all have some things in common. Since the purpose of making a new word is to have it available for later use. Every defining word creates a place for its new word in the FORTH dictionary. No mat- ter which defining word actually created it, the new word has a few elements of structure in common with the rest of the lan- guage. Their descriptions follow. The Name Field contains the characters that make up the name as- signed to the action of the word. It is this field that is used by the outer interpreter to determine if an entry you have made matches any in the dictionary. Closely associated with the Name Field is the Length Field which holds a count of the numbers of letters in the words name. It also usually contains two flags used in the compilation process. The Link Field holds a pointer that points to the previous word in the dictionary. By the use of this field the outer inter- preter can move from word to word in the dictionary, taking each in sequential order. Only the location of the latest word added to the vocabulary need be saved. Any other word in the diction- ary can be found by searching from there to the next, etc. Definitions, therefore, do not have to be limited to any par- ticular length. The pointer will always allow enough room for the parameters and fields used in definitions. The Parameter Field Pointer is the field that Max-FORTH uses to link the seperated heads sections (consisting of Length, Name, Link and Parameter Field Pointer) and the codes sections (consisting of Code Field and Parameter Field). The Code Field contains the address of the inner interpreter. All inner interpreters are written in machine code. Remember, the computer can execute machine code and nothing else. Each defining word has its own inner interpreter already written in machine code as part of the inner portion of the language (this portion of FORTH is often called the "KERNEL"). The Code Field then will identify the interpreter of the word that entered it into the dictionary as the one to decode and perform the func- tions it was defined to do. The actual functions which will be performed depends on the parameter(s) assigned to the word during the defining process. The Parameter Field contains the information placed in it by the defining word and required by the inner interpreter assigned to it. In other words, the Parameter Field contains specially en- coded entries that the inner interpreter of that defining word will understand. 29 Now that you have been introduced to the common elements of every FORTH language, (with the exception of the Parameter Field Pointer which is unique to Max-FORTH and RSC-FORTH) it is time to look into the defining words one at a time and learn each ones function. Since : has already been introduced and is the most commonly used, it will be taken first. When the word : is executed (i.e., found in the input stream by the outer interpreter), it creates a place for a new word in the dictionary and looks in the input stream for a string following it. This string will be used as the name of the new word. The Code Field is made to point at the inner interpreter of : (note: although this inner interpreter does not have a FORTH name, it is usually refered to by its assembly label, DOCOL or DOCOLON ). Since most of the words defined in the FORTH language itself are themselves products of colon definitions DOCOLON is the most commonly used of all inner interpreters. Besides some elementary error checking, the execution of : does one sig- nificant thing. It changes the state of the outer interpreter from its normal function to the compilation state. This is done by setting a flag. When in the compilation state, the outer interpreter checks each word found in the input stream to see if it is an "immediate" word. More will be said on immediate words in a bit, however, suffice it to say that very few words in the language are "immediates". If the word is not immediate, the more common case, instead of executing the word taken from the input stream, the outer interpreter will place the address of that word's Code Field into the next empty spot in the dictionary. Since : already put the head of a word to be defined into the dictionary, this new entry will be a part of the definition being built. The inner interpreter, DOCOLON , will use the parameters so con- structed to execute the function of this word later on. Each non-immediate word following the : will have the address of its Code Field inserted into the definition until the outer interpreter is taken out of the compilation state. The way to end a : definition is by using the word ; . This word, pronounced "semicolon", is an immediate word. As implied ear- lier, immediate words are not compiled into definitions, they are rather executed immediately by the outer interpreter regardless of its current state. The execution of ; causes some error checking to be performed to see if the definition in progress has any detectable loose ends. If none are found a terminator is added to the definition so that DOCOLON will not pass out the parameters of this word during execution and accidentally try to use a following word's fields. Like DOCOLON , this terminator has no assigned FORTH name but is refered to in conversations as SEMIS . Finally, the finishing touches are put on the newly defined colon word and FORTH pointers are updated so this word can be found when the dictionary is searched and the outer inter- preter is taken out of the compilation state. In the first example where NO-EFFECT was defined, all the ele- ments of the preceding descriptions were used. When the outer interpreter encountered : it created a spot in the dictionary built around the name NO-EFFECT with a link to the previous name 30 in the dictionary and Code Field contents that pointed to DOCOLON . The parameter field received only one entry, that of SEMIS when ; was found immediately following the name. It is just as easy to define words that do have a significant effect using the : and ; pair. If you were working on a formula and calculating the sum of a variable and constant, it might be useful to define a word that enters the constant and adds it to the value on the stack. For the sake of simplicity, suppose the constant was 3. To define a word to substitute for entering 3 + every time a new calcula- tion was started, a single word could be used instead. You would use the colon definition structure to create it. For example : CALC 3 + ; ret If you have entered this example, CALC is now a new word in your FORTH that can be used instead of 3 + . To try the new word, enter 2 CALC ret and FORTH will respond with 5 OK CALC is fully functional and as much part of the language now as any other word. In fact, once you have created a word such as CALC it can be used in other definitions. In this way, large programming tasks can be broken up into very small segments which can each be programmed and tested until the entire task can be- come a combination of smaller, already defined words built up in pyramid style. For further illustration, assume that adding 3 to the variable was only part of the required work to arrive at the computed answer. The complete function also requires the sum to be multi- plied by a constant, for this example 2 . Based on the word already done, a new word could be defined to perform this more complex function. : FUNCTION CALC 2 * ; ret The word FUNCTION , here defined , when executed causes CALC to operate, adding 3 to the number on the stack. Control returns to FUNCTION when CALC is finished (i.e., DOCOLON finds SEMIS ), a 2 is placed on the stack and that number and the previ- ously calculated mid term are multiplied. To try the new defini- tion, enter 2 FUNCTION ret The response will be 10 which is 2 with 3 added and then multi- plied by 2. Try other numbers of your choice to verify to your satisfaction how well FUNCTION works. 31 To try another example the following word will plot an asterisk in the column numbered by the value on the stack. The definiton using the colon structure is as follows: : PLOT CR SPACE ." *" ; ret The CR starts the output on a new line. The number from the stack is used by SPACES to put the spaces between the start of the line and the asterisks displayed by the ." *"structure. As you can see, with only a very few words from the original dic- tionary combined with numbers and use of the stack, very powerful new words can be made. Any previously defined word can be used in a current definition. The : defining word provides a place in the dictionary, enters the name, and causes the following words to be compiled, adding meaning to the new word under con- struction. The next defining word to be studied is CONSTANT . Sometimes in programming, a single number maybe used several places in a program in performing calculations because of its significance as a parameter. It is often much easier to assign a name to the num- ber for later use than to repeat the entry of the number at every occurence. This is particularly true in cases where the value of the number may be changed to another value after the program is tested. Rather than requiring several editing changes whenever the number is resident in the body of the program, only one line would need be modified. The assignment of a new value to the name and recompilation of the program would be the only effort required. Such an assignment could be made using a : definition, for in- stance : MULTIPLIER 300 ; . When MULTIPLIER is executed, it would leave its assigned value of 300 in the stack for use in the following computations. This is not, however, very efficient use of the computers memory space because : causes three times storage to be used in MULTIPLIER 's Parameter Fields as are really required to hold the number 300 of this example. In order to store numbers inside a : definition, the Code Field Address of a word called LIT (short for literal value) is inserted in the parameters indicating that the following location is not a Code Field Address, but instead a number to be entered on the stack. Of course, the parameter field of MULTIPLIER must be terminated with the address of SEMIS because MULTIPLIER is a : definition. This takes up a third place in this words parameter field. A better use of the computer's resources would be to use the defining word CONSTANT to enter such values into the program. Like all defining words CONSTANT creates a place in the diction- ary for the word under construction with the name assigned by the programmer. Unlike : , when CONSTANT is used to enter a word, the inner interpreter assigned to the word is a routine refered to as DOCON or DOCONSTANT . This routine performs only one function. It takes the first location in the parameter field (the only location in the parameter field, by the way) and treat- 32 ing it as a number, puts a copy of it on the stack. The number was assigned by the defining word CONSTANT when the word was created. To make a CONSTANT definition, the value to be assigned to the name is first put on the stack. The word CONSTANT is entered followed by the name to be assigned. Execution of a constant creates a name in the dictionary with the address of DOCON in the Code Field Address and the top value from the stack in the parameter field. The new definition is then complete. No equiv- alent to ; is required with CONSTANT because the state of the Outer Interpreter is not changed and DOCOL looks for only one parameter. The word written earlier with : could be rewritten as follows 300 CONSTANT MULTIPLIER ret In this format, MULTIPLIER is not only more memory efficient, it is also faster. No time is spent executing DOCOL , LIT and SEMIS . All the actions needed to put the value on the stack are programmed in DOCON which is more efficient. Once a word is defined using CONSTANT , there is no direct single word way of changing its value. Unlike other languages, however, it is possible to change a constant's value without recompiling the entire program. If the program is stored in RAM (alterable computer memory) and not ROM (permanent computer storage) and the address of the defined word's parameter field can be found, the contents of that address can be changed. In that way, at some future point when it becomes necessary to redefine the value of a constant, it is possible without major effort. In fact, the values of constants can be dynamically al- tered under program control if the program is in RAM. Although this is not a recommended procedure, there is no effort made to to FORTH to "protect" the programmer from "himself". In order to learn how to alter a FORTH constant, it will be neces- sary to learn the use of three other words. These words allow the Parameter Field Address Pointer of an Max-FORTH named word to be found, the contents of a memory location to be brought from memory to stack, and a value from the stack to be stored at a specific address in memory. The first word is ' (pronounced "tick"). This word is always followed by a string. The purpose of ' is to search the dictionary for the name of the word repre- sented by the string that follows ' . Its action is much like that of the outer interpreter when it searches the dictionary. The word ' , however, returns the value of the Parameter Field Address Pointer on the top of the stack when the word is found, rather than to actually execute the word. Assuming the word MULTIPLIER has been added to FORTH as shown above with the defining word CONSTANT , its Parameter Field Ad- dress Pointer can be found by ' . Entering ' MULTIPLIER . will cause some number to be printed. The value of the number may or may not hold significance to you, depending on your familiarity with your computer installation. This is, however, the address where the parameter assigned by CONSTANT to MULTIPLIER was 33 stored. All computer memory locations are assigned with numbers called addresses. By using the addresses, any information in the computers memory can be found. Knowing the address of a piece of data is only the first step. The actual data that is kept in that address is entirely a dif- ferent matter. By knowing the address where data is stored in memory, it is possible to call up that data or fetch it from its address. The word that allows memory to be read is @ (pronounced "fetch"). You will be able to fetch the value from MULTIPLIER's paramemter field using @ . To try this, you must again use ' to find that address. Once the address is on the stack, rather than printing the address, it can be used as the input to @ to first find out where the pointer is pointing, and then, to actually get the value for the memory read. Entering ' MULTIPLIER @ @ . will display 300, the value assigned when the word was created. The word @ always takes the top number from the stack and using it as an address, replaces it with the con- tents of that address. This is a form of indirection, using a number (i.e., address) to find a number (i.e., contents of an address). Reread the above description if you do not understand the difference between an address and the contents of that ad- dress. With addition of one more word you will learn how to actually modify memory to be whatever you want. The word ! (pronounced "store") is used for this purpose. Unlike @ which required only one parameter from the stack, ! requires two. Not only is an address needed to tell where to store a value, but the value itself must precede the address on the stack. To actually modify the way the previously defined word MULTIPLIER works, you need only enter the value you wish to change it to, its Parameter Field Address and issue a store command as follows: 50 ' MULTIPLIER @ ! OK Typing MULTIPLIER . will cause a 50 to be printed rather than the originally defined value 300. With knowledge of @ and ! also comes a grave responsibility. Indiscriminate use of these commands will surely cause a system crash. Much like the knowledge of good and evil, the ability to read and modify memory directly changes the status of the user. Responsibility for their use comes with the knowledge. If you do not thoroughly understand the significance of reading or writing some location, it is exceedingly prudent not to do so. By using @ and ! with ' it is possible to change the value of an already defined constant. Sometimes during programming, it is necessary to have an easily alterable storage without using the stack. A printing program for example may need to count the number of lines sent to the printer, but may not know the nature of "what's on the stack where" when it is called by a higher level program. A variable is needed in such ocassion. 34 The defining word VARIABLE allows for the creation of such storage structures. The structure of VARIABLE is quite similar in nature to that of CONSTANT just described. The word VARI- ABLE creates a place in the dictionary for the name contained in the string following it. The interpreter pointed to by the new variable's Code Field Address is called DOVAR or DOVARIABLE . This interpreter is similar to DOCOL with a subtle but ex- teremely important difference. The parameter field of the new VARIABLE defined word contains the value of the variable, just as a CONSTANT defined word. DOVAR , however, does not cause that value to be brought to the stack when the variable is called. Instead the address of that value is brought out by a fetch or modified by a store. A variable created by VARIABLE COUNT could be useful in mainta- ing the number of lines printed without typing out the stack. In the program where the number of lines printed was desired, COUNT @ would bring the value to the top of stack. The value could be incremented by a 1+ COUNT ! or cleared by putting a zero into the variable with 0 COUNT ! . The entry COUNT . is not par- ticularly useful. This would cause the address of the data of count to be printed. The programmer is usually much more inter- ested in what is stored in a variable, than where it is stored. The word VARIABLE creates storage for the data in the dictioa- nary itself. This may or may not be particulary desirable. If you are working in an entirely RAM based system, that is all the memory locations that can be read as well as written to. Using VARIABLE is fine. If you are, however, preparing your program for permanent storage in ROM, memory that will be set up once and can never be rewritten (Read Only Memory), using the variable structure may cause serious hardships. In such a situation, there are two possible working solutions. In both, the actual data is placed outside of the dictionary proper. If a free area of RAM is known to exist, the programmer can define a constant that will point at it. For example, if free RAM is available to the user at location 16038, the follow- ing step will give this address to the name FREE-VAR : 16384 CONSTANT FREE-VAR ret Now, the name FREE-VAR will be used as the address of the usable data. Using a constant in a ROM coded program is quite suitable as long as it is not to be changed, which is again not recommended practice. FREE-VAR can be used just as the variable defined COUNT can. Entering FREE-VAR @ will bring the data to the stack and FREE-VAR ! will put data away in that storage place. The second method is provided in most ROM based FORTH systems. Since FORTH itself maintains a number of variables in RAM, a spe- cial area is reserved to temporary storage called a user area. System variables that contain the number base for input and out- put functions, the length of characters that can be contained in a name , etc., are kept there for FORTH . 35 The user can also take advantage of some of the unassigned por- tion of that area by defining "user variables". The defining word USER is designed for this purpose. When a word defined with USER is called, the address of the data is left on the stack for fetch and store operations, just as the one defined with VARIABLE . Beyond this, the similarities of these two defining words end. When a user variable is defined, it is the offset into the user area that is taken from the stack rather than its preliminary value. The interpreter DOUSE is assigned to these words. DOUSE takes the offset to compute the actual address where the data lies. For example, if COUNT were to be designed to make use of the user area, it could be written as 64 USER COUNT , which means COUNT is kept in the sixty fourth location in the user area. Note that it is necessary to pick where in the user area each newly defined user variable is to go. It is important also to avoid conflicts with the system user variables which are usually in the first few locations in the user area. Once defined, user variables can be normally used in exactly the same way as any ordinary variable. The final defining words in FORTH will only be mentioned now. They are and a few others to be covered later. Let us suffice to say for the moment that their remarkable structure not only allow you to define new words, but also define new words that can be used to define new defining words. This proves the amazing nature of FORTH. The third level of understanding in FORTH is that, it is possible to create words which can further create new words. In this way a new data structures and other types of definition can be added as easily as the words that will eventually use them. The process of defining new words, called extensibility, of FORTH is truly remarkable. Structures At this point, you have learned how to define new words in order to program your problem in the FORTH language. Perhaps, if you are familiar with programming in some other language, you recog- nize the fact that all the examples shown thus far have been "straight line" code. That is, there have been no examples where conditional decisions have been made. Neither has there been any use of repetitive loops. Without these structures, programming is relatively useless. If the computer is not allowed to make decisions and take definitive actions based on those decisions, problems in general are more quickly solved with a hand cal- culator without the time-consumming process of programming. It is well known that the computer's power comes not from being able to make large monumental decisions at once, but rather that it takes many small iterative steps in arriving at a final solu- tion. In order to access this aspect of programming in the FORTH programming language, you must now learn the use of structures. 36 One of the reasons that structures were not taught earlier in this discourse is that, in FORTH they can only be used in defined words. They cannot be used directly from the keyboard the same way that + and - are. The reason for this lies in the way the Outer Interpreter works. In order for this interpreter to work, only one word can be recognized at a time. It can not parse out two names at once and has no way of remembering other names that have been used before hand. This ability to establish the location of the code for two different routines is necessary to make decisions. Based on the result of a decision one block of code or another will be executed. This is called "branching". Structures can be set up inside of FORTH words at the time of their compilation, however. When the Outer Interpreter is in the compilation mode rather than the execution mode it uses the Return Stack in order to remember where in the definition a branch is to be made later. The simplest form of a structure is perhaps the IF THEN construct. It will be introduced first. Quite often when making a decision, it is useful to look at the problem with all the possible alternatives carefully laid out. The simplest decision is one where, if one thing is true, a specific action will be taken. If it is not true, no special ac- tion is needed. An example of those in the English language would be "If it is raining, I will take my umbrella." The basis of the decision rests on the status of the weather. If it is raining, a special action must be performed. If it is not rain- ing, no such action is demanded. Taking the umbrella is the par- ticular action in question at the time. In FORTH, there is a word IF that causes an action to be taken based on the determined truth of a predefined term. This word is always used with the word THEN which is used to indicate the termination of the required action. IF makes its decision of whether to branch or not by taking a type of value from the stack, referred to as Boolean. A Boolean value has only two pos- sible values, true or false. Since the computer deals in 0's and 1's and doesn't understand concepts as abstract as right and wrong or true and false, the input to an IF word must be a num- ber. The way FORTH handles true and false is to assign the Boolean false to the number "0". Of course, if there are only two Boolean values in existence and the number "0" is one of them, it is totally arbitrary what the actual numerical value is assigned to true. In fact this is exactly the way FORTH treats the true Boolean value. If it is not "0" and therefore false, it must be true. To illustrate the use of the decision making power of the word IF the folowing example is exhibited: : TODAY IF ." TAKE YOUR UMBRELLA AND" THEN ." GO TO THE OFFICE" ; This definition called TODAY takes a truth value from the stack and prints the comment in the ." field if it is true. Other- wise, program control is passed to the instruction after the THEN . Here is another ." that has a comment that will be printed regardless of the value taken from the stack. To true this example, type the word TODAY preceded by a number that rep- 37 resents a Boolean truth value, i.e, 0 TODAY . The value 0 is false, meaning that it is not raining if that is what has been decided upon. The printed result will read, TODAY GO TO THE OFFICEOK If you were able to hook a rain gauge to your computer and read it with a word named CHECK which would leave a zero when it was not raining and a non-zero when it was, entering CHECK TODAY would give you your morning marching orders. Sometimes a more complex form of conditional is required than a simple IF THEN combination. It maybe necessary to take one ac- tion when a thing is true and an entirely different one if it is false. In FORTH, the structure that allows this kind of condi- tional is the IF ELSE THEN combination. Applied to English, it is similar to the biforcated statement "If it is cold I will take my fur hat, else I'd rather take my straw hat instead". An example similar to the one used for the simple IF THEN is presented as follows: : LOWTEMP ." THIS TIME I'LL TAKE MY" IF ." FUR " ELSE ." STRAW " THEN ." HAT! " ; To test the operation of the IF ELSE THENstructure enter: 1 LOWTEMP ret and notice the comment about the fur hat. To use a false value with LOWTEMP will ellicit a remark instead about a straw hat. Much more complex actions could be defined for execution between the IF and ELSE as well as the ELSE and THEN . These ." messages are used only for simplicity. Although the IF was said to always be used with the the THEN earlier, there is ac- tually another word that can be used with the IF instead. The word END and can replace the word THEN . There is no dif- ference between the action of the words, however. The other spellings are provided in the language only to make certain struc- tures more readable. Which one to use is left to the discretion of the programmer. It would be ridiculous of course, if you had to hand feed every truth value to the computer as was the case above before it could make a decision. For this reason, the language FORTH has a num- ber of relational operators. Such words allow testing of numbers on the stack and determination of their status in comparison with others. The relationship of less than, greater than, equal to and a special less than that disregards the positive/negative sign of the numbers can be derived from comparison of two stack numbers. A single stack entry can be checked for less than zero or equal to zero. Finally, a Boolean takes two numbers from the stack and leaves a single remaining truth value in their place. The truth value will be a "1" if the deeper value on the stack is less than the later entered number. That is to say, that the truth value will indicate true if the lower value is less than the value on the Top of Stack. If this is not the case, i.e., 38 they are equal or the Top of Stack is the lesser of the two, the < word will leave a false value of "0" on the stack in their place. It would probably be useful to review a moment the way the - word was detailed to work in FORTH as compared to algebraic nota- tion. The second value down on the stack was the object of the subtraction, the Top of Stack value was subtracted from it. You were told to visualize the two numbers in the order they were en- tered on the stack and then imagining the operator between them to reconstruct the algebraic syntax. This method of visualiza- tion will be quite useful when working with these relative value operators. Before experimenting with < operator, enter the following: : T-OR-F IF ." TRUE" ELSE ." FALSE" THEN ; ret This word will allow you to see the resultant truth value left on the stack by a relational operator. Hopefully, the words "TRUE" and "FALSE" will have more graphic significance than would 1's and 0's printed. Now try entering : 6 9 < .S T-OR-F ret The result should be a 1 printed by the .S and the word "TRUE" following it. Other cases can be explored with entries of 9 6 < T-OR-F and 6 6 < T-OR-F which are both false. The greater than relation is tested by the word > . Again if you should ever have trouble remembering the order in which the operands are taken in respect to the operator, try the algebraic translation method of visualization. After some practice, the order of these operations will become second nature to you. Try all three of the above examples with the 6 and 9 entries to be- come familiar with the > word. To determine if two values on the stack are identical, the word = may be used. Try the above examples replacing the < with = instead. Remember that these operators always take two numbers off the stack and leave a truth value in their place. If the original values are to be preserved for use in a later routine, it will be necessary to make copies of them with DUP , etc. for the operator to work within their place. The unsigned unrelational operator mentioned earlier is the word U< . To experiment with this word do the above examples replac- ing the < with U< . The results will be the same as before 39 for the 6 and 9 entries. Repeat both sets of examples with -6 and -9 instead and the difference between the two less than's should be apparent. Often it is desirable to test a pair of numbers for the opposite direction from that of the provided operators. The NOT word is provided to invert truth values for such occassions. Try to find if two numbers are not equal with this entry: 6 9 = NOT T-OR-F ret The NOT word actually has the same effect as the single number operator 0= . Try the example substituting 0= in the place of NOT and see the results are identical. The last remaining relational operator to be mentioned is 0< . This structure will run faster on most FORTH implementations than using a separate 0 and < entry sequence, but has virtually the same effect. Relational operators are usually used in consonance with IF's in programming. An example follows: : SIZE> DUP 10 > IF ." TOO LARGE" THEN . ; ret This word, SIZE> , checks the number passed to it to make sure it is not greater than 10. If it is, a warning message is printed first. A very common structure used in programming is the loop. Concep- tually, a loop is a string of instruction that are repeated in order for a given number of times. This eliminates the need to write the same instructions over and over again in sequence when writing the program. Say for example you wanted to write a program that listed all the numbers from 0 to but not including 10, with their squared value beside them. If you were to write all the individual instructions to make this table, it would look like this: : SQ-TBL 1 1 1 . * . CR 2 2 2 . * . CR 3 3 3 . * . CR 4 4 4 . * . CR 5 5 5 . * . CR 6 6 6 . * . CR 7 7 7 . * . CR 8 8 8 . * . CR 9 9 9 . * . CR ; ret As you can see the program is long and tedious because of the con- stant repetition. There is another disadvantage as well, in that, changing the program to make the same table up to 19 is twice as much work. The work already done is of little more use than as a pattern to the programming for the extended numbers above 9. By using a looping structure, it is possible to save a good deal of effort in writing programs of this type and write a much more useful program as well. Writing a loop structure with only the relational operators and the condition IF ELSE THEN words is very difficult. This is because FORTH's very nature en- courages structured programming. One of the main requirements of structured programming is that no "GO TO" like commands be used when programming. There are no "GO TO" words in FORTH. Although it is possible to create them, it is not necessary as you will see shortly. The only way to write a loop with IF ELSE THEN's 40 without "GO TO" commands is by using a method called "reentrant code" where one of the routines called in a words definitions is itself. That is, the word being defined will be set up to call itself when it runs. It will continue to recall itself as many times as necessary to do the looping desired. There are two powerful reasons why this is not a useful solution at this point. First, to actually make a definition available to be called before it even finishes, takes some sophisticated manipulation on the FORTH compilation process, which is beyond the understanding of most moderately competent FORTH users. Secondly, most FORTH systems limit the number of times words can call other words. This is usually below a hundred. Many applications where loops are used can exceed several thousand iteration of the loop, precluding the use of reentrant coding structures for solution. If you are discouraged by the number of methods that are not ef- fective in creating loops, take heart, FORTH offers quite a large number of versatile structures that will just fit the bill. The first to be presented works wonderfully for reworking the last example. The structure is made up of the two words DO and LOOP . When a loop is desired two numbers are passed to the DO word. They are the upper limit of the loop and the number to start the looping with. The count of the loop will start at the top value on the stack and continue until the top limit is met. Any words between the DO and the LOOP will be executed as many times as it takes to meet the upper limit. It is the run- time part of the word LOOP that actually does the counting. Each time LOOP is encountered in the execution, the count has one added to it. It is then tested to see if it is equal to or greater than the upper limit. If it is, the loop is terminated. If not, it branches back to the word immediately following the DO . The looping continues until the final condition is met before execution continues with the rest of words following the LOOP . The squaring table example follows: : SQ-TBL 10 1 DO I I I . * . CR LOOP ; ret 41 42 A P P E N D I C E S 43 WORDS LIST FOR Max-FORTH V1.0 6/86 The following words list was captured from a Max-FORTH V1.0 sys- tem. To conserve ROM space, only the character count and the non-underlined characters actually exist in the internal ROM, i.e., SPACES and SPACEZ are not differentiated. Unless you set WIDTH to three (number of characters --- maximum is 31) the names you enter will be normal length. 44 F893 TASK EBE0 ( FE26 @ FE00 C@ FDF3 ! FDE6 C! FA0E 2@ F9F8 2! E7C4 : E7DA ; FDCF + FDC4 - FA9F 1-! FA90 1+! FA81 +! F88B * F881 / FD47 >< FD52 SWAP F9E0 2OVER F9EC 2SWAP FD8F DUP F9D8 2DUP FD3F OVER FD2B ROT F9CA 2ROT FA73 PICK FA2D ROLL FA4D -ROLL FD83 DROP F9C8 2DROP FD7A >R FD73 R> FC09 = FC3A NOT FC28 0= F96A D0= FC1F 0> FC16 0< FBFD U< FBE8 < F97A DU< F972 D< F962 D= FBE0 > FDB3 AND FDA5 OR FD97 XOR EF4E IF EF42 THEN EF2C ELSE EF22 BEGIN EF14 UNTIL EF02 REPEAT EEFA WHILE EEEC AGAIN EF14 END EE54 DO EE81 LOOP EE60 +LOOP FAE6 K FADE J FAD6 I FAD6 R@ EEA2 LEAVE FEBB EXIT F8FC KEY F8F4 EMIT F8EC ?TERMINAL FBD8 S->D FBC9 ABS F942 DABS FBAD MIN F92E DMIN FB9D MAX F91C DMAX F763 SPACES FA1D DEPTH F6DE CR F6BE TYPE F6B2 COUNT F68A -TRAILING FC80 1+ FC75 2+ FC6A 1- FC5F 2- FC50 2/ FC45 2* F9A8 D+ F982 D- F907 D2/ F83D /MOD F835 MOD F829 */MOD F81F */ FB39 UM* FB05 UM/MOD FAFA NEGATE F956 DNEGATE E802 CONSTANT E7F2 VARIABLE E810 2CONSTANT E7E8 2VARIABLE FAEE EXECUTE FD6A SP@ F7B9 CMOVE> F7E3 CMOVE FEBB ;S E846 CODE-SUB E83A CODE E82A END-CODE E81C USER F597 . F5A9 .R F5B5 D. F58F U. F59F U.R F5BF D.R F616 #S F624 # F605 SIGN F5F5 #> F5EB <# F587 ? F6EC EXPECT E70E QUERY F647 BL F555 STATE F552 CURRENT F54F CONTEXT F54C SCR F549 BLK F507 DP F52B OFFSET F540 FLD F53D DPL F534 >IN F4FB BASE F4E6 S0 F4EF TIB F53A #TIB F537 SPAN F56C C/L F1C9 FIRST F1C1 LIMIT F564 PAD EF82 HERE EF7A ALLOT EF6E , EF62 C, F77B SPACE FD85 ?DUP EDF4 TRANSVERSE EF5A LATEST EC64 COMPILE EC5C [ EC51 ] F4CC HEX F4C3 DECIMAL EC39 ;CODE EC31 EBED ." EC12 .( F793 FILL F78B ERASE F783 BLANK F5DD HOLD F225 WORD F45C CONVERT F406 NUMBER EBBE FIND EADE ID. E896 CREATE EACE [COMPILE] EAAA LITERAL E75E INTERPRET E9FE IMMEDIATE E864 VOCABULARY E9F4 FORTH E9EC EDITOR E9E4 ASSEMBLER E9DA DEFINITIONS E9D2 RECURSE EE3E >MARK EF82 RESOLVE EE26 BODY EE1E CFA EE0F N