CODE
( "name" -- )
CODE ( "name" -- )

call ALSO and add ASSEMBLER wordlist if available. Add PROC ENTER assembler snippet as needed for the architecture into the PFA. The CFA is setup (a) with the PFA adress in traditional ITC or (b) with an infoblock as for sbr-coded colon words.

Remember that not all architectures are support and that the ASSEMBLER wordset is not compiled into pfe by default. Use always the corresponding END-CODE for each CODE start. The new word name is not smudged.

END-CODE
( "name" -- )
END-CODE ( "name" -- )

call PREVIOUS and add PROC LEAVE assembler snippet as needed for the architecture - usually includes bits to "return from subroutine". Remember that not all architectures are support and PFE usually does only do variants of call-threading with a separate loop for the inner interpreter that does "call into subroutine". Some forth implementations do "jump into routine" and the PROC LEAVE part would do "jump to next routine" also known as next-threading. The sbr-call-threading is usually similar to the native subroutine-coding of the host operating system. See CODE

BLOCK
( block-u -- block-addr )
[ANS]
BLOCK ( block-u -- block-addr ) [ANS]

load the specified block into a block buffer and return the address of that block buffer - see also BUFFER

BUFFER
( block-u -- block-addr )
[ANS]
BUFFER ( block-u -- block-addr ) [ANS]

get the block buffer address for the specified block - if it had not been loaded already it is not filled with data from the disk unlike BLOCK does.

SAVE-BUFFERS
( -- )
[ANS]
SAVE-BUFFERS ( -- ) [ANS]

write all modified buffer to the disk, see UPDATE and FLUSH

EMPTY-BUFFERS
( -- )
[ANS]
EMPTY-BUFFERS ( -- ) [ANS]

unassign all block buffers, does not even UPDATE

FLUSH
( -- )
[ANS]
FLUSH ( -- ) [ANS]

call SAVE-BUFFERS and then unassign all block buffers with EMPTY-BUFFERS

LIST
( block-u -- )
[ANS]
LIST ( block-u -- ) [ANS]

display the block

LOAD
( block-u -- ?? )
[FORTH]
LOAD ( block-u -- ?? ) [FORTH]

INTERPRET the specified BLOCK

THRU
( block1-u block2-u -- )
[ANS]
THRU ( block1-u block2-u -- ) [ANS]

LOAD a number of block in sequence.

UPDATE
( -- )
[ANS]
UPDATE ( -- ) [ANS]

mark the current block buffer as modified, see FLUSH

BLK
( -- block-u* )
[ANS]
BLK ( -- block-u* ) [ANS]

the direct use of BLK and SCR is depracated (very traditional variables for I/O system)

SCR
( -- scr-n* )
[ANS]
SCR ( -- scr-n* ) [ANS]

the direct use of BLK and SCR is depracated (very traditional variables for I/O system)

CLOSE-BLOCKFILE
( -- )
[FTH] w32for
CLOSE-BLOCKFILE ( -- ) [FTH] w32for

w32for-implementation:

      blockhandle -1 <> if flush close-file drop then
      -1 set-blockfile

in pfe:

      : CLOSE-BLOCKFILE
        BLOCK-FILE ?DUP IF FLUSH CLOSE-FILE DROP THEN
        OFF> BLOCK-FILE ;

OPEN-BLOCKFILE
( "filename" -- )
[FTH] w32for
OPEN-BLOCKFILE ( "filename" -- ) [FTH] w32for

w32for-implementation:

        close-blockfile
        parse-word r/w open-file abort" failed to open block-file"
        set-blockfile
        empty-buffers

CREATE-BLOCKFILE
( blocks-count "filename" -- )
[FTH] w32for
CREATE-BLOCKFILE ( blocks-count "filename" -- ) [FTH] w32for

w32for-implementation:

        close-blockfile
        parse-word r/w create-file abort" failed to create block-file"
        set-blockfile
        dup b/buf m* blockhandle resize-file
        abort" unable to create a file of that size"
        empty-buffers
        0 do i wipe loop
        flush

pfe does not wipe the buffers

USING
( "filename" -- )
[EXT] [obsolete]
USING ( "filename" -- ) [EXT] [obsolete]

use filename as a block file OBSOLETE word, use OPEN-BLOCKFILE

      : USING OPEN-BLOCKFILE ;

USING-NEW
( "filename" -- )
[EXT] [obsolete]
USING-NEW ( "filename" -- ) [EXT] [obsolete]

like USING but can create the file OBSOLETE word, use CREATE-BLOCKFILE

      : USING-NEW 0 CREATE-BLOCKFILE ;

SET-BLOCKFILE
( block-file* -- )
[EXT] win32for
SET-BLOCKFILE ( block-file* -- ) [EXT] win32for

win32forth uses a system-filedescriptor where -1 means unused in the BLOCKHANDLE, but we use a "FILE*"-like structure, so NULL means NOT-IN-USE. Here we set it.

BLOCK-FILE
( -- block-file* )
[EXT]
BLOCK-FILE ( -- block-file* ) [EXT]

return blockhandle as last set by SET-BLOCKFILE

B/BUF
( -- bytesperbuffer-count )
[EXT]
B/BUF ( -- bytesperbuffer-count ) [EXT]
#ELSE
( -- )
[FTH]
#ELSE ( -- ) [FTH]

The implementation of #ELSE is done in C for speed and being less error prone. Better use the ANSI-compatible [IF] [ELSE] [THEN] construct.

#ENDIF
( -- )
[FTH]
#ENDIF ( -- ) [FTH]

end of #IF #IFDEF #IFNOTDEF and #ELSE contructs

        (a dummy word that does actually nothing, but #ELSE may look for it)

#IF
( -- C: state-save-flag mfth-if-magic S: )
[FTH]
#IF ( -- C: state-save-flag mfth-if-magic S: ) [FTH]

prepares for a following #IS_TRUE or #IS_FALSE, does basically switch off compile-mode for the enclosed code.
better use the ANSI style [IF] [ELSE] [THEN] construct.

#IS_TRUE
( C: state-save-flag mfth-if-magic S: test-flag -- )
[FTH]
#IS_TRUE ( C: state-save-flag mfth-if-magic S: test-flag -- ) [FTH]

checks the condition on the `CS-STACK`.
Pairs with #IF
better use the ANSI style [IF] [ELSE] [THEN] construct.

#IS_FALSE
( C: state-save-flag mfth-if-magic S: test-flag -- )
[FTH]
#IS_FALSE ( C: state-save-flag mfth-if-magic S: test-flag -- ) [FTH]

checks the condition on the `CS-STACK`.
Pairs with #IF
better use the ANSI style [IF] [ELSE] [THEN] construct.

#IFDEF
( "word" -- )
[FTH]
#IFDEF ( "word" -- ) [FTH]

better use `[DEFINED] word [IF]` - the word [IF] is ANSI-conform.

#IFNOTDEF
( "word" -- )
[FTH]
#IFNOTDEF ( "word" -- ) [FTH]

better use `[DEFINED] word [NOT] [IF]` - the word [IF] and [ELSE] are ANSI-conform, while #IFDEF #ELSE are not.

//
( [...<cr>] -- )
[FTH]
// ( [...<cr>] -- ) [FTH]

a line-comment

#define
( "name" "value" -- )
[FTH]
#define ( "name" "value" -- ) [FTH]

create an alias, will actually make a DEFERed word, and it has the magic to handle number-arguments

#pragma
( "word" "evaluate<cr>" -- )
[FTH]
#pragma ( "word" "evaluate<cr>" -- ) [FTH]

pass the word to ENVIRONMENT? If the word does *not* exist, the rest of the line is parsed away with // - therefore, if the executed word does not consume the line itself, the rest of the line is still executed. examples:

      #pragma warnings on // if warnings is a variable, ON can set it
      #pragma stack-cells 50 < [if] .( not enough stackcells ) [then]
      #pragma simply anything else you like to have in environment or not

implementation:

      : #pragma ?exec
        bl word count environment? if exit then ( interpret the rest of the line )
        [compile] \               ( parse away the rest of the line as a comment )
      ;

link,
( some-list* -- )
[EXT]
link, ( some-list* -- ) [EXT]

      : link,        here over @ a, swap ! ;

chain-link
( -- chain-link* )
[EXT]
chain-link ( -- chain-link* ) [EXT]

a system variable used at new-chain

new-chain
( "name" -- )
[EXT] [DOES: -- new-chain* ]
new-chain ( "name" -- ) [EXT] [DOES: -- new-chain* ]

create a new chain and register in chain-link

      : new-chain create: 0 , ['] noop , chain-link link, ;

layout of a chain: /cell field ->chain.link /cell field ->chain.exec /cell field ->chain.next

.chain
( some-chain* -- )
[EXT]
.chain ( some-chain* -- ) [EXT]

show chain - compare with WORDS

.chains
( -- )
[EXT]
.chains ( -- ) [EXT]

show all chains registered in the system - compare with VLIST

do-chain
( some-chain* -- )
[EXT]
do-chain ( some-chain* -- ) [EXT]

execute chain

      : do-chain being @ ?dup while dup>r cell+ @execute r> repeat ;

chain-add-before
( some-chain* "word-to-add" -- )
[EXT]
chain-add-before ( some-chain* "word-to-add" -- ) [EXT]

add chain item, for reverse chain like BYE

      : chain-add-before ' >r here over @ , r> , swap ! ;
      ( chain-add-before link, ' , )

chain-add
( some-chain* "word-to-add" -- )
[EXT]
chain-add ( some-chain* "word-to-add" -- ) [EXT]

add chain item, for normal setup, at end of do-chain

      : chain-add ' >r begin dup @ while @ repeat here swap ! 0 , r> , ;
      ( chain-add begin dup @ while @ repeat  here swap ! 0, ' , )

semicolon-chain
( -- semicolon-chain* )
[EXT] [OLD]
semicolon-chain ( -- semicolon-chain* ) [EXT] [OLD]

do not use.

NEW-WORDLIST
( "name" -- )
[EXT] [DOES: -- new-wordlist* ]
NEW-WORDLIST ( "name" -- ) [EXT] [DOES: -- new-wordlist* ]

create a new WORDLIST and a "name" with a runtime of ( -- wordlist* )

      : NEW-WORDLIST WORDLIST VALUE ;
      : NEW-WORDLIST CREATE: WORDLIST ;

usually used for DO-ALL-WORDS / DO-SYNONYM

.WORDS
( some-wordlist* -- )
[EXT]
.WORDS ( some-wordlist* -- ) [EXT]

print the WORDLIST interactivly to the user

      : .WORDS ALSO SET-CONTEXT WORDS PREVIOUS ;

WORDS / ORDER / NEW-WORDLIST / DO-ALL-WORDS

DO-ALL-WORDS
( some-wordlist* -- )
[EXT]
DO-ALL-WORDS ( some-wordlist* -- ) [EXT]

EXECUTE each entry in the wordlist in the reverse order defined

      : DO-ALL-WORDS
           0 FIRST-NAME
           BEGIN ?DUP WHILE
              DUP NAME> EXECUTE
              NAME-NEXT
           REPEAT
      ;

to run the NEW-WORDLIST in original order, use REDO-ALL-WORDS

REDO-ALL-WORDS
( some-wordlist* -- )
[EXT]
REDO-ALL-WORDS ( some-wordlist* -- ) [EXT]

EXECUTE each entry in the wordlist in the original order defined

      : REDO-ALL-WORDS
           0 FIRST-NAME
           0 SWAP ( under )
           BEGIN ?DUP WHILE
              DUP NAME> SWAP ( under )
              NAME-NEXT
           REPEAT
           BEGIN ?DUP WHILE
              EXECUTE
           REPEAT
      ;

to run the NEW-WORDLIST in last-run-first order, use DO-ALL-WORDS

DO-ALL-WORDS-WHILE-LOOP
( some-wordlist* test-xt* -- )
[EXT]
DO-ALL-WORDS-WHILE-LOOP ( some-wordlist* test-xt* -- ) [EXT]

EXECUTE each entry in the wordlist in the reverse order defined but only as long as after EXECUTE of "word" a TRUE flag is left on the stack. The wordlist execution is cut when a FALSE flag is seen. (the current wordlist entry is _not_ on the stack!)

      : DO-ALL-WORDS-WHILE-LOOP >R
           0 FIRST-NAME
           BEGIN ?DUP WHILE
              R@ EXECUTE 0= IF R>DROP DROP EXIT THEN
              DUP NAME> EXECUTE
              NAME-NEXT
           REPEAT R>DROP
      ;

compare with DO-ALL-WORDS-WHILE

DO-ALL-WORDS-WHILE
( some-wordlist* "word" -- )
[EXT]
DO-ALL-WORDS-WHILE ( some-wordlist* "word" -- ) [EXT]

EXECUTE each entry in the wordlist in the reverse order defined but only as long as after EXECUTE of "word" a TRUE flag is left on the stack. The wordlist execution is cut when a FALSE flag is seen. (the current wordlist entry is _not_ on the stack!)

      : DO-ALL-WORDS-WHILE '
           STATE @ IF LITERAL, COMPILE DO-ALL-WORDS-WHILE-LOOP EXIT THEN
           >R 0 FIRST-NAME
           BEGIN ?DUP WHILE
              R@ EXECUTE 0= IF R>DROP DROP EXIT THEN
              DUP NAME> EXECUTE
              NAME-NEXT
           REPEAT R>DROP
      ;

to run the NEW-WORDLIST in original order, use REDO-ALL-WORDS

DO-SYNONYM
( some-wordlist* "do-name" "orig-name" -- )
[EXT]
DO-SYNONYM ( some-wordlist* "do-name" "orig-name" -- ) [EXT]

create a SYNONYM in the specified wordlist.

      : DO-SYNONYM GET-CURRENT SWAP SET-CURRENT SYNONYM SET-CURRENT ;

DO-ALIAS / DO-ALL-WORDS / NEW-WORDLIST / WORDLIST / ORDER

ALIAS-ATEXIT
( some-xt* "name" -- )
[EXT]
ALIAS-ATEXIT ( some-xt* "name" -- ) [EXT]

create a defer word that is initialized with the given x-token.

      : ALIAS-ATEXIT ATEXIT-WORDLIST DO-ALIAS ;

ATEXIT-WORDLIST DO-ALL-WORDS

DO-ALIAS
( some-xt* definition-wordlist* "do-name" -- )
[EXT]
DO-ALIAS ( some-xt* definition-wordlist* "do-name" -- ) [EXT]

create an ALIAS with the exec-token in the specified wordlist

      : DO-ALIAS GET-CURRENT SWAP SET-CURRENT SWAP ALIAS SET-CURRENT ;

DO-SYNONYM

ATEXIT-WORDLIST
( -- atexit-do-wordlist* )
[EXT]
ATEXIT-WORDLIST ( -- atexit-do-wordlist* ) [EXT]

BYE will run this wordlist, last added being run first

      : BYE ... ATEXIT-WORDLIST DO-ALL-WORDS ... ;
      : FORGET ... ATEXIT-WORDLIST DO-ALL-WORDS-WHILE BIGGER-THAN-HERE ... ;
      WORDLIST VALUE ATEXIT-WORDLIST

DO-ALL-WORDS / LOADED note: parts of these will be run by FORGET when the HERE mark becomes lower than the definition you had added after that to this chainlist. (that is to run destroyer aliases). ALIAS-ATEXIT / FORGET

PROMPT-WORDLIST
( -- prompt-do-wordlist* )
[EXT]
PROMPT-WORDLIST ( -- prompt-do-wordlist* ) [EXT]

QUIT inits will run this wordlist, last added being run first

      : QUIT ... PROMPT-WORDLIST DO-ALL-WORDS ... ;
      WORDLIST VALUE PROMPT-WORDLIST

DO-ALL-WORDS / ABORT-WORDLIST

ABORT-WORDLIST
( -- abort-redo-wordlist* )
[EXT]
ABORT-WORDLIST ( -- abort-redo-wordlist* ) [EXT]

ABORT inits will run this wordlist, first added being run first

      : ABORT ... ABORT-WORDLIST REDO-ALL-WORDS ... ;
      WORDLIST VALUE ABORT-WORDLIST

REDO-ALL-WORDS / PROMPT-WORDLIST

Z@
( addr -- f: z )
Z@ ( addr -- f: z )
Z!
( addr f: z -- )
Z! ( addr f: z -- )
X@
( zaddr -- f: x )
X@ ( zaddr -- f: x )
X!
( zaddr f: x -- )
X! ( zaddr f: x -- )
Y@
( zaddr -- f: y )
Y@ ( zaddr -- f: y )
Y!
( zaddr f: x -- )
Y! ( zaddr f: x -- )
Z.
(f: z -- )
Z. (f: z -- )

Emit the complex number, including the sign of zero when signbit() is available.

ZS.
(f: z -- )
ZS. (f: z -- )

Emit the complex number in scientific notation, including the sign of zero when signbit() is available.

REAL
(f: x y -- x )
REAL (f: x y -- x )
IMAG
(f: x y -- y )
IMAG (f: x y -- y )
CONJG
(f: x y -- x -y )
CONJG (f: x y -- x -y )
ZDROP
(f: z -- )
ZDROP (f: z -- )
ZDUP
(f: z -- z z )
ZDUP (f: z -- z z )
ZSWAP
(f: z1 z2 -- z2 z1 )
ZSWAP (f: z1 z2 -- z2 z1 )
ZOVER
(f: z1 z2 -- z1 z2 z1 )
ZOVER (f: z1 z2 -- z1 z2 z1 )
ZNIP
(f: z1 z2 -- z2 )
ZNIP (f: z1 z2 -- z2 )
ZTUCK
(f: z1 z2 -- z2 z1 z2 )
ZTUCK (f: z1 z2 -- z2 z1 z2 )
ZROT
(f: z1 z2 z3 -- z2 z3 z1 )
ZROT (f: z1 z2 z3 -- z2 z3 z1 )
-ZROT
(f: z1 z2 z3 -- z3 z1 z2 )
-ZROT (f: z1 z2 z3 -- z3 z1 z2 )
Z+
(f: z1 z2 -- z1+z2 )
Z+ (f: z1 z2 -- z1+z2 )
Z-
(f: z1 z2 -- z1-z2 )
Z- (f: z1 z2 -- z1-z2 )
Z*
(f: x y u v -- x*u-y*v x*v+y*u )
Z* (f: x y u v -- x*u-y*v x*v+y*u )

Uses the algorithm followed by JVN: (x+iy)*(u+iv) = [(x+y)*u - y*(u+v)] + i[(x+y)*u + x*(v-u)] Requires 3 multiplications and 5 additions.

Z/
(f: u+iv z -- u/z+iv/z )
Z/ (f: u+iv z -- u/z+iv/z )

Kahan-like algorithm *without* due attention to spurious over/underflows and zeros and infinities.

ZNEGATE
(f: z -- -z )
ZNEGATE (f: z -- -z )
Z2*
(f: z -- z*2 )
Z2* (f: z -- z*2 )
Z2/
(f: z -- z/2 )
Z2/ (f: z -- z/2 )
I*
(f: x y -- -y x )
I* (f: x y -- -y x )
-I*
(f: x y -- y -x )
-I* (f: x y -- y -x )
1/Z
(f: z -- 1/z )
1/Z (f: z -- 1/z )

Kahan algorithm *without* due attention to spurious over/underflows and zeros and infinities.

Z^2
(f: z -- z^2 )
Z^2 (f: z -- z^2 )

Kahan algorithm without removal of any spurious NaN created by overflow. It deliberately uses (x-y)(x+y) instead of x^2-y^2 for the real part.

|Z|^2
(f: x y -- |z|^2 )
|Z|^2 (f: x y -- |z|^2 )
Z^N
( n f: z -- z^n )
Z^N ( n f: z -- z^n )
X+
(f: z a -- x+a y )
X+ (f: z a -- x+a y )
X-
(f: z a -- x-a y )
X- (f: z a -- x-a y )
Y+
(f: z a -- x y+a )
Y+ (f: z a -- x y+a )
Y-
(f: z a -- x y-a )
Y- (f: z a -- x y-a )
Z*F
(f: x y f -- x*f y*f )
Z*F (f: x y f -- x*f y*f )
Z/F
(f: x y f -- x/f y/f )
Z/F (f: x y f -- x/f y/f )
F*Z
(f: f x y -- f*x f*y )
F*Z (f: f x y -- f*x f*y )
F/Z
(f: f z -- f/z )
F/Z (f: f z -- f/z )

Kahan algorithm *without* due attention to spurious over/underflows and zeros and infinities.

Z*I*F
(f: z f -- z*if )
Z*I*F (f: z f -- z*if )
-I*Z/F
(f: z f -- z/[if] )
-I*Z/F (f: z f -- z/[if] )
I*F*Z
(f: f z -- if*z )
I*F*Z (f: f z -- if*z )
I*F/Z
(f: f z -- [0+if]/z )
I*F/Z (f: f z -- [0+if]/z )

Kahan algorithm *without* due attention to spurious over/underflows and zeros and infinities.

Z*>REAL
(f: z1 z2 -- Re[z1*z2] )
Z*>REAL (f: z1 z2 -- Re[z1*z2] )

Compute the real part of the complex product without computing the imaginary part. Recommended by Kahan to avoid gratuitous overflow or underflow signals from the unnecessary part.

Z*>IMAG
(f: z1 z2 -- Im[z1*z2] )
Z*>IMAG (f: z1 z2 -- Im[z1*z2] )

Compute the imaginary part of the complex product without computing the real part.

|Z|
(f: x y -- |z| )
|Z| (f: x y -- |z| )
ZBOX
(f: z -- box[z] )
ZBOX (f: z -- box[z] )

Defined *only* for zero and infinite arguments. This difffers from Kahan's CBOX [p. 198] by conserving signs when only one of x or y is infinite, consistent with the other cases, and with its use in his ARG [p. 199].

ARG
(f: z -- principal.arg[z] )
ARG (f: z -- principal.arg[z] )
>POLAR
(f: x y -- r theta )
>POLAR (f: x y -- r theta )

Convert the complex number z to its polar representation, where theta is the principal argument.

POLAR>
(f: r theta -- x y )
POLAR> (f: r theta -- x y )
ZSSQS
(f: z -- rho s: k )
ZSSQS (f: z -- rho s: k )

Compute rho = |(x+iy)/2^k|^2, scaled to avoid overflow or underflow, and leave the scaling integer k. Kahan, p. 200.

ZSQRT
(f: z -- sqrt[z] )
ZSQRT (f: z -- sqrt[z] )

Compute the principal branch of the square root, with Re sqrt[z] >= 0. Kahan, p. 201.

ZLN
(f: z -- ln|z|+i*theta )
ZLN (f: z -- ln|z|+i*theta )

Compute the principal branch of the complex natural logarithm. The angle theta is the principal argument. This code uses Kahan's algorithm for the scaled logarithm CLOGS(z,J) = ln(z*2^J), with J=0 and blind choices of the threshholds T0, T1, and T2. Namely, T0 = 1/sqrt(2), T1 = 5/4, and T2 = 3;

ZEXP
(f: z -- exp[z] )
ZEXP (f: z -- exp[z] )
Z^
(f: x y u v -- [x+iy]^[u+iv] )
Z^ (f: x y u v -- [x+iy]^[u+iv] )

Compute in terms of the principal argument of x+iy.

ZCOSH
(f: z -- cosh[z] )
ZCOSH (f: z -- cosh[z] )
ZSINH
(f: z -- sinh[z] )
ZSINH (f: z -- sinh[z] )
ZTANH
(f: z -- tanh[z] )
ZTANH (f: z -- tanh[z] )

Kahan, p. 204, including his divide by zero signal suppression for infinite values of tan(). To quote the very informative "=>'man math'" on our Darwin system about IEEE 754: "Divide-by-Zero is signaled only when a function takes exactly infinite values at finite operands."

ZCOTH
(f: z -- 1/tanh[z] )
ZCOTH (f: z -- 1/tanh[z] )
ZCOS
(f: z -- cosh[i*z] )
ZCOS (f: z -- cosh[i*z] )
ZSIN
(f: z -- -i*sinh[i*z] )
ZSIN (f: z -- -i*sinh[i*z] )
ZTAN
(f: z -- -i*tanh[i*z] )
ZTAN (f: z -- -i*tanh[i*z] )
ZCOT
(f: z -- -i*coth[-i*z] )
ZCOT (f: z -- -i*coth[-i*z] )
ZACOS
(f: z -- u+iv=acos[z] )
ZACOS (f: z -- u+iv=acos[z] )

Kahan, p.202.

ZACOSH
(f: z -- u+iv=acosh[z] )
ZACOSH (f: z -- u+iv=acosh[z] )

Kahan, p.203.

ZASIN
(f: z -- u+iv=asin[z] )
ZASIN (f: z -- u+iv=asin[z] )

Kahan, p.203.

ZASINH
(f: z -- -i*asin[i*z] )
ZASINH (f: z -- -i*asin[i*z] )

Kahan, p. 203, couth.

ZATANH
(f: z -- u+iv=atanh[z] )
ZATANH (f: z -- u+iv=atanh[z] )

Kahan, p. 203.

ZATAN
(f: z -- -i*atanh[i*z] )
ZATAN (f: z -- -i*atanh[i*z] )

Kahan, p. 204, couth.

ZCONSTANT
( "name" f: z -- )
"name" execution: (f: -- z )
ZCONSTANT ( "name" f: z -- ) "name" execution: (f: -- z )

Define a word that leaves x+iy on the fp stack upon execution.

ZLITERAL Compilation: (f: z -- ) Run: (f: -- z )
ZVARIABLE
( "name" -- )
"name" exection: ( -- zaddr )
ZVARIABLE ( "name" -- ) "name" exection: ( -- zaddr )

Allocate aligned memory for an fp complex number, with the real part first in memory, and define a word that leaves the address on the data stack.

!
( value some-cell* -- | value addr* -- [?] )
[ANS]
! ( value some-cell* -- | value addr* -- [?] ) [ANS]

store value at addr (sizeof CELL)

#
( n,n -- n,n' )
[ANS]
# ( n,n -- n,n' ) [ANS]

see also HOLD for old-style forth-formatting words and PRINTF of the C-style formatting - this word divides the argument by BASE and add it to the picture space - it should be used inside of <# and #>

#>
( n,n -- hold-str-ptr hold-str-len )
[ANS]
#> ( n,n -- hold-str-ptr hold-str-len ) [ANS]

see also HOLD for old-style forth-formatting words and PRINTF of the C-style formatting - this word drops the argument and returns the picture space buffer

#S
( n,n -- 0,0 )
[ANS]
#S ( n,n -- 0,0 ) [ANS]

see also HOLD for old-style forth-formatting words and PRINTF of the C-style formatting - this word does repeat the word # for a number of times, until the argument becomes zero. Hence the result is always null - it should be used inside of <# and #>

CFA'
( 'name' -- name-xt* )
[FTH]
"CFA'" ( 'name' -- name-xt* ) [FTH]

return the execution token of the following name. This word is _not_ immediate and may not do what you expect in compile-mode. See ['] and '> - note that in FIG-forth the word ' had returned the PFA (not the CFA) and therefore this word was introduced being the SYNONYM of the ans-like word '

'
( 'name' -- name-xt* )
[ANS]
"'" ( 'name' -- name-xt* ) [ANS]

return the execution token of the following name. This word is _not_ immediate and may not do what you expect in compile-mode. See ['] and '> - note that in FIG-forth the word of the same name had returned the PFA (not the CFA) and was immediate/smart, so beware when porting forth-code from FIG-forth to ANSI-forth.

(
( 'comment<closeparen>' -- )
[ANS]
"(" ( 'comment<closeparen>' -- ) [ANS]

eat everything up to the next closing paren - treat it as a comment.

*
( a# b# -- mul-a#' | a b -- mul-a' [??] )
[ANS]
"*" ( a# b# -- mul-a#' | a b -- mul-a' [??] ) [ANS]

return the multiply of the two args

*/
( a# b# c# -- scale-a#' | a b c -- scale-a' [??] )
[ANS]
"*\/" ( a# b# c# -- scale-a#' | a b c -- scale-a' [??] ) [ANS]

regard the b/c as element Q - this word has an advantage over the sequence of * and / by using an intermediate double-cell value

*/MOD
( a# b# c# -- div-a# mod-a# | a b c -- div-a mod-a [??] )
[ANS]
"*\/MOD" ( a# b# c# -- div-a# mod-a# | a b c -- div-a mod-a [??] ) [ANS]

has an adavantage over the sequence of * and /MOD by using an intermediate double-cell value.

+
( a* b# -- a*' | a# b* -- b*' | a# b# -- a#' | a b -- a' [??] )
[ANS]
+ ( a* b# -- a*' | a# b* -- b*' | a# b# -- a#' | a b -- a' [??] ) [ANS]

return the sum of the two args

+!
( value# some-cell* -- | value some* -- [?] )
[ANS]
+! ( value# some-cell* -- | value some* -- [?] ) [ANS]

add val to the value found in addr

      simulate:
        : +! TUCK @ + SWAP ! ;

((+LOOP))
( increment# -- )
[HIDDEN]
"((+LOOP))" ( increment# -- ) [HIDDEN]

compiled by +LOOP

+LOOP
( increment# R: some,loop -- )
[ANS]
+LOOP ( increment# R: some,loop -- ) [ANS]

compile ((+LOOP)) which will use the increment as the loop-offset instead of just 1. See the DO and LOOP construct.

,
( value* -- | value# -- | value -- [?] )
[ANS]
"," ( value* -- | value# -- | value -- [?] ) [ANS]

store the value in the dictionary

      simulate:
        : , DP  1 CELLS DP +!  ! ;

-
( a* b# -- a*' | a# b* -- b*' | a# b# -- a#' | a* b* -- diff-b#' | a b -- a' [??] )
[ANS]
"-" ( a* b# -- a*' | a# b* -- b*' | a# b# -- a#' | a* b* -- diff-b#' | a b -- a' [??] ) [ANS]

return the difference of the two arguments

.
( value# -- | value* -- [?] | value -- [??] )
[ANS]
"." ( value# -- | value* -- [?] | value -- [??] ) [ANS]

print the numerical value to stdout - uses BASE

((."))
( -- )
[HIDDEN] skipstring
'((.\"))' ( -- ) [HIDDEN] skipstring

compiled by => ." string"

."
( [string<">] -- )
[ANS]
'.\"' ( [string<">] -- ) [ANS]

print the string to stdout

/
( a# b# -- a#' | a b -- a' [???] )
[ANS]
"/" ( a# b# -- a#' | a b -- a' [???] ) [ANS]

return the quotient of the two arguments

/MOD
( a# b# -- div-a#' mod-a#' | a b -- div-a' mod-a' [??] )
[ANS]
"/MOD" ( a# b# -- div-a#' mod-a#' | a b -- div-a' mod-a' [??] ) [ANS]

divide a and b and return both quotient n and remainder m

0<
( value -- test-flag )
[ANS]
0< ( value -- test-flag ) [ANS]

return a flag that is true if val is lower than zero

      simulate:
       : 0< 0 < ;

0=
( 0 -- test-flag! | value! -- 0 | value -- test-flag )
[ANS]
0= ( 0 -- test-flag! | value! -- 0 | value -- test-flag ) [ANS]

return a flag that is true if val is just zero

      simulate:
       : 0= 0 = ;

1+
( value -- value' )
[ANS]
1+ ( value -- value' ) [ANS]

return the value incremented by one

      simulate:
       : 1+ 1 + ;

1-
( value -- value' )
[ANS]
1- ( value -- value' ) [ANS]

return the value decremented by one

      simulate:
        : 1- 1 - ;

2!
( x,x variable* -- )
[ANS]
2! ( x,x variable* -- ) [ANS]

double-cell store

2*
( a# -- a#' | a -- a' [??] )
[ANS]
2* ( a# -- a#' | a -- a' [??] ) [ANS]

multiplies the value with two - but it does actually use a shift1 to be faster

      simulate:
       : 2* 2 * ; ( canonic) : 2* 1 LSHIFT ; ( usual)

2/
( a# -- a#' | a -- a' [??] )
[ANS]
2/ ( a# -- a#' | a -- a' [??] ) [ANS]

divides the value by two - but it does actually use a shift1 to be faster

      simulate:
       : 2/ 2 / ; ( canonic) : 2/ 1 RSHIFT ; ( usual)

2@
( variable* -- x,x )
[ANS]
2@ ( variable* -- x,x ) [ANS]

double-cell fetch

2DROP
( a b -- )
[ANS]
2DROP ( a b -- ) [ANS]

double-cell drop, also used to drop two items

2DUP
( a,a -- a,a a,a )
[ANS]
2DUP ( a,a -- a,a a,a ) [ANS]

double-cell duplication, also used to duplicate two items

      simulate:
        : 2DUP OVER OVER ; ( wrong would be : 2DUP DUP DUP ; !!)

2OVER
( a,a b,b -- a,a b,b a,a )
[ANS]
2OVER ( a,a b,b -- a,a b,b a,a ) [ANS]

double-cell over, see OVER and 2DUP

      simulate:
        : 2OVER SP@ 2 CELLS + 2@ ;

2SWAP
( a,a b,b -- b,b a,a )
[ANS]
2SWAP ( a,a b,b -- b,b a,a ) [ANS]

double-cell swap, see SWAP and 2DUP

      simulate:
        : 2SWAP LOCALS| B1 B2 A1 A2 | B2 B1 A2 A1 ;

(NEST)
( -- )
[HIDDEN]
"(NEST)" ( -- ) [HIDDEN]

compiled by : (see also (NONAME) compiled by :NONAME )

:
( 'name' -- )
[ANS] [NEW]
":" ( 'name' -- ) [ANS] [NEW]

create a header for a nesting word and go to compiling mode then. This word is usually ended with ; but the execution of the resulting colon-word can also return with EXIT

((;))
( -- )
[HIDDEN] [EXIT]
"((;))" ( -- ) [HIDDEN] [EXIT]

compiled by ; and maybe ;AND -- it will perform an EXIT

;
( -- )
[ANS] [EXIT] [END]
";" ( -- ) [ANS] [EXIT] [END]

compiles ((;)) which does EXIT the current colon-definition. It does then end compile-mode and returns to execute-mode. See : and :NONAME

<
( a* b* -- test-flag | a# b# -- test-flag | a b -- test-flag [?] )
[ANS]
< ( a* b* -- test-flag | a# b# -- test-flag | a b -- test-flag [?] ) [ANS]

return a flag telling if a is lower than b

<#
( -- )
[ANS]
<# ( -- ) [ANS]

see also HOLD for old-style forth-formatting words and PRINTF of the C-style formatting - this word does initialize the pictured numeric output space.

=
( a* b* -- test-flag | a# b# -- test-flag | a b -- test-flag [?] )
[ANS]
= ( a* b* -- test-flag | a# b# -- test-flag | a b -- test-flag [?] ) [ANS]

return a flag telling if a is equal to b

>
( a* b* -- test-flag | a# b# -- test-flag | a b -- test-flag [?] )
[ANS]
> ( a* b* -- test-flag | a# b# -- test-flag | a b -- test-flag [?] ) [ANS]

return a flag telling if a is greater than b

>BODY
( some-xt* -- some-body* )
[ANS]
>BODY ( some-xt* -- some-body* ) [ANS]

adjust the execution-token (ie. the CFA) to point to the parameter field (ie. the PFA) of a word. this is not a constant operation - most words have their parameters at "1 CELLS +" but CREATE/DOES-words have the parameters at "2 CELLS +" and ROM/USER words go indirect with a rom'ed offset i.e. "CELL + @ UP +"

>NUMBER
( a,a str-ptr str-len -- a,a' str-ptr' str-len)
[ANS]
>NUMBER ( a,a str-ptr str-len -- a,a' str-ptr' str-len) [ANS]

try to convert a string into a number, and place that number at a,a respeciting BASE

>R
( value -- R: value )
[ANS]
>R ( value -- R: value ) [ANS]

save the value onto the return stack. The return stack must be returned back to clean state before an exit and you should note that the return-stack is also touched by the DO ... WHILE loop. Use R> to clean the stack and R@ to get the last value put by >R

?DUP
( 0 -- 0 | value! -- value! value! | value -- 0 | value! value! )
[ANS]
?DUP ( 0 -- 0 | value! -- value! value! | value -- 0 | value! value! ) [ANS]

one of the rare words whose stack-change is condition-dependet. This word will duplicate the value only if it is not zero. The usual place to use it is directly before a control-word that can go to different places where we can spare an extra DROP on the is-null-part. This makes the code faster and often a little easier to read.

      example:
        : XX BEGIN ?DUP WHILE DUP . 2/ REPEAT ; instead of
        : XX BEGIN DUP WHILE DUP . 2/ REPEAT DROP ;

@
( value* -- value )
[ANS]
@ ( value* -- value ) [ANS]

fetch the value from the variables address

ABS
( value# -- value#' )
[ANS]
ABS ( value# -- value#' ) [ANS]

return the absolute value

ACCEPT
( buffer-ptr buffer-max -- buffer-len )
[ANS]
ACCEPT ( buffer-ptr buffer-max -- buffer-len ) [ANS]

get a string from terminal into the named input buffer, returns the number of bytes being stored in the buffer. May provide line-editing functions.

ALIGN
( -- )
[ANS]
ALIGN ( -- ) [ANS]

will make the dictionary aligned, usually to a cell-boundary, see ALIGNED

ALIGNED
( addr -- addr' )
[ANS]
ALIGNED ( addr -- addr' ) [ANS]

uses the value (being usually a dictionary-address) and increment it to the required alignment for the dictionary which is usually in CELLS - see also ALIGN

ALLOT
( allot-count -- )
[ANS]
ALLOT ( allot-count -- ) [ANS]

make room in the dictionary - usually called after a CREATE word like VARIABLE or VALUE to make for an array of variables. Does not initialize the space allocated from the dictionary-heap. The count is in bytes - use CELLS ALLOT to allocate a field of cells.

AND
( value mask -- value' )
[ANS]
AND ( value mask -- value' ) [ANS]

mask with a bitwise and - be careful when applying it to logical values.

BEGIN
( -- )
[ANS] [LOOP]
BEGIN ( -- ) [ANS] [LOOP]

start a control-loop, see WHILE and REPEAT

C!
( value# variable#* -- | value# variable* [?] )
[ANS]
C! ( value# variable#* -- | value# variable* [?] ) [ANS]

store the byte-value at address, see => !

C,
( value# -- )
[ANS]
C, ( value# -- ) [ANS]

store a new byte-value in the dictionary, implicit 1 ALLOT, see => ,

C@
( value#* -- value# | value* -- value# [?] )
[ANS]
C@ ( value#* -- value# | value* -- value# [?] ) [ANS]

fetch a byte-value from the address, see @

CELL+
( value -- value' )
[ANS]
CELL+ ( value -- value' ) [ANS]

adjust the value by adding a single Cell's width - the value is often an address or offset, see CELLS

CELLS
( value# -- value#' )
[ANS]
CELLS ( value# -- value#' ) [ANS]

scale the value by the sizeof a Cell the value is then often applied to an address or fed into ALLOT

CHAR
( 'word' -- char# )
[ANS]
CHAR ( 'word' -- char# ) [ANS]

return the (ascii-)value of the following word's first character.

CHAR+
( value -- value' )
[ANS]
CHAR+ ( value -- value' ) [ANS]

increment the value by the sizeof one char - the value is often a pointer or an offset, see CHARS

CHARS
( value# -- value#' )
[ANS]
CHARS ( value# -- value#' ) [ANS]

scale the value by the sizeof a char - the value is then often applied to an address or fed into ALLOT (did you expect that sizeof(p4char) may actually yield 2 bytes?)

((CONSTANT))
( -- )
[HIDDEN]
"((CONSTANT))" ( -- ) [HIDDEN]

runtime compiled by CONSTANT

CONSTANT
( value 'name' -- )
[ANS] [DOES: -- value ]
CONSTANT ( value 'name' -- ) [ANS] [DOES: -- value ]

CREATE a new word with runtime ((CONSTANT)) so that the value placed here is returned everytime the constant's name is used in code. See VALUE for constant-like names that are expected to change during execution of the program. In a ROM-able forth the CONSTANT-value may get into a shared ROM-area and is never copied to a RAM-address.

COUNT
( string-bstr* -- string-ptr' string-len | some* -- some*' some-len [?] )
[ANS]
COUNT ( string-bstr* -- string-ptr' string-len | some* -- some*' some-len [?] ) [ANS]

usually before calling TYPE

(as an unwarranted extension, this word does try to be idempotent).

CR
( -- )
[ANS]
CR ( -- ) [ANS]

print a carriage-return/new-line on stdout

DECIMAL
( -- )
[ANS]
DECIMAL ( -- ) [ANS]

set the BASE to 10

      simulate:
        : DECIMAL 10 BASE ! ;

DEPTH
( -- depth# )
[ANS]
DEPTH ( -- depth# ) [ANS]

return the depth of the parameter stack before the call, see SP@ - the return-value is in CELLS

((DO))
( end# start# -- )
[HIDDEN]
"((DO))" ( end# start# -- ) [HIDDEN]

compiled by DO

DO
( end# start# | end* start* -- R: some,loop )
[ANS] [LOOP]
DO ( end# start# | end* start* -- R: some,loop ) [ANS] [LOOP]

pushes $end and $start onto the return-stack ( >R ) and starts a control-loop that ends with LOOP or +LOOP and may get a break-out with LEAVE . The loop-variable can be accessed with I

((VAR))
( -- pfa )
[HIDDEN]
"((VAR))" ( -- pfa ) [HIDDEN]

the runtime compiled by VARIABLE

((BUILDS))
( -- pfa )
[HIDDEN]
"((BUILDS))" ( -- pfa ) [HIDDEN]

the runtime compiled by CREATE which is not much unlike a VARIABLE (in ANS Forth Mode we reserve an additional DOES-field)

((DOES>))
( -- pfa )
[HIDDEN]
"((DOES>))" ( -- pfa ) [HIDDEN]

runtime compiled by DOES>

(DOES>)
( -- pfa )
[HIDDEN]
"(DOES>)" ( -- pfa ) [HIDDEN]

execution compiled by DOES>

DOES>
( -- does* )
[ANS] [END] [NEW]
"DOES>" ( -- does* ) [ANS] [END] [NEW]

does twist the last CREATE word to carry the (DOES>) runtime. That way, using the word will execute the code-piece following DOES> where the pfa of the word is already on stack. (note: FIG option will leave pfa+cell since does-rt is stored in pfa)

CREATE
( 'name' -- )
[ANS]
CREATE ( 'name' -- ) [ANS]

create a name with runtime ((VAR)) so that everywhere the name is used the pfa of the name's body is returned. This word is not immediate and according to the ANS Forth documents it may get directly used in the first part of a DOES> defining word - in traditional forth systems the word <BUILDS</link> was used for that and CREATE was defined to be the first part of a VARIABLE word (compare with CREATE: and the portable expression 0 BUFFER:)

<BUILDS
( 'name' -- )
[FTH]
<BUILDS ( 'name' -- ) [FTH]

make a HEADER whose runtime will be changed later using DOES>
note that ans'forth does not define <BUILDS</link> and it suggests to use CREATE directly.
... if you want to write FIG-programs in pure pfe then you have to use CREATE: to get the FIG-like meaning of CREATE whereas the ans-forth CREATE is the same as <BUILDS</link>

      : <BUILDS BL WORD HEADER DOCREATE A, 0 A, ;

DROP
( a -- )
[ANS]
DROP ( a -- ) [ANS]

just drop the word on the top of stack, see DUP

DUP
( a -- a a )
[ANS]
DUP ( a -- a a ) [ANS]

duplicate the cell on top of the stack - so the two topmost cells have the same value (they are equal w.r.t = ) , see DROP for the inverse

(BRANCH)
( -- )
[HIDDEN]
"(BRANCH)" ( -- ) [HIDDEN]

execution compiled by ELSE - just a simple BRANCH

((ELSE))
( -- )
OBSOLETE (FIXME: to be removed in pfe-34)
"((ELSE))" ( -- ) OBSOLETE (FIXME: to be removed in pfe-34)
ELSE
( -- )
[HIDDEN]
ELSE ( -- ) [HIDDEN]

will compile an ((ELSE)) BRANCH that performs an unconditional jump to the next THEN - and it resolves an IF for the non-true case

EMIT
( char# -- )
[ANS]
EMIT ( char# -- ) [ANS]

print the char-value on stack to stdout

ENVIRONMENT?
( name-ptr name-len -- 0 | ?? name-flag! )
[ANS]
ENVIRONMENT? ( name-ptr name-len -- 0 | ?? name-flag! ) [ANS]

check the environment for a property, usually a condition like questioning the existance of specified wordset, but it can also return some implementation properties like "WORDLISTS" (the length of the search-order) or "#LOCALS" (the maximum number of locals)

Here it implements the environment queries as a SEARCH-WORDLIST in a user-visible vocabulary called ENVIRONMENT

      : ENVIRONMENT?
        ['] ENVIRONMENT >WORDLIST SEARCH-WORDLIST
        IF  EXECUTE TRUE ELSE  FALSE THEN ;

EVALUATE
( str-ptr str-len -- )
[ANS]
EVALUATE ( str-ptr str-len -- ) [ANS]

INTERPRET the given string, SOURCE id is -1 during that time.

EXECUTE
( some-xt* -- ??? )
[ANS]
EXECUTE ( some-xt* -- ??? ) [ANS]

run the execution-token on stack - this will usually trap if it was null for some reason, see >EXECUTE

      simulate:
       : EXECUTE >R EXIT ;

EXIT
( -- )
[ANS] [EXIT]
EXIT ( -- ) [ANS] [EXIT]

will unnest the current colon-word so it will actually return the word calling it. This can be found in the middle of a colon-sequence between : and ;

FILL
( mem-ptr mem-len char# -- )
[ANS]
FILL ( mem-ptr mem-len char# -- ) [ANS]

fill a memory area with the given char, does now simply call p4_memset()

FIND
( name-bstr* -- name-bstr* 0 | name-xt* -1|1 )
[ANS]
FIND ( name-bstr* -- name-bstr* 0 | name-xt* -1|1 ) [ANS]

looks into the current search-order and tries to find the name string as the name of a word. Returns its execution-token or the original-bstring if not found, along with a flag-like value that is zero if nothing could be found. Otherwise it will be 1 (a positive value) if the word had been immediate, -1 otherwise (a negative value).

FM/MOD
( n1,n1# n2# -- div-n1# mod-n1# )
[ANS]
"FM/MOD" ( n1,n1# n2# -- div-n1# mod-n1# ) [ANS]

divide the double-cell value n1 by n2 and return both (floored) quotient n and remainder m

HERE
( -- here* )
[ANS]
HERE ( -- here* ) [ANS]

used with WORD and many compiling words

      simulate:   : HERE DP @ ;

HOLD
( char# -- )
[ANS]
HOLD ( char# -- ) [ANS]

the old-style forth-formatting system -- this word adds a char to the picutred output string.

I
( R: some,loop -- S: i# )
[ANS]
I ( R: some,loop -- S: i# ) [ANS]

returns the index-value of the innermost DO .. LOOP

(?BRANCH)
( -- )
[HIDDEN]
"(?BRANCH)" ( -- ) [HIDDEN]

execution word compiled by IF - just some simple => ?BRANCH

((IF))
( -- )
OBSOLETE (FIXME: to be removed in pfe-34)
"((IF))" ( -- ) OBSOLETE (FIXME: to be removed in pfe-34)

use (?BRANCH)

IF
( value -- )
[ANS]
IF ( value -- ) [ANS]

checks the value on the stack (at run-time, not compile-time) and if true executes the code-piece between IF and the next ELSE or THEN . Otherwise it has compiled a branch over to be executed if the value on stack had been null at run-time.

IMMEDIATE
( -- )
[ANS]
IMMEDIATE ( -- ) [ANS]

make the LATEST word immediate, see also CREATE

INVERT
( value# -- value#' )
[ANS]
INVERT ( value# -- value#' ) [ANS]

make a bitwise negation of the value on stack. see also NEGATE

J
( R: some,loop -- S: j# )
[ANS]
J ( R: some,loop -- S: j# ) [ANS]

get the current DO ... LOOP index-value being the not-innnermost. (the second-innermost...) see also for the other loop-index-values at I and K

KEY
( -- char# )
[ANS]
KEY ( -- char# ) [ANS]

return a single character from the keyboard - the key is not echoed.

LEAVE
( R: some,loop -- R: some,loop )
[ANS]
LEAVE ( R: some,loop -- R: some,loop ) [ANS]

quit the innermost DO .. LOOP - it does even clean the return-stack and branches to the place directly after the next LOOP

((LIT))
( -- value )
[HIDDEN]
"((LIT))" ( -- value ) [HIDDEN]

execution compiled by LITERAL

LITERAL
( C: value -- S: value )
[ANS]
LITERAL ( C: value -- S: value ) [ANS]

if compiling this will take the value from the compiling-stack and puts in dictionary so that it will pop up again at the run-time of the word currently in creation. This word is used in compiling words but may also be useful in making a hard-constant value in some code-piece like this:

      : DCELLS [ 2 CELLS ] LITERAL * ; ( will save a multiplication at runtime)

(in most configurations this word is statesmart and it will do nothing in interpret-mode. See LITERAL, for a non-immediate variant)

((LOOP))
( -- )
[HIDDEN]
"((LOOP))" ( -- ) [HIDDEN]

execution compiled by LOOP

LOOP
( R: some,loop -- )
[ANS] [REPEAT]
LOOP ( R: some,loop -- ) [ANS] [REPEAT]

resolves a previous DO thereby compiling ((LOOP)) which does increment/decrement the index-value and branch back if the end-value of the loop has not been reached.

LSHIFT
( value# shift-count -- value#' )
[ANS]
LSHIFT ( value# shift-count -- value#' ) [ANS]

does a bitwise left-shift on value

M*
( a# b# -- a,a#' )
[ANS]
M* ( a# b# -- a,a#' ) [ANS]

multiply and return a double-cell result

MAX
( a# b# -- a#|b# | a* b* -- a*|b* | a b -- a|b [??] )
[ANS]
MAX ( a# b# -- a#|b# | a* b* -- a*|b* | a b -- a|b [??] ) [ANS]

return the maximum of a and b

MIN
( a# b# -- a#|b# | a* b* -- a*|b* | a b -- a|b [??] )
[ANS]
MIN ( a# b# -- a#|b# | a* b* -- a*|b* | a b -- a|b [??] ) [ANS]

return the minimum of a and b

MOD
( a# b# -- mod-a# | a b# -- mod-a# [??] )
[ANS]
MOD ( a# b# -- mod-a# | a b# -- mod-a# [??] ) [ANS]

return the module of "a mod b"

MOVE
( from-ptr to-ptr move-len -- )
[ANS]
MOVE ( from-ptr to-ptr move-len -- ) [ANS]

p4_memcpy an area

NEGATE
( value# -- value#' )
[ANS]
NEGATE ( value# -- value#' ) [ANS]

return the arithmetic negative of the (signed) cell

      simulate:   : NEGATE -1 * ;

OR
( a b# -- a' | a# b -- b' | a b -- a' [??] )
[ANS]
OR ( a b# -- a' | a# b -- b' | a b -- a' [??] ) [ANS]

return the bitwise OR of a and b - unlike AND this is usually safe to use on logical values

OVER
( a b -- a b a )
[ANS]
OVER ( a b -- a b a ) [ANS]

get the value from under the top of stack. The inverse operation would be TUCK

((POSTPONE))
( -- )
[HIDDEN]
"((POSTPONE))" ( -- ) [HIDDEN]

execution compiled by POSTPONE

POSTPONE
( [word] -- )
[ANS]
POSTPONE ( [word] -- ) [ANS]

will compile the following word at the run-time of the current-word which is a compiling-word. The point is that POSTPONE takes care of the fact that word may be an IMMEDIATE-word that flags for a compiling word, so it must be executed (and not pushed directly) to compile sth. later. Choose this word in favour of COMPILE (for non-immediate words) and [COMPILE] (for immediate words)

QUIT
( -- )
[EXIT]
QUIT ( -- ) [EXIT]

this will throw and lead back to the outer-interpreter. traditionally, the outer-interpreter is called QUIT in forth itself where the first part of the QUIT-word had been to clean the stacks (and some other variables) and then turn to an endless loop containing QUERY and EVALUATE (otherwise known as INTERPRET ) - in pfe it is defined as a THROW ,

      : QUIT -56 THROW ;

R>
( R: a -- a R: )
[ANS]
R> ( R: a -- a R: ) [ANS]

get back a value from the return-stack that had been saved there using >R . This is the traditional form of a local var space that could be accessed with R@ later. If you need more local variables you should have a look at LOCALS| which does grab some space from the return-stack too, but names them the way you like.

R@
( R: a -- a R: a )
[ANS]
R@ ( R: a -- a R: a ) [ANS]

fetch the (upper-most) value from the return-stack that had been saved there using >R - This is the traditional form of a local var space. If you need more local variables you should have a look at LOCALS| , see also >R and R> . Without LOCALS-EXT there are useful words like 2R@ R'@ R"@ R!

RECURSE
( ? -- ? )
[ANS]
RECURSE ( ? -- ? ) [ANS]

when creating a colon word the name of the currently-created word is smudged, so that you can redefine a previous word of the same name simply by using its name. Sometimes however one wants to recurse into the current definition instead of calling the older defintion. The RECURSE word does it exactly this.

        traditionally the following code had been in use:
        : GREAT-WORD [ UNSMUDGE ] DUP . 1- ?DUP IF GREAT-WORD THEN ;
        now use
        : GREAT-WORD DUP . 1- ?DUP IF RECURSE THEN ;

REPEAT
( -- )
[ANS] [REPEAT]
REPEAT ( -- ) [ANS] [REPEAT]

ends an unconditional loop, see BEGIN

ROT
( a b c -- b c a )
[ANS]
ROT ( a b c -- b c a ) [ANS]

rotates the three uppermost values on the stack, the other direction would be with -ROT - please have a look at LOCALS| and VAR that can avoid its use.

RSHIFT
( value# shift-count# -- value#' )
[ANS]
RSHIFT ( value# shift-count# -- value#' ) [ANS]

does a bitwise logical right-shift on value (ie. the value is considered to be unsigned)

((S"))
( -- string-ptr string-len )
[HIDDEN]
'((S"))' ( -- string-ptr string-len ) [HIDDEN]

execution compiled by S"

S"
( [string<">] -- string-ptr string-len)
[ANS]
'S"' ( [string<">] -- string-ptr string-len) [ANS]

if compiling then place the string into the currently compiled word and on execution the string pops up again as a double-cell value yielding the string's address and length. To be most portable this is the word to be best being used. Compare with C" and non-portable "

S>D
( a# -- a,a#' | a -- a,a#' [??] )
[ANS]
S>D ( a# -- a,a#' | a -- a,a#' [??] ) [ANS]

signed extension of a single-cell value to a double-cell value

SIGN
( a# -- )
[ANS]
SIGN ( a# -- ) [ANS]

put the sign of the value into the hold-space, this is the forth-style output formatting, see HOLD

SM/REM
( a,a# b# -- div-a# rem-a# )
[ANS]
SM/REM ( a,a# b# -- div-a# rem-a# ) [ANS]

see /MOD or FM/MOD or UM/MOD or SM/REM

SOURCE
( -- buffer* IN-offset# )
[ANS]
SOURCE ( -- buffer* IN-offset# ) [ANS]

the current point of interpret can be gotten through SOURCE. The buffer may flag out TIB or BLK or a FILE and IN gives you the offset therein. Traditionally, if the current SOURCE buffer is used up, REFILL is called that asks for another input-line or input-block. This scheme would have made it impossible to stretch an [IF] ... [THEN] over different blocks, unless [IF] does call REFILL

SPACE
( -- )
[ANS]
SPACE ( -- ) [ANS]

print a single space to stdout, see SPACES

      simulate:    : SPACE  BL EMIT ;

SPACES
( space-count -- )
[ANS]
SPACES ( space-count -- ) [ANS]

print n space to stdout, actually a loop over n calling SPACE , but the implemenation may take advantage of printing chunks of spaces to speed up the operation.

SWAP
( a b -- b a )
[ANS]
SWAP ( a b -- b a ) [ANS]

exchanges the value on top of the stack with the value beneath it

THEN
( -- )
[ANS]
THEN ( -- ) [ANS]

does resolve a branch coming from either IF or ELSE

TYPE
( string-ptr string-len -- )
[ANS]
TYPE ( string-ptr string-len -- ) [ANS]

prints the string-buffer to stdout, see COUNT and EMIT

U.
( value# -- | value -- [?] )
[ANS]
U. ( value# -- | value -- [?] ) [ANS]

print unsigned number to stdout

U<
( a b -- test-flag )
[ANS]
U< ( a b -- test-flag ) [ANS]

unsigned comparison, see <

UM*
( a# b# -- a,a#' )
[ANS]
UM* ( a# b# -- a,a#' ) [ANS]

unsigned multiply returning double-cell value

UM/MOD
( a,a# b# -- div-a#' mod-a#' )
[ANS]
"UM/MOD" ( a,a# b# -- div-a#' mod-a#' ) [ANS]

see /MOD and SM/REM

UNLOOP
( R: some,loop -- )
[ANS]
UNLOOP ( R: some,loop -- ) [ANS]

drop the DO .. LOOP runtime variables from the return-stack, usually used just in before an EXIT call. Using this multiple times can unnest multiple nested loops.

UNTIL
( test-flag -- )
[ANS] [REPEAT]
UNTIL ( test-flag -- ) [ANS] [REPEAT]

ends an control-loop, see BEGIN and compare with WHILE

VARIABLE
( 'name' -- )
[ANS] [DOES: -- name* ]
VARIABLE ( 'name' -- ) [ANS] [DOES: -- name* ]

CREATE a new variable, so that everytime the variable is name, the address is returned for using with @ and => ! - be aware that in FIG-forth VARIABLE did take an argument being the initial value. ANSI-forth does different here.

WHILE
( test-flag -- )
[ANS]
WHILE ( test-flag -- ) [ANS]

middle part of a BEGIN .. WHILE .. REPEAT control-loop - if cond is true the code-piece up to REPEAT is executed which will then jump back to BEGIN - and if the cond is null then WHILE will branch to right after the REPEAT (compare with UNTIL that forms a BEGIN .. UNTIL loop)

WORD
( delimiter-char# -- here* )
[ANS]
WORD ( delimiter-char# -- here* ) [ANS]

read the next SOURCE section (thereby moving >IN ) up to the point reaching $delimiter-char - the text is placed at HERE - where you will find a counted string. You may want to use PARSE instead.

XOR
( a# b# -- a#' )
[ANS]
XOR ( a# b# -- a#' ) [ANS]

return the bitwise-or of the two arguments - it may be unsafe use it on logical values. beware.

[
( -- )
[ANS]
[ ( -- ) [ANS]

leave compiling mode - often used inside of a colon-definition to make fetch some very constant value and place it into the currently compiled colon-defintion with => , or LITERAL - the corresponding unleave word is ]

[']
( [name] -- name-xt* )
[ANS]
['] ( [name] -- name-xt* ) [ANS]

will place the execution token of the following word into the dictionary. See ' for non-compiling variant.

[CHAR]
( [word] -- char# )
[ANS]
[CHAR] ( [word] -- char# ) [ANS]

in compile-mode, get the (ascii-)value of the first charachter in the following word and compile it as a literal so that it will pop up on execution again. See CHAR and forth-83 ASCII

]
( -- )
[ANS]
] ( -- ) [ANS]

enter compiling mode - often used inside of a colon-definition to end a previous [ - you may find a => , or LITERAL nearby in example texts.

.(
( [message<closeparen>] -- )
[ANS]
".(" ( [message<closeparen>] -- ) [ANS]

print the message to the screen while reading a file. This works too while compiling, so you can whatch the interpretation/compilation to go on. Some Forth-implementations won't even accept a => ." message" outside compile-mode while the (current) pfe does.

.R
( value# precision# -- | value precision# -- [??] )
[ANS]
.R ( value# precision# -- | value precision# -- [??] ) [ANS]

print with precision - that is to fill a field of the give prec-with with right-aligned number from the converted value

0<>
( 0 -- 0 | value! -- value-flag! | value -- value-flag )
[ANS]
"0<>" ( 0 -- 0 | value! -- value-flag! | value -- value-flag ) [ANS]

returns a logical-value saying if the value was not-zero. This is most useful in turning a numerical value into a boolean value that can be fed into bitwise words like AND and XOR - a simple IF or WHILE doesn't need it actually.

0>
( 0 -- 0 | value! -- value-flag! | value -- value-flag )
[ANS]
0> ( 0 -- 0 | value! -- value-flag! | value -- value-flag ) [ANS]

return value greater than zero

      simulate:    : 0> 0 > ;

2>R
( a,a -- R: a,a )
[ANS]
2>R ( a,a -- R: a,a ) [ANS]

save a double-cell value onto the return-stack, see >R

2R>
( R: a,a -- a,a R: )
[ANS]
2R> ( R: a,a -- a,a R: ) [ANS]

pop back a double-cell value from the return-stack, see R> and the earlier used 2>R

2R@
( R: a,a -- a,a R: a,a )
[ANS]
2R@ ( R: a,a -- a,a R: a,a ) [ANS]

fetch a double-cell value from the return-stack, that had been previously been put there with 2>R - see R@ for single value. This can partly be a two-cell LOCALS| value, without LOCALS-EXT there are alos other useful words like 2R! R'@ R"@

(NONAME)
( -- )
[HIDDEN]
"(NONAME)" ( -- ) [HIDDEN]

compiled by :NONAME (see also (NEST) compiled by : (execution is identical))

:NONAME
( -- C: noname,word )
[ANS]
:NONAME ( -- C: noname,word ) [ANS]

start a colon nested-word but do not use CREATE - so no name is given to the colon-definition that follows. When the definition is finished at the corresponding ; the start-address (ie. the execution token) can be found on the outer cs.stack that may be stored used elsewhere then.

<>
( a b -- a-flag )
[ANS]
"<>" ( a b -- a-flag ) [ANS]

return true if a and b are not equal, see =

((?DO))
( a b -- )
[HIDDEN]
"((?DO))" ( a b -- ) [HIDDEN]

execution compiled by => ?DO

?DO
( end# start# | end* start* -- R: some,loop )
[ANS]
?DO ( end# start# | end* start* -- R: some,loop ) [ANS]

start a control-loop just like DO - but don't execute atleast once. Instead jump over the code-piece if the loop's variables are not in a range to allow any loop.

AGAIN
( -- )
[ANS] [REPEAT]
AGAIN ( -- ) [ANS] [REPEAT]

ends an infinite loop, see BEGIN and compare with WHILE

((C"))
( -- string-bstr* )
[HIDDEN]
'((C"))' ( -- string-bstr* ) [HIDDEN]

execution compiled by C" string"

C"
( [string<">] -- string-bstr* )
[ANS]
'C"' ( [string<">] -- string-bstr* ) [ANS]

in compiling mode place the following string in the current word and return the address of the counted string on execution. (in exec-mode use a POCKET and leave the bstring-address of it), see S" string" and the non-portable " string"

CASE
( value -- value )
[ANS]
CASE ( value -- value ) [ANS]

start a CASE construct that ends at ENDCASE and compares the value on stack at each OF place

COMPILE,
( some-xt* -- )
[ANS]
"COMPILE," ( some-xt* -- ) [ANS]

place the execution-token on stack into the dictionary - in traditional forth this is not even the least different than a simple => , but in call-threaded code there's a big difference - so COMPILE, is the portable one. Unlike COMPILE , [COMPILE] and POSTPONE this word does not need the xt to have actually a name, see :NONAME

CONVERT
( a,a# string-bstr* -- a,a# a-len# )
[ANS] [OLD]
CONVERT ( a,a# string-bstr* -- a,a# a-len# ) [ANS] [OLD]

digit conversion, obsolete, superseded by >NUMBER

ENDCASE
( value -- )
[ANS]
ENDCASE ( value -- ) [ANS]

ends a CASE construct that may surround multiple sections of OF ... ENDOF code-portions. The ENDCASE has to resolve the branches that are necessary at each ENDOF to point to right after ENDCASE

ENDOF
( -- )
[ANS]
ENDOF ( -- ) [ANS]

resolve the branch need at the previous OF to mark a code-piece and leave with an unconditional branch at the next ENDCASE (opened by CASE )

ERASE
( buffer-ptr buffer-len -- )
[ANS]
ERASE ( buffer-ptr buffer-len -- ) [ANS]

fill an area will zeros.

      2000 CREATE DUP ALLOT ERASE

EXPECT
( str-ptr str-len -- )
[ANS] [OLD]
EXPECT ( str-ptr str-len -- ) [ANS] [OLD]

input handling, see WORD and PARSE and QUERY the input string is placed at str-adr and its length

      in => SPAN - this word is superceded by => ACCEPT

HEX
( -- )
[ANS]
HEX ( -- ) [ANS]

set the input/output BASE to hexadecimal

      simulate:        : HEX 16 BASE ! ;

MARKER
( 'name' -- )
[ANS]
MARKER ( 'name' -- ) [ANS]

create a named marker that you can use to FORGET , running the created word will reset the dict/order variables to the state at the creation of this name.

      : MARKER PARSE-WORD (MARKER) ;

see also ANEW which is not defined in ans-forth but which uses the MARKER functionality in the way it should have been defined.

      : MARKER PARSE-WORD (MARKER) ;

NIP
( a b -- b )
[ANS]
NIP ( a b -- b ) [ANS]

drop the value under the top of stack, inverse of TUCK

      simulate:        : NIP SWAP DROP ;

((OF))
( check val -- check )
[HIDDEN]
"((OF))" ( check val -- check ) [HIDDEN]

execution compiled by OF

OF
( value test -- value )
[ANS]
OF ( value test -- value ) [ANS]

compare the case-value placed lately with the comp-value being available since CASE - if they are equal run the following code-portion up to ENDOF after which the case-construct ends at the next ENDCASE

PAD
( -- pad* )
[ANS]
PAD ( -- pad* ) [ANS]

transient buffer region

PARSE
( delim-char# -- buffer-ptr buffer-len )
[ANS]
PARSE ( delim-char# -- buffer-ptr buffer-len ) [ANS]

parse a piece of input (not much unlike WORD) and place it into the given buffer. The difference with word is also that WORD would first skip any delim-char while PARSE does not and thus may yield that one. In a newer version, PARSE will not copy but just return the word-span being seen in the input-buffer - therefore a transient space.

PARSE-NAME
( "chars" -- buffer-ptr buffer-len )
[Forth200x]
PARSE-NAME ( "chars" -- buffer-ptr buffer-len ) [Forth200x]

This word is identical with the PFE implementation PARSE-WORD

The only difference between the 1994 ANS-Forth PARSE-WORD and the 2005 Forth200x PARSE-NAME is in the explicit condition of whitespace-only - while 1994 reads "If the parse area is empty, the resulting string has a zero length." you will find that the 2005 version says "If the parse area is empty or contains only white space, the resulting string has length zero."

PARSE-WORD
( "chars" -- buffer-ptr buffer-len )
[ANS]
PARSE-WORD ( "chars" -- buffer-ptr buffer-len ) [ANS]

the ANS'94 standard describes this word in a comment under PARSE, section A.6.2.2008 - quote:

Skip leading spaces and parse name delimited by a space. c-addr is the address within the input buffer and u is the length of the selected string. If the parse area is empty, the resulting string has a zero length.

If both PARSE and PARSE-WORD are present, the need for WORD is largely eliminated. Note that Forth200x calls it PARSE-NAME and clarifies that non-empty whitespace-only input is returned as a zero length string as well.

PICK
( value ...[n-1] n -- value ...[n-1] value )
[ANS]
PICK ( value ...[n-1] n -- value ...[n-1] value ) [ANS]

pick the nth value from under the top of stack and push it note that

        0 PICK -> DUP         1 PICK -> OVER

REFILL
( -- refill-flag )
[ANS]
REFILL ( -- refill-flag ) [ANS]

try to get a new input line from the SOURCE and set >IN accordingly. Return a flag if sucessful, which is always true if the current input comes from a terminal and which is always false if the current input comes from EVALUATE - and may be either if the input comes from a file

RESTORE-INPUT
( input...[input-len] input-len -- )
[ANS]
RESTORE-INPUT ( input...[input-len] input-len -- ) [ANS]

inverse of SAVE-INPUT

ROLL
( value ...[n-1] n -- ...[n-1] value )
[ANS]
ROLL ( value ...[n-1] n -- ...[n-1] value ) [ANS]

the extended form of ROT

         2 ROLL -> ROT

SAVE-INPUT
( -- input...[input-len] input-len )
[ANS]
SAVE-INPUT ( -- input...[input-len] input-len ) [ANS]

fetch the current state of the input-channel which may be restored with RESTORE-INPUT later

((TO))
( value -- )
[HIDDEN]
"((TO))" ( value -- ) [HIDDEN]

execution compiled by TO

TO
( value [name] -- )
[ANS]
TO ( value [name] -- ) [ANS]

set the parameter field of name to the value, this is used to change the value of a VALUE and it can be also used to change the value of LOCALS|

TUCK
( a b -- b a b )
[ANS]
TUCK ( a b -- b a b ) [ANS]

shove the top-value under the value beneath. See OVER and NIP

      simulate:    : TUCK  SWAP OVER ;

U.R
( value# precision# -- )
[ANS]
U.R ( value# precision# -- ) [ANS]

print right-aligned in a prec-field, treat value to be unsigned as opposed to => .R

U>
( a b -- a-flag )
[ANS]
U> ( a b -- a-flag ) [ANS]

unsigned comparison of a and b, see >

UNUSED
( -- unused-len )
[ANS]
UNUSED ( -- unused-len ) [ANS]

return the number of cells that are left to be used above HERE

((VALUE))
( -- value )
[HIDDEN]
"((VALUE))" ( -- value ) [HIDDEN]

runtime compiled by VALUE

VALUE
( value 'name' -- )
[HIDDEN] [DOES: -- value ]
VALUE ( value 'name' -- ) [HIDDEN] [DOES: -- value ]

CREATE a word and initialize it with value. Using it later will push the value back onto the stack. Compare with VARIABLE and CONSTANT - look also for LOCALS| and VAR

WITHIN
( a# b# c# -- a-flag | a* b* c* -- a-flag )
[ANS]
WITHIN ( a# b# c# -- a-flag | a* b* c* -- a-flag ) [ANS]

a widely used word, returns ( b <= a && a < c ) so that is very useful to check an index a of an array to be within range b to c

[COMPILE]
( [word] -- )
[ANS]
[COMPILE] ( [word] -- ) [ANS]

while compiling the next word will be place in the currently defined word no matter if that word is immediate (like IF ) - compare with COMPILE and POSTPONE

\
( [comment<eol>] -- )
[ANS]
"\\" ( [comment<eol>] -- ) [ANS]

eat everything up to the next end-of-line so that it is getting ignored by the interpreter.

"
( [string<">] -- string-bstr* )
[FTH]
'"' ( [string<">] -- string-bstr* ) [FTH]

         or perhaps ( [string<">] -- string-ptr string-len )

This is the non-portable word which is why the ANSI-committee on forth has created the two other words, namely S" and C" , since each implementation (and in pfe configurable) uses another runtime behaviour. FIG-forth did return bstring which is the configure default for pfe.

BL
( -- bl-char# )
[ANS]
BL ( -- bl-char# ) [ANS]

a quick constant returning the blank character in host encoding, in ascii that is 0x20

TIB
( -- tib-char* )
[ANS]
TIB ( -- tib-char* ) [ANS]

traditional variable for forth terminal I/O system. (Terminal Input Buffer) ( TIB SPAN SOURCE BLK REFILL )

SOURCE
( -- source# )
[ANS]
SOURCE ( -- source# ) [ANS]

traditional variable for forth terminal I/O system. ( TIB SPAN SOURCE BLK REFILL )

>IN
( -- inputpoint# )
[ANS]
>IN ( -- inputpoint# ) [ANS]

traditional variable for forth terminal I/O system. ( TIB SPAN SOURCE BLK REFILL )

SPAN
( -- span-count )
[ANS]
SPAN ( -- span-count ) [ANS]

traditional variable for forth terminal I/O system. ( TIB SOURCE SOURCE-ID BLK )

SOURCE-ID
( -- source# )
[ANS]
SOURCE-ID ( -- source# ) [ANS]

modern variable for forth terminal I/O system. ( TIB SPAN >IN SOURCE BLK )

STATE
( -- state-flag )
[ANS]
STATE ( -- state-flag ) [ANS]

traditional variable for forth outer interpreter. ( : [ ] LITERAL COMPILE POSTPONE BASE NUMBER )

FALSE
( -- 0 )
[ANS]
FALSE ( -- 0 ) [ANS]

places zero on the stack to express the code want to do a boolean evaluation with this value. (IF)

TRUE
( -- true! )
[ANS]
TRUE ( -- true! ) [ANS]

places FALSE INVERT on the stack to express the code want to do a boolean evaluation with this value. (IF) - we chose the FIG79/FTH83 value of allbitsset to make it easier to do logical computations using bitwise operands like AND OR NOT , however ANS-Forth programs shall not assume a specific representation of the truth value and handle just the cases =0 and <>0

ENVIRONMENT STACK-CELLS
( -- stackdepth# )
[ENVIRONMENT]
"ENVIRONMENT STACK-CELLS" ( -- stackdepth# ) [ENVIRONMENT]

the number of cells allocated for the parameter stack of forth. it can be set with a startup option to match different needs of applications. (like ENVIRONMENT RETURN-STACK-CELLS) unless the parameter-stack is made in hardware (like on some special forth CPUs)

ENVIRONMENT RETURN-STACK-CELLS
( -- stackdepth# )
[ENVIRONMENT]
"ENVIRONMENT RETURN-STACK-CELLS" ( -- stackdepth# ) [ENVIRONMENT]

the number of cells allocated for the return stack of forth. it can be set with a startup option to match different needs of applications. (like ENVIRONMENT STACK-CELLS) unless the return-stack is made in hardware (like on some special forth CPUs) or aliased with the return-stack provided by the hosting operating system for the forth process thread.

ENVIRONMENT /COUNTED-STRING
( -- string-max )
[ENVIRONMENT]
"ENVIRONMENT /COUNTED-STRING" ( -- string-max ) [ENVIRONMENT]

the maximum number of chars in a counted string created with words like C\" or PLACE - in general, the counted string can use all bits from the first CHAR of the string, so it expands to 1 /CHAR LSHIFT 1- being 255 for octet systems.

ENVIRONMENT /HOLD
( -- hold-max )
[ENVIRONMENT]
"ENVIRONMENT /HOLD" ( -- hold-max ) [ENVIRONMENT]

traditional constant for the forth I/O system, moved into the environment in ans-forth systems. ( HLD HOLD ENVIRONMENT /PAD)

ENVIRONMENT /PAD
( -- pad-max )
[ENVIRONMENT]
"ENVIRONMENT /PAD" ( -- pad-max ) [ENVIRONMENT]

traditional constant for the forth I/O system, moved into the environment in ans-forth systems. ( HLD HOLD ENVIRONMENT /HOLD)

ENVIRONMENT ADDRESS-UNIT-BITS
( -- unit-len )
[ENVIRONMENT]
"ENVIRONMENT ADDRESS-UNIT-BITS" ( -- unit-len ) [ENVIRONMENT]

a constant useful to retarget forth applications to unusual hardware that has not 8 bits per address unit (i.e. not an octet-addressable system). This includes some desktop calculators and wristwatch calculators with a 4 bit address system, and some special DSP cpus with 24 bit or 32 bit address units. All these are deeply embedded for special purpose applications.

ENVIRONMENT FLOORED
( -- true! )
[ENVIRONMENT]
"ENVIRONMENT FLOORED" ( -- true! ) [ENVIRONMENT]

a flag whether division/modulo is floored or not. since pfe builds on top of C, it takes its style of computations in all respects, please refer to the ISO C standard for further interpretations.

ENVIRONMENT MAX-CHAR
( -- char-max )
[ENVIRONMENT]
"ENVIRONMENT MAX-CHAR" ( -- char-max ) [ENVIRONMENT]

a constant to check representation limits, expands to 255 in octet-char systems like PFE.

ENVIRONMENT MAX-N
( -- int-max )
[ENVIRONMENT]
"ENVIRONMENT MAX-N" ( -- int-max ) [ENVIRONMENT]

a constant to check representation limits, here it is the the largest usable signed integer. In a 16-bit two's-complement system this is 32767, and likewise higher in 32-bit and 64-bit versions of PFE. (like ENVIRONMENT MAX-U)

        TRUE 1 RSHIFT CONSTANT MAX-N

ENVIRONMENT MAX-U
( -- uint-max )
[ENVIRONMENT]
"ENVIRONMENT MAX-U" ( -- uint-max ) [ENVIRONMENT]

a constant to check representation limits, here it is the the largest usable unsigned integer. In a 16-bit two's-complement system this is 65535, and likewise higher in 32-bit and 64-bit versions of PFE. (like ENVIRONMENT MAX-N)

        TRUE CONSTANT MAX-U

0<=
( a -- flag )
0<= ( a -- flag )

      simulate    : 0<= 0> 0= ;

0>=
( a -- flag )
0>= ( a -- flag )

      simulate    : 0>= 0< 0= ;

<=
( a b -- flag )
<= ( a b -- flag )

      simulate    : <= > 0= ;

>=
( a b -- flag )
>= ( a b -- flag )

      simulate    : >= < 0= ;

U<=
( a b -- flag )
U<= ( a b -- flag )

      simulate    : U<= U> 0= ;

U>=
( a b -- flag )
U>= ( a b -- flag )

      simulate    : U>= U< 0= ;

UMAX
( a b -- max )
UMAX ( a b -- max )

see MAX

UMIN
( a b -- min )
UMIN ( a b -- min )

see MIN , MAX and UMAX

LICENSE
( -- )
LICENSE ( -- )

show a lisence info - the basic PFE system is licensed under the terms of the LGPL (Lesser GNU Public License) - binary modules loaded into the system and hooking into the system may carry another LICENSE

      : LICENSE [ ENVIRONMENT ] FORTH-LICENSE TYPE ;

WARRANTY
( -- )
WARRANTY ( -- )

show a warranty info - the basic PFE system is licensed under the terms of the LGPL (Lesser GNU Public License) - which exludes almost any liabilities whatsoever - however loadable binary modules may hook into the system and their functionality may have different WARRANTY infos.

.VERSION
( -- )
.VERSION ( -- )

show the version of the current PFE system

      : .VERSION [ ENVIRONMENT ] FORTH-NAME TYPE FORTH-VERSION TYPE ;

.CVERSION
( -- )
.CVERSION ( -- )

show the compile date of the current PFE system

      : .CVERSION [ ENVIRONMENT ] FORTH-NAME TYPE FORTH-DATE TYPE ;

STRING,
( str len -- )
STRING, ( str len -- )

Store a string in data space as a counted string.

      : STRING, HERE  OVER 1+  ALLOT  PLACE ;

PARSE,
( "chars<">" -- )
PARSE, ( "chars<">" -- )

Store a char-delimited string in data space as a counted string. As seen in Bawd's

      : ," [CHAR] " PARSE  STRING, ; IMMEDIATE

this implementation is much different from Bawd's

      : PARSE, PARSE STRING, ;

"PARSE,\""
( "chars<">" -- )
"PARSE,\"" ( "chars<">" -- )

Store a quote-delimited string in data space as a counted string.

      : ," [CHAR] " PARSE  STRING, ; IMMEDIATE

implemented here as

      : PARSE," [CHAR] " PARSE, ; IMMEDIATE

(MARKER)
( str-ptr str-len -- )
"(MARKER)" ( str-ptr str-len -- )

create a named marker that you can use to FORGET , running the created word will reset the dict/order variables to the state at the creation of this name.

      : (MARKER) (CREATE) HERE ,
              GET-ORDER DUP , 0 DO ?DUP IF , THEN LOOP 0 ,
              ...
        DOES> DUP @ (FORGET)
              ...
      ;

ANEW
( 'name' -- )
ANEW ( 'name' -- )

creates a MARKER if it doesn't exist, or forgets everything after it if it does. (it just gets executed).

Note: in PFE the ANEW will always work on the ENVIRONMENT-WORDLIST which has a reason: it is never quite sure whether the same DEFINITIONS wordlist is in the search ORDER that the original ANEW MARKER was defined in. Therefore, ANEW would be only safe on systems that do always stick to FORTH DEFINITIONS. Instead we will CREATE the ANEW MARKER in the ENVIRONMENT and use a simple SEARCH-WORDLIST on the ENVIRONMENT-WORDLIST upon re-run.

      \ old
      : ANEW BL WORD   DUP FIND NIP IF EXECUTE THEN   (MARKER) ;
      \ new
      : ANEW
        PARSE-WORD  2DUP ENVIRONMENT-WORDLIST SEARCH-WORDLIST IF  EXECUTE  THEN
        GET-CURRENT >R ENVIRONMENT-WORDLIST SET-CURRENT  (MARKER)  R> SET-CURRENT ;

((MARKER))
( -- )
"((MARKER))" ( -- )

runtime compiled by MARKER

_strpush_
( zstr* -- S: str* str# )
_strpush_ ( zstr* -- S: str* str# )

push a C-string onto the SP runtime-stack, as if S" string" was used

      : _strpush_ s! _strlen_ s! ;

_pocket_
( -- str* )
_pocket_ ( -- str* )

return the next pocket for interactive string input.

      : _pocket_ _pockets@_ _pocket@_ th  _pocket@_ 1+ _pockets#_ mod to _pocket@_ ;

_-trailing_
( str* str# -- str#' )
_-trailing_ ( str* str# -- str#' )

chop off trailing spaces for the stringbuffer. returns the new length, so for an internal counted string, use

        <x> dup count _-trailing_ c!
        : _-trailing_ begin dup while
           2dup + c@ bl <> if nip exit then
           1- repeat nip ;

_lower_
( str* str# -- )
_lower_ ( str* str# -- )

_tolower_ applied to a stringbuffer

      : _lower_ 0 do dup c@ _tolower_ over c! 1+ loop drop ;

_upper_
( str* str# -- )
_upper_ ( str* str# -- )

_toupper_ applied to a stringbuffer

      : _upper_ 0 do dup c@ _toupper_ over c! 1+ loop drop ;

_zplaced_
( str* str# dst* max# -- dst* )
[alias] _store_c_string_
_zplaced_ ( str* str# dst* max# -- dst* ) [alias] _store_c_string_

copy stringbuffer into a field as a zero-terminated string.

      : _zsplaced_ rot 2dup > if drop 1- else nip then _zplace_ ;

_pocket_zplaced
( str* str# -- pocket* )
[alias] _pocket_c_string_
_pocket_zplaced ( str* str# -- pocket* ) [alias] _pocket_c_string_

store a string-span as a zero-terminated string into another pocket-pad

      : _pocket_zplaced _pocket_ _/pocket_ _zplaced_ ;

_zplaced_filename_
( str* str# dst* max# -- dst* )
[alias] _store_filename_
_zplaced_filename_ ( str* str# dst* max# -- dst* ) [alias] _store_filename_

copy stringbuffer into a field as a zero-terminated filename-string, a shell-homedir like "~username" will be expanded, and the platform-specific dir-delimiter is converted in on the fly ('/' vs. '\\')

_pocket_fileame_
( str* str# -- dst* )
_pocket_fileame_ ( str* str# -- dst* )

a new pocket with the given filename as asciiz

      : _pocket_filename_ _pocket_ /pocket _zplaced_filename_

_search_
( str* str# key* key# -- 0 | key-in-str* )
_search_ ( str* str# key* key# -- 0 | key-in-str* )

search for substring p2/u2 in string p1/u1, returns null if not found or a pointer into str*,str# that has lenght of key#

_match_
( zpattern* zstring* ignorecase? -- yes? )
_match_ ( zpattern* zstring* ignorecase? -- yes? )

Match string against pattern. Pattern knows wildcards `*' and `?' and `\' to escape a wildcard.

_dig>num_
( c n* base -- ?ok )
_dig>num_ ( c n* base -- ?ok )

Get value of digit c into *n, return flag: valid digit.

_num2dig_
( val -- c )
_num2dig_ ( val -- c )

make digit

_hold_
( c -- )
_hold_ ( c -- )

insert into pictured numeric output string

_?number_
( str* str# dcell* -- ?ok )
_?number_ ( str* str# dcell* -- ?ok )

try to convert into number, see => ?NUMBER

_ud.r_
( d,d str* str# base -- str* )
_ud.r_ ( d,d str* str# base -- str* )

This is for internal use only (SEE and debugger), The real UD.R etc. words uses HOLD and the memory area below PAD

_d.r_
( d,d str* str# base -- str* )
_d.r_ ( d,d str* str# base -- str* )

This is for internal use only (SEE and debugger), The real UD.R etc. words use HOLD and the memory area below PAD

_._
( i str* str# base -- str* )
_._ ( i str* str# base -- str* )

This is for internal use only (SEE and debugger), The real => . etc. words use HOLD and the memory area below PAD

_outc_
( char -- )
[alias] _outc
_outc_ ( char -- ) [alias] _outc

emit single character, (output adjusting the OUT variable, see _putc_ to do without)

      : _emit_ _putc_ _?xy_ drop out ! ;

_ztype_
( zstr* -- )
[alias] _outs
_ztype_ ( zstr* -- ) [alias] _outs

type a string (output adjusting the OUT variable, see _puts_ to do without)

      : _ztype_ _puts_ _?xy_ drop out ! ;

_outf_
( ... zstr* -- n# )
_outf_ ( ... zstr* -- n# )

type a string with formatting (output adjusting the OUT variable, see _puts_ and _outs_ )

      : _outf_ 0x200 lbuffer: buf[]  buf[] _vsprintf_  buf[] _outs_ ;

_type_
( str* str# -- )
_type_ ( str* str# -- )

type counted string to terminal (output adjusting the OUT variable, see _puts_ and _outs_ )

      : _type_ 0 do c@++ _putc_ loop drop _flush_ _?xy drop out ! ;

_typeline_
( str* str# -- )
_typeline_ ( str* str# -- )

type counted string to terminal, if it does not fit in full on the current line, emit a CR before (output adjusting the OUT variable, see _type_ and _outs_ )

      : _typeline_ out @ over + cols @ > if cr then _type_ ;

_emits_
( n# ch -- )
_emits_ ( n# ch -- )

type a string of chars by repeating a single character which is usually a space, see SPACES (output adjusting the OUT variable, see _type_ and _outs_ )

      : _emits_ swap 0 do dup _putc_ loop drop _flush_ _?xy_ drop out ! ;

_tab_
( n# -- )
_tab_ ( n# -- )

type a string of space up to the next tabulator column (output adjusting the OUT variable, see _emits and _typeonline )

      : _tab_ dup out @ - swap mod bl _emits_ ;

_.line_
( file* block# line# -- )
_.line_ ( file* block# line# -- )
_expect_noecho_
( str* str# -- span# )
_expect_noecho_ ( str* str# -- span# )

EXPECT counted string from terminal, without echo, so no real editing it will however convert backspace and tabulators, break on newline/escape

_expect_
( str* str# -- span# )
_expect_ ( str* str# -- span# )

EXPECT counted string from terminal, with echo, so one can use simple editing facility with backspace, but nothing more. it's very traditional, you want to use a lined-like function instead!

_accept_
( str* str# -- span# )
_accept_ ( str* str# -- span# )

better input facility using lined if possible, otherwise call _expect_noecho when running in a pipe or just _expect_ if no real terminal attached.

QUERY
( -- )
QUERY ( -- )

source input: read from terminal using _accept_ with the returned string to show up in TIB of /TIB size.

_source_
( str*& str#& -- )
_source_ ( str*& str#& -- )

see SOURCE - dispatch input source

_size_saved_input_
( -- iframe-size )
_size_saved_input_ ( -- iframe-size )
_link_saved_input_
( iframe* -- )
_link_saved_input_ ( iframe* -- )

see SAVE-INPUT

_save_input_
( iframe-stack* -- iframe-stack*' )
_save_input_ ( iframe-stack* -- iframe-stack*' )

see SAVE-INPUT

_unlink_saved_input_
( iframe* -- )
_unlink_saved_input_ ( iframe* -- )

see RESTORE-INPUT

_restore_input_
( iframe-stack* -- iframe-stack*' )
_restore_input_ ( iframe-stack* -- iframe-stack*' )

see RESTORE-INPUT

_refill_
( -- flag )
_refill_ ( -- flag )

see REFILL

_skip_delimiter_
( del -- )
_skip_delimiter_ ( del -- )

SKIP-DELIMITER

_word:parse_
( delim -- <end?> )
_word:parse_ ( delim -- <end?> )
_parse_
( delim -- ptr len )
_parse_ ( delim -- ptr len )

      : _parse_ _word:parse_ _word*_ s! _word#_ s! ;

_word>here_
( -- here* )
_word>here_ ( -- here* )

complement _word:parse_ to arrive at the normal WORD implementation will also ensure the string is zero-terminated - this makes a lot of operations easier since most forth function can receive a string-span directly but some need a string-copy and that is usually because it has to be passed down into a C-defined function with zerotermined string. Just use p4_HERE+1 (which is also the returnvalue of this function!) to have the start of the zero-terminated string. Note that this function may throw with P4_ON_PARSE_OVER if the string is too long (it has set *DP=0 to ensure again that THROW will report PFE.word. as the offending string)

_word_
( del -- here* )
_word_ ( del -- here* )

      : _word_ dup _skip_delimiter_ _word:parse_ _word>here_ ;

DEBUG
( "word" -- )
[FTH]
DEBUG ( "word" -- ) [FTH]

this word will place an debug-runtime into the CFA of the following word. If the word gets executed later, the user will be prompted and can decide to single-step the given word. The debug-stepper is interactive and should be self-explanatory. (use NO-DEBUG to turn it off again)

NO-DEBUG
( "word" -- )
[FTH]
NO-DEBUG ( "word" -- ) [FTH]

the inverse of " DEBUG word "

(SEE) ( some-xt* -- ) [FTH]

decompile the token-sequence - used by SEE name

ADDR>NAME
( word-addr* -- word-nfa*!' | 0 )
[FTH]
ADDR>NAME ( word-addr* -- word-nfa*!' | 0 ) [FTH]

search the next corresponding namefield that address is next too. If it is not in the base-dictionary, then just return 0 as not-found.

ADDR>NAME
( word-addr* -- word-nfa!*' | 0 )
[FTH]
ADDR>NAME ( word-addr* -- word-nfa!*' | 0 ) [FTH]

search the next corresponding namefield that address is next too. If it is not in the base-dictionary, then just return 0 as not-found.

COME_BACK
( -- )
[FTH]
COME_BACK ( -- ) [FTH]

show the return stack before last exception along with the best names as given by ADDR>NAME

ONLY
( -- )
ONLY ( -- )

the only-vocabulary is special. Calling it will erase the search ORDER of vocabularies and only allows to name some very basic vocabularies. Even ALSO is not available.

      example:
        ONLY FORTH ALSO EXTENSIONS ALSO DEFINITIONS

FORTH
( -- )
FORTH ( -- )

      : FORTH FORTH-WORDLIST CONTEXT ! ;

(LOADM) ( module-bstr* -- module-sucess# ) [FTH]
LOADM
( "filename" -- )
[FTH]
LOADM ( "filename" -- ) [FTH]

dlmap the shared object (or share an already mapped object) and run the per-thread initialization code. This is the user-convenient function, otherwise use (LOADM)

      simulate:
        : LOADM  BL WORD
          ((IS_MODULE_LOADED)) IF EXIT THEN
          HERE (LOADM)  0= IF ." -- load failed: " HERE COUNT TYPE CR THEN ;

LOCAL-DLSYM
( [symbol] -- symbol-addr )
[FTH] [EXEC]
LOCAL-DLSYM ( [symbol] -- symbol-addr ) [FTH] [EXEC]

lookup the symbol that follows and leave the address (or null)

LOCAL_DLCALL
( x...[8] [symbol] -- x...[8] )
[FTH] [EXEC]
LOCAL_DLCALL ( x...[8] [symbol] -- x...[8] ) [FTH] [EXEC]

does not do any stack changes, the caller must clean up the stack himself. You don't even get the return value (sigh)

lt_dlinit
( -- dlinit-ior# )
[FTH]
lt_dlinit ( -- dlinit-ior# ) [FTH]

initialiize library, usually open the program itself so that its handles can be found under "0"

lt_dlopenext
( module-ptr module-len -- module-dl-handle*! | 0 )
[FTH]
lt_dlopenext ( module-ptr module-len -- module-dl-handle*! | 0 ) [FTH]

walk the searchpath for dlopen and try to open a binary module under the given name with the usual file extension for the current system.

lt_dlsym
( symbol-ptr symbol-len module-dl-handle* -- symbol*! | 0 )
[FTH]
lt_dlsym ( symbol-ptr symbol-len module-dl-handle* -- symbol*! | 0 ) [FTH]

try to find the name in the binary module denoted by its handle .. if handle is null, use the main body of the program

lt_dlclose
( module-dl-handle* -- module-ior# )
[FTH]
lt_dlclose ( module-dl-handle* -- module-ior# ) [FTH]

close handle that was returned by lt_dlopenext

lt_dlerror
( -- dlerror-zstr* )
lt_dlerror ( -- dlerror-zstr* )

returns string describing the last dlerror as for lt_dlopenext and lt_dlsym

(2CONSTANT) ( -- x1 x2 )

runtime portion of 2CONSTANT

2CONSTANT
( x1 x2 "name" -- )
2CONSTANT ( x1 x2 "name" -- )

create a word that contains the specified twocell number in its body. when the name is executed, these numbers are left on the stack

        12. 2CONSTANT X .s
        <emtpy stack> ok
        X .s
        0 12 ok

(2LITERAL) ( -- x1 x2 )

runtime portion of 2LITERAL

2LITERAL
( x1 x2 -- )
immediate
2LITERAL ( x1 x2 -- ) immediate

compile a double-cell number to the current definition. When run, the doubele-cell is left on the stack for execution.

        ( -- x1 x2 )

(in most configurations this word is statesmart and it will do nothing in interpret-mode. See 2LITERAL, for a non-immediate variant)

2VARIABLE
( -- )
2VARIABLE ( -- )

CREATE a new variable definition. When executed leave the >BODY address on stack. In pfe, the data area of a 2VARIABLE is ERASEd initially.

D+
( d1.ud1 d2.ud2 -- d3.ud3 )
D+ ( d1.ud1 d2.ud2 -- d3.ud3 )

the double-cell sum operation ( + )

D-( d1.ud1 d2.ud2 -- d3.ud3 )

the double-cell diff operation ( - )

D.R
( d1.d1 n -- )
D.R ( d1.d1 n -- )

aligned output for a double-cell number ( => .R )

D.
( d1.d1 -- )
D. ( d1.d1 -- )

freefield output for a double-cell number ( => . )

D0<
( d1.d1 -- flag )
D0< ( d1.d1 -- flag )

the double-cell less-than-zero operation ( 0< )

D0=
( d1.d1 -- flag )
D0= ( d1.d1 -- flag )

the double-cell equal-to-zero operation ( 0= )

D2*
( d1.d1 -- d1.d1' )
D2* ( d1.d1 -- d1.d1' )

the double-cell arithmetic shiftleft-by-1 operation ( 2* )

D2/
( d1.d1 -- d1.d1' )
D2/ ( d1.d1 -- d1.d1' )

the double-cell arithmetic shiftright-by-1 operation ( 2/ )

D<
( d1.d1 d2.d2 -- flag )
D< ( d1.d1 d2.d2 -- flag )

the double-cell is-less operation ( < )

D>S
( d.d -- n )
D>S ( d.d -- n )

result is the numeric equivalent of d. If the double number was greater than what could fit into a single cell number, the modulo cellsize will be left since the higher-significant bits are just DROPed

D=
( d1.d1 d2.d2 -- flag )
D= ( d1.d1 d2.d2 -- flag )

the double-cell is-equal operation ( = )

DABS
( d1.d1 -- d1.d1' )
DABS ( d1.d1 -- d1.d1' )

the double-cell abs operation ( ABS )

DMAX
( d1.d1 d2.d2 -- d1.d1|d2.d2 )
DMAX ( d1.d1 d2.d2 -- d1.d1|d2.d2 )

the double-cell max operation ( MAX )

DMIN
( d1.d1 d2.d2 -- d1.d1|d2.d2 )
DMIN ( d1.d1 d2.d2 -- d1.d1|d2.d2 )

the double-cell max operation ( MIN )

DNEGATE
( d1.d1 -- d1.d1' )
DNEGATE ( d1.d1 -- d1.d1' )

the double-cell arithmetic negate operation ( NEGATE )

M*/
( d1.d1 n1 +n2 -- d2.d2 )
"M*\/" ( d1.d1 n1 +n2 -- d2.d2 )

the double-cell multiply-divide operation using a triple-cell intermediate result for * ( *\/ )

M+
( d1.d1 n1 -- d2.d2 )
"M+" ( d1.d1 n1 -- d2.d2 )

the double-cell mixed-operand sum operation ( + / D+ )

ENVIRONMENT MAX-D
( -- d.d )
"ENVIRONMENT MAX-D" ( -- d.d )

ENVIRONMENT definition to check with ENVIRONMENT? if the double-cell wordset is present, the signed-max number is left.

"ENVIRONMENT MAX-UD ( -- d.d )

ENVIRONMENT definition to check with ENVIRONMENT? if the double-cell wordset is present, the unsigned-max number is left.

2ROT
( d1,d1 d2,d2 d3,d3 -- d2,d2 d3,d3 d1,d1 )
2ROT ( d1,d1 d2,d2 d3,d3 -- d2,d2 d3,d3 d1,d1 )

the double-cell ROT operation. actively moves six cells, i.e.

        ( x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2 )

DU<
( d1,d1 d2,d2 -- flag )
DU< ( d1,d1 d2,d2 -- flag )

the double-cell unsigned-is-less operation ( U< )

LITERAL,
( value -- )
LITERAL, ( value -- )

take the value from stack (or cs-stack) and compile a runtime-code and the value as for LITERAL ... this word is never state-smart, it is not immediate, and has therefore no complications with POSTPONE (compare also with COMPILE, to make a call-stub with an exectoken)

2LITERAL,
( x1,x2 -- )
2LITERAL, ( x1,x2 -- )

take the double-value from stack (or cs-stack) and compile a runtime-code and the value as for 2LITERAL ... this word is never state-smart, it is not immediate, and has therefore no complications with POSTPONE (compare also with COMPILE, to make a call-stub with an exectoken)

DCELLS
( x -- x' )
DCELLS ( x -- x' )

computes the number of address units for the specified number of double-cells

      : DCELLS CELLS 2* ;

DLSHIFT
( x1,x2 y -- z1,z2 )
DLSHIFT ( x1,x2 y -- z1,z2 )

shift-left a double-cell value. The shift-count is given as a single-cell.

DRSHIFT
( x1,x2 y -- z1,z2 )
DRSHIFT ( x1,x2 y -- z1,z2 )

shift-right a double-cell value. The shift-count is given as a single-cell. This is an arithmetic shift as for a signed double-cell value.

MAX-MCOUNT
( -- u )
MAX-MCOUNT ( -- u )

Leave the largest mstring count provided by the implementation. Canonical values are 255 and 2^32-1. "max-m-count"

/MCOUNT
( -- u )
/MCOUNT ( -- u )

Leave the size of the mstring count field provided by the implementation in ANS Forth character units, nominally bytes. Canonical sizes are one character and one cell. "slash-m-count"

EMPTY$
( $: -- empty$ )
EMPTY$ ( $: -- empty$ )

Push the MSA of a fixed, external representation of the empty string onto the string stack. "empty-string"

\n$
( $: -- newline$ )
\n$ ( $: -- newline$ )

Push the MSA of a fixed, external string whose body is the Unix newline character onto the string stack. "newline-string"

DSTRINGS
( -- dfa )
DSTRINGS ( -- dfa )

A Forth variable that holds the address of the current string space, where all dynamic string operations take place. "d-strings"

(M!) ( a.s msa -- )

(M!) is the same as Wil Baden's PLACE, except it assumes the buffer address msa to be aligned, and stores the ANS Forth string a.s as a measured string, zero-filled to trailing alignment. As with PLACE, it is assumed that the mstring copy does not clobber the old string, and there is no check for room starting at msa. "parens-m-store"

PARSE>S
( [ccc<char>] char -- addr len )
PARSE>S ( [ccc<char>] char -- addr len )

Parse the input stream up to the first occurrence of char, which is parsed away. If executing in compilation mode, append run-time semantics to the current definition that leaves the ANS Forth string representation on the stack. In interpretation mode, leave the ANS Forth string representation for a stored copy, which may be transient in the style of S". In either mode, the format of the stored string is implementation dependent. "parse-to-s"

NOTE: The interpreted copy is a nontransient in this implementation, and both copies are mstrings.

S`
( [ccc<`>] -- addr len )
S` ( [ccc<`>] -- addr len )

An immediate version of parse>s where the delimiter is `. In particular, the stored string in interpret mode is not transient. "s-back-tick"

M,S
( addr len -- addr' len )
M,S ( addr len -- addr' len )

ALLOT room and store the ANS Forth string into aligned data space as an mstring, leaving data space zero-filled to alignment; and leave the length and new body address. It is assumed that len is unsigned. An error is thrown if len is larger than the system parameter MAX_DATA_STR. "m-comma-s"

NOTE: MAX_DATA_STR is returned by

        S" /SCOPY" ENVIRONMENT?

NOTE: M,S differs from STRING, in Wil Baden's Tool Belt in that it stores an aligned, measured string with zero-filled alignment instead of a counted string, and it leaves the ANS Forth string representation of the stored string.

MCOUNT@
( msa -- count )
MCOUNT@ ( msa -- count )

Fetch the count of the mstring at msa. "m-count-fetch"

MCOUNT!
( count msa -- )
MCOUNT! ( count msa -- )

Store the count in the measured string count field at msa, without checking that it fits. "m-count-store"

MCOUNT
( msa -- body.addr count )
MCOUNT ( msa -- body.addr count )

Convert the mstring MSA to its ANS Forth string representation. "m-count"

-MCOUNT
( addr len -- msa )
-MCOUNT ( addr len -- msa )

Convert the ANS Forth representation of an mstring to its MSA. "minus-m-count"

0STRINGS
( -- )
0STRINGS ( -- )

Set all string variables holding bound string values in string space to the empty string, and clear string space, including the string buffer, string stack, and string stack frames. "zero-strings"

NOTE: If used for under the hood development, this word must be executed only when string space is in a valid state.

$GARBAGE?
( -- flag )
$GARBAGE? ( -- flag )

Leave true if there is garbage in the current string space. Not normally used, since garbage collection is transparent. "string-garbage-question"

$GC-OFF
( -- )
$GC-OFF ( -- )

Disable garbage collection in the current string space. An error will be thrown if garbage collection is attempted. "string-g-c-off"

$GC-ON
( -- )
$GC-ON ( -- )

Enable garbage collection in the current string space. This is the default. "string-g-c-on"

$GC-LOCK@
( -- flag )
$GC-LOCK@ ( -- flag )

Fetch the dstring garbage collection "off" state. Intended for saving the off state for later restoration after a usage of $GC-ON or $GC-OFF. "string-g-c-lock-fetch"

$GC-LOCK!
( flag -- )
$GC-LOCK! ( flag -- )

Set the dstring garbage collection "off" state according to flag. Intended for restoring the off state previously fetched by $GC-LOCK@. "string-g-c-lock-fetch"

$UNUSED
( -- u )
$UNUSED ( -- u )

Leave the number of bytes available for dynamic strings and string stack entries in the string buffer. "string-unused"

COLLECT-$GARBAGE
( -- collected-flag )
COLLECT-$GARBAGE ( -- collected-flag )

If string space is not marked as containing garbage, return false. If there is garbage, throw an error when garbage collection is disabled. Otherwise remove the garbage and return true. Garbage collection is "transparent", so the user would not normally use this word. "collect-string-garbage"

MAKE-$SPACE
( size #frames -- addr )
MAKE-$SPACE ( size #frames -- addr )

Allocate and initialize a string space with size bytes available for the string buffer including the string stack, and with a string frame stack for frame description entries holding up to #frames. The size is rounded up to cell alignment, and the buffer begins and ends with cell alignment. Return addr, the address of the string space. The standard word FREE with addr as input can be used to release the space. "make-string-space"

/$BUF
( -- u )
/$BUF ( -- u )

Leave the size in address units allocated for the current string buffer. "slash-string-buf"

MAX-#$FRAMES
( -- u )
MAX-#$FRAMES ( -- u )

Leave the number of string frames allowed on the string frame stack for the current string space. "max-number-string-frames"

$!
( $var.dfa $: a$ -- )
$! ( $var.dfa $: a$ -- )

Store the string MSA on the string stack in the variable whose DFA is on the parameter stack. "string-store"

NOTES: The only situation in which $! copies the string value is when it is a bound string already stored in another variable. In that case, the new copy is the one that is stored in the variable. In particular, external strings are not copied.

If the string value held by the string variable on entry is a bound string that is also referenced deeper on the string stack, its back link is reset to point to the deepest string stack reference. If it is a bound string not deeper on the string stack and not identical to the input string, its back link is set to zero, making it garbage. If it is an external string, its MSA in the variable is simply written over by that popped from the string stack.

$@
( $var.pfa -- $: a$ )
$@ ( $var.pfa -- $: a$ )

Leave the MSA of the string held by the string variable. "string-fetch"

$"
( [ccc<">] -- $: str )
$" ( [ccc<">] -- $: str )

Parse ccc delimited by " (double quote) and store it in data space as an mstring. If interpreting, leave the MSA on the string stack. If compiling, append run-time semantics to the current definition that leaves the MSA on the string stack. A program should not alter the stored string. An error is thrown if the quoted string length is larger than the system parameter MAX_DATA_STR (see SM,). "string-quote"

NOTE: In contrast to S", the string stored by $" when interpreting is not transient.

The implementation is based on PFE code for S".

$`
( [ccc<`>] -- $: str )
$` ( [ccc<`>] -- $: str )

Parse ccc delimited by ` (back-tick). This is "$"" with back tick instead of double quote as the delimiter. "string-back-tick"

$CONSTANT
( "name" $: a$ -- )
$CONSTANT ( "name" $: a$ -- )

Create a definition for "name" with the execution semantics "name" execution: ($: -- a$ )

It is assumed that the input string resides as a measured, unchanging string outside of string space. "string-constant"

For example:

        $" This is a sample string." $constant sample$

$VARIABLE
( "name" -- )
$VARIABLE ( "name" -- )

        "name" execution:	( -- dfa )

Create an ordinary Forth variable and initialize it to the address of a fixed, external, measured representation of the empty string, such as that pushed onto the string stack by EMPTY$. "string-variable""

PARSE>$
( [ccc<char>] char -- $: ccc$ )
PARSE>$ ( [ccc<char>] char -- $: ccc$ )

Parse the input stream up to the first occurrence of char, which is parsed away, and store the string as an external measured string. If executing in compilation mode, append run-time semantics to the current definition that leaves the MSA on the string stack. In interpretation mode, leave the MSA on the string stack, where the stored copy, unlike PARSE>S, is required to be nontransient.

($: ( "ccc<paren>" -- )

A synonym for (. Immediate. "paren-string-colon"

$.
( $: a$ -- )
$. ( $: a$ -- )

Display the string on the terminal. If the system implementation of TYPE has its output vectored, $. uses the same vector. "string-dot"

$2DROP
( $: a$ b$ -- )
$2DROP ( $: a$ b$ -- )

Drop the two topmost string stack entries, marking them as garbage if appropriate. "string-two-drop"

$2DUP
( $: a$ b$ -- a$ b$ a$ b$ )
$2DUP ( $: a$ b$ -- a$ b$ a$ b$ )

Leave copies of the two topmost string stack entries. The string values are not copied. "string-two-dupe"

$DEPTH
( -- n )
$DEPTH ( -- n )

Leave the number of items on the string stack. "string-depth"

$DROP
( $: a$ -- )
$DROP ( $: a$ -- )

Drop the topmost string stack entry, marking it as garbage if it is initially bound to the top of the string stack. "string-drop"

$DUP
( $: a$ -- a$ a$ )
$DUP ( $: a$ -- a$ a$ )

Leave a copy of the topmost string stack entry. The string value is not copied. "string-dupe"

$NIP
($: a$ b$ -- b$ )
$NIP ($: a$ b$ -- b$ )

Drop the next to top item from the string stack. "string-nip"

NOTE: Because of essential string space bookkeeping, the system level implementation can be little more efficient than the high-level definition:

        : $NIP  $SWAP $DROP ;

$OVER
( $: a$ b$ -- a$ b$ a$ )
$OVER ( $: a$ b$ -- a$ b$ a$ )

Leave a copy of the next most accessible string stack entry on top of the string stack. The string value is not copied. "string-over"

$PICK
( u $: au$ ... a0$ -- au$ ... a0$ au$ )
$PICK ( u $: au$ ... a0$ -- au$ ... a0$ au$ )

Copy the u-th string stack entry to the top of the string stack. The string value is not copied. Throw an error if the input string stack does not have at least u+1 items. "string-pick"

$SWAP
( $: a$ b$ -- b$ a$ )
$SWAP ( $: a$ b$ -- b$ a$ )

Exchange the two most accessible strings on the string stack. Throw an error if there are less than two strings on the stack. Neither string value is copied. "string-swap"

$EXCHANGE
( i j -- )
$EXCHANGE ( i j -- )

($: maxth$ ... minth$ ... -- minth$ ... maxth$ ... ) Exchange the ith and jth strings on the string stack, where the top is the 0th. Throw an error if there are not at least max[i,j] + 1 strings on the stack. Neither string value is copied. "string-exchange"

$S>
( $: a$ -- S: a.s )
$S> ( $: a$ -- S: a.s )

Drop a$ from the string stack and leave it as a ANS Forth string a.s, without copying. "string-s-from"

WARNING: If a$ is a bound string, it may move or disappear at the next garbage collection, making a.s invalid. This can be avoided by sandwiching sections of code where this could occur between $GC-OFF and $GC-ON.

$,S
( $: a$ -- S: a.s )
$,S ( $: a$ -- S: a.s )

Drop a$ from the string stack, copy it into data space as a measured string, and leave it as an ANS Forth string a.s. An error is thrown if the string length is larger than the system parameter MAX_DATA_STR (see M,S). "string-comma-s"

$S@
( $: a$ -- a$ S: a.s )
$S@ ( $: a$ -- a$ S: a.s )

Leave the string stack unchanged, and leave the string body address and length on the data stack. "string-s-fetch"

WARNING: If a$ is a bound string, it may move at the next garbage collection, making a.s invalid. This can be avoided by sandwiching sections of code where this could occur between $GC-OFF and $GC-ON.

$TUCK
($: a$ b$ -- b$ a$ b$ )
$TUCK ($: a$ b$ -- b$ a$ b$ )

Copy the top string stack item just below the second item. The string value is not copied. "string-tuck"

NOTE: Because of essential string space bookkeeping, the system level implementation can be little more efficient than the high-level definition:

        : $TUCK  $SWAP $OVER ;

$TYPE
($: a$ -- )
$TYPE ($: a$ -- )

Display the string on the terminal. A deprecated $. synonym. "string-type"

>$S
( a.s -- $: a$ )
>$S ( a.s -- $: a$ )

Push the external ANS Forth string a.s onto the string stack, without copying the string value into the string buffer. It is an unchecked error if the Forth string a.s is not stored as an external measured string. "to-string-s"

WARNING: If the string value of a.s is actually in the string buffer and not external, the push operation may generate a garbage collection that invalidates its MSA.

>$S-COPY
( a.s -- $: a$ )
>$S-COPY ( a.s -- $: a$ )

Copy the external string value whose body address and count are on the parameter stack into the string buffer and push it onto the string stack. Errors are thrown if the count is larger than MAX_MCOUNT, if there is not enough room in string space, even after garbage collection, or if there is an unterminated string concatenation. The input external string need not exist as a measured string. "to-string-s-copy"

NOTE: MAX_MCOUNT is the largest size the count field of a measured string can hold, e.g., 255, 64K-1, or 4,096M-1. It is returned by:

        S" /DYNAMIC-STRING" ENVIRONMENT?

WARNING: This word should not be used when the input string is a bound string because the copy operation may generate a garbage collection which invalidates its MSA.

$+
($: a$ -- )
$+ ($: a$ -- )

If a$ is the empty string, drop it and do nothing else.

In particular, do not start a new concatenation, which would lock string space against new nonconcatenating copies.

Otherwise append the string body to the end of the string currently being concatenated as the last string in the string buffer, and update its count field. If there is no concatenating string, start one. An error is thrown if the size of the combined string would be larger than MAX_MCOUNT or if there is not enough room in string space even after a garbage collection.

If garbage collection occurs, a$ remains valid even when it is in the string buffer.

When there is a concatenating string, concatenation is the only basic string operation that can copy a string into the string buffer. "string-plus"

S+
( a.s -- )
S+ ( a.s -- )

If a.s is the empty string, drop it and do nothing else.

Append the ANS Forth string body to the end of the string currently being concatenated as the last string in the string buffer, and update its count field. If there is no concatenating string, start one. An error is thrown if the size of the combined string would be larger than MAX_MCOUNT or if there is not enough room in string space even after a garbage collection.

S+ is most commonly used on external strings, not assumed to exist as mstrings. In contrast to $+, garbage collection could invalidate a.s if it is a dynamic string in the string buffer. S+ can be used in that situation if garbage collection is turned off with $GC-OFF.

When there is a concatenating string, concatenation is the only basic string operation that can copy a string into the string buffer. "s-plus"

PARSE-S+
( [ccc<char>] char -- )
PARSE-S+ ( [ccc<char>] char -- )

Parse the input stream up to the first occurrence of char, which is parsed away. If executing in compilation mode, append run-time semantics to the current definition that concatenates the characters parsed from the string. Otherwise concatenate the characters. "parse-s-plus"

ENDCAT
( -- $: cat$ | empty$ )
ENDCAT ( -- $: cat$ | empty$ )

If there is no concatenating string, do nothing but leave the empty string. If there is, leave it as a string bound to the top of the string stack, and terminate concatenation, permitting normal copies into the string buffer. "end-cat"

$+"
( [ccc<quote>] -- )
$+" ( [ccc<quote>] -- )

This word is immediate. In compilation mode it appends run-time semantics to the current definition that concatenates the quoted string according to the specification for $+. In interpretation mode it concatenates the string. An error is thrown if the length of the quoted string is longer than the system parameter MAX_DATA_STR (see M,S). "string-plus-quote"

$+`
( [ccc<backtick>] -- )
$+` ( [ccc<backtick>] -- )

The same as $+" but with back tick instead of double quote as delimiter. "string-plus-back-tick"

#$ARGS
( -- u )
#$ARGS ( -- u )

Leave the number of entries in the topmost string frame. Throw an error if the frame stack is empty. "number-string-args"

$ARGS{
( arg1'$ ... argN'$ "arg1 ... argN <}>" -- )
$ARGS{ ( arg1'$ ... argN'$ "arg1 ... argN <}>" -- )

         compilation: ( -- $: arg1$ ... argN$ )

Immediate and compilation-only.

Copy the argument strings across lines to the string buffer, push them onto the string stack with "argN" the most accessible, and make them into the top compile-time string stack frame. Compile the run-time code to make an argument frame out of the N most accessible run-time string stack entries. Inform the system text interpreter that it should compile run-time code for any white-space delimited argument encountered in the text of the definition, that concatenates the corresponding string in the run-time frame. At the semicolon terminating the definition, drop the compile-time argument frame and compile code to drop the run-time argument frame.

The code between $ARGS{ ... } and the terminating semicolon is not allowed to make a net change in the string stack depth, because that would interfere with the automatic dropping of the string argument frame at the semicolon. "string-args-brace"

Syntax for defining a string macro GEORGE:

          : george  ($: a$ b$ c$ -- cat$ )
            $ARGS{ arg1 arg2 arg3 }
            cat" This is arg1:  " arg1 cat" ." ENDCAT $. ;

The blank following the last argument is required. For a macro with no arguments, $ARGS{ } does nothing but add useless overhead and should be omitted. Two of the arguments in this example are ignored and could have been left out. Note that ENDCAT would not be legal in this word without something like $. to remove the concatenated string from the string stack before the terminating semicolon. It is normal to use an $ARGS{ } word as a step in a concatenation that is terminated elsewhere.

Sample syntax using the string macro george:

          $" bill"  $" sue"  $" marie"  george $.

The resulting display is:

          This is arg1:  bill.

NOTE: Macro argument labels must be distinct from each other and from any local labels that appear in the same definition, and there is no check for that.

NOTE: At the moment the semantics of $ARGS{ is undefined before DOES>.

$FRAME
( u -- )
$FRAME ( u -- )

Push the description of a string stack frame starting at the top of the string stack and containing u entries onto the string frame stack. Errors are thrown if the frame stack would overflow or if the depth of the string stack above the top frame, if there is one, is less than u. The value u = 0 is allowed. "string-frame"

NOTE: This implementation pushes u and the string stack pointer onto the frame stack.

$FRAME-DEPTH
( -- u )
$FRAME-DEPTH ( -- u )

Leave the number of string frames currently on the string frame stack. "string-frame-depth"

DROP-$FRAME
($: frame*$ i*$ -- i*s )
DROP-$FRAME ($: frame*$ i*$ -- i*s )

Drop the topmost string frame from the string frame stack, and the corresponding strings, frame*$, from the string stack. An error is thrown if either stack would underflow. The cases where the frame has zero entries on the string stack and/or there are zero or more items on the string stack above the top frame item are handled properly. "drop-string-frame"

FIND-$ARG
( s -- u true | false )
FIND-$ARG ( s -- u true | false )

Leave true and its index u in the top string frame if the ANS Forth string matches an element of the frame, else leave false. The index of the top frame element is zero. "find-string-arg"

TH-$ARG
( u -- $: arg$ )
TH-$ARG ( u -- $: arg$ )

Leave the u-th string in the topmost string frame, where the index u of the top element is zero. Throw an error if the frame stack is empty or if the top frame contains less than u+1 strings. "th-string-arg"

(DROP-$FRAME) ( -- )

Cleanup code for the end of a definition that uses $ARGS{. ;-semicolon should be overloaded to compile it automatically if dynamic string arguments were in use. "paren-drop-string-frame-paren"

$POP
( $: a$ -- s: a$)
$POP ( $: a$ -- s: a$)

Abort if the string stack would underflow when popped.

Otherwise pop the top of the string stack and push it onto the data stack.

If the string is in the current string space and initially bound to the top of the string stack, mark it as garbage by setting its back link to NULL and set the garbage flag.

This word violates the rule that only ANS Forth strings should appear on the data stack, and so is under the hood. "string-pop"

$PUSH-EXT
( a$ -- $: a$ )
$PUSH-EXT ( a$ -- $: a$ )

Pop an external mstring address from the data stack and push it onto the string stack after checking for room, invoking garbage collection if necessary. Not to be used with a dynamic string because a garbage collection can invalidate its address.

This word violates the normal rule that only ANS Forth strings should appear on the data stack, and so is under the hood. "string-push-ext"

$BREAKP@
( -- $stack.break.addr )
$BREAKP@ ( -- $stack.break.addr )

"string-break-p-fetch"

$BUFP@
( -- $buffer.addr )
$BUFP@ ( -- $buffer.addr )

"string-buf-p-fetch"

$FBREAKP@
( -- frame.stack.break.addr )
$FBREAKP@ ( -- frame.stack.break.addr )

"string-f-break-p-fetch"

$FSP0@
( -- initial.frame.stack.top.addr )
$FSP0@ ( -- initial.frame.stack.top.addr )

"string-f-s-p-zero-fetch"

$FSP@
( -- frame.stack.top.addr )
$FSP@ ( -- frame.stack.top.addr )

"string-f-s-p-fetch"

$SP0@
( -- initial.string.stack.top.addr )
$SP0@ ( -- initial.string.stack.top.addr )

"string-s-p-zero-fetch"

$SP@
( -- string.stack.top.addr )
$SP@ ( -- string.stack.top.addr )

"string-s-p-fetch"

/$SFRAME-ITEM
( -- frame.stack.item.size )
/$SFRAME-ITEM ( -- frame.stack.item.size )

"slash-string-frame-item"

/$SFRAME-STACK
( -- max.frame.stack.size )
/$SFRAME-STACK ( -- max.frame.stack.size )

"slash-string-frame-stack"

/$SPACE-HEADER
( -- $space.header.size )
/$SPACE-HEADER ( -- $space.header.size )

"slash-string-space-header"

0$SPACE
( $space.addr -- )
0$SPACE ( $space.addr -- )

Clear the string buffer, string stack, and string frame stack in the string space starting at space.addr. Any string variables holding strings in the string buffer are left pointing into limbo. This may be executed with the string space in an invalid state, as long as the /$BUF and MAX-#$FRAMES fields of its string space structure are intact. "zero-string-space"

NOTE: This word does not zero fill the string buffer.

CAT$P@
( -- cat$.msa | 0 )
CAT$P@ ( -- cat$.msa | 0 )

"cat-string-fetch"

IN-$BUFFER?
( msa -- flag )
IN-$BUFFER? ( msa -- flag )

Leave true if the mstring is in the string buffer. "in-string-buffer-question"

ENVIRONMENT DSTRINGS-EXT
( -- datecoded-version )
"ENVIRONMENT DSTRINGS-EXT" ( -- datecoded-version )

an ENVIRONMENT constant to be checked with ENVIRONMENT? the value is currently encoded as a datecode with a decimal printout of format like YYMMDD

ENVIRONMENT /SCOPY
( -- MAX_DATA_STR )
"ENVIRONMENT /SCOPY" ( -- MAX_DATA_STR )

an ENVIRONMENT constant to be checked with ENVIRONMENT? returns the configuration value of MAX_DATA_STR

ENVIRONMENT /DYNAMIC-STRING
( -- MAX_MCOUNT )
"ENVIRONMENT /DYNAMIC-STRING" ( -- MAX_MCOUNT )

an ENVIRONMENT constant to be checked with ENVIRONMENT? returns the configuration value of MAX_MCOUNT

EDIT-BLOCK
( blk -- )
EDIT-BLOCK ( blk -- )

start the internal block-editor on the assigned block

EDIT-TEXT name ( -- )

start an external EDITOR with the specified filename

EDIT-ERROR
( -- )
EDIT-ERROR ( -- )

if an error occured, this routine can be called to invoke an appropriate EDITOR (see also EDIT-BLOCK)

[ANS]
( -- )
immediate
[ANS] ( -- ) immediate

the VOCABULARY that holds only the standardwords. see FORTH for a definition that will search-also point to ANS'

FORTH
( -- )
FORTH ( -- )

in pfe it is not actually a VOCABULARY anymore but behaves likewise. it will fetch the VALUE from FORTH-WORDLIST and execute it as if it were a VOCABULARY

EXTENSIONS
( -- )
EXTENSIONS ( -- )

in pfe it is not actually a VOCABULARY anymore but behaves likewise. it will fetch the VALUE from EXTRA-WORDLIST and execute it as if it were a VOCABULARY

INTERPRET-FIND
( CS: dest* -- dest* )
executes ( -- ) experimental
INTERPRET-FIND ( CS: dest* -- dest* ) executes ( -- ) experimental

check the next word from QUERY and try to look it up with FIND - if found then execute the token right away and branch out of the loop body (usually do it AGAIN )

INTERPRET-NUMBER
( CS: dest* -- dest* )
executes ( -- ) experimental
INTERPRET-NUMBER ( CS: dest* -- dest* ) executes ( -- ) experimental

check the next word from QUERY and try to parse it up with => ?NUMBER - if parseable then postpone the number for execution and branch out of the loop body (usually do it AGAIN )

REQUIRED
( ... str-ptr str-len -- ??? )
REQUIRED ( ... str-ptr str-len -- ??? )

the filename argument is loaded via INCLUDED as an extension package to the current system. The filename is registered in the current ENVIRONMENT so that it is only INCLUDED once (!!) if called multiple times via REQUIRED or REQUIRES

REQUIRES
( ... "file-name" -- ... )
REQUIRES ( ... "file-name" -- ... )

old variant of Forth200x REQUIRE name

REQUIRE
( ... "file-name" -- ... )
REQUIRE ( ... "file-name" -- ... )

parses the next WORD and passes it to REQUIRED this is the self-parsing version of REQUIRED and it does parrallel INCLUDE w.r.t. INCLUDED

ENVIRONMENT
( -- )
ENVIRONMENT ( -- )

execute the VOCABULARY runtime for the ENVIRONMENT-WORDLIST

      : ENVIRONMENT  ENVIRONMENT-WORDLIST CONTEXT ! ;
      ' ENVIRONMENT  ALIAS [ENV] IMMEDIATE

see newstyle ENVIRONMENT?

ENVIRONMENT-WORDLIST
( -- wid )
ENVIRONMENT-WORDLIST ( -- wid )

return the WORDLIST id of the ENVIRONMENT so it could be passed to CURRENT (via SET-CURRENT)

      WORDLIST VALUE ENVIRONMENT-WORDLIST ;

ENVIRONMENT?
( a1 n1 -- false | ?? true )
ENVIRONMENT? ( a1 n1 -- false | ?? true )

check the environment for a property, usually a condition like questioning the existance of specified wordset, but it can also return some implementation properties like "WORDLISTS" (the length of the search-order) or "#LOCALS" (the maximum number of locals)

Here it implements the environment queries as a SEARCH-WORDLIST in a user-visible vocabulary called ENVIRONMENT

      : ENVIRONMENT?
        ['] ENVIRONMENT >WORDLIST SEARCH-WORDLIST
        IF  EXECUTE TRUE ELSE  FALSE THEN ;

special extension: a search for CORE will also find a definition of CORE-EXT or CORE-EXT-EXT or CORE-EXT-EXT-EXT - it just has to be below the ansi-standard maximum length of 31 chars.

if a name like "dstrings-ext" is given, and no such entry can be found, then envQ will try to trigger a (LOADM) of that module, in the hope that this implicit-load does in fact define the answer. Use with care, it's a very new feature.

NEEDS
( name -- )
NEEDS ( name -- )

A self-parsing variant of an environment-query check. It is similar to a simulation like

      : NEEDS PARSE-WORD 2DUP ENVIRONMENT?
        IF DROP ( extra value ) 2DROP ( success - be silent )
        ELSE TYPE ." not available " CR THEN ;

however that would only match those worset-envqueries which return a single extra item under the uppermost TRUE flag in the success case. Instead it works more like

      : NEEDS PARSE-WORD 2DUP ENVIRONMENT-WORDLIST SEARCH-WORDLIST
        IF 2DROP ( success - be silent and just drop the parsed word )
        ELSE TYPE ." not available " CR THEN ;

however we add the same extension as in ENVIRONMENT? as that it can automatically load a wordset module to fullfil a query that looks like "[wordsetname]-ext". Therefore, the following two lines are pretty much identical:

      LOADM floating
      NEEDS floating-ext

the difference between the two: if somebody did provide a forth level implementation of floating-ext then that implementation might have registered a hint "floating-ext" in the environment-wordlist. This extra-hint will inhibit loading of the binary module even if it exists and not been loaded so far. The LOADM however will not check the ENVIRONMENT-WORDLIST and only check its loadlist of binary wordset modules in the system.

It is therefore recommended to use NEEDS instead of LOADM unless you know you want the binary module, quickly and uncondtionally.

ENVIRONMENT HOST-SYSTEM
( -- str len )
"ENVIRONMENT HOST-SYSTEM" ( -- str len )

returns the HOST-SYTEM type, can be used to distinguish different runtime environments. (see .STATUS)

ENVIRONMENT CASE-SENSITIVE?
( -- flag )
"ENVIRONMENT CASE-SENSITIVE?" ( -- flag )

Classifying Forth systems 7 by J Thomas on comp.lang.forth, 06.Feb.2001 ------------------------------------------- Thomas' spec did not reveal whether to return the system-wide LOWER_CASE or the wordlist-local NOCASE-state. For now, it returns the wordlist-local state.

ENVIRONMENT FORTH-NAME
( -- caddr len )
"ENVIRONMENT FORTH-NAME" ( -- caddr len )

Classifying Forth systems 6 by J Thomas on comp.lang.forth, 03.Feb.2001 -------------------------------------------

The string should be a name, like ProForth or SwiftForth

------------------------------------------- Thomas' spec did not reveal whether to return a longname or shortname. For now, it returns the short name.

ENVIRONMENT FORTH-VERSION
( -- caddr len )
"ENVIRONMENT FORTH-VERSION" ( -- caddr len )

Classifying Forth systems 6 by J Thomas on comp.lang.forth, 03.Feb.2001 -------------------------------------------

The string will give a version number, whatever the implementor chooses.

------------------------------------------- Thomas' spec did not reveal whether to return a compact or talkative version spec. For now, it returns the long version-string.

ENVIRONMENT FORTH-CONTACT
( -- caddr len )
"ENVIRONMENT FORTH-CONTACT" ( -- caddr len )

Classifying Forth systems 6 by J Thomas on comp.lang.forth, 03.Feb.2001 -------------------------------------------

The string will give a name-and-address or website etc.

------------------------------------------- Thomas' spec did not reveal whether to return a URL-form and a readable free-form. For now, it returns the URL-form of the sourceforge project.

CATCH
( catch-xt* -- 0 | throw#! )
[ANS]
CATCH ( catch-xt* -- 0 | throw#! ) [ANS]

execute the given execution-token and catch any exception that can be caught therein. software can arbitrarily raise an exception using THROW - the value 0 means there was no exception, other denote implementation dependent exception-codes.

THROW
( throw#! -- [THROW] | throw# -- )
[ANS]
THROW ( throw#! -- [THROW] | throw# -- ) [ANS]

raise an exception - it will adjust the depth of all stacks and start interpreting at the point of the latest CATCH
if n is null nothing happens, the -1 (ie. FALSE ) is the raise-code of ABORT - the other codes are implementation dependent and will result in something quite like ABORT

ABORT
( -- [THROW] )
[ANS]
ABORT ( -- [THROW] ) [ANS]

throw - cleanup some things and go back to the QUIT routine

      : ABORT -1 THROW ;

((ABORT")) ( -- ) [HIDDEN]

compiled by ABORT" what"

ABORT"
( [string<">] -- [THROW] )
[ANS]
'ABORT"' ( [string<">] -- [THROW] ) [ANS]

throw like ABORT but print an additional error-message to stdout telling what has happened.

NEXT-EXCEPTION
( -- throw#!* )
[EXT]
NEXT-EXCEPTION ( -- throw#!* ) [EXT]

used for runtime allocation of a new throw id.

(EXCEPTION-STRING: ( exception# [description<closeparen>] -- )

append a node with the given id and a pointer to an extern zstring to the NEXT-EXCEPTION chain-list.

AT-XY
( col# row# -- )
[ANS]
AT-XY ( col# row# -- ) [ANS]

move the cursor position to the given row and column of the screen. If the output device is not a terminal this will have no effect but can still send an escape sequence.

KEY?
( -- key-flag )
[ANS]
KEY? ( -- key-flag ) [ANS]

if a character is available from the keyboard, return true. The KEY word will retrieve the actual character.

EKEY
( -- key-code# )
[ANS]
EKEY ( -- key-code# ) [ANS]

return a keyboard event, the encoding may differ, esp. that it can contain special keys.

EKEY>CHAR
( key-code# -- key-code# 0 | char# true! )
[ANS]
EKEY>CHAR ( key-code# -- key-code# 0 | char# true! ) [ANS]
EKEY?
( -- ekey-flag )
[ANS]
EKEY? ( -- ekey-flag ) [ANS]

check if a character is available from the keyboard to be received - unlike KEY? it will not discard non-visible codes.

EMIT?
( -- emit-flag )
[ANS]
EMIT? ( -- emit-flag ) [ANS]

if EMIT can safely output characters without blocking the forth by waiting for an indefinite time.

MS
( milliseconds# -- )
[ANS]
MS ( milliseconds# -- ) [ANS]

wait at least the specified milliseconds (suspend the forth tasklet)

TIME&amp;DATE
( -- sec# min# hrs# day# month# year# )
[ANS]
TIME&amp;DATE ( -- sec# min# hrs# day# month# year# ) [ANS]

return the broken down current time

PAGE
( -- )
[ANS]
PAGE ( -- ) [ANS]

CLRSCR

#!
( "...<eol>" -- )
#! ( "...<eol>" -- )

ignores the rest of the line, defining `#!' is used to support forth scripts executed by the unix kernel

CLOCK@
( --- clock-ticks# )
[EXT]
CLOCK@ ( --- clock-ticks# ) [EXT]

return clock(2) - the number of clocks of this process. To get the number of seconds, divide by CLOCKS_PER_SEC as represented in the ENVIROMENT for a hosted forth system. A similar scheme is used by MS@ to compute the clock time rounded to milliseconds (named in similarity with MS sleep).

Remember that the process clock will wrap around at some point, therefore only use difference values between two clock reads.

GETTIMEOFDAY
( -- milliseconds# epochseconds# )
[EXT]
GETTIMEOFDAY ( -- milliseconds# epochseconds# ) [EXT]

returns SVR/BSD gettimeofday(2). Incompatible with 16-bit systems as the numbers can not be properly represented, hence TIME&DATE is more portable.

ENVIRONMENT CLOCKS_PER_SEC
( -- tick-count# )
[ENVIRONMENT]
"ENVIRONMENT CLOCKS_PER_SEC" ( -- tick-count# ) [ENVIRONMENT]

the system's scheduler heartbeat clock (also known as jiffies or simply HZ) for every function that expects time-values in ticks.

MS@
( -- milliseconds# )
[EXT]
MS@ ( -- milliseconds# ) [EXT]

elapsed time since start of process (or system) - in millseconds. The granularity is per clock ticks as per ENVIRONMENT CLOCKS_PER_SEC For the current wall clock in milliseconds, ask GETTIMEOFDAY.

Remember that the process clock will wrap around at some point, therefore only use difference values between two clock reads. Also note that on many desktop systems the process scheduler ticks per 1/100s or 1/60s so that the difference of two continuous reads of the process clock will show steps of 10 to 16 milliseconds.

see also CLOCK@ and MS

BIN
( access-mode# -- access-mode#' )
[ANS]
BIN ( access-mode# -- access-mode#' ) [ANS]

modify the give file access-mode to be a binary-mode

CLOSE-FILE
( some-file* -- some-errno# )
[ANS]
CLOSE-FILE ( some-file* -- some-errno# ) [ANS]

close the file and return the status-code

CREATE-FILE
( name-ptr name-len open-mode# -- name-file* name-errno# )
[ANS]
CREATE-FILE ( name-ptr name-len open-mode# -- name-file* name-errno# ) [ANS]

create the file with the given name and open it - returns the file id and a status code. A code of zero means success. An existing file of the same name is truncated upon open.

DELETE-FILE
( name-ptr name-len -- name-errno# )
[ANS]
DELETE-FILE ( name-ptr name-len -- name-errno# ) [ANS]

delete the named file and return a status code

FILE-POSITION
( some-file* -- p,pos# some-errno# )
[ANS]
FILE-POSITION ( some-file* -- p,pos# some-errno# ) [ANS]

return the current position in the file and return a status code. A code of zero means success.

FILE-SIZE
( some-file* -- s,size# some-errno# )
[ANS]
FILE-SIZE ( some-file* -- s,size# some-errno# ) [ANS]

return the current size of the file and return a status code. A code of zero means success.

INCLUDE-FILE
( some-file* -- )
[ANS]
INCLUDE-FILE ( some-file* -- ) [ANS]

INTERPRET the given file

INCLUDED
( name-ptr name-len -- )
[ANS]
INCLUDED ( name-ptr name-len -- ) [ANS]

open the named file and then INCLUDE-FILE see also the interactive INCLUDE

OPEN-FILE
( name-ptr name-len open-mode# -- name-file* name-errno# )
[ANS]
OPEN-FILE ( name-ptr name-len open-mode# -- name-file* name-errno# ) [ANS]

open the named file with mode. returns the file id and a status code. A code of zero means success.

READ-FILE
( buf-ptr buf-len some-file* -- buf-count some-errno# )
[ANS]
READ-FILE ( buf-ptr buf-len some-file* -- buf-count some-errno# ) [ANS]

fill the given string buffer with characters from the buffer. A status code of zero means success and the returned count gives the number of bytes actually read. If an error occurs the number of already transferred bytes is returned.

READ-LINE
( buf-ptr buf-len some-file* -- buf-count buf-flag some-errno# )
[ANS]
READ-LINE ( buf-ptr buf-len some-file* -- buf-count buf-flag some-errno# ) [ANS]

fill the given string buffer with one line from the file. A line termination character (or character sequence under WIN/DOS) may also be placed in the buffer but is not included in the final count. In other respects this function performs a READ-FILE

REPOSITION-FILE
( o,offset# some-file* -- some-errno# )
[ANS]
REPOSITION-FILE ( o,offset# some-file* -- some-errno# ) [ANS]

reposition the file offset - the next FILE-POSITION would return o.offset then. returns a status code where zero means success.

RESIZE-FILE
( s,size# some-file* -- some-errno# )
[ANS]
RESIZE-FILE ( s,size# some-file* -- some-errno# ) [ANS]

resize the give file, returns a status code where zero means success.

WRITE-FILE
( buf-ptr buf-len some-file* -- some-errno# )
[ANS]
WRITE-FILE ( buf-ptr buf-len some-file* -- some-errno# ) [ANS]

write characters from the string buffer to a file, returns a status code where zero means success.

WRITE-LINE
( buf-ptr buf-len some-file* -- some-errno# )
[ANS]
WRITE-LINE ( buf-ptr buf-len some-file* -- some-errno# ) [ANS]

write characters from the string buffer to a file, and add the line-terminator to the end of it. returns a status code.

FILE-STATUS
( file-ptr file-len -- file-subcode# file-errno# )
[ANS]
FILE-STATUS ( file-ptr file-len -- file-subcode# file-errno# ) [ANS]

check the named file - if it exists the status errno code is zero. The status subcode is implementation-specific and usually matches the file access permission bits of the filesystem.

FLUSH-FILE
( some-file* -- some-errno# )
[ANS]
FLUSH-FILE ( some-file* -- some-errno# ) [ANS]

flush all unsaved buffers of the file to disk. A status code of zero means success.

RENAME-FILE
( oldname-ptr oldname-len newname-ptr newname-len -- newname-errno# )
[ANS]
RENAME-FILE ( oldname-ptr oldname-len newname-ptr newname-len -- newname-errno# ) [ANS]

rename the file named by "oldname" to the name of "newname" returns a status-code where zero means success.

R/O
( -- readonly-mode# )
[ANS]
R/O ( -- readonly-mode# ) [ANS]

a bitmask for OPEN-FILE ( R/O R/W W/O BIN )

W/O
( -- writeonly-mode# )
[ANS]
W/O ( -- writeonly-mode# ) [ANS]

a bitmask for OPEN-FILE or CREATE-FILE ( R/O R/W W/O BIN )

R/W
( -- readwrite-mode# )
[ANS]
R/W ( -- readwrite-mode# ) [ANS]

a bitmask for OPEN-FILE or CREATE-FILE ( R/O R/W W/O BIN )

ENVIRONMENT MAX-FILES
( -- files-max )
[ENVIRONMENT]
"ENVIRONMENT MAX-FILES" ( -- files-max ) [ENVIRONMENT]

the number of opened file-ids allowed during compilation. portable programs can check this with ENVIRONMENT?

INCLUDE
( "filename" -- ??? )
[FTH]
INCLUDE ( "filename" -- ??? ) [FTH]

load the specified file, see also LOAD" filename"

COPY-FILE
( src-ptr src-len dst-ptr dst-len -- copy-errno# )
[FTH]
COPY-FILE ( src-ptr src-len dst-ptr dst-len -- copy-errno# ) [FTH]

like RENAME-FILE, copies the file from src-name to dst-name and returns an error-code or null

MOVE-FILE
( src-ptr src-len dst-ptr dst-len -- move-errno# )
[FTH]
MOVE-FILE ( src-ptr src-len dst-ptr dst-len -- move-errno# ) [FTH]

like RENAME-FILE, but also across-volumes
moves the file from src-name to dst-name and returns an error-code or null

FILE-R/W
( buffer* use-block# flag? some-file* -- )
[FTH]
FILE-R/W ( buffer* use-block# flag? some-file* -- ) [FTH]

like FIG-Forth `R/W`

FILE-BLOCK
( use-block# some-file* -- buffer* )
[FTH]
FILE-BLOCK ( use-block# some-file* -- buffer* ) [FTH]
FILE-BUFFER
( use-block# some-file* -- buffer* )
[FTH]
FILE-BUFFER ( use-block# some-file* -- buffer* ) [FTH]
FILE-EMPTY-BUFFERS
( some-file* -- )
[FTH]
FILE-EMPTY-BUFFERS ( some-file* -- ) [FTH]
FILE-FLUSH
( some-file* -- )
[FTH]
FILE-FLUSH ( some-file* -- ) [FTH]

      simulate      : FILE-FLUSH DUP FILE-SAVE-BUFFERS FILE-EMTPY-BUFFERS ;

FILE-LIST
( use-block# some-file* -- )
[FTH]
FILE-LIST ( use-block# some-file* -- ) [FTH]
FILE-LOAD
( use-block# some-file* -- )
[FTH]
FILE-LOAD ( use-block# some-file* -- ) [FTH]
FILE-SAVE-BUFFERS
( some-file* -- )
[FTH]
FILE-SAVE-BUFFERS ( some-file* -- ) [FTH]
FILE-THRU
( lo-block# hi-block# some-file* -- )
[FTH]
FILE-THRU ( lo-block# hi-block# some-file* -- ) [FTH]

see THRU

FILE-UPDATE
( some-file* -- )
[FTH]
FILE-UPDATE ( some-file* -- ) [FTH]
( f: a -- n,n )

b is the integer representation of a

we use truncation towards zero. compare with F>S and its "FROUND>S" / "FTRUNC>S"

INTERPRET-FLOAT
( CS: dest* -- dest* )
executes ( -- F: f# ) experimental
INTERPRET-FLOAT ( CS: dest* -- dest* ) executes ( -- F: f# ) experimental

check the next word from QUERY and try to parse it as a floating number - if parseable then postpone the value on the floating stack and branch out of the loop body (usually do it AGAIN )

FP@
( -- addr )
FP@ ( -- addr )

returns the floating point stack pointer

FP!
( addr -- )
FP! ( addr -- )

sets the floating point stack pointer - this is the inverse of FP@

F?
( f: a b -- s: a==b )
F? ( f: a b -- s: a==b )
F<>
( f: a b -- s: a!=b )
F<> ( f: a b -- s: a!=b )
S>F
( n -- f: x )
S>F ( n -- f: x )

it's inverse is F>S - convert a cell parameter to floating-point.

FTRUNC>S
(f: x -- s: n )
FTRUNC>S (f: x -- s: n )

The word F>S was sometimes defined with a different behavior than FTRUNC>S which is the type-cast behaviour of C according to C99 section 6.3.1.4 - truncation would also match the ANS-Forth specification for F>D.

Some systems used F>S defined to FROUND>S instead. The pfe provides explicit words for both conversions, the word FROUND>S and FTRUNC>S which return single-cell parameters for a floating point number with the conversion method of FTRUNC or FROUND.

In PFE, F>S is a synonym pointing to FTRUNC>S in analogy of the behavior of F>D where no explicit word exists. The inverse of F>S is the cast conversion of S>F.

FROUND>S
(f: x -- s: n)
FROUND>S (f: x -- s: n)

complements FTRUNC>S for applications that expect F>S to be defined with a rounding behavior like

      : FROUND>S FROUND FTRUNC>S ;

FTRUNC
(f: x -- x' )
FTRUNC (f: x -- x' )

truncate towards zero, discard a fractional part. See also FTRUNC>S conversion and the FROUND and FLOOR adaptors.

      : FTRUNC FDUP F0< IF FCEIL ELSE FLOOR THEN ;

(When available, uses a single call to C99 trunc() internally)

-FROT
(f: x1 x2 x3 -- x3 x1 x2 )
-FROT (f: x1 x2 x3 -- x3 x1 x2 )

F-stack equivalent of -ROT

note, some systems call this work F-ROT, here it is the inverse of FROT

FNIP
(f: x1 x2 -- x2 )
FNIP (f: x1 x2 -- x2 )

F-stack equivalent of NIP

FTUCK
(f: x1 x2 -- x2 x1 x2 )
FTUCK (f: x1 x2 -- x2 x1 x2 )

F-stack equivalent of TUCK

1/F
(f: x -- 1/x )
1/F (f: x -- 1/x )
F^2
(f: x -- x^2 )
F^2 (f: x -- x^2 )
F^N
( u f: x -- x^u )
F^N ( u f: x -- x^u )

For large exponents, use F** instead. Of course u=-1 is large.

F2/
(f: x -- x/2 )
F2/ (f: x -- x/2 )
F2*
(f: x -- x*2 )
F2* (f: x -- x*2 )
F0>
(f: x -- s: flag )
F0> (f: x -- s: flag )
F0<>
(f: x -- s: flag )
F0<> (f: x -- s: flag )
2+
( a# -- a#' | a* -- a*' | a -- a' [??] )
[FTH]
2+ ( a# -- a#' | a* -- a*' | a -- a' [??] ) [FTH]

add 2 to the value on stack (and leave the result there)

      simulate:
        : 2+ 2 + ;

2-
( a# -- a#' | a* -- a*' | a -- a' [??] )
[FTH]
2- ( a# -- a#' | a* -- a*' | a -- a' [??] ) [FTH]

substract 2 from the value on stack (and leave the result there)

      simulate:
        : 2- 2 - ;

COMPILE
( "word" -- )
[FTH]
COMPILE ( "word" -- ) [FTH]

compile the next word. The next word should not be immediate, in which case you would have to use [COMPILE]. For this reason, you should use the word POSTPONE, which takes care it.

      simulate:
        : COMPILE  R> DUP @ , CELL+ >R ;  ( not immediate !!! )

((VOCABULARY)) ( -- ) [HIDDEN]

runtime of a VOCABULARY

VOCABULARY
( "name" -- )
[FTH]
VOCABULARY ( "name" -- ) [FTH]

create a vocabulary of that name. If the named vocabulary is called later, it will run ((VOCABULARY)) , thereby putting it into the current search order. Special pfe-extensions are accessible via CASE-SENSITIVE-VOC and SEARCH-ALSO-VOC

      simulate:
        : VOCABULARY  CREATE ALLOT-WORDLIST
             DOES> ( the ((VOCABULARY)) runtime )
               CONTEXT !
        ; IMMEDIATE

-->
( -- )
[FTH]
--> ( -- ) [FTH]

does increase BLK and refills the input-buffer from there. Does hence break interpretation of the current BLK and starts with the next. Old-style forth mechanism. You should use INCLUDE

      : --> ?LOADING REFILL ;

K
( -- k# )
[FTH]
K ( -- k# ) [FTH]

the 3rd loop index just like I and J

OCTAL
( -- )
[FTH]
OCTAL ( -- ) [FTH]

sets BASE to 8. Compare with HEX and DECIMAL

      simulate:
        : OCTAL  8 BASE ! ;

SP@
( -- sp-cell* )
[FTH]
SP@ ( -- sp-cell* ) [FTH]

the address of the top of stack. Does save it onto the stack. You could do

        : DUP  SP@ @ ;

!BITS
( x-bits# x-addr mask# -- )
[FTH]
!BITS ( x-bits# x-addr mask# -- ) [FTH]

at the cell pointed to by addr, change only the bits that are enabled in mask

      simulate:
        : !BITS  >R 2DUP @ R NOT AND SWAP R> AND OR SWAP ! DROP ;

**
( a# b# -- power-a# )
[FTH]
** ( a# b# -- power-a# ) [FTH]

raise second to top power

><
( a -- a' )
[FTH] [OLD]
>< ( a -- a' ) [FTH] [OLD]

byte-swap a word

depracated: use NTOHS which does the same as this word when the local byte-order seems to have no match, and be otherwise a no-op. Note that only the two lower bytes of the top-of-cell are swapped.

>MOVE<
( from-addr* to-addr* count# -- )
[FTH] [OLD]
>MOVE< ( from-addr* to-addr* count# -- ) [FTH] [OLD]

see MOVE , does byte-swap for each word underway.

depracated: this word has not been very useful lately. It does still stem from times of 16bit forth systems that wanted to interchange data blocks. It is better to use functionality based on NTOHS or NTOHL. Note that this word >MOVE< does swap each 2byte. It is not useful for byte-swapping WCHAR strings as the count is given in bytes, not wchar items.

@BITS
( x-addr mask# -- x-value# )
[FTH]
@BITS ( x-addr mask# -- x-value# ) [FTH]

see the companion word => !BITS

      simulate:
        : @BITS  SWAP @ AND ;

SEAL
( -- )
[FTH]
SEAL ( -- ) [FTH]

looks through the search-order and kills the ONLY wordset - hence you can't access the primary vocabularies from there.

C+!
( n addr -- )
C+! ( n addr -- )

Add the low-order byte of _n_ to the byte at _addr_, removing both from the stack.

>WORDLIST
( xt -- wordl* )
">WORDLIST" ( xt -- wordl* )

convert a VOCABULARY-xt into its wordlist reference (as in win32forth)

BOUNDS
( str len -- str+len str )
BOUNDS ( str len -- str+len str )

Convert _str len_ to range for DO-loop.

      : BOUNDS  ( str len -- str+len str )  OVER + SWAP ;

OFF
( addr -- )
OFF ( addr -- )

Store 0 at _addr_. Defined in f84 as OFF. See antonym ON!.

       : OFF  ( addr -- )  0 SWAP ! ;

ON!
( addr -- )
ON! ( addr -- )

Store -1 at _addr_. Defined in f83 as ON. See antonym OFF!.

       : ON!  ( addr -- )  -1 SWAP ! ;

APPEND
( str len add2 -- )
APPEND ( str len add2 -- )

Append string _str len_ to the counted string at _addr_. a.k.a. +PLACE of the PLACE family

      : APPEND   2DUP 2>R  COUNT +  SWAP MOVE ( ) 2R> C+! ;

+PLACE
( str len add2 -- )
+PLACE ( str len add2 -- )

Append string _str len_ to the counted string at _addr_. a.k.a. APPEND (being a SYNONYM now)

      : +PLACE   2DUP 2>R  COUNT +  SWAP MOVE ( ) 2R> C+! ;

APPEND-CHAR
( char addr -- )
APPEND-CHAR ( char addr -- )

Append _char_ to the counted string at _addr_. a.k.a. C+PLACE of the PLACE family

      : APPEND-CHAR   DUP >R  COUNT  DUP 1+ R> C!  +  C! ;

C+PLACE
( char addr -- )
C+PLACE ( char addr -- )

Append _char_ to the counted string at _addr_. a.k.a. APPEND-CHAR (being a SYNONYM now)

      : C+PLACE   DUP >R  COUNT  DUP 1+ R> C!  +  C! ;

PLACE
( str len addr -- )
PLACE ( str len addr -- )

Place the string _str len_ at _addr_, formatting it as a counted string.

      : PLACE  2DUP 2>R  1+ SWAP  MOVE  2R> C! ;
      : PLACE  2DUP C!   1+ SWAP CMOVE ;

PERFORM
( addr -- ? )
PERFORM ( addr -- ? )

see @EXECUTE which reads better

?LEAVE
( cond -- )
?LEAVE ( cond -- )

leave a (innermost) loop if condition is true

NOOP
( -- )
NOOP ( -- )

do nothing, used as a place-holder where an execution word is needed

RP@
( -- addr )
RP@ ( -- addr )

returns the return stack pointer

      example:
        : R@ RP@ @ ;

RP!
( addr -- )
RP! ( addr -- )

sets the return stack pointer, reverse of RP@

SP!
( ... addr -- )
SP! ( ... addr -- )

sets the stack pointer, reverse of SP@

-ROT
( a b c -- c a b )
-ROT ( a b c -- c a b )

inverse of ROT

CSET
( n addr -- )
CSET ( n addr -- )

set bits in byte at given address

      simulate:
        : CSET  TUCK @ SWAP OR SWAP ! ;

CRESET
( n addr -- )
CRESET ( n addr -- )

reset bits in byte at given address

      simulate:
        : CRESET  TUCK @ SWAP NOT AND SWAP ! ;

CTOGGLE
( n addr -- )
CTOGGLE ( n addr -- )

toggle bits in byte at given address

      simulate:
        : CTOGGLE  TUCK @ SWAP XOR SWAP ! ;

TOGGLE
( c-addr charmask -- )
TOGGLE ( c-addr charmask -- )

toggle the bits given in charmask, see also SMUDGE and = UNSMUDGE

      example: the fig-style SMUDGE had been defined such
        : FIG-SMUDGE LATEST >FFA (SMUDGE#) TOGGLE ;

3DUP
( x y z -- x y z x y z )
3DUP ( x y z -- x y z x y z )

Copy top three elements on the stack onto top of stack.

      : 3DUP   THIRD THIRD THIRD ;

or

      : 3DUP  3 PICK 3 PICK 3 PICK ;

3DROP
( x y z -- )
3DROP ( x y z -- )

Drop the top three elements from the stack.

      : 3DROP   DROP 2DROP ;

4DUP
( a b c d -- a b c d a b c d )
4DUP ( a b c d -- a b c d a b c d )

      simulate:
       : 4DUP  4 PICK 4 PICK 4 PICK 4 PICK ;

4DROP
( x y z -- )
4DROP ( x y z -- )

Drop the top three elements from the stack.

      : 4DROP   2DROP 2DROP ;

TOUPPER
( c1 -- c2 )
TOUPPER ( c1 -- c2 )

convert a single character to upper case

        : TOUPPER  >R _toupper ;

UPPER
( addr cnt -- )
UPPER ( addr cnt -- )

convert string to upper case

      simulate:
        : UPPER  0 DO  DUP I +  DUP C@ UPC SWAP C!  LOOP  DROP ;

LOWER
( addr cnt -- )
LOWER ( addr cnt -- )

convert string to lower case This is not in L&P's F83 but provided for symmetry

      simulate:
        : LOWER  0 DO  DUP I +  DUP C@ >R _tolower SWAP C!  LOOP  DROP ;

ASCII
( [word] -- val )
ASCII ( [word] -- val )

state smart version of CHAR or [CHAR] resp.

      simulate:
        : ASCII  [COMPILE] [CHAR]
                 STATE @ IF [COMPILE] LITERAL THEN ;

CONTROL
( [word] -- val )
CONTROL ( [word] -- val )

see ASCII, but returns char - '@'

      simulate:
        : CONTROL  [COMPILE] [CHAR]  [CHAR] @ -
                   STATE @ IF [COMPILE] LITERAL THEN ;

NUMBER?
( addr -- d flag )
NUMBER? ( addr -- d flag )

convert counted string to number - used in inner interpreter ( INTERPRET ), flags if conversion was successful

      example:
        BL WORD  HERE NUMBER? 0= IF ." not a number " THEN .

VOCS
( -- )
VOCS ( -- )

list all vocabularies in the system

      simulate:
        : VOCS VOC-LINK @ BEGIN DUP WHILE
                                DUP ->WORDLIST.NAME @ ID.
                                ->WORDLIST.LINK @
                          REPEAT DROP ;

@EXECUTE
( xt -- ? )
@EXECUTE ( xt -- ? )

same as @ EXECUTE , but checks for null as xt and silently ignores it. Same as in most forths where defined.

      simulate:
        : @EXECUTE  @ ?DUP IF EXECUTE THEN ;

EMITS
( n char -- )
EMITS ( n char -- )

Emit _char_ _n_ times.

      : EMITS             ( n char -- )
         SWAP 0 ?DO  DUP EMIT  LOOP DROP ;

also compare

      : SPACES BL EMITS ;
      : SPACE BL EMIT ;

FILE-CHECK
( n -- )
FILE-CHECK ( n -- )

Check for file access error.

      \ : FILE-CHECK    ( n -- )  THROW ;
      : FILE-CHECK      ( n -- )  ABORT" File Access Error " ;

MEMORY-CHECK
( n -- )
MEMORY-CHECK ( n -- )

Check for memory allocation error.

      \ : MEMORY-CHECK  ( n -- )  THROW ;
      : MEMORY-CHECK    ( n -- )  ABORT" Memory Allocation Error " ;

++
( addr -- )
++ ( addr -- )

Increment the value at _addr_.

      : ++  ( addr -- )  1 SWAP +! ;

@++
( addr -- addr' x )
@++ ( addr -- addr' x )

Fetch the value _x_ from _addr_, and increment the address by one cell.

      : @++  ( addr -- addr' x )  DUP CELL+ SWAP  @ ;

!++
( addr x -- addr' )
!++ ( addr x -- addr' )

Store the value _x_ into _addr_, and increment the address by one cell.

      : !++  ( addr x -- addr' )  OVER !  CELL+ ;

S>F
( n -- x )
S>F ( n -- x )
FTRUNC>S
( x -- n )
FTRUNC>S ( x -- n )
FROUND>S
( x -- n )
FROUND>S ( x -- n )
FTRUNC
( x -- x' )
FTRUNC ( x -- x' )
-FROT
( x1 x2 x3 -- x3 x1 x2 )
-FROT ( x1 x2 x3 -- x3 x1 x2 )
FNIP
( x1 x2 -- x2 )
FNIP ( x1 x2 -- x2 )
FTUCK
( x1 x2 -- x2 x1 x2 )
FTUCK ( x1 x2 -- x2 x1 x2 )
1/F
( x -- 1/x )
1/F ( x -- 1/x )
F^2
( x -- x^2 )
F^2 ( x -- x^2 )
F^N
( x u -- x^u )
F^N ( x u -- x^u )

For large exponents, use F** instead. Of course u=-1 is large.

F2/
( x -- x/2 )
F2/ ( x -- x/2 )
F2*
( x -- x*2 )
F2* ( x -- x*2 )
F0>
( x -- flag )
F0> ( x -- flag )
F0<>
( x -- flag )
F0<> ( x -- flag )
open-dir
( c_addr u -- wdirid wior )
gforth open_dir
open-dir ( c_addr u -- wdirid wior ) gforth open_dir

will vanish without warning. see gforth documentation.

read-dir
( c_addr u1 wdirid -- u2 flag wior )
gforth read_dir
read-dir ( c_addr u1 wdirid -- u2 flag wior ) gforth read_dir

will vanish without warning. see gforth documentation.

close-dir
( wdirid -- wior )
gforth close_dir
close-dir ( wdirid -- wior ) gforth close_dir

will vanish without warning. see gforth documentation.

linked
( list -- )
\ gforth
linked ( list -- ) \ gforth

      : linked        here over @ a, swap ! ;

(note: win32forth calls it "link," )

chained
( xt list -- )
\ gforth
chained ( xt list -- ) \ gforth

generic chains

      : chained  linked , ;

chainperform
( list -- )
\ gforth
chainperform ( list -- ) \ gforth

      : chainperform  BEGIN @ dup WHILE dup cell+ perform REPEAT drop ;

>NAME
( cfa -- nfa )
>NAME ( cfa -- nfa )

converts a pointer to the code-field (CFA) to point then to the corresponding name-field (NFA)

      implementation-specific simulation:
        : >NAME  >LINK L>NAME ;

>LINK
( cfa -- lfa )
>LINK ( cfa -- lfa )

converts a pointer to the code-field (CFA) to point then to the corresponding link-field (LFA) - in some configurations this can be a very slow operation since the system might need to walk through all header-words in the system, looking for a >NAME that has the cfa and *then* returning the "N>LINK" result here - which might be none at all if the word is a :NONAME. Use always >NAME and treat this word as non-portable just like any assumption about the contents of the >LINK-field. Only in fig-mode and for traditional fig-mode programs, this word may possibly have enough extra assertions to be somewhat reliable. (and fig-mode did not know about SYNONYMs - see note at LINK>).

BODY>
( pfa -- cfa )
BODY> ( pfa -- cfa )

trying to convert a pointer to the parameter-field (PFA) to point then to the corresponding code-field (CFA) - note that this is not necessarily the inverse of >BODY instead it is a fast implementation assuming a VARIABLE thing had been used. Every use of "BODY>" is warned in the logfile.

      implementation-specific simulation:
        : BODY> CELL - ;

NAME>
( nfa -- cfa )
NAME> ( nfa -- cfa )

converts a pointer to the name-field (NFA) to point then to the corresponding code-field (CFA)

In all cases but a SYNONYM the pfe will behave not unlike the original fig-forth did - being identical to N>LINK LINK> .

LINK>
( lfa -- cfa )
LINK> ( lfa -- cfa )

converts a pointer to the link-field (LFA) to point then to the corresponding code-field (CFA)

BEWARE: this one does not care about SYNONYMs and it is the only way to get at the data of a SYNONYM. Therefore, if you have a synonym called A for an old word B then there is a different result using "NAME>" on an A-nfa or using "N>LINK LINK>" since the first "NAME>" will return the xt of B while the latter will return the xt of A - but executing an xt of A is an error and it will THROW

this difference is intentional to allow knowledgable persons to do weird things looking around in the dictionary. The forth standard words will not give you much of a chance to get hold of the nfa of a SYNONYM word anyway - asking FIND for a word A will return the execution token of B immediatly and "NAME>" on that one lead to the nfa of B and not that of A.

L>NAME
( lfa -- nfa )
L>NAME ( lfa -- nfa )

converts a pointer to the link-field (LFA) to point then to the corresponding name-field (CFA) - this one is one of the slowest operation available. One should always use the inverse operation N>LINK and cache an older value if that is needed. Some words might be linked but they do not have a name-field (just the other fields) but this word can not detect that and will try to look into the bits of the dictionary anway in the assumption that there is something - and if done in the wrong place it might even segfault. Only in fig-mode and for traditional fig-mode programs, this word may possibly have enough extra assertions to be somewhat reliable. (and fig-mode did not know about SYNONYMs - see note at LINK>).

      implementation-specific configure-dependent fig-only simulation:
      : L>NAME BEGIN DUP C@ 128 AND 0= WHILE 1- REPEAT ;

N>LINK
( nfa -- lfa )
N>LINK ( nfa -- lfa )

converts a pointer to the name-field (NFA) to point then to the corresponding link-field (LFA) - this operation is quicker than the inverse L>NAME. This word is a specific implementation detail and should not be used by normal users - instead use always NAME> which is much more portable. Many systems may possibly not even have a >LINK-field in the sense that a @ on this adress will lead to another >NAME. Any operation on the resulting >LINK-adress is even dependent on the current configuration of PFE - only in fig-mode you are asserted to have the classic detail. (and fig-mode did not know about SYNONYMs - see note at LINK>).

      implementation-specific configure-dependent fig-only simulation:
        : N>LINK  C@ + ;

>FFA
( nfa -- ffa )
obsolete
>FFA ( nfa -- ffa ) obsolete

converts a pointer to the name-field (NFA) to point then to the corresponding flag-field (FFA) - in traditinal Forth this is the same address. pfe _can_ do different.

      implementation-specific configure-dependent simulation:
        : FFA  1- ;

FFA>
( ffa -- nfa )
obsolete
FFA> ( ffa -- nfa ) obsolete

converts a pointer to the flag-field (FFA) to point then to the corresponding name-field (NFA) - in traditinal Forth this is the same address. pfe _can_ do different.

      implementation-specific configure-dependent simulation:
        : FFA  1+ ;

NAME>STRING
( name-token -- str-ptr str-len )
NAME>STRING ( name-token -- str-ptr str-len )

convert a name-token into a string-span, used to detect the name for a word and print it. The word ID. can be defined as

      : ID. NAME>STRING TYPE ;

the implementation of NAME>STRING depends on the header layout that is defined during the configuration of the forth system.

      : NAME>STRING COUNT 31 AND ; ( for fig-like names )
      : NAME>STRING COUNT ;        ( default, name is a simple counted string )
      : NAME>STRING @ ZCOUNT ;     ( name-token is a pointer to a C-level string )
      : NAME>STRING COUNT 31 AND   ( hybrid of fig-like and zero-terminated )
           DUP 31 = IF DROP 1+ ZCOUNT THEN
      ;
      : NAME>STRING HEAD:: COUNT CODE:: PAD PLACE PAD ; ( different i86 segments )

HEADER,
( str-ptr str-len -- )
HEADER, ( str-ptr str-len -- )

CREATE a new header in the dictionary from the given string, without CFA

      usage: : VARIABLE  BL WORD COUNT HEADER, DOVAR , ;

$HEADER
( bstring -- )
$HEADER ( bstring -- )

CREATE a new header in the dictionary from the given string with the variable runtime (see HEADER, and CREATE:)

      usage: : VARIABLE  BL WORD $HEADER ;

LATEST
( -- nfa )
LATEST ( -- nfa )

return the NFA of the lateset definition in the CURRENT vocabulary

SMUGDE
( -- )
SMUGDE ( -- )

the FIG definition toggles the SMUDGE bit, and not all systems have a smudge bit - instead one should use REVEAL or HIDE

      : SMUDGE LAST @ >FFA SMUDGE-MASK TOGGLE ;
      : SMUDGE LAST @ NAME-FLAGS@ SMUDGE-MASK XOR LAST @ NAME-FLAGS! ;
      : HIDE   LAST @ NAME-FLAGS@ SMUDGE-MASK  OR LAST @ NAME-FLAGS! ;

HIDE
( -- )
HIDE ( -- )

the FIG definition toggles the SMUDGE bit, and not all systems have a smudge bit - instead one should use REVEAL or HIDE

      : HIDE LAST @ FLAGS@ SMUDGE-MASK XOR LAST @ FLAGS! ;

RECURSIVE
( -- )
RECURSIVE ( -- )

REVEAL the current definition making it RECURSIVE by its own name instead of using the ans-forth word to RECURSE.

      ' REVEAL ALIAS RECURSIVE IMMEDIATE

REVEAL
( -- )
REVEAL ( -- )

the FIG definition toggles the SMUDGE bit, and not all systems have a smudge bit - instead one should use REVEAL or HIDE

      : REVEAL LAST @ FLAGS@ SMUDGE-MASK INVERT AND LAST @ FLAGS! ;
      : REVEAL LAST @ CHAIN-INTO-CURRENT ;

IMMEDIATE-MASK
( -- bit-mask )
IMMEDIATE-MASK ( -- bit-mask )

returns the bit-mask to check if a found word is immediate (use in conjunction with NAME-FLAGS@ and NAME-FLAGS! )

         " my-word" FIND-NAME IF NAME-FLAGS@ IMMEDIATE-MASK AND
                            IF ." immediate" THEN ELSE DROP THEN

SMUDGE-MASK
( -- bit-mask )
SMUDGE-MASK ( -- bit-mask )

returns the bit-mask to check if a found word is smudge (use in conjunction with NAME-FLAGS@ and NAME-FLAGS! )

         " my-word" FIND-NAME IF NAME-FLAGS@ SMUDGE-MASK AND
                            IF ." smudge" THEN ELSE DROP THEN

NAME-FLAGS@
( nfa -- nfa-flags )
NAME-FLAGS@ ( nfa -- nfa-flags )

get the nfa-flags that corresponds to the nfa given. Note that in the fig-style would include the nfa-count in the lower bits. (see NAME-FLAGS!)

NAME-FLAGS!
( nfa-flags nfa -- )
NAME-FLAGS! ( nfa-flags nfa -- )

set the nfa-flags of nfa given. Note that in the fig-style the nfa-flags would include the nfa-count in the lower bits - therefore this should only set bits that had been previously retrieved with NAME-FLAGS@

      : IMMEDIATE LAST @ NAME-FLAGS@ IMMEDIATE-MASK OR LAST @ NAME-FLAGS! ;

((DEFER)) ( -- )

runtime of DEFER words

DEFER
( 'word' -- )
DEFER ( 'word' -- )

create a new word with ((DEFER))-semantics

      simulate:
        : DEFER  CREATE 0, DOES> ( the ((DEFER)) runtime )
           @ ?DUP IF EXECUTE THEN ;
        : DEFER  DEFER-RT HEADER 0 , ;

declare as `"DEFER deferword"`
and set as `"['] executionword IS deferword"` (in pfe, you can also use `TO deferword` to set the execution)

IS
( xt-value [word] -- )
IS ( xt-value [word] -- )

set a DEFER word (in pfe: set the DOES-field - which is the BODY-field in ans-mode and therefore the same as TO / in fig-mode the DOES-field is one cell higher up than for a CREATE: VARIABLE Use IS freely on each DOES-words in both modes).

      : IS '
        STATE @ IF LITERAL, POSTPONE >DOES-BODY POSTPONE !
        ELSE >DOES-BODY ! THEN
      ; IMMEDIATE

ACTION-OF
( [word] -- xt-value )
ACTION-OF ( [word] -- xt-value )

get the BEHAVIOR of a DEFER word when executed. If being compiled then the ACTION-OF will be the value of [word] at the time of execution and not that of compilation time (non-constant).

In PFE it does actually pick whatever is stored in the DOES-field of a word and therefore ACTION-OF may applied to all DOES-words.

DEFER!
( xt-value xt-defer -- )
DEFER! ( xt-value xt-defer -- )

A Forth200x definition that is not very useful.

BEHAVIOR
( xt1 -- x2 )
BEHAVIOR ( xt1 -- x2 )

A defintion from OpenBoot that is identical Forth200x DEFER@

DEFER@
( xt1 -- xt2 )
DEFER@ ( xt1 -- xt2 )

get the execution token xt2 that would be executed by the DEFER identified by xt1.

This command is used to obtain the execution contents of a deferred word. A typical use would be to retrieve and save the execution behavior of the deferred word, set the deferred word to a new behavior, and then later restore the old behavior.

If the deferred word identified by _xt1_ is associated with some other deferred word, _xt2_ is the execution token of that other deferred word. To retrieve the execution token of the word currently associated with that other deferred word, use the phrase DEFER@ DEFER@ .

Experience: BEHAVIOR was used many years in OpenBoot and OpenFirmware systems.

In PFE it is the inverse of an IS operation and it will never fail if applied to a word with atleast a body. That's just like IS can be applied to almost every DOES> word where DEFER@ will get the value back.

ALIAS
( some-xt* "name" -- )
[EXT]
ALIAS ( some-xt* "name" -- ) [EXT]

create a defer word that is initialized with the given x-token. DO-ALIAS

SYNONYM
( "newname" "oldname" -- )
SYNONYM ( "newname" "oldname" -- )

make an name-alias for a word - this is very different from a DEFER since a DEFER will resolve at runtime. Changing the target of a DEFER via IS will result in changing the BEHAVIOR of all words defined earlier and containing the name of the DEFER.

A SYNONYM however does not have any data field (theoretically not even an execution token), instead it gets resolved at compile time. In theory, you can try to FIND the name of the SYNONYM but as soon as you apply NAME> the execution token of the end-point is returned. This has also the effect that using the inverse >NAME operation will result in the name-token of the other name.

        SYNONYM CREATE <BUILDS ( like it is in ANS Forth )
        : FOO CREATE DOES> @ ;
        SEE FOO
        : foo <builds
          does> @ ;
        SYNONYM CREATE CREATE:
        : BAR CREATE 10 ALLOT ;
        SEE BAR
        : bar create: 10 allot ;

(only LINK> does not care about SYNONYMs)

"SYNONYM-OBSOLETED
( "newname" "oldname" -- )
"SYNONYM-OBSOLETED ( "newname" "oldname" -- )

same as SYNONYM but on the first use an error message will be displayed on both the screen and the sys-log.

(DEPRECATED: ( "newname" [message<closeparen>] -- )

add a message for the following word "newname" that should be shown once upon using the following word. Use it like

        (DEPRECATED: myword is obsoleted in Forth200X)
        : myword ." hello world" ;

(CHECK-DEPRECATED) ( nfa* -- nfa* )

an internal function that will check a word name to have any deprecation attribution - some words have a (one time) message to be shown to the user, while OBSOLETED-SYNONYM will show a message and rebuild itself as a normal SYNONYM. - Note that most deprecations are only shown once and that they are not emitted when having REDEFINED-MSG OFF.

EXTERN,-DEPRECATED:
( "newname" zstring* -- )
EXTERN,-DEPRECATED: ( "newname" zstring* -- )

compile a pointer to an extern (loader) z-string to the dictionary and on execution show a deprecation message once. Note: the new name is smudged+immediate, so it you can not FIND it right after compilation.

see also (DEPRECATED: name message) for the real thing

EXTERN,-LOGMESSAGE:
( "newname" zstring* -- )
EXTERN,-LOGMESSAGE: ( "newname" zstring* -- )

compile a pointer to an extern (loader) z-string to the dictionary and on execution show a logging message once. Note: this name is NOT smudged+immediate.

see also (DEPRECATED: name message) for deprecation messages

(HELP) ( str-ptr str-len -- )

display help for the specified word (not functional yet)

OPEN-TERMINAL-LOGFILE
( s-buf s-len -- )
OPEN-TERMINAL-LOGFILE ( s-buf s-len -- )

open terminal logfile named by the string-buffer all further output to the terminal window is also logged into this file. This is especially useful in embedded environments where the terminal connection is often not used or it is directed to a different location that does not easily allow to redirect the forth output to a file for further examination.

CLOSE-TERMINAL-LOGFILE
( -- )
CLOSE-TERMINAL-LOGFILE ( -- )

close terminal logfile opened with OPEN-TERMINAL-LOGFILE

TERMINAL-ANSWER-LINK
( -- sap#* )
TERMINAL-ANSWER-LINK ( -- sap#* )

send terminal-output as a data-message to the specified link sap. Unlike TERMINAL-OUTPUT-LINK the data-messages are in line-mode. The flushed characters are buffered until a non-printable character is seen. This is somewhat more useful when treating pfe as a print service and testing machine, but can not provide for interactivity.

      60 TERMINAL-ANSWER-LINK !
      ...
      TERMINAL-ANSWER-LINK OFF

TERMINAL-OUTPUT-LINK
( -- sap#* )
TERMINAL-OUTPUT-LINK ( -- sap#* )

send terminal-output as a data-message to the specified link sap. This can be used in an embedded systems for a terminal session simulation. setting zero-sap will disable sending message-frames (the zero sap is therefore not usable for output-to-link). The startup default is zero.

      60 TERMINAL-OUTPUT-LINK !
      ...
      TERMINAL-OUTPUT-LINK OFF

TERMINAL-INPUT-LINK
( -- sap#* )
TERMINAL-INPUT-LINK ( -- sap#* )

let the forth stdin-handling look for data-messages on this link too. These will be interpreted like messages that come from the interactive forth terminal. This can be used in an embedded systems for a terminal session simulation. setting zero-sap will disable interpreting these incoming data-frames as keyboard-strings (so that the zero sap is therefore not usable for an input-link!). The startup default is zero.

      60 TERMINAL-INPUT-LINK !
      ...
      TERMINAL-INPUT-LINK OFF

TERMINAL-EMULATION-STATE
( -- state* )
TERMINAL-EMULATION-STATE ( -- state* )

returns the address of the emulations state variable so it can be read and explicitly changed to another value from forth text. This is a very questionable thing to do as the emulation-state is actually an enumerated value, the ESE will just show question-marks setting this variable to something not understood.

SDL_init
( flags -- int )
SDL_init ( flags -- int )

This function loads the SDL dynamically linked library and initializes the subsystems specified by 'flags' (and those satisfying dependencies) Unless the SDL_INIT_NOPARACHUTE flag is set, it will install cleanup signal handlers for some commonly ignored fatal signals (like SIGSEGV)

      int SDL_Init(Uint32 flags);

SDL_InitSubSystem
( flags -- int )
SDL_InitSubSystem ( flags -- int )

This function initializes specific SDL subsystems

      int SDL_InitSubSystem(Uint32 flags);

SDL_QuitSubSystem
( flags -- )
SDL_QuitSubSystem ( flags -- )

This function cleans up specific SDL subsystems

      void SDL_QuitSubSystem(Uint32 flags);

SDL_WasInit
( flags -- mask )
SDL_WasInit ( flags -- mask )

This function returns mask of the specified subsystems which have been initialized. If 'flags' is 0, it returns a mask of all initialized subsystems.

      Uint32 SDL_WasInit(Uint32 flags);

SDL_Quit
( -- )
SDL_Quit ( -- )

This function cleans up all initialized subsystems and unloads the dynamically linked library. You should call it upon all exit conditions.

      void SDL_Quit(void);

SDL_SetError
( str-ptr str-len -- )
SDL_SetError ( str-ptr str-len -- )

set it, based on

      void SDL_SetError(const char *fmt, ...);

SDL_GetError
( -- str-ptr str-len )
SDL_GetError ( -- str-ptr str-len )

get it, based on

      char * SDL_GetError(void);

SDL_ClearError
( -- )
SDL_ClearError ( -- )

clear it.

      void SDL_ClearError(void);

SDL_RWFromFile
( Z-modestr* Z-filename* -- SDL_RWops* )
SDL_RWFromFile ( Z-modestr* Z-filename* -- SDL_RWops* )

A Functions to create SDL_RWops structures from various data sources

      SDL_RWops * SDL_RWFromFile(const char *file, const char *mode);

SDL_RWFromFP
( autoclose STDIO-FILE* -- SDL_RWops* )
SDL_RWFromFP ( autoclose STDIO-FILE* -- SDL_RWops* )

A Functions to create SDL_RWops structures from various data sources

      SDL_RWops * SDL_RWFromFP(FILE *fp, int autoclose);

SDL_RWFromMem
( size mem* -- SDL_RWops* )
SDL_RWFromMem ( size mem* -- SDL_RWops* )

A Functions to create SDL_RWops structures from various data sources

      SDL_RWops * SDL_RWFromMem(void *mem, int size);

SDL_AllocRW
( -- SDL_RWops* )
SDL_AllocRW ( -- SDL_RWops* )

A Functions to create SDL_RWops structures from various data sources

      SDL_RWops * SDL_AllocRW(void);

SDL_FreeRW
( SDL_RWops* -- )
SDL_FreeRW ( SDL_RWops* -- )

A Functions to create SDL_RWops structures from various data sources

      void SDL_FreeRW(SDL_RWops *area);

SDL_RWseek
( whence offset rwops-context -- status )
SDL_RWseek ( whence offset rwops-context -- status )

Macro-based call to easily read and write from an SDL_RWops structure

      define SDL_RWseek(ctx, offset, whence) (ctx)->seek(ctx, offset, whence)

SDL_RWtell
( rwops-context -- status )
SDL_RWtell ( rwops-context -- status )

Macro-based call to easily read and write from an SDL_RWops structure

      define SDL_RWtell(ctx)                 (ctx)->seek(ctx, 0, SEEK_CUR)

SDL_RWread
( n size ptr rwops-context -- status )
SDL_RWread ( n size ptr rwops-context -- status )

Macro-based call to easily read and write from an SDL_RWops structure

      define SDL_RWread(ctx, ptr, size, n)   (ctx)->read(ctx, ptr, size, n)

SDL_RWwrite
( n size ptr rwops-context -- status )
SDL_RWwrite ( n size ptr rwops-context -- status )

Macro-based call to easily read and write from an SDL_RWops structure

      define SDL_RWwrite(ctx, ptr, size, n)   (ctx)->read(ctx, ptr, size, n)

SDL_RWclose
( rwops-context -- status )
SDL_RWclose ( rwops-context -- status )

Macro-based call to easily read and write from an SDL_RWops structure

      define SDL_RWtell(ctx)                 (ctx)->seek(ctx, 0, SEEK_CUR)

SDL_GetTicks
( -- value )
SDL_GetTicks ( -- value )

Get the number of milliseconds since the SDL library initialization. Note that this value wraps if the program runs for more than ~49 days.

      Uint32 SDL_GetTicks(void);

SDL_Delay
( value -- )
SDL_Delay ( value -- )

Wait a specified number of milliseconds before returning

      void SDL_Delay(Uint32 ms);

SDL_AudioInit
( Z-str -- status )
SDL_AudioInit ( Z-str -- status )

One of the functions that are used internally, and should not be used unless you have a specific need to specify the audio driver you want to use.

      int SDL_AudioInit(const char *driver_name);

SDL_AudioQuit
( -- )
SDL_AudioQuit ( -- )

One of the functions that are used internally, and should not be used unless you have a specific need to specify the audio driver you want to use.

      void SDL_AudioQuit(void);

SDL_AudioDriverName
( maxlen namebuf -- namebuf | 0 )
SDL_AudioDriverName ( maxlen namebuf -- namebuf | 0 )

This function fills the given character buffer with the name of the audio driver, and returns a pointer to it if the audio driver has been initialized. It returns NULL if no driver has been initialized.

      char *SDL_AudioDriverName(char *namebuf, int maxlen);

SDL_OpenAudio
( SDL_AudioSpec-obtained SDL_AudioSpec-desired -- status )
;
SDL_OpenAudio ( SDL_AudioSpec-obtained SDL_AudioSpec-desired -- status );

This function opens the audio device with the desired parameters, and returns 0 if successful, placing the actual hardware parameters in the structure pointed to by 'obtained'. If 'obtained' is NULL, the audio data passed to the callback function will be guaranteed to be in the requested format, and will be automatically converted to the hardware audio format if necessary. This function returns -1 if it failed to open the audio device, or couldn't set up the audio thread.

When filling in the desired audio spec structure, 'desired->freq' should be the desired audio frequency in samples-per-second. 'desired->format' should be the desired audio format. 'desired->samples' is the desired size of the audio buffer, in samples. This number should be a power of two, and may be adjusted by the audio driver to a value more suitable for the hardware. Good values seem to range between 512 and 8096 inclusive, depending on the application and CPU speed. Smaller values yield faster response time, but can lead to underflow if the application is doing heavy processing and cannot fill the audio buffer in time. A stereo sample consists of both right and left channels in LR ordering. Note that the number of samples is directly related to time by the following formula: ms = (samples*1000)/freq 'desired->size' is the size in bytes of the audio buffer, and is calculated by SDL_OpenAudio(). 'desired->silence' is the value used to set the buffer to silence, and is calculated by SDL_OpenAudio(). 'desired->callback' should be set to a function that will be called when the audio device is ready for more data. It is passed a pointer to the audio buffer, and the length in bytes of the audio buffer. This function usually runs in a separate thread, and so you should protect data structures that it accesses by calling SDL_LockAudio() and SDL_UnlockAudio() in your code. 'desired->userdata' is passed as the first parameter to your callback function.

The audio device starts out playing silence when it's opened, and should be enabled for playing by calling SDL_PauseAudio(0) when you are ready for your audio callback function to be called. Since the audio driver may modify the requested size of the audio buffer, you should allocate any local mixing buffers after you open the audio device.

      int SDL_OpenAudio(SDL_AudioSpec *desired, SDL_AudioSpec *obtained);

SDL_GetAudioStatus
( -- status )
SDL_GetAudioStatus ( -- status )

Get the current audio state:

       typedef enum {
             SDL_AUDIO_STOPPED = 0,
             SDL_AUDIO_PLAYING,
             SDL_AUDIO_PAUSED
       } SDL_audiostatus;
      int SDL_audiostatus SDL_GetAudioStatus(void);

SDL_LoadWAV_RW
( audio_len audio_buf spec* freesrc rwops* -- spec* )
SDL_LoadWAV_RW ( audio_len audio_buf spec* freesrc rwops* -- spec* )

This function loads a WAVE from the data source, automatically freeing that source if 'freesrc' is non-zero. For example, to load a WAVE file, you could do: SDL_LoadWAV_RW(SDL_RWFromFile("sample.wav", "rb"), 1, ...);

If this function succeeds, it returns the given SDL_AudioSpec, filled with the audio data format of the wave data, and sets 'audio_buf' to a malloc()'d buffer containing the audio data, and sets 'audio_len' to the length of that audio buffer, in bytes. You need to free the audio buffer with SDL_FreeWAV() when you are done with it.

This function returns NULL and sets the SDL error message if the wave file cannot be opened, uses an unknown data format, or is corrupt. Currently raw and MS-ADPCM WAVE files are supported.

      SDL_AudioSpec *SDL_LoadWAV_RW (
     		SDL_RWops *src, int freesrc,
                     SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len);

SDL_LoadWAV
( audio_len audio_buf spec* rwops* -- spec* )
SDL_LoadWAV ( audio_len audio_buf spec* rwops* -- spec* )

Compatibility convenience function -- loads a WAV from a file see SDL_LoadWAV_RW

SDL_FreeWAV
( audiobuf* -- )
SDL_FreeWAV ( audiobuf* -- )

This function frees data previously allocated with SDL_LoadWAV_RW()

      void SDL_FreeWAV(Uint8 *audio_buf);

SDL_ConvertAudio
( cvt* -- standard-inst )
SDL_ConvertAudio ( cvt* -- standard-inst )

Once you have initialized the 'cvt' structure using SDL_BuildAudioCVT(), created an audio buffer cvt->buf, and filled it with cvt->len bytes of audio data in the source format, this function will convert it in-place to the desired format. The data conversion may expand the size of the audio data, so the buffer cvt->buf should be allocated after the cvt structure is initialized by SDL_BuildAudioCVT(), and should be cvt->len*cvt->len_mult bytes long.

      int SDL_ConvertAudio(SDL_AudioCVT *cvt);

SDL_MixAudio
( volume len src dst -- )
SDL_MixAudio ( volume len src dst -- )

This takes two audio buffers of the playing audio format and mixes them, performing addition, volume adjustment, and overflow clipping. The volume ranges from 0 - 128, and should be set to SDL_MIX_MAXVOLUME for full audio volume. Note this does not change hardware volume. This is provided for convenience -- you can mix your own audio data.

      define SDL_MIX_MAXVOLUME 128
      void SDL_MixAudio(Uint8 *dst, Uint8 *src, Uint32 len, int volume);

SDL_LockAudio
( -- )
SDL_LockAudio ( -- )

The lock manipulated by these functions protects the callback function. During a LockAudio/UnlockAudio pair, you can be guaranteed that the callback function is not running. Do not call these from the callback function or you will cause deadlock.

      void SDL_LockAudio(void);

SDL_UnlockAudio
( -- )
SDL_UnlockAudio ( -- )

The lock manipulated by these functions protects the callback function. During a LockAudio/UnlockAudio pair, you can be guaranteed that the callback function is not running. Do not call these from the callback function or you will cause deadlock.

      void SDL_UnlockAudio(void);

SDL_Linked_Version
( -- SDL_version* )
SDL_Linked_Version ( -- SDL_version* )

This function gets the version of the dynamically linked SDL library. it should NOT be used to fill a version structure, instead you should use the SDL_Version() macro. see SDL_LinkedVersion

      extern DECLSPEC const SDL_version * SDL_Linked_Version(void);

SDL_LinkedVersion
( -- SDL_versionnum )
SDL_LinkedVersion ( -- SDL_versionnum )

This function gets the version of the dynamically linked SDL library. it should NOT be used to fill a version structure, instead you should use the SDL_Version() macro. see SDL_LinkedVersion

      implementation applies the SDL_VERSIONNUM macro to
      extern DECLSPEC const SDL_version * SDL_Linked_Version(void);

SDL_CompiledVersion
( -- SDL_versionnum )
SDL_CompiledVersion ( -- SDL_versionnum )

This function gets the version of the SDL library headers the PFE has been linked with. It returns the compact code from SDL_VERSIONNUM macro

(LOCAL) ( strptr strcnt -- )

this word is used to create compiling words that can declare LOCALS| - it shall not be used directly to declare a local, the pfe provides LVALUE for that a purpose beyond LOCALS|

LOCALS|
( xN ... x2 x1 [name1 .. nameN <|>] -- )
LOCALS| ( xN ... x2 x1 [name1 .. nameN <|>] -- )

create local identifiers to be used in the current definition. At runtime, each identifier will be assigned a value from the parameter stack.
The identifiers may be treated as if being a VALUE , it does also implement the ansi TO extensions for locals. Note that the identifiers are only valid inside the currently compiled word, the SEE decompiled word will show them as <A> ... <N> a.s.o.
see also LVALUE

LVALUE
( value [name] -- )
LVALUE ( value [name] -- )

declares a single local VALUE using (LOCAL) - a sequence of LVALUE declarations can replace a LOCALS| argument, ie. `LOCALS| a b c |` is the same as `LVALUE a LVALUE b LVALUE c` . This should also clarify the runtime stack behaviour of LOCALS| where the stack parameters seem to be assigned in reverse order as opposed to their textual identifier declarations.
compare with VALUE and the pfe's convenience word VAR.

      : LVALUE
        STATE @ IF
          VALUE
        ELSE
          BL WORD COUNT DUP (LOCAL) (TO)
        THEN
      ; IMMEDIATE

LBUFFER:
( size [name] -- )
LBUFFER: ( size [name] -- )

declares a single local VALUE using (LOCAL) - which will hold the address of an area like BUFFER: but carved from the return-stack (as in C with alloca). This local buffer will be automatically given up at the end of the word. The return-stack-pointer will be increased only at the time of this function (and the address assigned to the LVALUE) so that the provided size gets determined at runtime. Note that in some configurations the forth-return-stack area is quite small - for large string operations you should consider to use a POCKET-PAD in pfe.

      : LBUFFER:
        STATE @ IF
          BUFFER:
        ELSE
          :NONAME ( size -- rp* ) R> RP@ - DUP RP! SWAP >R ;NONAME
          COMPILE, POSTPONE LVALUE
        THEN
      ; IMMEDIATE

ENVIRONMENT #LOCALS
( -- number )
"ENVIRONMENT #LOCALS" ( -- number )

the number of local names allowed during compilation. portable programs can check this with ENVIRONMENT?

ALLOCATE
( size# -- alloc*! 0 | 0 errno#! )
[ANS]
ALLOCATE ( size# -- alloc*! 0 | 0 errno#! ) [ANS]

Allocate a chunk of memory from the system heap. use FREE to release the memory area back to the system.
A code of zero means success.

FREE
( alloc* -- errno# )
[ANS]
FREE ( alloc* -- errno# ) [ANS]

Free the memory from ALLOCATE A code of zero means success.

RESIZE
( alloc* newsize# -- alloc*' errno# )
[ANS]
RESIZE ( alloc* newsize# -- alloc*' errno# ) [ANS]

Resize the system memory chunk. A code of zero means success. Our implementation returns the old pointer on failure.

COLD
( -- )
[FTH]
COLD ( -- ) [FTH]

cold abort - reinitialize everything and go to QUIT routine ... this routine is implemented as a warm-boot in pfe.

      : COLD [ ALSO ENVIRONMENT ] EMPTY SCRIPT-FILE INCLUDED QUIT ;

.LINE
( line# block# -- )
[FTH]
.LINE ( line# block# -- ) [FTH]
UD.R
( x,x# r# -- )
[FTH]
UD.R ( x,x# r# -- ) [FTH]
UD.
( x,x# -- )
[FTH]
UD. ( x,x# -- ) [FTH]

see also UD.R

.NAME
( some-nfa* -- )
[FTH]
.NAME ( some-nfa* -- ) [FTH]

use ID. or better NAME>STRING TYPE (the => .NAME word is not very portable across forth systems)

ID.
( some-nfa* -- )
[FTH]
ID. ( some-nfa* -- ) [FTH]

print the name-field pointed to by the nfa-argument. a synonym for .NAME - but this word is more portable due its heritage from fig-forth.

in fig-forth the name-field is effectivly a bstring with some flags, so the nfa's count has to be masked out, e.g.

      : .NAME COUNT 32 AND TYPE ;

in other pfe configurations, the name might not contain the flags it it just a counted string - and there may be even more possibilities.

      : .NAME COUNT TYPE ;

you should more and more convert your code to use the sequence NAME>STRING TYPE which is widely regarded as the better variant.

-ROLL
( x...[n-1] y n# -- y x...[n-1] | num# -- )
[FTH]
-ROLL ( x...[n-1] y n# -- y x...[n-1] | num# -- ) [FTH]

the inverse of ROLL

RANDOM
( n# -- random# )
[FTH]
RANDOM ( n# -- random# ) [FTH]

returns random number with 0 <= n2 < n1)

      : RANDOM ?DUP IF _random SWAP MOD ELSE _random THEN ;

SRAND
( seed# -- )
[FTH]
SRAND ( seed# -- ) [FTH]
UNDER+
( n1 x n2 -- n1+n2 x [??] | n1 n2 -- n1+n2 n2 [??] )
[FTH]
UNDER+ ( n1 x n2 -- n1+n2 x [??] | n1 n2 -- n1+n2 n2 [??] ) [FTH]

quicker than

      : UNDER+  ROT + SWAP ;

Note: the old pfe version of UNDER+ is obsolete as it is in conflict with a comus word of the same name. The behavior of this word will continue to exist under the name of (UNDER+). Users are encouraged to use the comus behavior of UNDER+ which does already exist under the name of +UNDER. In the future pfe will be changed to pick up the comus behavior making UNDER+ and +UNDER to be synonyms. In the current version there will be load-time warning on usages of "UNDER+".

+UNDER
( n1 x n2 -- n1+n2 x )
[EXT]
+UNDER ( n1 x n2 -- n1+n2 x ) [EXT]

quicker than

      : UNDER+  ROT + SWAP ;

Note: the old pfe version of UNDER+ is obsolete as it is in conflict with a comus word of the same name. The behavior of this word will continue to exist under the name of (UNDER+). Users are encouraged to use the comus behavior of UNDER+ which does already exist under the name of +UNDER. In the future pfe will be changed to pick up the comus behavior making UNDER+ and +UNDER to be synonyms. In the current version there will be load-time warning on usages of "UNDER+".

(UNDER+)
( n1 n2 -- n1+n2 n2 )
[FTH]
"(UNDER+)" ( n1 n2 -- n1+n2 n2 ) [FTH]

quicker than

      : (UNDER+) TUCK + SWAP ; or : (UNDER+) DUP UNDER+ ;

((+TO)) ( val -- ) [HIDDEN]

execution compiled by +TO adds the stack-val to the lvalue compiled

((+TO.local)) ( val -- ) [HIDDEN]

same as ((+TO)) when the lvalue is a LOCALS| value
compiled by +TO

+TO
( val [name] -- )
[FTH]
+TO ( val [name] -- ) [FTH]

add the val to the named VALUE or LOCALS| value

BUILD-ARRAY
( x#...[dim] dim# -- memsize# )
[FTH]
BUILD-ARRAY ( x#...[dim] dim# -- memsize# ) [FTH]

writes X, n1, ... nX into the dictionary - returns product n1 * n2 * ... * nX

ACCESS-ARRAY
( x#...[dim#] array* --- array* value# )
[FTH]
ACCESS-ARRAY ( x#...[dim#] array* --- array* value# ) [FTH]

see BUILD-ARRAY

SOURCE-LINE
( -- source-line# )
[FTH]
SOURCE-LINE ( -- source-line# ) [FTH]

if SOURCE is from EVALUATE (or QUERY ) then the result is 0 else the line-numbers start from 1

SOURCE-NAME
( -- source-name-ptr source-name-len )
[FTH]
SOURCE-NAME ( -- source-name-ptr source-name-len ) [FTH]

if SOURCE is from INCLUDE then the result is the filename, otherwise a generic name for the SOURCE-ID is given.

TH'POCKET
( pocket# -- pocket-ptr pocket-len )
[FTH]
TH'POCKET ( pocket# -- pocket-ptr pocket-len ) [FTH]

returns the specified pocket as a S" string reference

POCKET-PAD
( -- pocket-ptr )
[FTH]
POCKET-PAD ( -- pocket-ptr ) [FTH]

This function Returns the next pocket. A pocket has usually the size of a maxstring, see ENVIRONMENT /STRING (but can be configured to be different, mostly when MAXPATH > /STRING ) Note that a pocket is a temporary and forth internal functions do sometimes call POCKET-PAD too, especially when building filenames and getting a literal (but temporary) string from the keyboard. Functions are not expected to hold references to this transient area any longer than building a name and calling another word with it.

Usage of a pocket pad is a good way to make local temporary buffers superfluous that are only used to construct a temporary string that usually gets swallowed by another function.

      depracated code:
        create temp-buffer 255 allot
        : make-temp ( str buf )
               temp-buffer place  " .tmp" count temp-buffer append
               temp-buffer count make-file ;
      replace with this:
        : make-temp ( str buf )
             pocket-pad >r
             r place  " .tmp" count r append
             r> count make-file
        ;

WL-HASH
( buf-ptr buf-len -- buf-hash# )
[FTH]
WL-HASH ( buf-ptr buf-len -- buf-hash# ) [FTH]

calc hash-code for selection of thread in a threaded-vocabulary

TOPMOST
( some-wordlist* -- some-topmost-nfa* )
[FTH]
TOPMOST ( some-wordlist* -- some-topmost-nfa* ) [FTH]

that last valid word in the specified vocabulary

LS.WORDS
( -- )
[FTH]
LS.WORDS ( -- ) [FTH]

see WORDS

LS.PRIMITIVES
( -- )
[FTH]
LS.PRIMITIVES ( -- ) [FTH]

see WORDS

LS.COLON-DEFS
( -- )
[FTH]
LS.COLON-DEFS ( -- ) [FTH]

see WORDS

LS.DOES-DEFS
( -- )
[FTH]
LS.DOES-DEFS ( -- ) [FTH]

see WORDS

LS.CONSTANTS
( -- )
[FTH]
LS.CONSTANTS ( -- ) [FTH]

see WORDS

LS.VARIABLES
( -- )
[FTH]
LS.VARIABLES ( -- ) [FTH]

see WORDS

LS.VOCABULARIES
( -- )
[FTH]
LS.VOCABULARIES ( -- ) [FTH]

see WORDS

LS.MARKERS
( -- )
[FTH]
LS.MARKERS ( -- ) [FTH]

see WORDS

W@
( some-wchar* -- some-wchar# | some* -- some# [?] )
[FTH]
W@ ( some-wchar* -- some-wchar# | some* -- some# [?] ) [FTH]

fetch a 2byte-val from address

W!
( value# some-wchar* -- | value# wchar* -- [?] )
[FTH]
W! ( value# some-wchar* -- | value# wchar* -- [?] ) [FTH]

store a 2byte-val at addressed 2byte-value

W+!
( value# some-wchar* -- | value# wchar* -- [?] )
[FTH]
W+! ( value# some-wchar* -- | value# wchar* -- [?] ) [FTH]

add a 2byte-val to addressed 2byte-value

TAB
( tab-n# -- )
[FTH]
TAB ( tab-n# -- ) [FTH]

jump to next column divisible by n

BACKSPACE
( -- )
[FTH]
BACKSPACE ( -- ) [FTH]

reverse of SPACE

?STOP
( -- stop-flag )
[FTH]
?STOP ( -- stop-flag ) [FTH]

check for 'q' pressed - see => ?CR

START?CR
( -- )
[FTH]
START?CR ( -- ) [FTH]

initialized for more-like effect - see => ?CR

?CR
( -- cr-flag )
[FTH]
?CR ( -- cr-flag ) [FTH]

like CR , stop 25 lines past START?CR

CLOSE-ALL-FILES
( -- )
[FTH]
CLOSE-ALL-FILES ( -- ) [FTH]
.MEMORY
( -- )
[FTH]
.MEMORY ( -- ) [FTH]
.STATUS
( -- )
[FTH]
.STATUS ( -- ) [FTH]

display internal variables

      : .STATUS .VERSION .CVERSION .MEMORY .SEARCHPATHS .DICTVARS .REGSUSED ;

*EMIT*
( -- handler-xt* )
[FTH]
*EMIT* ( -- handler-xt* ) [FTH]

initialized to (EMIT)

(EMIT) ( char# -- ) [FTH]

like EMIT and always to screen - the routine to be put into *EMIT*

*EXPECT*
( -- handler-xt* )
[FTH]
*EXPECT* ( -- handler-xt* ) [FTH]

initialized to (EXPECT)

(EXPECT) ( a b -- ) [FTH]

like EXPECT and always from screen - the routine to be put into *EXPECT*

*KEY*
( -- handler-xt* )
[FTH]
*KEY* ( -- handler-xt* ) [FTH]

initialized to (KEY)

(KEY) ( -- key# ) [FTH]

like KEY and always from screen - the routine to be put into *KEY*

(TYPE) ( str* len# -- ) [FTH]

like TYPE and always to screen - the routine to be put into *TYPE*

STANDARD-I/O
( -- )
[FTH]
STANDARD-I/O ( -- ) [FTH]

initialize *TYPE* , *EMIT* , *EXPECT* and *KEY* to point directly to the screen I/O routines,
namely (TYPE) , (EMIT) , (EXPECT) , (KEY)

((EXECUTES)) ( fkey# -- ) [HIDDEN]

compiled by EXECUTES

EXECUTES
( fkey# [word] -- )
[EXT]
EXECUTES ( fkey# [word] -- ) [EXT]

stores the execution token of following word into the callback pointer for the specified function-key

HELP
( "name" -- )
[FTH] [EXEC]
HELP ( "name" -- ) [FTH] [EXEC]

will load the help module in the background and hand over the parsed name to (HELP) to be resolved. If no (HELP) word can be loaded, nothing will happen.

EDIT-BLOCKFILE
( "name" -- )
[FTH] [EXEC]
EDIT-BLOCKFILE ( "name" -- ) [FTH] [EXEC]

will load the edit module in the background and look for a word called EDIT-BLOCK that could be used to edit the blockfile. If no EDIT-BLOCKFILE word can be loaded, nothing will happen. Otherwise, OPEN-BLOCKFILE is called followed by 0 EDIT-BLOCK to start editing the file at the first block.

ARGC
( -- arg-count )
[FTH]
ARGC ( -- arg-count ) [FTH]
ARGV
( arg-n# -- arg-ptr arg-len )
[FTH]
ARGV ( arg-n# -- arg-ptr arg-len ) [FTH]
EXPAND-FN
( name-ptr name-len buf-ptr -- buf-ptr buf-len )
[FTH]
EXPAND-FN ( name-ptr name-len buf-ptr -- buf-ptr buf-len ) [FTH]

      : e.g. s" includefile" POCKET-PAD EXPAND-FN ;

((LOAD")) ( -- ? ) [HIDDEN]
LOAD"
( [filename<">] -- ??? )
[FTH] [OLD]
LOAD" ( [filename<">] -- ??? ) [FTH] [OLD]

load the specified file - this word can be compiled into a word-definition obsolete! use OPEN-BLOCKFILE name LOAD

SYSTEM
( command-ptr command-len -- command-exitcode# )
[FTH]
SYSTEM ( command-ptr command-len -- command-exitcode# ) [FTH]

run a shell command (note: embedded systems have no shell)

((SYSTEM")) ( ... -- exitcode# ) [HIDDEN]

compiled by SYSTEM" commandline"

SYSTEM"
( [command-line<">] -- command-exitcode# )
[FTH] [OLD]
SYSTEM" ( [command-line<">] -- command-exitcode# ) [FTH] [OLD]

run a shell command (note:embedded systems have no shell) obsolete! use S" string" SYSTEM

OK
( -- )
OK ( -- )

it usually prints "ok"

CREATE:
( "name" -- )
[FTH]
CREATE: ( "name" -- ) [FTH]

this creates a name with the VARIABLE runtime. Note that this is the FIG-implemenation of CREATE whereas in ANS-Forth mode we have a CREATE identical to FIG-style <BUILDS</link>

      : CREATE: BL WORD $HEADER DOVAR A, ;

BUFFER:
( size# "name" -- )
[FTH]
BUFFER: ( size# "name" -- ) [FTH]

this creates a name with the VARIABLE runtime and ALLOTs memory

      : BUFFER: BL WORD $HEADER DOVAR A, ALLOT ;

R'@
( R: a b -- a R: a b )
[FTH]
R'@ ( R: a b -- a R: a b ) [FTH]

fetch the next-under value from the returnstack. used to interpret the returnstack to hold two LOCALS| values. ( R@ / 2R@ / R>DROP / R"@)

R'!
( x R: a b -- R: x b )
[FTH]
R'! ( x R: a b -- R: x b ) [FTH]

store the value into the next-under value in the returnstack. used to interpret the returnstack to hold two LOCALS| values. see R'@ for inverse operation

R"@
( R: a b c -- a R: a b c )
[FTH]
R"@ ( R: a b c -- a R: a b c ) [FTH]

fetch the second-under value from the returnstack. used to interpret the returnstack to hold three LOCALS| values. see R"! for inverse operation ( R'@ R@ / 2R@ / R>DROP )

R"!
( x R: a b c -- R: x b c )
[FTH]
R"! ( x R: a b c -- R: x b c ) [FTH]

store the value into the second-under value in the returnstack. used to interpret the returnstack to hold three LOCALS| values. see R"@ for inverse operation

R!
( x R: a -- R: x )
[FTH]
R! ( x R: a -- R: x ) [FTH]

store the value as the topmost value in the returnstack. see R@ for inverse operation ( R'@ / R"@ / 2R@ / 2R!)

2R!
( x y R: a b -- R: x y )
[FTH]
2R! ( x y R: a b -- R: x y ) [FTH]

store the value as the topmost value in the returnstack. see 2R@ for inverse operation ( R'@ / R"@ / 2R@ / 2R!)

DUP>R
( val -- val R: val )
[FTH]
DUP>R ( val -- val R: val ) [FTH]

shortcut, see R>DROP
note again that the following will fail:

      : DUP>R DUP >R ;

R>DROP
( R: val -- R: )
[FTH]
R>DROP ( R: val -- R: ) [FTH]

shortcut (e.g. in CSI-Forth)
note that the access to R is configuration dependent - only in a traditional fig-forth each NEST will be one cell wide - in case that there are no LOCALS| of course. And remember, the word above reads like the sequence R> and DROP but that is not quite true.

      : R>DROP R> DROP ; ( is bad - correct might be )  : R>DROP R> R> DROP >R ;

2R>2DROP
( R: a b -- R: )
[FTH]
2R>2DROP ( R: a b -- R: ) [FTH]

this is two times R>DROP but a bit quicker. it is however really quick compared to the sequence 2R> and 2DROP

CLEARSTACK
( -- )
[FTH]
CLEARSTACK ( -- ) [FTH]

reset the parameter stack to be empty

      : CLEARSTACK  S0 SP! ;

LOWER-CASE
( -- uppercase-var* )
[OLD]
LOWER-CASE ( -- uppercase-var* ) [OLD]

Call to enable lower-case symbols as input Replace code of "LOWER-CASE OFF" with "NO TO UPPER-CASE?" see UPPER-CASE?

UPPER-CASE?
( -- uppercase-flag )
UPPER-CASE? ( -- uppercase-flag )

Call to check whether lower-case symbols in input can match words defined in uppercase. Actually it sets the internal wordl-flag which has some bit-defs used when creating new vocabularies.

This flag VALUE is modifiable with TO

        YES TO UPPER-CASE?

REDEFINED-MSG
( -- redefined-var* )
[OLD]
REDEFINED-MSG ( -- redefined-var* ) [OLD]

Call to enable warnings if creating symbols being in the ORDER Replace code of "REDEFINED-MSG OFF" with "NO TO REDEFINED-MSG?" see REDEFINED-MSG?

REDEFINED-MSG?
( -- redefined-flag )
REDEFINED-MSG? ( -- redefined-flag )

Call to check whether the system will emit warnings if creating symbols being already defined in the CURRENT vocabulary.

This flag VALUE is modifiable with TO

        YES TO REDEFINED-MSG?

QUOTED-PARSE
( -- quotedparse-var* )
[OLD]
QUOTED-PARSE ( -- quotedparse-var* ) [OLD]

Call to enable quoted-parse extension in PARSE WORDs Replace code of "QUOTED-PARSE OFF" with "NO TO QUOTED-PARSE?" see QUOTED-PARSE?

QUOTED-PARSE?
( -- quotedparse-flag )
QUOTED-PARSE? ( -- quotedparse-flag )

Call to check for quoted-parse extension in PARSE WORDs

This flag VALUE is modifiable with TO

        YES TO QUOTED-PARSE?

RAND_MAX
( -- rand-max )
[ENVIRONMENT]
RAND_MAX ( -- rand-max ) [ENVIRONMENT]

maximum value for RANDOM

( -- fid ) - the standard file-handles of the task
MODULE
( "name" -- old-current )
MODULE ( "name" -- old-current )

create a new WORDLIST with the given name. It will also have an implicit hidden vocabulary just as well and all DEFINITIONS will go into that hidden wordlist. Therefore the old CURRENT is memorized on the cs-stack.

effectivly, CONTEXT[1] will have the wordlist-id of the public wordlist "name" and CONTEXT[0] will have the hidden wordlist contained in "name" - the hidden wordlist will always be known as HIDDEN' so that it can be re-referenced without need to use ALSO just to access a single definition from just another vocabulary. Note that HIDDEN' is defined immediate (a VOCABULARY' ) to modify the ORDER inside a colon definition.

      : MODULE
        CURRENT @ ( -- old-current )
        VOCABULARY
        ALSO LATEST NAME> EXECUTE ALSO DEFINITIONS
        C" HIDDEN'" $CREATE WORDLIST CONTEXT !
      ;

END-MODULE
( old-current -- )
END-MODULE ( old-current -- )

clean up the cs-stack from the last MODULE definition. Effectivly, MODULE definitions can be nested.

      : END-MODULE ( old-current )
        PREVIOUS PREVIOUS CURRENT !

EXPORT
( old-current "name" -- old-current )
EXPORT ( old-current "name" -- old-current )

the named word in the hidden dictionary (i.e. the wordlist referenced in CURRENT) is exported into the public wordlist of it (i.e. which is in this implementation CONTEXT[1]). The actual implemenation will create a DEFER-word in the public wordlist withits parameter area pointing to the cfa of the hidden implementation.

      : EXPORT
        CURRENT @ CONTEXT CELL+ @ CURRENT !
        DEFER CURRENT !
        LATEST COUNT CURRENT @ SEARCH-WORDLIST
        IF LATEST NAME> >BODY ! ELSE ABORT" can't find word to export" THEN
      ;

EXPOSE-MODULE
( "name" -- )
EXPOSE-MODULE ( "name" -- )

affects the search order, ALSO module-wid CONTEXT ! hidden'

      : EXPOSE-MODULE
         ALSO S" HIDDEN'"
         ' DUP VOC? ABORT?" is no vocabulary" >VOC
         SEARCH-WORDLIST 0= IF " no hidden vocabulary found" THEN
         DUP VOC? ABORT?" hidden is no vocabulary" EXECUTE
      ;

ALSO-MODULE
( "name" -- )
ALSO-MODULE ( "name" -- )

affects the search-order, ALSO module-wid CONTEXT !

      : ALSO-MODULE
        ' DUP VOC? ABORT?" is no vocabulary"
        ALSO EXECUTE
      ;

NVRAM,WORDS
( -- )
NVRAM,WORDS ( -- )

Print a list of WORDS in the NVRAM buffer. Try to show also the current value, atleast for NVRAM numbers and strings. Words can be added or changed with the help of NVRAM,SET or NVRAM,USE

Values in the NVRAM buffer will survive a COLD reboot, in many hosted environments however the NVRAM will be lost on program exit.

NVRAM,AS
( str-ptr str-len "varname" -- )
NVRAM,AS ( str-ptr str-len "varname" -- )

set the NVRAM variable to the specified string.

Some NVRAM strings do not take effect until next COLD reboot.

NVRAM,TO
( number "varname" -- )
NVRAM,TO ( number "varname" -- )

set the NVRAM variable to the specified number.

Most NVRAM numbers do not take effect until next COLD reboot.

NVRAM,Z@
( "varname" -- z-str )
NVRAM,Z@ ( "varname" -- z-str )

Return the string pointer of the NVRAM string item, or null if no such item exists.

NVRAM,S@
( "varname" -- str-ptr str-len )
NVRAM,S@ ( "varname" -- str-ptr str-len )

Return the string span of the NVRAM string item, or double null if no such item exists.

NVRAM,?@
( number "varname" -- number' )
NVRAM,?@ ( number "varname" -- number' )

Return the value of the NVRAM value item, or leave the original number untouched (i.e. the default value for your option).

NTOHS
( w -- w' )
NTOHS ( w -- w' )

if current host-encoding is bigendian, this is a NOOP otherwise byteswap the lower 16-bit bits of the topofstack. see W@ and W! (on some platforms, the upper bits are erased, on others not)

NTOHL
( l -- l' )
NTOHL ( l -- l' )

if current host-encoding is bigendian, this is a NOOP otherwise byteswap the lower 32-bit bits of the topofstack. see L@ and L! (being usually just @ and ! ) (on some platforms, the upper bits are erased, on others not)

DEFINITIONS
( -- )
DEFINITIONS ( -- )

make the current context-vocabulary the definition-vocabulary, that is where new names are declared in. see ORDER

GET-CURRENT
( -- voc )
GET-CURRENT ( -- voc )

return the current definition vocabulary, see DEFINITIONS

GET-ORDER
( -- vocn ... voc1 n )
GET-ORDER ( -- vocn ... voc1 n )

get the current search order onto the stack, see SET-ORDER

SEARCH-WORDLIST
( str-ptr str-len voc -- 0 | xt 1 | xt -1 )
SEARCH-WORDLIST ( str-ptr str-len voc -- 0 | xt 1 | xt -1 )

almost like FIND or (FIND) -- but searches only the specified vocabulary.

SET-CURRENT
( voc -- )
SET-CURRENT ( voc -- )

set the definition-vocabulary. see DEFINITIONS

SET-ORDER
( vocn ... voc1 n -- )
SET-ORDER ( vocn ... voc1 n -- )

set the search-order -- probably saved beforehand using GET-ORDER

WORDLIST
( -- voc )
WORDLIST ( -- voc )

return a new vocabulary-body for private definitions.

ALSO
( -- )
ALSO ( -- )

a DUP on the search ORDER - each named vocabulary replaces the topmost ORDER vocabulary. Using ALSO will make it fixed to the search-order. (but it is not nailed in trap-conditions as if using DEFAULT-ORDER )

      order:   vocn ... voc2 voc1 -- vocn ... voc2 voc1 voc1

ORDER
( -- )
ORDER ( -- )

show the current search-order, followed by the CURRENT DEFINITIONS vocabulary and the ONLY base vocabulary

PREVIOUS
( -- )
PREVIOUS ( -- )

the invers of ALSO , does a DROP on the search ORDER of vocabularies.

      order: vocn ... voc2 voc1 -- vocn ... voc2
      example: ALSO PRIVATE-VOC DEFINTIONS (...do some...) PREVIOUS DEFINITIONS

DEFAULT-ORDER
( -- )
DEFAULT-ORDER ( -- )

nail the current search ORDER so that it will even survive a trap-condition. This default-order can be explicitly loaded with RESET-ORDER

RESET-ORDER
( -- )
RESET-ORDER ( -- )

load the DEFAULT-ORDER into the current search ORDER - this is implicitly done when a trap is encountered.

ENVIRONMENT WORDLISTS
( -- value )
"ENVIRONMENT WORDLISTS" ( -- value )

the maximum number of wordlists in the search order

FORTH-WORDLIST
( -- voc )
FORTH-WORDLIST ( -- voc )

return the voc-address of the base FORTH-vocabulary (quite often the actual name is not FORTH )

$PID
( -- pid )
$PID ( -- pid )

calls system's `getpid`

$UID
( -- val )
$UID ( -- val )

calls system's `getuid`

$EUID
( -- val )
$EUID ( -- val )

calls system's `geteuid`

$GID
( -- val )
$GID ( -- val )

calls system's `getgid`

UMASK
( val -- ret )
UMASK ( val -- ret )

calls system's `umask`

$HOME
( -- str-ptr str-len )
$HOME ( -- str-ptr str-len )

calls system's `getenv(HOME)`

$USER
( -- str-ptr str-len )
$USER ( -- str-ptr str-len )

calls system's `getenv(USER)`

$CWD
( -- str-ptr str-len )
$CWD ( -- str-ptr str-len )

calls system's `getcwd`

PWD
( -- )
PWD ( -- )

calls system's `getcwd` and prints it to the screen

      : PWD  $CWD TYPE ;

CHDIR
( bstring -- )
CHDIR ( bstring -- )

change the current directory.

(under VxWorks it is global! do not use in scripts!!)
(RAISE) ( signal# -- ) [FTH]

send a SIGNAL to self OLD: use RAISE-SIGNAL

RAISE-SIGNAL
( signal# -- ior )
[FTH]
RAISE-SIGNAL ( signal# -- ior ) [FTH]
FORTH-SIGNAL
( handler-xt* signal# -- old-signal-xt* )
[FTH]
FORTH-SIGNAL ( handler-xt* signal# -- old-signal-xt* ) [FTH]

install signal handler - return old signal handler

SMART-INTERPRET-INIT
( -- )
SMART-INTERPRET-INIT ( -- )

creates a set of interpret-words that are used in the inner interpreter, so if a word is unknown to the interpreter-loop it will use the first char of that word, attach it to an "interpret-" prefix, and tries to use that IMMEDIATE-=>'DEFER'-word on the rest of the word. This SMART-INTERPRET-INIT will set up words like interpret-" so you can write `"hello"` instead of `" hello"` and it creates interpret-\ so that words like `\if-unix` are ignoring the line if the word `\if-unknown` is unknown in itself. This is usually not activated on startup.

SMART-INTERPRET!
( -- )
SMART-INTERPRET! ( -- )

enables/disables the SMART-INTERPRET extension in INTERPRET , (actually stores an XT in DEFER inside the mainloop interpreter)

gethostbyname
( name -- hostent )
gethostbyname ( name -- hostent )
socket
( class type proto -- fd )
socket ( class type proto -- fd )
connect
( fd sock size -- err )
connect ( fd sock size -- err )
fdopen
( fd fileattr -- file )
fdopen ( fd fileattr -- file )
htonl
( x -- x' )
htonl ( x -- x' )
host>addr
( addr u -- x )
"host>addr" ( addr u -- x )

coverts an internet path into a IPv$ adress the resulting address in network by order

open-socket
( addr u port -- fid )
open-socket ( addr u port -- fid )
NARROW-CHANGER(
( changer# "stackhelp<rp>" -- )
[EXT]
"NARROW-CHANGER(" ( changer# "stackhelp<rp>" -- ) [EXT]
NARROW-INPUTLIST(
( changer# "stackhelp<rp>" -- )
[EXT]
"NARROW-INPUTLIST(" ( changer# "stackhelp<rp>" -- ) [EXT]
NARROW-OUTPUTLIST(
( changer# "stackhelp<rp>" -- )
[EXT]
"NARROW-OUTPUTLIST(" ( changer# "stackhelp<rp>" -- ) [EXT]
NARROW-INPUT-VARIANT(
( variant# changer# "stackhelp<rp>" -- )
[EXT]
"NARROW-INPUT-VARIANT(" ( variant# changer# "stackhelp<rp>" -- ) [EXT]

0 = default, 1 = 'S', 2 = 'R', ... 4 = 'P', ... 7 = 'M', .. 14 = 'F'

NARROW-OUTPUT-VARIANT(
( variant# changer# "stackhelp<rp>" -- )
[EXT]
"NARROW-OUTPUT-VARIANT(" ( variant# changer# "stackhelp<rp>" -- ) [EXT]
NARROW-INPUT-STACK(
( stk-char variant# changer# "stackhelp<rp>" -- )
[EXT]
"NARROW-INPUT-STACK(" ( stk-char variant# changer# "stackhelp<rp>" -- ) [EXT]

0 = default, 1 = 'S', 2 = 'R', ... 4 = 'P', ... 7 = 'M', .. 14 = 'F'

NARROW-OUTPUT-STACK(
( stk-char variant# changer# "stackhelp<rp>" -- )
[EXT]
"NARROW-OUTPUT-STACK(" ( stk-char variant# changer# "stackhelp<rp>" -- ) [EXT]
NARROW-INPUT-ARGUMENT(
( arg# stk-char variant# changer# "stackhelp<rp>" -- )
[EXT]
"NARROW-INPUT-ARGUMENT(" ( arg# stk-char variant# changer# "stackhelp<rp>" -- ) [EXT]

0 = default, 1 = 'S', 2 = 'R', ... 4 = 'P', ... 7 = 'M', .. 14 = 'F' arg# is [0] = TOS and [1] = UNDER, same as the pick values where 3 2 1 0 2 pick . =:= 2

NARROW-OUTPUT-ARGUMENT(
( arg# stk-char variant# changer# "stackhelp<rp>" -- )
[EXT]
"NARROW-OUTPUT-ARGUMENT(" ( arg# stk-char variant# changer# "stackhelp<rp>" -- ) [EXT]

arg# is [0] = TOS and [1] = UNDER, same as the pick values where 3 2 1 0 2 pick . =:= 2

NARROW-INPUT-ARGUMENT-NAME(
( arg# stk-char variant# changer# "stackhelp<rp>" -- )
[EXT]
"NARROW-INPUT-ARGUMENT-NAME(" ( arg# stk-char variant# changer# "stackhelp<rp>" -- ) [EXT]

0 = default, 1 = 'S', 2 = 'R', ... 4 = 'P', ... 7 = 'M', .. 14 = 'F' arg# is [0] = TOS and [1] = UNDER, same as the pick values where 3 2 1 0 2 pick . =:= 2

NARROW-OUTPUT-ARGUMENT-NAME(
( arg# stk-char variant# changer# "stackhelp<rp>" -- )
[EXT]
"NARROW-OUTPUT-ARGUMENT-NAME(" ( arg# stk-char variant# changer# "stackhelp<rp>" -- ) [EXT]

arg# is [0] = TOS and [1] = UNDER, same as the pick values where 3 2 1 0 2 pick . =:= 2

NARROW-INPUT-ARGUMENT-TYPE(
( arg# stk-char variant# changer# "stackhelp<rp>" -- )
[EXT]
"NARROW-INPUT-ARGUMENT-TYPE(" ( arg# stk-char variant# changer# "stackhelp<rp>" -- ) [EXT]

0 = default, 1 = 'S', 2 = 'R', ... 4 = 'P', ... 7 = 'M', .. 14 = 'F' arg# is [0] = TOS and [1] = UNDER, same as the pick values where 3 2 1 0 2 pick . =:= 2

NARROW-OUTPUT-ARGUMENT-TYPE(
( arg# stk-char which# "stackhelp<rp>" -- )
[EXT]
"NARROW-OUTPUT-ARGUMENT-TYPE(" ( arg# stk-char which# "stackhelp<rp>" -- ) [EXT]

arg# is [0] = TOS and [1] = UNDER, same as the pick values where 3 2 1 0 2 pick . =:= 2

CANONIC-INPUT-TYPE(
( arg# stk-char variant# changer# "stackhelp<rp>" -- )
[EXT]
"CANONIC-INPUT-TYPE(" ( arg# stk-char variant# changer# "stackhelp<rp>" -- ) [EXT]

0 = default, 1 = 'S', 2 = 'R', ... 4 = 'P', ... 7 = 'M', .. 14 = 'F' arg# is [0] = TOS and [1] = UNDER, same as the pick values where 3 2 1 0 2 pick . =:= 2

CANONIC-OUTPUT-TYPE(
( arg# stk-char variant# changer# "stackhelp<rp>" -- )
[EXT]
"CANONIC-OUTPUT-TYPE(" ( arg# stk-char variant# changer# "stackhelp<rp>" -- ) [EXT]

arg# is [0] = TOS and [1] = UNDER, same as the pick values where 3 2 1 0 2 pick . =:= 2

REWRITER-TEST(
( "tracked-stack -- input-stack<rp>" -- )
[EXT]
"REWRITER-TEST(" ( "tracked-stack -- input-stack<rp>" -- ) [EXT]

suppose that the left side is a tracked stack line during compiling and the right side is a candidate changer input stack. Test whethr the candidate does match and the complete changer would be allowed to run a rewrite in the track stack buffer.

Possible conditions include: the left side has not enough arguments or... any argument on the right side has a type specialization that does not match as a valid suffix to their counterpart on the left side.

REWRITER-INPUT-ARG(
( arg# "tracked-stack -- changer<rp>" -- )
[EXT]
"REWRITER-INPUT-ARG(" ( arg# "tracked-stack -- changer<rp>" -- ) [EXT]

suppose that the left side is a tracked stack line during compiling and the right side is a candidate changer input stack. Assume the righthand candidate does match - look at the given argument on the left side and show the prefix being copied to the output trackstack when the rewrite-rule is gettin applied later.

REWRITE-LINE(
( "stack-layout<rp>" -- )
[EXT]
"REWRITE-LINE(" ( "stack-layout<rp>" -- ) [EXT]

fill rewrite-buffer with a stack-layout to be processed. see REWRITE-SHOW.

REWRITE-SHOW.
( -- )
[EXT]
"REWRITE-SHOW." ( -- ) [EXT]

show current rewrite-buffer.

REWRITE-STACK-TEST(
( "stackhelp<rp>" -- )
[EXT]
"REWRITE-STACK-TEST(" ( "stackhelp<rp>" -- ) [EXT]

check whether this stackhelp does match on current rewrite-buffer and say oK/No respectivly.

REWRITE-INPUT-ARG(
( arg# "stackhelp<rp>" -- )
[EXT]
"REWRITE-INPUT-ARG(" ( arg# "stackhelp<rp>" -- ) [EXT]

check whether this stackhelp does match on current rewrite-buffer and in the given input match show us the argument but only the good prefix i.e. the type constraint being cut off already.

REWRITE-STACK-RESULT(
( "stackhelp<rp>" -- )
[EXT]
"REWRITE-STACK-RESULT(" ( "stackhelp<rp>" -- ) [EXT]

rewrite the current rewrite-buffer and show the result that would occur with this stackhelp being applied.

NARROW-INPUT-NOTATION(
( notation# changer# "stackhelp<rp>" -- )
[EXT]
"NARROW-INPUT-NOTATION(" ( notation# changer# "stackhelp<rp>" -- ) [EXT]
NARROW-OUTPUT-NOTATION(
( notation# changer# "stackhelp<rp>" -- )
[EXT]
"NARROW-OUTPUT-NOTATION(" ( notation# changer# "stackhelp<rp>" -- ) [EXT]
REWRITE-STACKDEF-RESULT(
( "stackhelp<rp>" -- )
[EXT]
"REWRITE-STACKDEF-RESULT(" ( "stackhelp<rp>" -- ) [EXT]

assume: only one changer (if more are provided then only the first is used) only one stackdef variant in inputlist

REWRITE-TEST(
( "stackhelp<rp>" -- )
[EXT]
"REWRITE-TEST(" ( "stackhelp<rp>" -- ) [EXT]

Test whether the given changer would match the current line. assume: only one changer (if more are provided then only the first is used)

|(
( [string<rp>] -- )
[EXT]
"|(" ( [string<rp>] -- ) [EXT]

add a checkstack notation for the LAST word or just try to match the given notation with the stacklayout traced so far - possibly casting a few types as needed.

STACKHELPS
( [name] -- )
[EXT]
STACKHELPS ( [name] -- ) [EXT]

show all possible stackhelps for this name.

STACKHELP
( [name] -- )
[EXT]
STACKHELP ( [name] -- ) [EXT]

show the stackhelp info registered for this name.

STACKHELP-WORDLIST
( -- stackhelp-wordlist* )
[EXT]
STACKHELP-WORDLIST ( -- stackhelp-wordlist* ) [EXT]
-TRAILING
( str-ptr str-len -- str-ptr str-len' )
-TRAILING ( str-ptr str-len -- str-ptr str-len' )

check the given buffer if it contains whitespace at its end. If so, shorten str-len to meet the last non-whitespace character in the buffer.

/STRING
( str-ptr str-len n -- str-ptr' str-len' )
/STRING ( str-ptr str-len n -- str-ptr' str-len' )

shorten the buffer from the beginning by n characters, i.e.

       str-ptr += n ;
       str-len -= n;

BLANK
( str-ptr str-len -- )
BLANK ( str-ptr str-len -- )

FILL a given buffer with BL blanks

CMOVE
( from-ptr to-ptr len# -- )
CMOVE ( from-ptr to-ptr len# -- )

memcpy an area from->to for len bytes, starting at the lower addresses, see CMOVE>

CMOVE>
( from-ptr to-ptr len# -- )
CMOVE> ( from-ptr to-ptr len# -- )

memcpy an area from->to for len bytes, starting with the higher addresses, see CMOVE

COMPARE
( str1-ptr str1-len str2-ptr str2-len -- diff# )
COMPARE ( str1-ptr str1-len str2-ptr str2-len -- diff# )

compare both str-buffers, return 0 if they are equal, -1 if lower or shorter, and 1 if greater or longer

SEARCH
( str1-ptr str1-len str2-ptr str2-len -- str1-ptr' str1-len' flag )
SEARCH ( str1-ptr str1-len str2-ptr str2-len -- str1-ptr' str1-len' flag )

search the str-buffer1 for the text of str-buffer2, if it is contained return TRUE and return buffer-values that point to the contained string, otherwise return FALSE and leave the original str-buffer1.

SLITERAL
( C: str-ptr str-len -- S: str-ptr str-len )
SLITERAL ( C: str-ptr str-len -- S: str-ptr str-len )

this word does almost the same as LITERAL - it takes an S" string as specified in the CS-STACK at compile time and compiles into the current definition where it is returned as if there were a direct string-literal. This can be used to compute a string-literal at compile-time and hardwire it.

      example:
        : ORIGINAL-HOME  [ $HOME COUNT ] SLITERAL ; ( -- str-ptr str-len )

FIELD
( offset size "name" -- offset+size )
FIELD ( offset size "name" -- offset+size )

create a field - the workhorse for both STRUCT and STRUCTURE implementations. The created fieldname is an OFFSET:-word that memorizes the current offset in its PFA and will add that offset on runtime. This forth-word does *not* align.

      : FIELD CREATE
        OVER ,
        +
      DOES>
         @ +
      ;

SIZEOF
( "name" -- size )
SIZEOF ( "name" -- size )

get the size-value from a previous structure definition

      : SIZEOF   ' >BODY @  STATE @ IF [COMPILE] LITERAL THEN ; IMMEDIATE

STRUCTURE
( "name" -- here zero-offset )
exec
STRUCTURE ( "name" -- here zero-offset ) exec

start a structure definition

      : STRUCTURE: CREATE !CSP
        HERE
        0 DUP ,
      DOES>
        CREATE @ ALLOT
      ;

ENDSTRUCTURE
( here some-offset -- )
ENDSTRUCTURE ( here some-offset -- )

finalize a previously started STRUCTURE definition

      : ENDSTRUCTURE  SWAP !  ?CSP ;

STRUCT
( "name" -- here zero-offset )
STRUCT ( "name" -- here zero-offset )

begin definition of a new structure (mpe.000)

      : STRUCT CREATE  !CSP
        HERE
        0 DUP ,
      DOES>
        @
      ;

END-STRUCT
( here some-offset -- )
END-STRUCT ( here some-offset -- )

terminate definition of a new structure (mpe.000)

      : END-STRUCT  SWAP !  ?CSP ;

SUBRECORD
( outer-offset "name" -- outer-offset here zero-offset )
SUBRECORD ( outer-offset "name" -- outer-offset here zero-offset )

begin definition of a subrecord (mpe.000)

      : STRUCT CREATE
        HERE
        0 DUP ,
      DOES>
        @
      ;

END-SUBRECORD
( outer-offset here some-offset -- outer-offset+some )
END-SUBRECORD ( outer-offset here some-offset -- outer-offset+some )

end definition of a subrecord (mpe.000)

      : END-SUBRECORD  TUCK SWAP !  + ;

ARRAY-OF
( some-offset n len "name" -- some-offset )
ARRAY-OF ( some-offset n len "name" -- some-offset )

a FIELD-array

      : ARRAY-OF * FIELD ;

VARIANT
( outer-offset "name" -- outer-offset here zero-offset )
VARIANT ( outer-offset "name" -- outer-offset here zero-offset )

Variant records describe an alternative view of the current record or subrecord from the start to the current point. The variant need not be of the same length, but the larger is taken

      : VARIANT SUBRECORD ;

END-VARIANT
( outer-offset here some-offset -- outer-offset )
END-VARIANT ( outer-offset here some-offset -- outer-offset )

terminate definition of a new variant (mpe.000)

      : END-STRUCT  TUCK SWAP !  2DUP < IF NIP ELSE DROP THEN ;

INSTANCE
( len "name" -- )
INSTANCE ( len "name" -- )

Create a named instance of a named structure.

      : INSTANCE  CREATE ALLOT ;

INSTANCE-ADDR
( len -- addr )
INSTANCE-ADDR ( len -- addr )

Create nameless instance of a structure and return base address.

      : INSTANCE-ADDR  HERE SWAP ALLOT ;

<MARK
( -- DP-mark )
compile-only
<MARK ( -- DP-mark ) compile-only

memorizes the current DP on the CS-STACK used for <RESOLVE</link> later. Useful for creation of compiling words, eg. BEGIN , see AHEAD

      simulate:
        : <MARK ?COMP  HERE ;

<RESOLVE
( DP-mark -- )
compile-only
<RESOLVE ( DP-mark -- ) compile-only

resolves a previous <MARK</link> , actually pushes the DP-address memorized at <MARK into the dictionary. Mostly used after <link>BRANCH or => ?BRANCH in compiling words like UNTIL

      simulate:
        : <RESOLVE ?COMP  , ;

MARK>
( -- DP-mark )
compile-only
MARK> ( -- DP-mark ) compile-only

makes room for a pointer in the dictionary to be resolved through RESOLVE> and does therefore memorize that cell's address on the CS-STACK Mostly used after BRANCH or => ?BRANCH in compiling words like IF or ELSE

      simulate:
        : MARK> ?COMP  HERE 0 , ;

RESOLVE>
( DP-mark -- )
compile-only
RESOLVE> ( DP-mark -- ) compile-only

resolves a pointer created by MARK> Mostly used in compiling words like THEN

      simulate:
        : RESOLVE> ?COMP  HERE SWAP ! ;

BRANCH
( -- )
BRANCH ( -- )

compiles a branch-runtime into the dictionary that can be resolved with MARK<d or <RESOLVE. Usage:

          BRANCH MARK&lt;     or
          BRANCH &gt;RESOLVE  or ...

this is the runtime-portion of ELSE - the use of ELSE should be preferred. See also => ?BRANCH

      : BRANCH COMPILE (BRANCH) ;

?BRANCH
( -- )
?BRANCH ( -- )

compiles a cond-branch-runtime into the dictionary that can be resolved with >MARK&d or RESOLVE>. Usage:

          ?BRANCH MARK&lt;     or
          ?BRANCH &gt;RESOLVE  or ...

this is the runtime-portion of IF - the use of IF should be preferred. See also BRANCH

      : ?BRANCH COMPILE (?BRANCH) ;

CONTEXT
( addr -- )
CONTEXT ( addr -- )

The variable that holds the or the topmost search-order wordlist. The new ansforth standard suggests the use of SET-CONTEXT and GET-CONTEXT instead of using CONTEXT => ! and CONTEXT @

CURRENT
( addr -- )
CURRENT ( addr -- )

The variable that holds the or the topmost compile-order wordlist. The new ansforth standard suggests the use of SET-CURRENT and GET-CURRENT instead of using CURRENT => ! and CURRENT @

SHOW-TERM-CONTROLS
( -- )
for debugging
SHOW-TERM-CONTROLS ( -- ) for debugging

show the current mappings for the terminal output may give hints about what is wrong if the output seems to miss some functionality

SHOW-TERM-ESC-KEYS
( -- )
for debugging
SHOW-TERM-ESC-KEYS ( -- ) for debugging

show the current mappings for the terminal input may give hints about what is wrong if the input seems to miss some functionality

SHOW-TERMCAP
( -- )
for debugging
SHOW-TERMCAP ( -- ) for debugging

print the termcap strings used for input and output may give hints about what is wrong if the terminal seems to miss some functionality

ASSUME_VT100
( -- )
ASSUME_VT100 ( -- )

load hardwired VT100-termcap into the terminal-driver

ASSUME_DUMBTERM
( -- )
ASSUME_DUMBTERM ( -- )

load hardwired DUMBTERM-termcap into the terminal-driver

GOTOXY
( x y -- )
GOTOXY ( x y -- )

move the cursor to the specified position on the screen - this is usually done by sending a corresponding esc-sequence to the terminal.

?XY
( -- x y )
?XY ( -- x y )

returns the cursor position on screen, on a real unix system this includes a special call to the screen driver, in remote systems this can be the expected position as seen on the client side's terminal driver.

K-SHIFT-MASK
( -- mask# )
K-SHIFT-MASK ( -- mask# )

this value is only usable on the result value of KEY>FKEY

Note that { K-F1-SHIFT <unequal> K-F1 K-SHIFT-MASK OR } because the first one is a plain ekey-value while the second refers to a decoded fkey-value.

EKEY>FKEY
( key-code# -- key-code# 0 | fkey-code# true! )
EKEY>FKEY ( key-code# -- key-code# 0 | fkey-code# true! )

If the input ekey value was not an extended key then flag is set to FALSE and the value is left unchanged. Compare to EKEY>CHAR for the inverse.

If the input eky was an extended key then the value will be modified such that shifted values are transposed to their base EKEY plus K-SHIFT-MASK - therefore the K-SHIFT-MASK is only apropriate for the result fkey-code values of this function.

TERM-CAPTURE-CONTROLS
( -- var-ptr )
TERM-CAPTURE-CONTROLS ( -- var-ptr )

enable/disable common visualization of terminal control sequences.

(TERM-CAPTURE-ON) ( -- )

start capturing any terminal output. Whether the captured output does include any control commands depends on the setting of (TERM-CAPTURE-CONTROLS)

(TERM-CAPTURE-OFF) ( -- )

reset terminal driver to the one being effective on the last TERM-CAPTURE-TEXT or TERM-CAPTURE-KEYS call.

(TERM-CAPTURE-BUFFER) ( capturebuffer-ptr capturebuffer-len -- )

start with new capture buffer.

(TERM-CAPTURE-RESULT) ( -- capturebuffer-ptr capturebuffer-len )

get fill state of current capture buffer.

TERM-CAPTURE-ON
( capturebuffer-ptr capturebuffer-len -- )
TERM-CAPTURE-ON ( capturebuffer-ptr capturebuffer-len -- )

init/start capturing terminal output

      :  TERM-CAPTURE-ON (TERM-CAPTURE-BUFFER) (TERM-CAPTURE-ON) ;

TERM-CAPTURE-OFF
( -- capturebuffer-ptr capturebuffer-len )
TERM-CAPTURE-OFF ( -- capturebuffer-ptr capturebuffer-len )

shutdown capturing terminal output

      :  TERM-CAPTURE-OFF (TERM-CAPTURE-OFF) (TERM-CAPTURE-RESULT) ;

TERMCATCH
( str-ptr str-len some-xt* -- str-ptr str-len' catch-code# )
TERMCATCH ( str-ptr str-len some-xt* -- str-ptr str-len' catch-code# )

create a catch-domain around the token to be executed. This works the same as CATCH. Additionally all terminal output of that word is being captured to the buffer being provided as an argument. The maximum length input argument is modified flagging the actual length of captured output stream as the output argument. Note that in most cases a POCKET-PAD is just not big enough, atleast many error condition notifications tend to be quite lengthy for byte counted forth strings.

      : TERMCATCH TERM-CAPTURE-ON CATCH >R TERM-CAPTURE-OFF R> ;

[VOID]
( -- flag )
[VOID] ( -- flag )

Immediate FALSE. Used to comment out sections of code. IMMEDIATE so it can be inside definitions.

NOT
( x -- flag )
NOT ( x -- flag )

Identical to `0=`, used for program clarity to reverse the result of a previous test.

WARNING: PFE's NOT uses bitwise complement INVERT instead of the logical complement 0=, so that loading TOOLBELT will change semantics. ... this difference in semantics has caused dpans94 to depracate the word. Only if TRUE is -1 it would be identical but not all words return -1 for true.

[DEFINED]
( "name" -- flag )
[DEFINED] ( "name" -- flag )

Search the dictionary for _name_. If _name_ is found, return TRUE; otherwise return FALSE. Immediate for use in definitions.

[DEFINED] word ( -- nfa|0 ) immediate does check for the word using find (so it does not throw like ' ) and puts it on stack. As it is immediate it does work in compile-mode too, so it places its argument in the cs-stack then. This is most useful with a directly following [IF] clause, so that sth. like an `[IFDEF] word` can be simulated through `[DEFINED] word [IF]`

      : [DEFINED] BL WORD FIND NIP ; IMMEDIATE

[UNDEFINED]
( "name" -- flag )
[UNDEFINED] ( "name" -- flag )

Search the dictionary for _name_. If _name_ is found, return FALSE; otherwise return TRUE. Immediate for use in definitions.

see [DEFINED]

C+!
( n addr -- )
C+! ( n addr -- )

Add the low-order byte of _n_ to the byte at _addr_, removing both from the stack.

EMPTY
( -- )
EMPTY ( -- )

Reset the dictionary to a predefined golden state, discarding all definitions and releasing all allocated data space beyond that state.

BOUNDS
( str len -- str+len str )
BOUNDS ( str len -- str+len str )

Convert _str len_ to range for DO-loop.

      : BOUNDS  ( str len -- str+len str )  OVER + SWAP ;

OFF
( addr -- )
OFF ( addr -- )

Store 0 at _addr_. See `ON`.

       : OFF  ( addr -- )  0 SWAP ! ;

ON
( addr -- )
ON ( addr -- )

Store -1 at _addr_. See `OFF`.

       : ON  ( addr -- )  -1 SWAP ! ;

APPEND
( str len add2 -- )
APPEND ( str len add2 -- )

Append string _str len_ to the counted string at _addr_. AKA `+PLACE`.

      : APPEND   2DUP 2>R  COUNT +  SWAP MOVE ( ) 2R> C+! ;

APPEND-CHAR
( char addr -- )
APPEND-CHAR ( char addr -- )

Append _char_ to the counted string at _addr_.

      : APPEND-CHAR   DUP >R  COUNT  DUP 1+ R> C!  +  C! ;

PLACE
( str len addr -- )
PLACE ( str len addr -- )

Place the string _str len_ at _addr_, formatting it as a counted string.

      : PLACE  2DUP 2>R  1+ SWAP  MOVE  2R> C! ;
      : PLACE  2DUP C!   1+ SWAP CMOVE ;

STRING,
( str len -- )
STRING, ( str len -- )

Store a string in data space as a counted string.

      : STRING, HERE  OVER 1+  ALLOT  PLACE ;

,"
( "<ccc><quote>" -- )
," ( "<ccc><quote>" -- )

Store a quote-delimited string in data space as a counted string.

      : ," [CHAR] " PARSE  STRING, ; IMMEDIATE

THIRD
( x y z -- x y z x )
THIRD ( x y z -- x y z x )

Copy third element on the stack onto top of stack.

      : THIRD   2 PICK ;

FOURTH
( w x y z -- w x y z w )
FOURTH ( w x y z -- w x y z w )

Copy fourth element on the stack onto top of stack.

      : FOURTH  3 PICK ;

3DUP
( x y z -- x y z x y z )
3DUP ( x y z -- x y z x y z )

Copy top three elements on the stack onto top of stack.

      : 3DUP   THIRD THIRD THIRD ;

or

      : 3DUP  3 PICK 3 PICK 3 PICK ;

3DROP
( x y z -- )
3DROP ( x y z -- )

Drop the top three elements from the stack.

      : 3DROP   DROP 2DROP ;

2NIP
( w x y z -- y z )
2NIP ( w x y z -- y z )

Drop the third and fourth elements from the stack.

      : 2NIP   2SWAP 2DROP ;

R'@
( -- x )
( R: x y -- x y )
R'@ ( -- x )( R: x y -- x y )

The second element on the return stack.

      : R'@   S" 2R@ DROP " EVALUATE ; IMMEDIATE

ANDIF
( p ... -- flag )
ANDIF ( p ... -- flag )

Given `p ANDIF q THEN`, _q_ will not be performed if _p_ is false.

      : ANDIF  S" DUP IF DROP " EVALUATE ; IMMEDIATE

ORIF
( p ... -- flag )
ORIF ( p ... -- flag )

Given `p ORIF q THEN`, _q_ will not be performed if _p_ is true.

      : ORIF   S" DUP 0= IF DROP " EVALUATE ; IMMEDIATE

SCAN
( str len char -- str+i len-i )
SCAN ( str len char -- str+i len-i )

Look for a particular character in the specified string.

      : SCAN
         >R  BEGIN  DUP WHILE  OVER C@ R@ -
             WHILE  1 /STRING  REPEAT THEN
         R> DROP ;

ie. scan for first occurence of c in string

        : SCAN >R BEGIN DUP OVER C@ R@ = 0= OR WHILE
                         1- SWAP 1- SWAP REPEAT R> DROP ;

SKIP
( str len char -- str+i len-i )
SKIP ( str len char -- str+i len-i )

Advance past leading characters in the specified string.

      : SKIP
        >R  BEGIN  DUP WHILE  OVER C@ R@ =
             WHILE  1 /STRING  REPEAT THEN
         R> DROP ;

ie. skip leading characters c

        : SKIP  >R BEGIN DUP OVER C@ R@ = OR WHILE
                         1- SWAP 1- SWAP REPEAT R> DROP ;

BACK
( str len char -- str len-i )
BACK ( str len char -- str len-i )

Look for a particular character in the string from the back toward the front.

      : BACK
         >R  BEGIN  DUP WHILE
             1-  2DUP + C@  R@ =
         UNTIL 1+ THEN
         R> DROP ;

/SPLIT
( a m a+i m-i -- a+i m-i a i )
/SPLIT ( a m a+i m-i -- a+i m-i a i )

Split a character string _a m_ at place given by _a+i m-i_. Called "cut-split" because "slash-split" is a tongue twister.

      : /SPLIT  DUP >R  2SWAP  R> - ;

IS-WHITE
( char -- flag )
IS-WHITE ( char -- flag )

Test char for white space.

      : IS-WHITE   33 - 0< ;

TRIM
( str len -- str len-i )
TRIM ( str len -- str len-i )

Trim white space from end of string.

      : TRIM
         BEGIN  DUP WHILE
             1-  2DUP + C@ IS-WHITE NOT
         UNTIL 1+ THEN ;

BL-SCAN
( str len -- str+i len-i )
BL-SCAN ( str len -- str+i len-i )

Look for white space from start of string

      : BL-SCAN
         BEGIN  DUP WHILE  OVER C@ IS-WHITE NOT
         WHILE  1 /STRING  REPEAT THEN ;

BL-SKIP
( str len -- str+i len-i )
BL-SKIP ( str len -- str+i len-i )

Skip over white space at start of string.

      : BL-SKIP
         BEGIN  DUP WHILE  OVER C@ IS-WHITE
         WHILE  1 /STRING  REPEAT THEN ;

STARTS?
( str len pattern len2 -- str len flag )
STARTS? ( str len pattern len2 -- str len flag )

Check start of string.

      : STARTS?   DUP >R  2OVER  R> MIN  COMPARE 0= ;

ENDS?
( str len pattern len2 -- str len flag )
ENDS? ( str len pattern len2 -- str len flag )

Check end of string.

      : ENDS?   DUP >R  2OVER  DUP R> - /STRING  COMPARE 0= ;

IS-DIGIT
( char -- flag )
IS-DIGIT ( char -- flag )

Test _char_ for digit [0-9].

      : IS-DIGIT   [CHAR] 0 -  10 U< ;

IS-ALPHA
( char -- flag )
IS-ALPHA ( char -- flag )

Test _char_ for alphabetic [A-Za-z].

      : IS-ALPHA  32 OR  [CHAR] a -  26 U< ;

IS-ALNUM
( char -- flag )
IS-ALNUM ( char -- flag )

Test _char_ for alphanumeric [A-Za-z0-9].

      : IS-ALNUM
         DUP IS-ALPHA  ORIF  DUP IS-DIGIT  THEN  NIP ;

#BACKSPACE-CHAR
( -- char )
#BACKSPACE-CHAR ( -- char )

Backspace character.

      8 CONSTANT #BACKSPACE-CHAR

#CHARS/LINE
( -- n )
#CHARS/LINE ( -- n )

Preferred width of line in source files. Suit yourself.

      62 VALUE    #CHARS/LINE

#EOL-CHAR
( -- char )
#EOL-CHAR ( -- char )

End-of-line character. 13 for Mac and DOS, 10 for Unix.

      13 CONSTANT #EOL-CHAR

#TAB-CHAR
( -- char )
#TAB-CHAR ( -- char )

Tab character.

      9 CONSTANT #TAB-CHAR

MAX-N
( -- n )
MAX-N ( -- n )

Largest usable signed integer.

      TRUE 1 RSHIFT        CONSTANT MAX-N

SIGN-BIT
( -- n )
SIGN-BIT ( -- n )

1-bit mask for the sign bit.

      TRUE 1 RSHIFT INVERT CONSTANT SIGN-BIT

CELL
( -- n )
CELL ( -- n )

Address units (i.e. bytes) in a cell.

      1 CELLS CONSTANT CELL

-CELL
( -- n )
-CELL ( -- n )

Negative of address units in a cell.

      -1 CELLS CONSTANT -CELL

SPLIT-NEXT-LINE
( src . -- src' . str len )
SPLIT-NEXT-LINE ( src . -- src' . str len )

Split the next line from the string.

      : SPLIT-NEXT-LINE
         2DUP #EOL-CHAR SCAN
         DUP >R  1 /STRING  2SWAP R> - ;

FIXME: inform Neil Bawd that this is probably not what he wanted. replace /STRING with /SPLIT here.

VIEW-NEXT-LINE
( src . str len -- src . str len str2 len2 )
VIEW-NEXT-LINE ( src . str len -- src . str len str2 len2 )

Copy next line above current line.

      : VIEW-NEXT-LINE
         2OVER 2DUP #EOL-CHAR SCAN NIP - ;

OUT
( -- addr )
OUT ( -- addr )

Promiscuous variable.

      VARIABLE OUT

TEMP
( -- addr )
TEMP ( -- addr )

Promiscuous variable.

      VARIABLE TEMP

NEXT-WORD
( -- str len )
NEXT-WORD ( -- str len )

Get the next word across line breaks as a character string. _len_ will be 0 at end of file.

      : NEXT-WORD
         BEGIN   BL WORD COUNT      ( str len )
             DUP IF EXIT THEN
             REFILL
         WHILE  2DROP ( ) REPEAT ;

LEXEME
( "name" -- str len )
LEXEME ( "name" -- str len )

Get the next word on the line as a character string. If it's a single character, use it as the delimiter to get a phrase.

      : LEXEME
         BL WORD ( addr) DUP C@ 1 =
             IF  CHAR+ C@ WORD  THEN
         COUNT ;

H#
( "hexnumber" -- n )
H# ( "hexnumber" -- n )

Get the next word in the input stream as a hex single-number literal. (Adopted from Open Firmware.)

      : H#  ( "hexnumber" -- n )  \  Simplified for easy porting.
         0 0 BL WORD COUNT
         BASE @ >R  HEX  >NUMBER  R> BASE !
             ABORT" Not Hex " 2DROP          ( n)
         STATE @ IF  POSTPONE LITERAL  THEN
         ; IMMEDIATE

\\
( "...<eof>" -- )
\\ ( "...<eof>" -- )

Ignore the rest of the input stream.

      : \\   BEGIN  -1 PARSE  2DROP  REFILL 0= UNTIL ;

FILE-CHECK
( n -- )
FILE-CHECK ( n -- )

Check for file access error.

      \ : FILE-CHECK    ( n -- )  THROW ;
      : FILE-CHECK      ( n -- )  ABORT" File Access Error " ;

MEMORY-CHECK
( n -- )
MEMORY-CHECK ( n -- )

Check for memory allocation error.

      \ : MEMORY-CHECK  ( n -- )  THROW ;
      : MEMORY-CHECK    ( n -- )  ABORT" Memory Allocation Error " ;

++
( addr -- )
++ ( addr -- )

Increment the value at _addr_.

      : ++  ( addr -- )  1 SWAP +! ;

@+
( addr -- addr' x )
@+ ( addr -- addr' x )

Fetch the value _x_ from _addr_, and increment the address by one cell.

      : @+  ( addr -- addr' x )  DUP CELL+ SWAP  @ ;

!+
( addr x -- addr' )
!+ ( addr x -- addr' )

Store the value _x_ into _addr_, and increment the address by one cell.

      : !+  ( addr x -- addr' )  OVER !  CELL+ ;

'th
( n "addr" -- &addr[n] )
'th ( n "addr" -- &addr[n] )

Address `n CELLS addr +`.

      : 'th     ( n "addr" -- &addr[n] )
         S" 2 LSHIFT " EVALUATE
         BL WORD COUNT EVALUATE
         S" + " EVALUATE
         ; IMMEDIATE

(.) ( n -- addr u )

Convert _n_ to characters, without punctuation, as for `.` (dot), returning the address and length of the resulting string.

      : (.)  ( n -- addr u )  DUP ABS 0 <# #S ROT SIGN #> ;

CELL-
( addr -- addr' )
CELL- ( addr -- addr' )

Decrement address by one cell

      : CELL-  ( addr -- addr' )  CELL - ;

EMITS
( n char -- )
EMITS ( n char -- )

Emit _char_ _n_ times.

      : EMITS             ( n char -- )
         SWAP 0 ?DO  DUP EMIT  LOOP DROP ;

HIWORD
( xxyy -- xx )
HIWORD ( xxyy -- xx )

The high half of the value.

      : HIWORD  ( xxyy -- xx )  16 RSHIFT ;

LOWORD
( xxyy -- yy )
LOWORD ( xxyy -- yy )

The low half of the value.

      : LOWORD  ( xxyy -- yy )  65535 AND ;

REWIND-FILE
( file-id -- ior )
REWIND-FILE ( file-id -- ior )

Rewind the file.

      : REWIND-FILE       ( file-id -- ior )
         0 0 ROT REPOSITION-FILE ;

.S
( -- )
.S ( -- )

print the stack content in vertical nice format. tries to show cell-stack and float-stack side-by-side,

Depending on configuration, there are two parameter stacks: for integers and for floating point operations. If both stacks are empty, .S will display the message `<stacks empty>`.

If only the floating point stack is empty, .S displays the integer stack items in one column, one item per line, both in hex and in decimal like this (the first item is topmost):

      12345 HEX 67890 .S
         	424080 [00067890]
              12345 [00003039] ok

If both stacks ar not empty, => .S displays both stacks, in two columns, one item per line

      HEX 123456.78E90 ok
      DECIMAL 123456.78E90 .S
         	   291 [00000123]          1.234568E+95
         1164414608 [45678E90] ok

Confusing example? Remember that floating point input only works when the BASE number is DECIMAL. The first number looks like a floating point but it is a goodhex double integer too - the number base is HEX. Thus it is accepted as a hex number. Second try with a decimal base will input the floating point number.

If only the integer stack is empty, => .S shows two columns, but he first columns is called <stack empty>, and the second column is the floating point stack, topmost item first.

?
( addr -- )
? ( addr -- )

Display the (integer) content of at address addr. This word is sensitive to BASE

      simulate:
        : ?  @ . ;

DUMP
( addr len -- )
DUMP ( addr len -- )

show a hex-dump of the given area, if it's more than a screenful it will ask using => ?CR

You can easily cause a segmentation fault of something like that by accessing memory that does not belong to the pfe-process.

SEE
( "word" -- )
SEE ( "word" -- )

decompile word - tries to show it in re-compilable form.

(SEE) tries to display the word as a reasonable indented source text. If you defined your own control structures or use extended control-flow patterns, the indentation may be suboptimal.

      simulate:
        : SEE  [COMPILE] ' (SEE) ;

WORDS
( -- )
WORDS ( -- )

uses CONTEXT and lists the words defined in that vocabulary. usually the vocabulary to list is named directly in before.

      example:
         FORTH WORDS  or  LOADED WORDS

AHEAD
( -- DP-mark ORIG-magic )
compile-only
AHEAD ( -- DP-mark ORIG-magic ) compile-only

      simulate:
        : AHEAD  BRANCH MARK> (ORIG#) ;

BYE
( -- )
no-return
BYE ( -- ) no-return

should quit the forth environment completly

CS-PICK
( 2a 2b 2c ... n -- 2a 2b 2c ... 2a )
CS-PICK ( 2a 2b 2c ... n -- 2a 2b 2c ... 2a )

pick a value in the compilation-stack - note that the compilation stack _can_ be seperate in some forth-implemenations. In PFE the parameter-stack is used in a double-cell fashion, so CS-PICK would 2PICK a DP-mark and a COMP-magic, see PICK

CS-ROLL
( 2a 2b 2c ... n -- 2b 2c ... 2a )
CS-ROLL ( 2a 2b 2c ... n -- 2b 2c ... 2a )

roll a value in the compilation-stack - note that the compilation stack _can_ be seperate in some forth-implemenations. In PFE the parameter-stack is used in a double-cell fashion, so CS-ROLL would 2ROLL a DP-mark and a COMP-magic, see ROLL

FORGET
( "word" -- )
FORGET ( "word" -- )

      simulate:
        : FORGET  [COMPILE] '  >NAME (FORGET) ; IMMEDIATE

[ELSE]
( -- )
[ELSE] ( -- )

eat up everything upto and including the next [THEN]. count nested [IF] ... [THEN] constructs. see [IF]

      this word provides a simple pre-compiler mechanism

[IF]
( flag -- )
[IF] ( flag -- )

check the condition in the CS-STACK. If true let the following text flow into INTERPRET , otherwise eat up everything upto and including the next [ELSE] or [THEN] . In case of skipping, count nested [IF] ... [THEN] constructs.

      this word provides a simple pre-compiler mechanism

ASSEMBLER
( -- )
ASSEMBLER ( -- )

set the ASSEMBLER-WORDLIST as current CONTEXT

CODE
( "name" -- )
CODE ( "name" -- )

CREATE a new name and put PFA adress into the CFA place.

NOTE: this description (PFA into CFA) is only correct for traditional indirect threaded code (ITC). The other variants use a block info in the CFA - there we will start a normal colon word which is cut off immediately by a ;CODE directive to enter the machine-level.

BE AWARE: The TOOLS-EXT will not provide an END-CODE or any other word in the ASSEMBLER wordlist which is required to start any useful assembler programming. After requiring ASSEMBLER-EXT you will see a second "CODE" in the EXTENSIONS wordlist that will also provide an optimized execution than the result of this standard-forth implemenation.

;CODE
( -- )
;CODE ( -- )

Does end the latest word (being usually some DOES> part) and enters machine-level (in EXEC-mode).

BE AWARE: The TOOLS-EXT will not provide an END-CODE or any other word in the ASSEMBLER wordlist which is required to start any useful assembler programming. After requiring ASSEMBLER-EXT you will see a second ";CODE" in the EXTENSIONS wordlist that will also provide an optimized execution than the result of this standard-forth implemenation.

The Standard-Forth implementation will actually compile a derivate of BRANCH into the dictionary followed by ;. The compiled word will not jump to the target adress (following the execution token) but it will call the target adress via the host C stack. The target machine level word (C domain) will just return here for being returned (Forth domain). Hence END-CODE may be a simple RET, comma!

END-CODE
( "name" -- )
END-CODE ( "name" -- )

call PREVIOUS and add PROC LEAVE assembler snippet as needed for the architecture - usually includes bits to "return from subroutine". Remember that not all architectures are support and PFE usually does only do variants of call-threading with a separate loop for the inner interpreter that does "call into subroutine".

Some forth implementations do "jump into routine" and the PROC LEAVE part would do "jump to next routine" also known as next-threading. The sbr-call-threading is usually similar to the native subroutine-coding of the host operating system. See CODE

On some machine types, this word is NOT DEFINED!

VLIST
( -- )
VLIST ( -- )

The VLIST command had been present in FIG and other forth implementations. It has to list all accessible words. In PFE it list all words in the search order. Well, the point is, that we do really just look into the search order and are then calling WORDS on that Wordl. That way you can see all accessible words in the order they might be found. Uses => ?CR

!CSP
( -- )
!CSP ( -- )

put SP into CSP
used in control-words

?CSP
( -- )
?CSP ( -- )

check that SP == CSP otherwise THROW
used in control-words

?COMP
( -- )
?COMP ( -- )

check that the current STATE is compiling otherwise THROW
often used in control-words

?EXEC
( -- )
?EXEC ( -- )

check that the current STATE is executing otherwise THROW
often used in control-words

?FILE
( file-id -- )
?FILE ( file-id -- )

check the file-id otherwise (fixme)

?LOADING
( -- )
?LOADING ( -- )

check that the currently interpreted text is from a file/block, otherwise THROW

?PAIRS
( a b -- )
?PAIRS ( a b -- )

if compiling, check that the two magics on the CS-STACK are identical, otherwise throw
used in control-words

?STACK
( -- )
?STACK ( -- )

check all stacks for underflow and overflow conditions, and if such an error condition is detected THROW

[VOID]
( -- flag )
[VOID] ( -- flag )

Immediate FALSE. Used to comment out sections of code. IMMEDIATE so it can be inside definitions.

      : [VOID] 0 ; immediate

DEFINED
( "name" -- flag )
DEFINED ( "name" -- flag )

Search the dictionary for _name_. If _name_ is found, return TRUE; otherwise return FALSE. Immediate for use in definitions.

This word will actually return what FIND returns (the NFA). does check for the word using find (so it does not throw like ' ) and puts it on stack. As it is immediate it does work in compile-mode too, so it places its argument in the cs-stack then. This is most useful with a directly following [IF] clause, so that sth. like an `[IFDEF] word` can be simulated through `[DEFINED] word [IF]`

      : DEFINED BL WORD COUNT (FIND-NFA) ;

[DEFINED]
( [name] -- flag )
[DEFINED] ( [name] -- flag )

Search the dictionary for _name_. If _name_ is found, return TRUE; otherwise return FALSE. Immediate for use in definitions.

This word will actually return what FIND returns (the NFA). does check for the word using find (so it does not throw like ' ) and puts it on stack. As it is immediate it does work in compile-mode too, so it places its argument in the cs-stack then. This is most useful with a directly following [IF] clause, so that sth. like an `[IFDEF] word` can be simulated through `[DEFINED] word [IF]`

      : [DEFINED] DEFINED ; IMMEDIATE
      : [DEFINED] BL WORD COUNT (FIND-NFA) ; IMMEDIATE

[UNDEFINED]
( [name] -- flag )
[UNDEFINED] ( [name] -- flag )

Search the dictionary for _name_. If _name_ is found, return FALSE; otherwise return TRUE. Immediate for use in definitions.

see [DEFINED]

      : [UNDEFINED] DEFINED 0= ; IMMEDIATE

(FORGET) ( addr -- )

forget everything above addr - used by FORGET

(DICTLIMIT) ( -- constvalue )

the upper limit of the forth writeable memory space, the variable DICTLIMIT must be below this line. stack-space and other space-areas are often allocated above DICTLIMIT upto this constant.

DICTFENCE is the lower end of the writeable dictionary

(DICTFENCE) ( -- constvalue )

the lower limit of the forth writeable memory space, the variable DICTFENCE must be above this line. Some code-areas are often moved in between DICTFENCE and this constant. To guard normal Forth code from deletion the usual practice goes with the FENCE variable

DICTLIMIT is the upper end of the writeable dictionary

FENCE
( -- var* )
FENCE ( -- var* )

a forth system variable - (FORGET) will not work below this address and any FORGET on a header below this mark will THROW

DICTFENCE
( -- var* )
DICTFENCE ( -- var* )

the lower end of usable area - the forth memory block minus the forth-VM backstore. Note that this is a variable by tradition but you should not move it.

DICTLIMIT
( -- var* )
DICTLIMIT ( -- var* )

the lower end of usable area - the forth memory block minus the forth-related DICTALLOCS at the upper end (e.g. POCKET-PAD ) Note that this is a variable by tradition but you should not move it.

_?stop_
( -- ?key )
_?stop_ ( -- ?key )

check for a keypress, and if it was 'q' being pressed

      : _?stop_ _key?_ _key_ [char] q = ;

_?cr_
( -- ?stopped )
_?cr_ ( -- ?stopped )

Like CR but stop after one screenful and return flag if 'q' pressed. Improved by aph@oclc.org (Andrew Houghton)

_for:COMPILE,
( xt -- )
"_for:COMPILE," ( xt -- )

does the work of POSTPONE on the execution token that you got from somewhere else - so it checks if the name (that correspond to the execution-token argument) is actually immediate, so it has to be executed to compile something, e.g. IF or THEN - see also POSTPONE , COMPILE , [COMPILE] , INTERPRET

warning: do not use this word anymore, it is an error to compile a token where the immediate-bit must be checked. The immediate-bit is a pure header information not present with headerless words as such. Furthermore, this function is subject to POSTPONE problems as well.

Newer code should use COMPILE, when trying to simulate a behavior similar to POSTPONE.

($
( [word] -- cs-token )
compile-only
"($" ( [word] -- cs-token ) compile-only

takes the execution token of the following word and saves it on the compile-stack. The correspondig closing ) will then feed it into >COMPILE - so this pair of word provides you with a prefix-operation syntax that you may have been seen in lisp-like languages.

        ($ IF ($ 0= A1 @ )) ($ THEN ." hello " )

Note that an opening simple ( paren is a comment.

)
( cs-token -- )
")" ( cs-token -- )

takes the execution-token from ($ and compiles it using >COMPILE

))
( cs-token cs-token -- )
"))" ( cs-token cs-token -- )

takes two execution-tokens from two of ($ and compiles them on after another using >COMPILE

      simulate:
         : )) [COMPILE] ) [COMPILE] ) ; IMMEDIATE

PFE-SPRINTF
( args ... format$ dest$ -- len-dest )
PFE-SPRINTF ( args ... format$ dest$ -- len-dest )

just like the standard sprintf() function in C, but the format is a counted string and accepts %#s to be the format-symbol for a forth-counted string. The result is a zeroterminated string at dest$ having a length being returned. To create a forth-counted string, you could use:

        variable A 256 ALLOT
        15 " example" " the %#s value is %i" A 1+ SPRINTF A C!
        A COUNT TYPE

PFE-PRINTF
( args ... format$ -- )
PFE-PRINTF ( args ... format$ -- )

uses SPRINTF to print to a temporary 256-char buffer and prints it to stdout afterwards. See the example at SPRINTF of what it does internally.

LOADF
( "filename" -- )
LOADF ( "filename" -- )

loads a file just like INCLUDE but does also put a MARKER in the LOADED dictionary that you can do a FORGET on to kill everything being loaded from that file.

(LOADF-LOCATE)
( xt -- nfa )
"(LOADF-LOCATE)" ( xt -- nfa )

the implementation of LOADF-LOCATE

LOADF-LOCATE
( "name" -- )
LOADF-LOCATE ( "name" -- )

look for the filename created by LOADF that had been defining the given name. LOADF has created a marker that is above the INCLUDED file and that marker has a body-value just below the INCLUDED file. Hence the symbol was defined during LOADF execution of that file.

      : LOADF-LOCATE ?EXEC POSTPONE ' (LOADF-LOCATE) .NAME ;

(;AND)
( -- )
"(;AND)" ( -- )

compiled by ;AND

;AND
( -- )
";AND" ( -- )

For the code piece between MAKE and ;AND , this word will do just an EXIT . For the code outside of the MAKE construct a branch-around must be resolved then.

((MAKE-))
( -- )
"((MAKE-))" ( -- )

compiled by MAKE

((MAKE))
( -- )
"((MAKE))" ( -- )

compiled by MAKE

DOER
( word -- )
DOER ( word -- )

In PFE it is a synonym to DEFER which a semistandard word. Unlike DEFER, the DOER-vector was set with an a small piece of code between MAKE and ;AND. The "DOER"-word should be replaced with DEFER IS, which is easy since the DEFER and DOER point to the same internal runtime.

MAKE
( [word] -- )
... ;AND
MAKE ( [word] -- ) ... ;AND

make a seperated piece of code between MAKE and ;AND and on execution of the MAKE the named word is twisted to point to this piece of code. The word is usually a DOER but the current implementation works on DEFER just as well, just as it does on other words who expect to find an execution-token in its PFA. You could even create a colon-word that starts with NOOP and can then make that colon-word be prefixed with the execution of the code piece. This MAKE does even work on LOCALS| and VAR but it is uncertain what that is good for.

OFFSET-RT
( value -- value+offset )
OFFSET-RT ( value -- value+offset )

this runtime will add the body-value to the value at top-of-stack. used heavily in structure access words, compiled by /FIELD

+CONSTANT
( offset "name" -- )
+CONSTANT ( offset "name" -- )

create a new offsetword. The word is created and upon execution it adds the offset, ie. compiling the OFFSET-RT runtime:

            ( address -- address+offset )

This word is just a convenience word, just use the word +FIELD directly and choose a DROP to flag the end of a current offset-field declaration series. See also /FIELD series to declare simple structures which end with a final CONSTANT to memorize the complete size. The /FIELD style is more traditional.

+FIELD
( offset "name" -- offset )
[deprecated]
+FIELD ( offset "name" -- offset ) [deprecated]

The word +FIELD is reserved by http://www.forth200x.org/structures.html so the old PFE usage of +FIELD has been renamed to +FIELD: to avoid a conflict. A deprecation warning will be shown when code uses this word that is already a SYNONYM of +FIELD: . As earlier PFE implementations have not been using +FIELD: one can use an ifdef to run modified PFE applications on old PFE implementations.

      [DEFINED] +FIELD: [NOT] [IF] SYNONYM +FIELD: +FIELD [THEN]

The Forth200x interpretation of +FIELD is already present in PFE under the name of /FIELD so you can already use it in your code. Any application that likes be forth200x conformant may use an ifdef of the format

      [DEFINED] /FIELD [IF] SYNONYM +FIELD /FIELD [THEN]

+FIELD:
( offset "name" -- offset )
+FIELD: ( offset "name" -- offset )

created a new name with an OFFSET-RT runtime using the given offset. Leave the offset-value untouched, so it can be modified with words like CHAR+ and CELL+ and SFLOAT+ ; This word is the simplest way to declared structure access words in forth - the two STRUCT modules contain a more elaborate series of words. Use this one like:

      0                        ( a fresh definition is started )
      +FIELD: zapp.a+ CHAR+     ( zero offset from the base of the struct )
      +FIELD: zapp.b+ CELL+     ( no alignment, starts off at 1 from base )
      +FIELD: zapp+   DROP      ( store size of complete zap structure )

      0 zapp+                  ( extend the zap structure )
      +FIELD: zappx.c+ CELL+    ( a new field )
      +FIELD: zappx+   DROP     ( and save it again )

      CREATE zapp1  0 zapp+ ALLOT ( a way to allocate a strucutre )

      zapp2 zapp.b+ @         ( read a value from the field )
      16 zapp2 zapp.b+ !      ( store a value in there )

this form is not the traditional form used in forth, it is however quite simple. Use the simplefield declaration with /FIELD to be compatible with traditional styles that build on top of sizeof constants in forth (which are not part of the ANS Forth standard).

/FIELD
( offset size "name" -- offset+size )
/FIELD ( offset size "name" -- offset+size )

created a new +FIELD name with an OFFSET-RT of offset. Then add the size value to the offset so that the next /FIELD declaration will start at the end of the field currently declared. This word is the simplest way to declared structure access words in forth - the two STRUCT modules contain a more elaborate series of words. This one is used like:

      0                        ( a fresh definition is started )
      /CHAR /FIELD ->zapp.a    ( zero offset from the base of the struct )
      /CELL /FIELD ->zapp.b    ( no alignment, starts off at 1 from base )
      CONSTANT /zapp           ( store size of complete zap structure )

      /zapp                    ( extend the zap structure )
      /CELL /FIELD ->zappx.c   ( a new field )
      CONSTANT /zappx          ( and save it again )

      CREATE zapp1 /zapp ALLOT ( a way to allocate a strucutre )
      /zapp BUFFER: zapp2      ( another way to do it, semi-standard )

      zapp2 ->zapp.b @         ( read a value from the field )
      16 zapp2 ->zapp.b !      ( store a value in there )

compare also with /CHAR /WCHAR /CELL /DCELL and use +FIELD as the lowlevel word, can simulate as

      : /FIELD SWAP +FIELD + ;

[NOT]
( a -- a' )
[NOT] ( a -- a' )

executes 0= but this word is immediate so that it does affect the cs-stack while compiling rather than compiling anything. This is useful just before words like [IF] to provide semantics of an `[IFNOT]`. It is most useful in conjunction with "=> [DEFINED] word" as it the sequence "`[DEFINED] word [NOT] [IF]`" can simulate "`[IFNOTDEF] word`"

REPLACE-IN
( to-xt from-xt n "name" -- )
REPLACE-IN ( to-xt from-xt n "name" -- )

will handle the body of the named word as a sequence of cells (or tokens) and replaces the n'th occurences of from-xt into to-xt. A negative value will change all occurences. A zero value will not change any.

X"
( "hex-q" -- bstring )
'X"' ( "hex-q" -- bstring )

places a counted string on stack containing bytes specified by hex-string - the hex string may contain spaces which will delimit the bytes

      example:
         X" 41 42 4344" COUNT TYPE ( shows ABCD )

EVALUATE-WITH
( i*x addr len xt[i*x--j*x] -- j*x )
EVALUATE-WITH ( i*x addr len xt[i*x--j*x] -- j*x )

added to be visible on the forth command line on request by MLG, he has explained the usage before a lot, you can get an idea from:

         : EVALUATE ['] INTERPRET EVALUATE-WITH ;

The word is used internally in PFE for the loadlist evaluation of the binary modules: where previously each loadercode had its own CREATE-execution we do now call the original forthish CREATE-word like, so bootstrapping a VARIABLE will now call VARIABLE itself and of course we need to set up the TIB-area to point to the name of the variable that shall be created in the forth dictionary:

      : LOAD-WORD ( arg-value str-ptr str-len loader-code -- )
           CASE
             #LOAD-VARIABLE OF ['] VARIABLE EVALUATE-WITH ENDOF
             ....
           ENDCASE
           CLEARSTACK
      ;

[VOCABULARY]
( "name" -- )
[VOCABULARY] ( "name" -- )

create an immediate vocabulary. Provides for basic modularization.

      : [VOCABULARY] VOCABULARY IMMEDIATE ;

[POSSIBLY]
( [name] -- ?? )
[POSSIBLY] ( [name] -- ?? )

check if the name exists, and execute it immediatly if found. Derived from POSSIBLY as seen in other forth systems.

      : [POSSIBLY] (') ?DUP IF EXECUTE THEN ; IMMEDIATE

[DEF]
( -- )
[DEF] ( -- )

immediatly set topmost CONTEXT voc to CURRENT compilation voc.

      : DEF' CURRENT @ CONTEXT ! ; IMMEDIATE

note that in PFE most basic vocabularies are immediate, so that you can use a sequence of

      FORTH ALSO  DEFINITIONS
      [DEF] : GET-FIND-3  [ANS] ['] FIND  [FIG] ['] FIND  [DEF] ['] FIND ;

where the first wordlist to be searched via the search order are [ANS] and [FIG] and FORTH (in this order) and which may or may not yield different flavours of the FIND routine (i.e. different XTs)

CONTEXT?
( -- number )
CONTEXT? ( -- number )

GET-CONTEXT and count how many times it is in the order but the CONTEXT variable itself. The returned number is therefore minus one the occurences in the complete search-order. usage:

        ALSO EXTENSIONS CONTEXT? [IF] PREVIOUS [THEN]
        ALSO DEF' DEFAULT-ORDER
      : CONTEXT?
        0 LVALUE _count
        GET-ORDER 1- SWAP  LVALUE _context
        0 ?DO _context = IF 1 +TO _count THEN LOOP
        _count
      ;

DEFS-ARE-CASE-SENSITIVE
( -- )
DEFS-ARE-CASE-SENSITIVE ( -- )

accesses CURRENT which is generally the last wordlist that the DEFINITIONS shall go in. sets there a flag in the vocabulary-definition so that words are matched case-sensitive.

      example:
         VOCABULARY MY-VOC  MY-VOC DEFINITIONS DEFS-ARE-CASE-SENSITIVE

CASE-SENSITIVE-VOC
( -- )
CASE-SENSITIVE-VOC ( -- )

accesses CONTEXT which is generally the last named VOCABULARY . sets a flag in the vocabulary-definition so that words are matched case-sensitive.

      example:
         VOCABULARY MY-VOC  MY-VOC CASE-SENSITIVE-VOC

OBSOLETE! use DEFS-ARE-CASE-SENSITIVE

DEFS-ARE-SEARCHED-ALSO
( -- )
DEFS-ARE-SEARCHED-ALSO ( -- )

binds CONTEXT with CURRENT. If the CURRENT VOCABULARY is in the search-order (later), then the CONTEXT vocabulary will be searched also. If the result of this word could lead into a recursive lookup with FIND it will throw `CURRENT_DELETED` and leave the CURRENT VOCABULARY unaltered.

      example:

MY-VOC DEFINITIONS MY-VOC-PRIVATE DEFS-ARE-SEARCHED-ALSO

SEARCH-ALSO-VOC
( -- )
SEARCH-ALSO-VOC ( -- )

OBSOLETE!! use DEFS-ARE-SEARCHED-ALSO

[EXECUTE]
( [word] -- )
[EXECUTE] ( [word] -- )

ticks the following word, and executes it - even in compiling mode.

      : [EXECUTE] ' EXECUTE ;

!NO
( -- false )
!NO ( -- false )

a synonym for FALSE

      !NO SMART-WORDS!

!USE
( -- true )
!USE ( -- true )

a synonym for TRUE

      !USE SMART-WORDS!

SPY_ON
( -- )
SPY_ON ( -- )

change the runtime-code of (NEST) to call a special word that prints info to the screen whenever a colon word is entered. It will print the name and the current stack, and results in a kind of execution trace over SPY' :-colon nested words.

SPY_OFF
( -- )
SPY_OFF ( -- )

disable SPY_ON nest-trace.

SPY' (NEST)
( -- )
"SPY' (NEST)" ( -- )

compiled by :

SPY' :
( name -- )
"SPY' :" ( name -- )

SPY:

SPY:
( name -- )
"SPY:" ( name -- )

create a header for a nesting word and go to compiling mode then. This word is usually ended with ; but the execution of the resulting colon-word can also return with EXIT this is the spy-version SPY_ON

SPY' ((SPY;))
( -- )
"SPY' ((SPY;))" ( -- )

compiled by ; and maybe ;AND -- it will perform an EXIT this is the SPY-version

SPY' ;
( -- )
"SPY' ;" ( -- )

;SPY

;SPY
( -- )
";SPY" ( -- )

compiles ((;)) which does EXIT the current colon-definition. It does then end compile-mode and returns to execute-mode. See : and :NONAME

SPY' EXIT
( -- )
"SPY' EXIT" ( -- )

SPY-EXIT

SPY-EXIT
( -- )
"SPY-EXIT" ( -- )

will unnest the current colon-word so it will actually return the word calling it. This can be found in the middle of a colon-sequence between : and ;

'>
( [name] -- xt )
"'>" ( [name] -- xt )

get the execution-token, ie the CFA, of the word following. This word is fully state-smart while the ANSI standard words namely ' and ['] are not.

((@>)) ( -- value )

execution compiled by @>

@>
( [name] -- value )
@> ( [name] -- value )

does fetch the value from the PFA of the named item, which may be about everything, including a VARIABLE , VALUE LVALUE , LOCALS| , VAR , DEFER , DOER , DOES> and more.

!>
( value [name] -- )
!> ( value [name] -- )

actually a synonym for TO but very common amongst forth interpreters

((INTO-)) ( -- value )

execution compiled by INTO

INTO
( [name] -- pfa )
INTO ( [name] -- pfa )

will return the parameter-field address of the following word. Unlike others, this word will also return the address of LOCALS| and local LVALUE - so in fact a `TO A` and `INTO A !` are the same. This word is most useful when calling C-exported function with a temporary local-VAR as a return-place argument - so the address of a local has to be given as an arg. Beware that you should not try to save the address anywhere else, since a local's address does always depend of the RP-depth - EXIT from a colon-word and the value may soon get overwritten. (see also TO )

.H2
( value -- )
.H2 ( value -- )

print hexadecimal, but with per-byte 0-padding

        0x0     -> 00
        0xf     -> 0f
        0x12    -> 12
        0x123   -> 0123
        0x1234  -> 1234
        0x12345 -> 012345

HERE-WORD
( char "name<char>" -- )
HERE-WORD ( char "name<char>" -- )

a FIG-compatible WORD. Where ANSI says "skip leading delimiters" this one acts as "skip leading whitespace". And it will not return anything and have the string parsed to HERE

Z"
( [chars<">] -- z* )
'Z"' ( [chars<">] -- z* )

scan the input to the next doublequote and create a buffer that holds the chars - return the address of that zero-terminated string-buffer, either POCKET-PAD or ALLOTed into the dictionary.

ZCOUNT
( z* -- z* len )
ZCOUNT ( z* -- z* len )

push length of z-string, additionally to the string addr itself.

      : ZSTRLEN ZCOUNT NIP ;

(see libc strlen(3)) / compare with COUNT / ZSTRLEN

ZSTRLEN
( z* -- len )
ZSTRLEN ( z* -- len )

push length of z-string.

      : ZSTRLEN ZCOUNT NIP ;

(see libc strlen(3)) / compare with ZMOVE / CMOVE

ZMOVE
( zsrc* zdest* -- )
ZMOVE ( zsrc* zdest* -- )

copy a zero terminated string (see libc strcpy(3)) / compare with ZSTRLEN / COUNT

APPENDZ
( caddr* u zdest* -- )
APPENDZ ( caddr* u zdest* -- )

Add the string defined by CADDR LEN to the zero terminated string at ZDEST - actually a SYNONYM of +ZPLACE of the ZPLACE family (see strncat(3)) / compare with ZPLACE / +PLACE

+ZPLACE
( caddr* u zdest* -- )
+ZPLACE ( caddr* u zdest* -- )

Add the string defined by CADDR LEN to the zero terminated string at ZDEST - (for older scripts the SYNONYM named APPENDZ exists) (see libc strncat(3)) / compare with ZPLACE / +PLACE

ZPLACE
( addr* len zaddr* -- )
ZPLACE ( addr* len zaddr* -- )

copy string and place as 0 terminated (see libc strncpy(3)) / see also +ZPLACE / Z+PLACE

C\"
( [backslashed-strings_<">] -- bstr* )
'C\\\"' ( [backslashed-strings_<">] -- bstr* )

scan the following text to create a literal just like C" does, but backslashes can be used to escape special chars. The rules for the backslashes follow C literals, implemented techniques are \n \r \b \a \f \v \e \777 and all non-alnum chars represent themselves, esp. \" \' \ \? \! \% \( \) \[ \] \{ \} etcetera. most importantly the doublequote itself can be escaped. but be also informed that the usage of \' and \" is not portable as some systems preferred to map [\'] into ["]. Here I use the experimental addition to map [\q] to ["] and [\i] to [']

S\"
( [backslashed-strings_<">] -- str cnt )
'S\\\"' ( [backslashed-strings_<">] -- str cnt )

scan the following text to create a literal just like S" does, but backslashes can be used to escape special chars. The rules for the backslashes follow C literals, implemented techniques are \n \r \b \a \f \v \e \777 and all non-alnum chars represent themselves, esp. \" \' \ \? \! \% \( \) \[ \] \{ \} etcetera. most importantly the doublequote itself can be escaped. but be also informed that the usage of \' and \" is not portable as some systems preferred to map [\'] into ["]. Here I use the experimental addition to map [\q] to ["] and [\i] to [']

Z\"
( [backslashed-strings_<">] -- zstr* )
'Z\\\"' ( [backslashed-strings_<">] -- zstr* )

scan the following text to create a literal just like Z" does, but backslashes can be used to escape special chars. The rules for the backslashes follow C literals, implemented techniques are \n \r \b \a \f \v \e \777 and all non-alnum chars represent themselves, esp. \" \' \ \? \! \% \( \) \[ \] \{ \} etcetera. most importantly the doublequote itself can be escaped but be also informed that the usage of \' and \" is not portable as some systems preferred to map [\'] into ["]. Here I use the experimental addition to map [\q] to ["] and [\i] to [']