**** VIRTUAL MACHINE CONTROL **** UP@ -- addr M,F83 "u-p-fetch" addr is the address of the currently active user area. The user area (or process control block) contains important forth system variables for which different copies need to be kept for different tasks. RP@ -- addr 79 "r-p-fetch" addr is the address of the top of the return stack. RP0 -- addr U addr is the address of a variable which contains the address of the bottom of the return stack. UP! addr -- "u-p-store" addr is the new starting address of the USER area. Warning: The new user area must have been already initialized before UP! is done, otherwise the system will probably crash. SP0 -- addr addr is the address of a variable which contains the address of the bottom of the data stack. SP! addr -- "s-p-store" addr is the address of the new top of the data stack. RP! addr -- "r-p-store" addr is the address of the new top of the return stack. Warning: This word should be used inside of words which do not exit, such as QUIT . There it is used to initialize the return stack with the phrase "RP0 @ RP!" **** STACK MANIPULATION **** NIP n1 n2 -- n2 F83 Remove the second element from the data stack and discard it. -ROT n1 n2 n3 --- n3 n1 n2 Local "minus-rote" The top three stack entries are rotated in the other direction than ROT, putting the top number in the deepest position. L>R l -- 32 "l-to-r" The 32 bit number l is moved from the data stack to the return stack. LR> -- l 32 "l-r-from" l is the 32 bit number that was previously on top of the return stack. LR> and its inverse L>R are especially useful for dealing with mixed 16 and 32 bit numbers on the data stack. 32 bit numbers can be temporarily moved to the return stack to expose 16 numbers that may be underneath. **** COMPARISON **** 0<> n -- flag Local "zero-not-equal" Tflag is true if n is not equal to zero. 0<= n -- flag Local "zero-less-or-equal" flag is true if n is less than or equal to zero. <> n1 n2 -- flag Local "not-equal" flag is true if n1 is not equal to n2. <= n1 n2 -- flag Local "less-or-equal" flag is true if n1 is less than or equal to n2. >= n1 n2 -- flag Local "greater-or-equal" flag is true if n1 is greater than or equal to n2. U> u1 n2 -- flag Local "u-greater" flag is true if u1 is greater than u2 (unsigned integer compare). 0>= n -- flag Local "zero-greater-or-equal" flag is true if n is greater than or equal to zero. U<= u1 n2 -- flag Local "u-less-or-equal" flag is true if u1 is less than or equal to u2 (unsigned integer compare). U>= u1 n2 -- flag Local "u-greater-or-equal" flag is true if u1 is greater than or equal to u2. (unsigned integer compare). Sign tests for double numbers. Use the L versions instead. D0<> d -- flag D0< d -- flag D0<= d -- flag D0> d -- flag D0>= d -- flag Comparisons for double numbers. Use the L versions instead. D< d1 d2 -- flag D> d1 d2 -- flag D<> d1 d2 -- flag DU> d1 d2 -- flag DU<= d1 d2 -- flag DU>= d1 d2 -- flag D>= d1 d2 -- flag D<= d1 d2 -- flag L< l1 l2 -- flag E "l-less-than" True if l1 is less than l2 (signed 32-bit integer compare) LU< ul1 ul2 -- flag E "l-u-less" flag is true if ul1 is less than ul2 (unsigned 32-bit integer compare) L0= l -- flag E "l-zero-equals" Leave true if l is zero. (32-bit compare) BETWEEN n min max -- f F83 flag is true if n is between min and max, inclusive of both endpoints. ( min <= n <= max ) WITHIN n min max -- f F83 flag is true if n is between min and max, inclusive of min and exclusive of max. ( min <= x < max ) **** ARITHMETIC **** UL* ul1 ul2 -- lproduct 32 Lproduct is the 32-bit product of the 32-bit unsigned multiplicands ul1 and ul2. UM/MOD ul.dividend un.divisor -- un.remainder un.quotient 83 "u-m-divide-mod" un.remainder is the remainder and un.quotient is the floor of the quotient after dividing ul.dividend by the divisor un.divisor. All values and arithmetic are unsigned. The dividend is a 32-bit number; the divisor and the results are the "normal" size for the system (the same width as the stack). M/MOD l.dividend n.divisor -- n.rem n.quot "m-divide-mod" N.remainder is the remainder and n.quotient is the floor of the quotient after dividing l.dividend by the divisor n.divisor. All values and arithmetic are signed. The dividend is a 32-bit number; the divisor and the results are the "normal" size for the system (the same width as the stack). Similar to UM/MOD except the arithmetic is signed. ?NEGATE n f -- -n "query-negate" or n f -- n Negate n if the flag is true. ?DNEGATE d1 f -- d2 "query-d-negate" or d1 f -- d1 d2 is the two's complement of d1 if the flag is true, otherwise does not modify d1. Not recommended. L+ l1 l2 -- l3 32 l3 is the arithmetic sum of l1 plus l2. All the numbers are 32 bits. See: "32-bit Compatibility" Note: This word takes the place of the 83-standard word D+, whose intended behavior for 32 bit Forth systems in unclear. L- l1 l2 -- l3 32 l3 is the result of subracting of l2 from l1. All the numbers are 32 bits. See: "32-bit Compatibility" Note: This word takes the place of the 83-standard word D-, whose intended behavior for 32 bit Forth systems in unclear. LNEGATE l1 -- l2 32 l2 is the two's complement of l1. See: "32-bit Compatibility" Note: This word takes the place of the 83-standard word DNEGATE, whose intended behavior for 32 bit Forth systems in unclear. ?LNEGATE l1 f -- l2 "query-l-negate" or l1 f -- l1 l2 is the two's complement of l1 if the flag is true, otherwise does not modify l1. L= l1 l2 -- flag 32 "l-equal" flag is true if l1 equals l2. LABS l -- ul 32 "l-absolute" ul is the absolute value of l. If l is -2,147,483,648 then ul is the same value. See: "arithmetic, two's complement" Note: This word takes the place of the 83-standard word DABS, whose intended behavior for 32 bit Forth systems in unclear. L2/ l1 -- l2 32 "l-two-divide" l2 is the result of l1 arithmetically shifted right one bit. The sign is included in the shift and remains unchanged. Note: This word takes the place of the 83-standard word D2/, whose intended behavior for 32 bit Forth systems in unclear. LMIN l1 l2 -- l3 32 "l-min" l3 is the lesser of l1 and l2. All numbers are 32 bits. Note: This word takes the place of the 83-standard word DMIN, whose intended behavior for 32 bit Forth systems in unclear. LMAX l1 l2 -- l3 32 "l-max" l3 is the greater of l1 and l2. All numbers are 32 bits. Note: This word takes the place of the 83-standard word DMAX, whose intended behavior for 32 bit Forth systems in unclear. L+! l addr -- 32 "l-plus-store" l (a 32 bit number) is added to the 32 bit value at address addr. FLIP w1 -- w2 w2 is the result of exchanging the bytes in the lower 16 bits of the number w2. WFLIP l1 -- l2 l2 is the result of exchanging the 16 bit halves of the 32 bit number l1. U2/ u1 -- u2 Local "u-two-divide" u2 is the result of u1 logically shifted right one bit. A zero is shifted into the vacated sign bit. 4* n1 -- n2 F83 "four-times" n2 is the result of shifting n1 left two bits. Zeros are shifted into the vacated bit positions. 8* n1 -- n2 F83 "eight-times" n2 is the result of shifting n1 left three bit. Zeros are shifted into the vacated bit positions. PERFORM addr-of-cfa -- F83 The stack argument is the address of a token. The Forth word specified by that token is executed. Equivalent to TOKEN@ EXECUTE . DIGIT char base -- digit true | char false If the character char is a digit in the specified base, returns the numeric value of that digit under true, else returns the character under false. Appropriate characters are 0-9, a-f, depending on base. SKIP addr1 len1 char -- addr2 len2 F83 Skip initial occurrences of the character char in an unpacked string. Addr1 is the starting address and len1 the length of an array of bytes. Addr2 is the address of the first byte in that array which is not the same as char. Len2 is the remaining number of bytes after addr2. This word is primarily used as part of WORD to skip initial blanks. SCAN addr1 len1 char -- addr2 len2 Find the first occurrence of the character char in an unpacked string. Addr1 is the starting address and len1 the length of an array of bytes. Addr2 is the address of the first byte in that array which is the same as char. Len2 is the remaining number of bytes after addr2. This word is primarily used as part of WORD to find the delimiter character which terminates a word. UNNEST -- F83 Compiled within a colon definition such that when executed, that colon definition returns control to the definition that passed control to it by returning control to the return point pn the top of the return stack. An error condition exists if the top of the return stack does not contain a valid return point. May not be used within a do-loop. See: ; "stack, return" "9.3 Return Stack" Note: This word behaves exactly the same as EXIT . UNNEST was used to end a colon definition in F83 so that the decompiler could distinguish the end of the colon definition from an EXIT that was explicitly compiled somewhere in the middle of the definition. The decompiler in this Forth system is smarter than the F83 decompiler, so this distinction is no longer necessary. **** LOGICAL OPERATIONS **** CSET byte-mask addr -- Local The byte at address addr is logically OR'ed with the mask byte-mask, thus setting the bits that were one in the mask. CRESET byte-mask addr -- Local The byte at address addr is logically AND'ed with the ones complement of the mask byte-mask, thus clearing the bits that were one in the mask. CTOGGLE byte-mask addr -- The byte at address addr is logically XOR'ed with the mask byte-mask, thus changing the bits that were one in the mask. TOGGLE addr byte-mask -- Like CTOGGLE, except the order of the operands is reversed. **** ADDRESS OPERATORS **** /C* n1 -- n2 32 "per-c-times" n2 is the result of multiplying n1 by the length in bytes of a "byte". This is useful for converting an index into a byte offset. On a byte-addressed machine, this doesn't do anything. /W* n1 -- n2 32 "per-w-times" n2 is the result of multiplying n1 by the length in bytes of a (16 bit) word. This is useful for converting an index into a byte offset. This is equivalent to 2* , but should be used in preference to 2* , as it is more portable. /L* n1 -- n2 32 "per-l-times" n2 is the result of multiplying n1 by the length in bytes of a (32 bit) longword. This is useful for converting an index into a byte offset. This is equivalent to 4* , but should be used in preference to 4* , as it is more portable. /N* n1 -- n2 32 "per-n-times" n2 is the result of multiplying n1 by the length in bytes of a "normal". This is useful for converting an index into a byte offset. CA+ addr1 index -- addr2 32 "character-address-plus" addr2 is the address of the index'th character after addr1. For byte-addressed machines, this is equivalent to + . CA+ should be used in preference to + because it more clearly expresses the intent of the operation and is more portable. WA+ addr1 index -- addr2 32 "word-address-plus" addr2 is the address of the index'th 16 bit word after addr1. For byte-addressed machines, this is equivalent to "2* +" . WA+ should be used in preference to "2* +" because it more clearly expresses the intent of the operation and is more portable. LA+ addr1 index -- addr2 32 "long-address-plus" addr2 is the address of the index'th 32 bit longword after addr1. For byte-addressed machines, this is equivalent to "4* +" . LA+ should be used in preference to "4* +" because it more clearly expresses the intent of the operation and is more portable. NA+ addr1 index -- addr2 32 "normal-address-plus" addr2 is the address of the index'th "normal" sized word after addr1. For 16 bit stacks, this is equivalent to WA+ . For 32 bit stacks, this is equivalent to LA+ . NA+ should be used in preference to WA+ or LA+ when the intent is to address items that are the same size as items on the stack. NA+ addr1 n -- addr2 Local addr2 is the result of incrementing address addr1 by n times the size of a "normal". If addr1 is the base address of an array of "normal"s, addr2 is the address of the n'th element of that array. CA1+ addr1 -- addr2 32 "character-address-one-plus" addr2 is the address of the next byte after addr1. For byte-addressed machines, this is equivalent to 1+ . CA1+ should be used in preference to 1+ because it more clearly expresses the intent of the operation and is more portable. WA1+ addr1 -- addr2 32 "word-address-one-plus" addr2 is the address of the next 16 bit word after addr1. For byte-addressed machines, this is equivalent to 2+ . WA1+ should be used in preference to 2+ because it more clearly expresses the intent of the operation and is more portable. LA1+ addr1 -- addr2 32 "long-address-one-plus" addr2 is the address of the next 16 bit word after addr1. For byte-addressed machines, this is equivalent to "4 +" . LA1+ should be used in preference to 4 + because it more clearly expresses the intent of the operation and is more portable. NA1+ addr1 -- addr2 32 addr2 is the result of incrementing address addr1 by the size of a "normal". Should be used instead of "2+", because "2+" doesn't work on 32-bit systems. NA1+ addr1 index -- addr2 32 "normal-address-one-plus" addr2 is the address of the next "normal" sized word after addr1. For 16 bit stacks, this is equivalent to WA1+ . For 32 bit stacks, this is equivalent to LA1+ . NA1+ should be used in preference to WA1+ or LA1+ when the intent is to address items that are the same size as items on the stack. TA1+ addr1 -- addr2 32 "token-address-one-plus" addr2 is the address of the next "token" after the one at addr1. A token is the way that an address is stored in memory. Depending on the implementation, a token may be a 32 bit absolute address, a 16 bit relative address, or something else. This word is provided to allow dictionary manipulation utilities like decompilers to be independent of the representation of addresses when they are stored in memory. BOUNDS addr1 len -- addr2 addr1 F83 addr2 is the sum of addr1 and len. BOUNDS is used to convert a starting address and a count into an ending address under a starting address, as required by do-loops. **** MEMORY REFERENCE **** L@ addr -- l 32 "l-fetch" l is the 32 bit number at addr. See: "32 bit compatibility" W@ addr -- w 32 "w-fetch" w is the 16 bit number at addr. If the stack width is 32 bits, w is padded on the left with zeroes. See: "32 bit compatibility" L u -- l 32 "n-to-l" l is the result of padding u on the left with zeros to form a 32 bit number. If the stack width is 32 bits, N->L doesn't do anything. S->L n -- l 32 "signed-to-l" l is the result of sign-extending n to form a 32 bit number. If the stack width is 32 bits, S->L doesn't do anything. L->N l -- n 32 "l-to-n" n is the result of converting the 32 bit number l to a "normal" sized number by possible truncation. If the stack width is 32 bits, L->N doesn't do anything. N->A n -- addr 32 "n-to-address" addr is the result of converting the number n to an absolute address. If the stack width is 16 bits, this involves relocation. If the stack width is 32 bits, N->A doesn't do anything. L->W l -- w 32 "l-to-w" w is the result of converting the 32 bit number l to a 16 bit number by truncating the high order bits. If the stack width is 16 bits, this operation results in a decrease of the stack depth. If the stack width is 32 bits, the stack depth doesn't change, but the high order 16 bits of the 32 bit number on the stack are changed to zeroes. N->W n -- w 32 "n-to-w" w is the result of converting the "normal" number n to a 16 bit number by possibly truncating the high order bits. If the stack width is 16 bits, this N->W doesn't do anything. If the stack width is 32 bits, the stack depth doesn't change, but the high order 16 bits of the 32 bit number on the stack are changed to zeroes. LWSPLIT l -- w.low w.high 32 "l-w-split" w.low is the least significant 16 bits and w.high the most significant 16 bits of the 32 bit number l. If the stack width is 16 bits, this doesn't do anything, since 32 bit numbers are represented on the stack as two 16 bit numbers. If the stack width is 32 bits, the stack depth increases, and the two numbers left on the stack each have zeroes in the high order 16 bits. This is useful for backwards compatibility with programs written for 16 bit Forth systems which take advantage of the representation of a 32 bit number as two 16 bit numbers and manipulate the halves of the number independently. WLJOIN w.low w.high -- l 32 "w-l-join" l is the result of concatenating the two 16 bit numbers w.low and w.high to form a 32 bit number. If the stack width is 16 bits, this doesn't do anything, since 32 bit numbers are represented on the stack as two 16 bit numbers. If the stack width is 32 bits, the stack depth decreases. WLJOIN is the inverse of LWSPLIT. NOOP -- F83 "no-op" Don't do anything. This can be used to waste time. **** OPERATING SYSTEM INTERFACE **** SYSCALL call# -- Local call# is a number specifying a service provided by the external operating system. That operating service is invoked. Any arguments required by the system service must be on the stack. They will not be removed from the stack by the system service. If the service returns a value, use RETVAL or LRETVAL to put it on the stack. Implementation Notes: When running under Unix, call# is a byte offset into an array of system call subroutine addresses provided by the C wrapper program that loads the Forth system. The appropriate values for call# for Unix may be found in forth/wrapper.c . When running stand-alone under the Sun PROM monitor, call# is a byte offset into the monitor "ROM vector". Appropriate values for call# for the PROM monitor may be found /usr/include/mon/romvec.h RETVAL -- n Local n is the return value from the last system service invoked by SYSCALL. RETVAL must be called immediately after SYSCALL, or the value may be overwritten. LRETVAL -- l Local l is the 32 bit return value from the last system service invoked by SYSCALL. LRETVAL must be called immediately after SYSCALL, or the value may be overwritten. BYE -- Deferred Local (BYE -- Default (Unix) STAND-BYE -- Default (Stand-alone) Exit from Forth back to the operating system. Implementation Notes: BYE is deferred so that the Forth system may be easily configured to run in different environments (e.g. under Unix or stand-alone). (BYE is the default implementation for Unix, which exits back to whatever process invoked Forth. STAND-BYE is the default implementation for running stand-alone under the Sun PROM monitor, which exits back to the monitor. When running under Unix, Forth will also exit if it gets an "end of file" condition on its input stream. **** DICTIONARY MAINTENANCE **** LINK@ lfa -- link Local "link-fetch" link is the address of the word which is linked to the word whose link field address is lfa. Link@ is provided in order to make dictionary manipulation utilities independent of the implementation of the dictionary structure. LINK! link addr -- Local "link-store" Store the address link at addr in the correct format for a dictionary link. Link@ is provided in order to make dictionary manipulation utilities independent of the implementation of the dictionary structure. LINK, link -- Local "link-comma" Store the address link into the dictionary at HERE in the correct format for a dictionary link. The dictionary pointer is advanced past the stored link. VFIND str voc-ptr -- cfa 1 Local "v-find" or str voc-ptr -- cfa -1 or str voc-ptr -- str false This is similar to FIND, except that instead of searching every vocabulary in the search order, VFIND only searches a single vocabulary, whose vocabulary pointer is voc-ptr. A vocabulary pointer is that number which is stored in CONTEXT by executing a vocabulary. 3DUP a b c -- a b c a b c F83 Duplicate the top three stack items. 4DUP a b c d-- a b c d a b c d F83 Duplicate the top three stack items. 2ROT a b c d e f -- c d e f a b 79 "two-rote" The top 3 pairs of numbers on the stack are rotated, bringing the third pair to the top of the stack. UALLOC size -- new-user-number Local new-user-number is the next available user number. Size bytes are allocated in the user area so that the next call to UALLOC will return a number past the bytes just allocated. NUSER -- Local A defining word used in the form: NUSER When name is later executed, it leaves the address of its data storage area, which is in the USER area. Enough space to store a single "normal" stack item is allocated. This is similar to the standard word USER, except that the user doesn't have to keep track of which USER area locations have already been used. W, w -- 32 "w-comma" Allocate enough space in the dictionary for a 16 bit word and store the least significant 16 bits of w there. L, l -- 32 "l-comma" Allocate enough space in the dictionary for a 32 bit longword and store l there. TOKEN, addr -- 32 "token-comma" Allocate enough space in the dictionary for a token and store addr there. A token is the representation of an address when it is stored in memory. Depending on the implementation, a token may be a 32 bit absolute address, a 16 bit relative address, or something else. See: token TOKEN@ addr1 -- addr2 32 "token-fetch" addr2 is the address stored at address addr1. When addr2 is in the memory, it is stored as a "token". A token is the representation of an address when it is stored in memory. Depending on the implementation, a token may be a 32 bit absolute address, a 16 bit relative address, or something else. See: token TOKEN! addr2 addr1 -- 32 "token-store" The address addr2 is stored at address addr1 as a "token". A token is the representation of an address when it is stored in memory. Depending on the implementation, a token may be a 32 bit absolute address, a 16 bit relative address, or something else. See: token .S -- "print-stack" The contents of the data stack are printed in unsigned format and in the current base. The top of the stack appears on the right. ALIGN -- The dictionary pointer is advanced to a machine alignment boundary. Any bytes skipped are filled with ASCII space characters (hex 20). If the dictionary pointer is already on an alignment boundary, no action is taken. For the 68000, which is word aligned, this aligns to a 16 bit word boundary. EVEN n1 -- n2 If n1 is odd, n2 is one more than n1. If n1 is even, n2 is n1. ?COMP -- "query-compiling" Aborts if executed while not in compiling state, printing the message "Compilation Only" ?EXEC -- "query-executing" Aborts if executed while not in execution state, printing the message "Execution Only" ?PAIRS n1 n2 -- "query-pairs" Aborts if n1 is not equal to n2, printing the message "Conditionals not paired". This is used to ensure that conditionals such as IF ... THEN are properly matched and nested. The way this works is: The beginning word of a conditional (such as IF) leaves a magic number (n1) on the stack. When the ending word of the conditional is encountered, it uses ?PAIRS checks that the magic number on the stack is the correct one. ?STACK -- "query-stack" Aborts if the stack pointer is outside of the space allocated to the data stack, and prints either "Stack Underflow" or "Stack Overflow" ?ENOUGH n -- "query-enough" Aborts if the stack depth excluding n is less than n. A word may use this to make sure that it has been called with enough arguments. UPPER addr len -- F83 Converts the unpacked string specified by addr and len to upper case; only lower case letters are changed. LOWER addr len -- F83 Converts the unpacked string specified by addr and len to lower case; only upper case letters are changed. COMP addr1 addr2 len -- n F83 Compares the byte arrays starting at addresses addr1 and addr2 and continuing for len bytes. n is 0 if the arrays are the same. n is 1 if the first differing character in the array at addr1 is numerically greater than the corresponding character in the array at addr2. n is -1 if the first differing character in the array at addr1 is numerically less than the corresponding character in the array at addr2. Upper and lower case letters are not treated as being the same. CAPS-COMP addr1 addr2 len -- n F83 Compares the byte arrays starting at addresses addr1 and addr2 and continuing for len bytes. n is 0 if the arrays are the same. n is 1 if the first differing character in the array at addr1 is numerically greater than the corresponding character in the array at addr2. n is -1 if the first differing character in the array at addr1 is numerically less than the corresponding character in the array at addr2. Upper and lower case letters are treated as indistinguishable. COMPARE addr1 addr2 len -- n F83 If the variable CAPS contains zero, performs a case-sensitive comparison as described by COMP. If CAPS contains nonzero, performs a case-insensitive comparison as described by CAPS-COMP. BACKSPACES n -- F83 Prints n backspace characters (hex 8) on the output stream. BEEP -- F83 Transmits a bell character (hex 7) to the output stream, which causes most terminals to make a sound. On the Sun Workstation when running in a SunWindow, this causes the window to flash. (LF -- Local Prints a linefeed character (hex 0a) on the output stream. (CR -- Local Prints a carriage return character (hex 0d) on the output stream. This does not send an accompanying linefeed character. LF -- Local Prints a linefeed character (hex 0a) on the output stream and updates the variables #LINE and #OUT. #LINE is incremented by one to indicate that one more line has been printed on the terminal. #OUT is set to zero to indicate that the cursor is at the left margin (because the Unix tty driver treats a linefeed character as the end of a line and adds a gratituitous carriage return). CRLF -- Local Equivalent to "(CR LF", ie prints both a carriage return and a linefeed on the output stream, and updates #LINE. **** NUMERIC I/O **** ? addr -- F83 "question-mark" The "normal" sized number at address addr is displayed, using the format of . . (U.) u -- addr len F83 "paren-u-dot" addr is the address and len the length of an array of characters which is the result of converting the unsigned number u to a printable string of ASCII characters. (.) n -- a len F83 "paren-dot" addr is the address and len the length of an array of characters which is the result of converting the number n to a printable string of ASCII characters. If n is negative, the first character in the string will be a minus (-) sign. S. n -- Local "signed-print" The absolute value of n is displayed in a free field format with a leading minus sign if n is negative. Even if the base is hex, the number will be printed in signed format. (UL.) ul -- addr len Local "paren-u-l-dot" Same as (U.) except that ul is explicitly a 32 bit number. UL. ul -- 32,Local "u-l-dot" Same as U. except that ul is explicitly a 32 bit number. UL.R ul +n -- 32,Local "u-l-dot-r" Same as U.R except that ul is explicitly a 32 bit number. (L.) l -- addr len 32,Local "u-l-dot-r" Same as (.) except that l is explicitly a 32 bit number. L. l -- 32,Local "l-dot" Same as . except that l is explicitly a 32 bit number. L.R l +n -- 32,Local "l-dot" Same as .R except that l is explicitly a 32 bit number. DPL -- addr F83 "d-p-l" The address of a variable containing information about the last number scanned by the text interpreter. If this variable contains -1, the number did not contain a decimal point. If the variable contains a non-negative number, the number it contains is the number to digits to the right of the decimal point in the last number scanned. LONG? -- flag Local "long-question" flag is true if the last number that was converted was a 32 bit number, as indicated by the presence of a decimal point in the number. NUMBER? addr -- l flag F83 "number-question" Convert the counted string at address addr into a 32-bit integer l. flag is true if the string contained only convertible characters. Convertible characters are digits in the current base, minus (-), and period (.). If the string contains unconvertible characters, flag is 0, and l is the number that was collected before the unconvertible character was encountered. For example, if the string is "123xyz", l is 123 and flag is 0. NUMBER addr -- l Deferred (NUMBER addr -- l Default F83 "paren-number" Convert the counted string at address addr, to a signed 32-bit number l, using the value of BASE. If the string contains unconvertible characters, NUMBER aborts. See: NUMBER? Implementation Note: In this implementation, NUMBER is a deferred word so that the user may substitute another implementation if desired. The default implementation is (NUMBER . In particular, it is often desireable not to abort if the string is not a number. NUMBER? is useful for this case. **** STRINGS **** /STRING addr1 len1 n -- addr2 len2 F83 If n is less than len1, addr2 is addr1 plus n and len2 is len1 minus n. If n is greater than or equal to len1, addr2 is addr1 plus len1 and len2 is zero. This accomplishes the effect of removing the first n characters from the string specified by addr1 and len1. PLACE addr1 len addr2 -- F83 The string specified by addr1 and len is moved to addr2. 'WORD -- addr F83 "tick-word" addr is the address that was returned by the previous execution of WORD , unless the dictionary pointer has been modified since WORD was executed. UPC char -- upper-case-char F83 upper-case-char is the upper case version of char. If char is not a lower case letter, it is left unchanged. LCC char -- lower-case-char F83 lower-case-char is the lower case version of char. If char is not a upper case letter, it is left unchanged. CANONICAL addr -- addr Local addr is the address of a packed string. That string is converted to "canonical form", the form in which names are stored in the dictionary. If CAPS contains zero, no action is taken. If CAPS contains nonzero, the dictionary is assumed to be all of a single case, and the string at addr is converted to that case. In this implementation, the "canonical form" is lower case. ", addr len -- Local "string-comma" addr is the address and len the length of an array of bytes. That array is stored in the dictionary at HERE as a packed string, and the dictionary pointer is advanced to allocate the space used by the string. ," -- (compiling) Local "comma-string" Used in the form: ," " A string , delimited by a double-quote character, is accepted from the input stream and stored in the dictionary at HERE, as a packed string, and the dictionary pointer is advanced to allocate the space used by the string. " -- addr Local "string" Used in the form: " ccc" Characters ccc are accepted from the input stream up to but not including the delimiting " (close-quote). The characters are stored in memory as a packed string and the address of that string addr is left on the stack. The first blank following " is not part of ccc, but ccc may contain blanks. ["] -- (compiling) Local,C,I "bracket-string" Used in the form: ["] ccc" Characters ccc are accepted from the input stream up to but not including the delimiting " (close-quote). The characters are stored in the dictionary as a packed string so that when the colon definition is later executed, the address of the string will be left on the stack. The first blank following " is not part of ccc, but ccc may contain blanks. "" -- addr Local "quote-quote" Used in the form: "" A sequence of characters not containing blanks is accepted from the input stream. The characters are stored in memory as a packed string and the address of that string addr is left on the stack. The blank after "", and any other blanks that may be between "" and the first non-blank character of are skipped. This is a very useful word, since it is very often desired to get a name such as a filename that is not allowed to contain any blanks. [""] -- (compiling) Local,C,I "bracket-quote-quote" Used in the form: [""] A sequence of characters not containing blanks is accepted from the input stream. The characters are stored in the dictionary as a packed string so that when the colon definition is later executed, the address of the string will be left on the stack. The blank after [""] , and any other blanks that may be between [""] and the first non-blank character of are skipped. **** COMPILING **** \ -- F83 "backslash" Ignore the remainder of the current input line. DEFINED -- addr 0 F83 or -- cfa n Used in the form: DEFINED If is found in the currently active search order, cfa is the compilation address of that word and n is 1 if the word is immediate, or -1 if the word is not immediate. If is not found, addr is that address of a packed string representing the "canonical form" (see CANONICAL) of that word. ?MISSING flag -- F83 If flag is true, aborts and prints the name of the last word read from the input stream, followed by a question mark (?). If flag is false, no action is taken. ASCII -- char I,M -- (compiling) Used in the form: ASCII ccc where the delimiter of ccc is a space. char is the ASCII character value of the first character in ccc. If interpreting, char is left on the stack. If compiling, compile char as a literal so that when the colon definition is later executed, char is left on the stack. CONTROL -- char I,M -- (compiling) Used in the form: CONTROL ccc where the delimiter of ccc is a space. char is the control character value of the first character in ccc. For example, if ccc is J, character is control J, or decimal 10. ccc may be either upper or lower case, with the same results either way. If interpreting, char is left on the stack. If compiling, compile char as a literal so that when the colon definition is later executed, char is left on the stack. CREATE -- Deferred M,79 (CREATE -- Default A defining word executed in the form: CREATE Creates a dictionary entry for . After is created, the next available dictionary location is the first byte of 's parameter field. When is subsequently executed, the address of the first byte of 's parameter field is left on the stack. CREATE does not allocate space in 's parameter field. Implementation Note: In this implementation, CREATE is a deferred word so that the user may substitute another implementation of CREATE if desired. The default implementation is (CREATE . "CREATE str -- M,Local "string-create" A defining word which takes it's name argument from the stack instead of from the input stream. str is the address of a packed string which is a name. Creates a dictionary entry for that name. After the name is created, the next available dictionary location is the first byte of that name's parameter field. When that name is subsequently executed, the address of the first byte of it's parameter field is left on the stack. "CREATE does not allocate space in the parameter field. See: CREATE !CSP -- F83 Remembers the current value of the stack pointer. Used in conjunction with ?CSP as a sanity check while compiling, to make sure that the stack depth does not change during the compilation of a word. ?CSP -- F83 Compares the current value of the stack pointer against a previously-remembered value. Used in conjunction with !CSP as a sanity check while compiling, to make sure that the stack depth does not change during the compilation of a word. HIDE -- F83 Makes the most recently created dictionary entry invisible, so that it will not be found in the dictionary, regardless of whether the entry was previously visible or invisible. Used to implement the behavior of : which states that a newly created word definition cannot be found in the dictionary until the corresponding ; or ;CODE is successfully processed. See: REVEAL In many other Forth implementations, this function is is performed by a word called SMUDGE . SMUDGE was a toggle, in that the way to undo a SMUDGE was to do another SMUDGE . The problem with this was that it was easy to screw up by executing SMUDGE when the word was already visible, thus making it invisible by mistake. The reason for making a word invisible while compiling it is so that you can redefine a word in terms of its old definition. For example, if you already have a word FOO , and you want a new word FOO which is the same as the old one except that it also does a carriage return, you could make the new one as follows: : FOO FOO CR ; A better example is found in the cold start initialization code. See (COLD REVEAL -- F83 Makes the most recently created dictionary entry visible, so that it will be found in the dictionary, regarless of whether the entry was previously visible or invisible. Used to implement the behavior of ; and ;CODE which allow the newly created word to be found. See: HIDE **** DICTIONARY MAINTENANCE **** (FORGET cfa -- F83 "paren-forget" cfa is the compilation address of a word. that word is deleted from the dictionary and also all words added to the dictionary after that word, regardless of their vocabulary. Implementation Note: The variable FENCE contains an address which is used to prevent accidentally FORGET'ing some critical part of the system. If the value store in FENCE is greater than cfa, (FORGET will abort with the message "below fence". **** CONTROL STRUCTURES **** ?LEAVE flag -- C,I,F83 "question-leave" -- (compiling) If flag is nonzero, transfers control to just beyond the next LOOP or +LOOP . The loop is terminated and loop control parameters are discarded. If flag is zero, no action is taken. May only be used in the form: DO ... ?LEAVE ... LOOP or DO ... ?LEAVE ... +LOOP ?LEAVE may appear within other control structures which are nested within the do-loop structure. More than one LEAVE may appear within a do-loop. See: "9.3 Return Stack". ?LEAVE is equivalent to the phrase "IF LEAVE THEN" ?DO w1 w2 -- C,I,F83 "question-do" -- sys (compiling) Used in the form: ?DO ... LOOP or ?DO ... +LOOP Begins a loop which terminates based on control parameters. The loop index begins at w2, and terminates based on the limit w1. See LOOP and +LOOP for details on how the loop is terminated. Unlike DO, loops begun with ?DO are not executed at all if w1 is equal to w2. sys is balanced with its corresponding LOOP or +LOOP . Note: When you write a do-loop, think carefully about whether you really want the loop to execute at least once. A large percentage of the time, ?DO is called for instead of DO . LLITERAL -- l C,I,32 l -- (compiling) Typically used in the form: [ 32-bit-number ] LLITERAL Compiles a system dependent operation so that when later executed, a 32 bit longword will be left on the stack. **** INTERPRETER IMPLEMENTATION **** LOSE -- Local Prints the message "Undefined word encountered" and aborts. LOSE is compiled into a colon definition when the compiler encounters an undefined word. If that colon definition is later executed, LOSE will execute and abort. This is in contrast to some other Forth systems which abort right away when the compiler sees an undefined word. Using the LOSE scheme, the compilation does not terminate upon encountering the undefined word, but instead proceeds and finds any other undefined words that may be in the file. This is a good scheme if compilation is very fast, as it is on the Sun Workstation. "COMPILE addr -- Local addr is the address of a packed string. That string represents a name that is either interpreted or compiled, according to the value of STATE and the immediate attribute on the word. See: forth/doc/interpreter.pr DO-DEFINED cfa -1 | cfa 1 -- ?? Deferred Local INTERPRET-DO-DEFINED cfa -1 | cfa 1 -- ?? Interpreting Local COMPILE-DO-DEFINED cfa -1 | cfa 1 -- Compiling DO-DEFINED is executed from within "COMPILE if the word under consideration is found in the dictionary. If the STATE is interpreting, INTERPRET-DO-DEFINED is installed in DO-DEFINED ; INTERPRET-DO-DEFINED simply executes the word. If the STATE is compiling, COMPILE-DO-DEFINED is installed in DO-DEFINED ; COMPILE-DO-DEFINED executes the word if the flag is 1, indicating that the word has the immediate attribute, or compiles the word if the flag is -1 (not immediate). The behavior of the text interpreter can be altered to make it do some pretty powerful things by installing still other words in DO-DEFINED . See: forth/doc/interpreter.pr LITERAL? str -- str false | literal true Deferred Local (LITERAL? str -- str false | literal true Default LITERAL? is called from within "COMPILE if the word under consideration was not found in the dictionary. LITERAL? decides if the string represents some value that should be compiled as a literal (e.g. a number). (LITERAL? is the default implementation of LITERAL? . (LITERAL? just checks to see if the string is a number. Other kinds of literals, such as string literals or floating point numbers or whatever, could be handled by installing a different word in LITERAL? . DO-LITERAL literal -- ?? Deferred Local INTERPRET-DO-LITERAL l -- l | n Interpreting COMPILE-DO-LITERAL l -- Compiling DO-LITERAL (not to be confused with the famous Doctor) is called from within "COMPILE if LITERAL? decides that that word under consideration is a literal. If the STATE is interpreting, INTERPRET-DO-LITERAL is installed in DO-LITERAL . INTERPRET-DO-LITERAL leaves the literal number on the stack. If the stack width is 16 bits, it uses DOUBLE? to decide if the number should be left as a "normal" or a "long". If the stack width is 32 bits, "normal" and "long" are the same. If the STATE is interpreting, COMPILE-DO-LITERAL is installed in DO-LITERAL . COMPILE-DO-LITERAL compiles a system dependent operation so that when later executed, the literal number will be left on the stack. If LITERAL? is changed to recognize other kinds of literals than just numbers, an appropriate word can be installed in DO-LITERAL to handle the other types of literals. DO-UNDEFINED str -- Deferred Local INTERPRET-DO-UNDEFINED str -- Interpreting COMPILE-DO-UNDEFINED str -- Compiling DO-UNDEFINED is called from within "COMPILE if the word under consideration is neither a previously-defined word nor a literal. If the STATE is interpreting, INTERPRET-DO-UNDEFINED is installed in DO-UNDEFINED . INTERPRET-DO-UNDEFINED prints an error message and throws away the rest of the input line. If the STATE is compiling, COMPILE-DO-UNDEFINED is installed in DO-UNDEFINED . COMPILE-DO-UNDEFINED prints an error message and compiles LOSE . See: LOSE See forth/doc/interpreter.pr for suggestions on how DO-UNDEFINED may be changed to make the text interpreter do interesting things. MORE? str -- str flag Local str is the address of a packed string. flag is true if the string is not zero-length, indicating that the input stream has not been exhausted. **** BOOTING **** WARM -- Local WARM is called when the Forth system is restarted after having been interrupted for some reason. WARM calls WARM-HOOK and then calls QUIT to give control to the text interpreter. See: WARM-HOOK Under Unix, certain signals such as SIGINT cause a warm start. Running stand-alone, the PROM monitor can jump to the Forth warm start entry point at hex 20004. WARM-HOOK -- Deferred (WARM-HOOK -- Default When the Forth system is restarted, WARM calls the deferred word WARM-HOOK to do any cleanup that is necessary. (WARM-HOOK is installed in WARM-HOOK by default; (WARM-HOOK clears the stacks. COLD -- Local COLD-HOOK -- Deferred Local (COLD-HOOK -- Default COLD is the first word called when the Forth system is first starting up. It initializes the user area then calls COLD-HOOK to perform some more initialization. (COLD-HOOK is the default implementation of COLD-HOOK; it sets BASE to decimal and makes the FORTH vocabulary the CONTEXT and CURRENT vocabulary. Packages loaded on top of the kernel can arrange to have their own initialization code performed when the Forth system is started by redefining (COLD-HOOK and installing the new version in COLD-HOOK as follows: : (COLD-HOOK (COLD-HOOK NEW-INIT ; ' (COLD-HOOK IS COLD-HOOK .ID nfa -- F83 "dot-i-d" nfa is a name field address of a dictionary entry. The name of that entry is printed. RECURSIVE -- C,I,F83 Used when compiling a colon definition. Makes the name of the colon definition being compiled visible, so that it will be found in the dictionary. This allows the word to be used recursively by compiling the name of the word inside of its own definition. For example, here is a recursive definition of factorial. : FACTORIAL ( n -- n-factorial ) RECURSIVE DUP IF DUP 1- FACTORIAL * ELSE 1+ THEN ; WHERE -- Deferred F83 (WHERE -- Default Local Tries to print a sensible message telling you the current location in the input stream. Called from ABORT and ABORT" . WHERE is deferred so a different implementation may be substituted. The default implementation (WHERE tells you the name of the last word that was defined, which is reasonably useful if you are compiling from a file. Another plausible implementation would attempt to place you in an editor positioned at the place where the error occurred. This kind of implementation is especially suitable for systems which compile relatively slowly; on the Sun Workstation, compilation is so fast that it is usually preferable to just get a list of all the errors, then fix them all at the same time. >USER pfa -- user-var-addr Local user-var-addr is the address of the data storage area of the user variable whose parameter field address is pfa. In this implementation, vocabularies and deferred words also keep their data in the user area, so >USER also works for them. WVARIABLE -- M,Local A defining word executed in the form: WVARIABLE A dictionary entry for is created and enough space for a 16 bit word is ALLOT'ed in its parameter field. This parameter field is to be used for contents of the variable. The application is responsible for initializing the contents of the variable which it creates. When is later executed, the address of its parameter field is placed on the stack. DEFER -- F83 A defining word executed in the form: DEFER Creates a dictionary entry for and makes it an "execution variable". is similar to a variable which contains the compilation address of another word; that other word is executed when is executed. The "other word" to be executed is stored into the data area of by IS or (IS . If is executed before it has been initialized by IS or (IS , an error message will be printed. See: IS (IS CRASH In this implementation, the data area where the address of the other word is stored is in the user area. CRASH -- F83 CRASH is the word which is installed in a deferred word when it is first defined, before some other word has been explicitly installed with IS (IS . If the deferred word which contains CRASH is executed, CRASH will abort with the message: <--deferred word not initialized where is the deferred word. There is an obscure case in which CRASH will print the wrong , but it is rare. The obscure case is this: if the deferred word was executed by pushing its compilation address on the stack, then using EXECUTE to execute it, CRASH does not have enough information to find the name of the deferred word; instead it will print the name of the last word interpreted from the input stream. (IS target-cfa deferred-cfa -- Local deferred-cfa is the compilation address of a deferred word. target-cfa is the compilation address of some other word. The target word is installed in the deferred so that execution of the deferred word will actually cause the execution of the target word. Example: ' (WARM-CODE ' WARM-CODE (IS IS target-cfa -- Interpreting Local Used in the form: ' IS is a deferred word. target-cfa is the compilation address of some other word. The target word is installed in the deferred so that execution of the deferred word will actually cause the execution of the target word. .OK -- Local Prints the Forth prompt "ok ". If the cursor is not at the beginning of a line when .OK is executed, .OK first does a CR . This behavior insures that the prompt occurs at the beginning of a line on the terminal, but does not generate spurious blank lines if the cursor was already at the beginning of a line. OK -- Local No action is taken. Defining OK to do nothing means that previous Forth command lines may be picked up with an editor or a mouse and fed back to the Forth interpreter without having to worry about stripping off the "ok " prompt from the line to be repeated. PROMPT -- Deferred Local (PROMPT -- Default Local PROMPT is executed before input is read from the input stream. It is conventionally set to print some prompt, such as the usual Forth prompt "ok ". Since it is deferred, any kind of prompt that you want may be installed instead. (PROMPT is installed in PROMPT by default. (PROMPT calls .OK to print the "ok " prompt, but it attempts to be smart by not prompting if the standard input is coming from a file. There is also a variable ?INTERACTIVE which may be used to control prompting. If ?INTERACTIVE contains zero, (PROMPT will not print anything. INPUT-FROM-FILE? -- flag Local flag is true if the input stream is coming from a file instead of from an interactive terminal. (PROMPT uses this to turn off prompting if a file is the input. The C wrapper program is the ultimate source of this information. STATUS -- Deferred F83 STATUS is called whenever the system prompts for more input. By default, NOOP is installed in STATUS . The system can be made to do convenient things before every prompt by installing an appropriate word in STATUS . For example: ' .S IS STATUS causes the stack contents to be printed before every prompt. KEY? -- flag Deferred F83 (KEY? -- flag Default Local flag is true if a character is waiting in the input stream. Implementation Notes: KEY? is deferred so that the Forth system may be easily configured to run in different environments (e.g. under Unix or stand-alone). (KEY? is the default implementation, which performs the key? function for Unix. When running under Unix, the normal tty mode is "cooked", which buffers an entire line of characters before it is made available to the Forth system. This means that any keys typed will not be seen until a return is also typed. If it is necessary to see characters immediately after they are typed, the tty driver may be put into "raw" mode with the Unix command "stty raw". .VERSION -- Local Prints the version number of this Forth system. At the time of this writing, the current version is 3.0.0 . TITLE -- F83 Prints the message 68000 Forth 83 - Unix version 3.0.0 ERROR-OUTPUT -- Deferred Local RESTORE-OUTPUT -- Deferred Local ERROR-OUTPUT is called before an error message is printed. RESTORE-OUTPUT is called after an error message is printed. If the file system is loaded, ERROR-OUTPUT causes output to go to the Unix standard output and RESTORE-OUTPUT restores the output stream to its previous destination. Before the file system is loaded, ERROR-OUTPUT and RESTORE-OUTPUT are NOOP's. PAUSE -- Deferred Local Used in multitasking. Causes the current task to be suspended and the next task in the task list to be activated. Before the multi-tasking package is loaded, this executes NOOP . 'TIB -- addr U,F83 "tick-t-i-b" The address on the stack of a variable which contains the address of the text input buffer. The text input buffer is an area of memory used to input from the input stream. It is possible to temporarily change the text input buffer by changing the contents of 'TIB . OFF addr -- F83 Store zero (false) at address `addr'. ON addr -- F83 Store -1 (true) at address `addr'.