implement LEAVE, [IF]…[ELSE]…[THEN], and various other changes
This commit is contained in:
parent
77607934cd
commit
447c212f09
22
jumpforth.S
22
jumpforth.S
|
|
@ -237,7 +237,7 @@ defconst SYS_GETPID,__NR_getpid
|
||||||
defconst SYS_BRK,__NR_brk
|
defconst SYS_BRK,__NR_brk
|
||||||
/* defconst SYS_SIGNAL,__NR_signal */
|
/* defconst SYS_SIGNAL,__NR_signal */
|
||||||
/* defconst SYS_UMOUNT2,__NR_umount2 */
|
/* defconst SYS_UMOUNT2,__NR_umount2 */
|
||||||
/* defconst SYS_IOCTL,__NR_ioctl */
|
defconst SYS_IOCTL,__NR_ioctl
|
||||||
/* defconst SYS_SETPGID,__NR_setpgid */
|
/* defconst SYS_SETPGID,__NR_setpgid */
|
||||||
/* defconst SYS_UMASK,__NR_umask */
|
/* defconst SYS_UMASK,__NR_umask */
|
||||||
/* defconst SYS_CHROOT,__NR_chroot */
|
/* defconst SYS_CHROOT,__NR_chroot */
|
||||||
|
|
@ -1226,6 +1226,14 @@ defcode DECREMENT,"-!"
|
||||||
subl %eax,(%ebx)
|
subl %eax,(%ebx)
|
||||||
NEXT
|
NEXT
|
||||||
|
|
||||||
|
/* ( x1 a-addr -- x2 ) Store x1 in the cell at a-addr and return the old value */
|
||||||
|
defcode XCHG
|
||||||
|
pop %eax
|
||||||
|
mov (%eax),%ebx
|
||||||
|
popl (%eax)
|
||||||
|
push %ebx
|
||||||
|
NEXT
|
||||||
|
|
||||||
defcode TWOSTORE,"2!"
|
defcode TWOSTORE,"2!"
|
||||||
pop %ebx
|
pop %ebx
|
||||||
popl (%ebx)
|
popl (%ebx)
|
||||||
|
|
@ -1238,6 +1246,18 @@ defcode TWOFETCH,"2@"
|
||||||
pushl (%ebx)
|
pushl (%ebx)
|
||||||
NEXT
|
NEXT
|
||||||
|
|
||||||
|
/* ( xd1 a-addr -- xd2 ) Store xd1 in the double-cell a-addr; return the old value */
|
||||||
|
/* Equivalent to: DUP 2@ 2>R 2! 2R> */
|
||||||
|
defcode TWOXCHG,"2XCHG"
|
||||||
|
pop %eax
|
||||||
|
mov 4(%eax),%ebx
|
||||||
|
mov (%eax),%ecx
|
||||||
|
popl (%eax)
|
||||||
|
popl 4(%eax)
|
||||||
|
push %ebx
|
||||||
|
push %ecx
|
||||||
|
NEXT
|
||||||
|
|
||||||
/* ( c-addr u char -- ) Fill u characters starting at c-addr with char */
|
/* ( c-addr u char -- ) Fill u characters starting at c-addr with char */
|
||||||
defcode FILL
|
defcode FILL
|
||||||
pop %eax
|
pop %eax
|
||||||
|
|
|
||||||
377
startup.4th
377
startup.4th
|
|
@ -90,7 +90,7 @@ DEFER THROW-UNWIND ( k*x n -- i*x <noreturn> )
|
||||||
SP@ 2DUP C! STDOUT SWAP 1 SYS_WRITE SYSCALL3 2DROP ;
|
SP@ 2DUP C! STDOUT SWAP 1 SYS_WRITE SYSCALL3 2DROP ;
|
||||||
|
|
||||||
\ Decrement the array size and increment the address by the same amount
|
\ Decrement the array size and increment the address by the same amount
|
||||||
: DROP-PREFIX ( c-addr u1 u2 -- c-addr+u2 u1-u2 ) TUCK - -ROT + SWAP ;
|
: /STRING ( c-addr u1 u2 -- c-addr+u2 u1-u2 ) TUCK - -ROT + SWAP ;
|
||||||
|
|
||||||
\ Write a character array to the given file descriptor
|
\ Write a character array to the given file descriptor
|
||||||
\ Repeat write syscall until entire string is written
|
\ Repeat write syscall until entire string is written
|
||||||
|
|
@ -106,7 +106,7 @@ DEFER THROW-UNWIND ( k*x n -- i*x <noreturn> )
|
||||||
2DROP RDROP EXIT
|
2DROP RDROP EXIT
|
||||||
THEN
|
THEN
|
||||||
ELSE
|
ELSE
|
||||||
DROP-PREFIX
|
/STRING
|
||||||
THEN
|
THEN
|
||||||
REPEAT
|
REPEAT
|
||||||
DROP RDROP ;
|
DROP RDROP ;
|
||||||
|
|
@ -192,12 +192,19 @@ DEFER THROW-UNWIND ( k*x n -- i*x <noreturn> )
|
||||||
\ Here this is just a LF (Unix convention) but it could be CR (Mac) or CR+LF (DOS)
|
\ Here this is just a LF (Unix convention) but it could be CR (Mac) or CR+LF (DOS)
|
||||||
: EOL ( -- "<eol>" ) LF EMIT ;
|
: EOL ( -- "<eol>" ) LF EMIT ;
|
||||||
|
|
||||||
|
\ Emit n blank (space) characters
|
||||||
|
: SPACES ( n -- "<spaces>" ) BEGIN ?DUP WHILE 1- SPACE REPEAT ;
|
||||||
|
|
||||||
\ Terminate the program, successfully
|
\ Terminate the program, successfully
|
||||||
\ This will never return, even if the system call does
|
\ This will never return, even if the system call does
|
||||||
: BYE ( -- <noreturn> )
|
: BYE ( -- <noreturn> )
|
||||||
BEGIN 0 SYS_EXIT SYSCALL1 DROP AGAIN ;
|
BEGIN 0 SYS_EXIT SYSCALL1 DROP AGAIN ;
|
||||||
|
|
||||||
|
\ With 32-bit cells, a double-cell number has 64 bits
|
||||||
|
\ Space is reserved for binary output with a leading minus sign and a trailing space
|
||||||
|
\ The minimum pictured numeric output buffer size is thus 66 bytes
|
||||||
80 CONSTANT PNO-BUFFER-BYTES
|
80 CONSTANT PNO-BUFFER-BYTES
|
||||||
|
|
||||||
CREATE PNO-BUFFER PNO-BUFFER-BYTES ALLOT
|
CREATE PNO-BUFFER PNO-BUFFER-BYTES ALLOT
|
||||||
PNO-BUFFER PNO-BUFFER-BYTES + CONSTANT PNO-BUFFER-END
|
PNO-BUFFER PNO-BUFFER-BYTES + CONSTANT PNO-BUFFER-END
|
||||||
CREATE PNO-POINTER PNO-BUFFER-END ,
|
CREATE PNO-POINTER PNO-BUFFER-END ,
|
||||||
|
|
@ -213,11 +220,7 @@ CREATE PNO-POINTER PNO-BUFFER-END ,
|
||||||
: SIGN ( n -- ) 0< IF [CHAR] - HOLD THEN ;
|
: SIGN ( n -- ) 0< IF [CHAR] - HOLD THEN ;
|
||||||
|
|
||||||
: #B ( ud1 u -- ud2 )
|
: #B ( ud1 u -- ud2 )
|
||||||
UM/MOD ROT DUP 10 >= IF
|
UM/MOD ROT DUP 10 >= IF 10 - [CHAR] A + ELSE [CHAR] 0 + THEN HOLD ;
|
||||||
10 - [CHAR] A +
|
|
||||||
ELSE
|
|
||||||
[CHAR] 0 +
|
|
||||||
THEN HOLD ;
|
|
||||||
|
|
||||||
: # ( ud1 -- ud2 ) 10 #B ;
|
: # ( ud1 -- ud2 ) 10 #B ;
|
||||||
|
|
||||||
|
|
@ -234,22 +237,26 @@ CREATE PNO-POINTER PNO-BUFFER-END ,
|
||||||
: D. ( d -- "<minus?><digits>" ) DUP -ROT DABS <# #S ROT SIGN #> TYPE ;
|
: D. ( d -- "<minus?><digits>" ) DUP -ROT DABS <# #S ROT SIGN #> TYPE ;
|
||||||
: . ( n -- "<minus?><digits>" ) S>D D. ;
|
: . ( n -- "<minus?><digits>" ) S>D D. ;
|
||||||
|
|
||||||
|
\ Return the number of words on the data and return stacks, respectively
|
||||||
|
: DEPTH ( -- n ) SP@ S0 SWAP - CELL / ;
|
||||||
|
: RDEPTH ( -- n ) RSP@ CELL+ R0 SWAP - CELL / ;
|
||||||
|
|
||||||
|
CREATE DISPLAY-ITEM-LIMIT 6 ,
|
||||||
|
|
||||||
\ Display the content of the data stack
|
\ Display the content of the data stack
|
||||||
: .DS ( -- "<text>" )
|
: .S ( -- "<text>" )
|
||||||
SP@ S0
|
"S(" TYPE DEPTH . "):" TYPE
|
||||||
CELL - 2DUP > IF 2DROP EXIT THEN DUP @ .
|
SP@ DUP DISPLAY-ITEM-LIMIT @ CELLS+ S0 UMIN
|
||||||
BEGIN
|
DUP S0 <> IF " …" TYPE THEN
|
||||||
CELL - 2DUP > IF 2DROP EXIT THEN DUP @ SPACE .
|
BEGIN 2DUP < WHILE CELL- DUP @ SPACE . REPEAT 2DROP EOL ;
|
||||||
AGAIN ;
|
|
||||||
|
|
||||||
\ Display the content of the return stack
|
\ Display the content of the return stack
|
||||||
: .RS ( -- "<text>" )
|
: .RS ( -- "<text>" )
|
||||||
\ Skip the topmost cell, which is the return address for the call to .RS
|
\ Skip the topmost cell, which is the return address for the call to .RS
|
||||||
RSP@ CELL + R0
|
"R(" TYPE RDEPTH 1- . "):" TYPE
|
||||||
CELL - 2DUP > IF 2DROP EXIT THEN DUP @ .
|
RSP@ CELL+ DUP DISPLAY-ITEM-LIMIT @ CELLS+ R0 UMIN
|
||||||
BEGIN
|
DUP R0 <> IF " …" TYPE THEN
|
||||||
CELL - 2DUP > IF 2DROP EXIT THEN DUP @ SPACE .
|
BEGIN 2DUP < WHILE CELL- DUP @ SPACE . REPEAT 2DROP EOL ;
|
||||||
AGAIN ;
|
|
||||||
|
|
||||||
\ Return the next address in the compilation/data area
|
\ Return the next address in the compilation/data area
|
||||||
: HERE ( -- addr ) CP @ ;
|
: HERE ( -- addr ) CP @ ;
|
||||||
|
|
@ -315,7 +322,7 @@ CREATE PNO-POINTER PNO-BUFFER-END ,
|
||||||
\ Our first control-flow primitive: <cond> IF <true> {ELSE <false>} THEN
|
\ Our first control-flow primitive: <cond> IF <true> {ELSE <false>} THEN
|
||||||
\
|
\
|
||||||
\ IF compiles an unresolved conditional branch.
|
\ IF compiles an unresolved conditional branch.
|
||||||
\ AHEAD compiles an unconditional branch (same effect as TRUE IF).
|
\ AHEAD compiles an unconditional branch (same effect as FALSE IF).
|
||||||
\ Both AHEAD and IF leave the address of the unresolved offset on the stack.
|
\ Both AHEAD and IF leave the address of the unresolved offset on the stack.
|
||||||
\
|
\
|
||||||
\ THEN consumes the offset address and resolves it to the next code address.
|
\ THEN consumes the offset address and resolves it to the next code address.
|
||||||
|
|
@ -323,12 +330,35 @@ CREATE PNO-POINTER PNO-BUFFER-END ,
|
||||||
\ ELSE inserts an unconditional branch (to THEN) and also resolves the
|
\ ELSE inserts an unconditional branch (to THEN) and also resolves the
|
||||||
\ previous forward reference (from IF).
|
\ previous forward reference (from IF).
|
||||||
\
|
\
|
||||||
: IF ( C: -- orig ) ( Runtime S: flag -- ) IMMEDIATE
|
\ Via ONWARD-IF and ONWARD-AHEAD the unresolve branch offset cell may be used
|
||||||
POSTPONE 0BRANCH HERE 0 , ;
|
\ as the link field of a linked list to connect multiple forward branches to
|
||||||
: AHEAD ( C: -- orig ) IMMEDIATE
|
\ the same THEN. When THEN is executed it will follow the links and update all
|
||||||
POSTPONE BRANCH HERE 0 , ;
|
\ the connected branches to the same location. The list is terminated with zero
|
||||||
|
\ in the link field. Example:
|
||||||
|
\
|
||||||
|
\ \ The IF and ONWARD-IF both branch to <code2> if the condition is false
|
||||||
|
\ \ This is functionally a short-circuit AND condition
|
||||||
|
\ \ Without the ELSE they would both branch to <code3>
|
||||||
|
\ <cond1> IF <cond2> ONWARD-IF <code1> ELSE <code2> THEN <code3>
|
||||||
|
\
|
||||||
|
\ ALWAYS is provided as a placeholder; it has the same effect as TRUE IF but
|
||||||
|
\ includes no branch. The "orig" value it leaves on the stack (zero) is ignored
|
||||||
|
\ by THEN and marks the end of the list if consumed by ONWARD-IF or ONWARD-AHEAD.
|
||||||
|
\ This can be used as a base for control structures with zero or more branches.
|
||||||
|
\
|
||||||
|
\ The low-level primitives:
|
||||||
|
: ALWAYS ( C: -- orig ) IMMEDIATE 0 ;
|
||||||
|
: ONWARD-IF ( C: orig1 -- orig2 ) IMMEDIATE
|
||||||
|
POSTPONE 0BRANCH HERE SWAP , ;
|
||||||
|
: ONWARD-AHEAD ( C: orig1 -- orig2 ) IMMEDIATE
|
||||||
|
POSTPONE BRANCH HERE SWAP , ;
|
||||||
: THEN ( C: orig -- ) IMMEDIATE
|
: THEN ( C: orig -- ) IMMEDIATE
|
||||||
HERE OVER - SWAP ! ;
|
BEGIN ?DUP WHILE HERE OVER - SWAP XCHG REPEAT ;
|
||||||
|
\ The derived control structures:
|
||||||
|
: IF ( C: -- orig ) ( Runtime S: flag -- ) IMMEDIATE
|
||||||
|
POSTPONE ALWAYS POSTPONE ONWARD-IF ;
|
||||||
|
: AHEAD ( C: -- orig ) IMMEDIATE
|
||||||
|
POSTPONE ALWAYS POSTPONE ONWARD-AHEAD ;
|
||||||
: ELSE ( C: orig1 -- orig2 ) IMMEDIATE
|
: ELSE ( C: orig1 -- orig2 ) IMMEDIATE
|
||||||
POSTPONE AHEAD SWAP POSTPONE THEN ;
|
POSTPONE AHEAD SWAP POSTPONE THEN ;
|
||||||
|
|
||||||
|
|
@ -372,38 +402,65 @@ CREATE PNO-POINTER PNO-BUFFER-END ,
|
||||||
\ with the number of references on top. Inside OF ... ENDOF there is additionally
|
\ with the number of references on top. Inside OF ... ENDOF there is additionally
|
||||||
\ a forward reference to the ENDOF (as with IF ... THEN) above the ENDCASE counter.
|
\ a forward reference to the ENDOF (as with IF ... THEN) above the ENDCASE counter.
|
||||||
\
|
\
|
||||||
\ Begin by creating a counter for the number of unresolved ENDOF forward references
|
\ Begin by creating a placeholder for the unresolved ENDOF forward references
|
||||||
: CASE ( C: -- 0 ) IMMEDIATE
|
: CASE ( C: -- 0 ) IMMEDIATE
|
||||||
0 ;
|
POSTPONE ALWAYS ;
|
||||||
\ At runtime compare the values on the top of the stack; branch to ENDOF if unequal
|
\ At runtime compare the values on the top of the stack; branch to ENDOF if unequal
|
||||||
\ Keep the first value for the next OF if unequal, otherwise consume both
|
\ Keep the first value for the next OF if unequal, otherwise consume both
|
||||||
: OF ( C: orign ... orig1 n -- orign ... orig1 n orig-of ) IMMEDIATE
|
: OF ( C: orign ... orig1 n -- orign ... orig1 n orig-of ) IMMEDIATE
|
||||||
POSTPONE OVER POSTPONE = POSTPONE IF POSTPONE DROP ;
|
POSTPONE OVER POSTPONE = POSTPONE IF POSTPONE DROP ;
|
||||||
\ Create a forward branch to ENDCASE and resolve the one from OF
|
\ Create a forward branch to ENDCASE and resolve the one from OF
|
||||||
: ENDOF ( C: orign ... orig1 n orig-of -- orign ... orig1 orig0 n+1 ) IMMEDIATE
|
: ENDOF ( C: orig-case1 orig-of -- orig-case2 ) IMMEDIATE
|
||||||
POSTPONE AHEAD -ROT POSTPONE THEN 1+ ;
|
SWAP POSTPONE ONWARD-AHEAD SWAP POSTPONE THEN ;
|
||||||
\ Drop the <x> value in case none of the OF...ENDOF clauses matched
|
\ Drop the <x> value in case none of the OF...ENDOF clauses matched
|
||||||
\ Resolve all the forward branches from ENDOF to the location after ENDCASE
|
\ Resolve all the forward branches from ENDOF to the location after ENDCASE
|
||||||
: ENDCASE ( C: orign ... orig1 n -- ) IMMEDIATE
|
: ENDCASE ( C: orig-case -- ) IMMEDIATE
|
||||||
POSTPONE DROP BEGIN ?DUP WHILE 1- SWAP POSTPONE THEN REPEAT ;
|
POSTPONE DROP POSTPONE THEN ;
|
||||||
|
|
||||||
\ Range loop: <limit> <index> DO <code> LOOP
|
\ Range loop: <limit> <index> DO <code> LOOP
|
||||||
\ <limit> <index> DO <code> <step> +LOOP
|
\ <limit> <index> DO <code> <step> +LOOP
|
||||||
: UNLOOP POSTPONE 2RDROP ; IMMEDIATE
|
\ <limit> <index> ?DO <code> LOOP
|
||||||
: DO POSTPONE 2>R POSTPONE BEGIN ; IMMEDIATE
|
\ <limit> <index> ?DO <code> <step> +LOOP
|
||||||
: (+LOOP) ( step limit index -- flag limit index' )
|
CREATE LEAVE-ORIG 0 ,
|
||||||
ROT + 2DUP = -ROT ;
|
: DO ( C: -- outer-stack dest S: limit index R: -- limit index ) IMMEDIATE
|
||||||
: +LOOP IMMEDIATE
|
POSTPONE 2>R LEAVE-ORIG @
|
||||||
POSTPONE 2R> POSTPONE (+LOOP) POSTPONE 2>R
|
POSTPONE ALWAYS LEAVE-ORIG !
|
||||||
POSTPONE UNTIL POSTPONE 2RDROP ;
|
POSTPONE BEGIN ;
|
||||||
' (+LOOP) (HIDE)
|
: ?DO ( C: -- outer-stack dest S: limit index R: -- limit index ) IMMEDIATE
|
||||||
: LOOP IMMEDIATE 1 POSTPONE LITERAL POSTPONE +LOOP ;
|
POSTPONE 2>R LEAVE-ORIG @
|
||||||
|
POSTPONE 2R@ POSTPONE <> POSTPONE IF LEAVE-ORIG !
|
||||||
|
POSTPONE BEGIN ;
|
||||||
|
: LEAVE ( C: -- S: -- R: limit index -- ) IMMEDIATE
|
||||||
|
LEAVE-ORIG @ POSTPONE ONWARD-AHEAD LEAVE-ORIG ! ;
|
||||||
|
: UNLOOP ( R: limit index -- ) IMMEDIATE
|
||||||
|
POSTPONE 2RDROP ;
|
||||||
|
: +LOOP ( C: outer-stack dest -- S: n -- R: {limit index} -- ) IMMEDIATE
|
||||||
|
POSTPONE RSP@ POSTPONE +! POSTPONE 2R@ POSTPONE = POSTPONE UNTIL
|
||||||
|
LEAVE-ORIG @ POSTPONE THEN POSTPONE UNLOOP LEAVE-ORIG ! ;
|
||||||
|
: LOOP ( C: outer-stack dest -- S: -- R: {limit index} -- ) IMMEDIATE
|
||||||
|
1 POSTPONE LITERAL POSTPONE +LOOP ;
|
||||||
|
' LEAVE-ORIG (HIDE)
|
||||||
|
|
||||||
\ Return the current index value from the innermost or next-innermost loop.
|
\ Return the current index value from the innermost or next-innermost loop.
|
||||||
\ The loops must be directly nested with no other changes to the return stack
|
\ The loops must be directly nested with no other changes to the return stack
|
||||||
: I 1 RPICK ;
|
: I 1 RPICK ;
|
||||||
: J 3 RPICK ;
|
: J 3 RPICK ;
|
||||||
|
|
||||||
|
\ Remove trailing whitespace from a string (only affects length)
|
||||||
|
: -TRAILING ( c-addr u1 -- c-addr u2 )
|
||||||
|
BEGIN DUP AND-THEN 2DUP 1- + C@ SPACE? THEN WHILE 1- REPEAT ;
|
||||||
|
|
||||||
|
\ Return -1, 0, or 1 if the left string is respectively
|
||||||
|
\ less than, equal to, or greater than the right string
|
||||||
|
: COMPARE ( c-addr1 u1 c-addr2 u2 -- -1 | 0 | 1 )
|
||||||
|
ROT SWAP 2DUP - >R UMIN 0 ?DO
|
||||||
|
( S: c-addr1 c-addr2 R: u1-u2 loop-sys )
|
||||||
|
OVER I + C@ OVER I + C@
|
||||||
|
( S: c-addr1 c-addr2 ch1 ch2 )
|
||||||
|
- ?DUP IF NIP NIP SIGNUM UNLOOP RDROP EXIT THEN
|
||||||
|
LOOP
|
||||||
|
2DROP R> SIGNUM ;
|
||||||
|
|
||||||
\ This function defines what happens when THROW is used outside of any CATCH
|
\ This function defines what happens when THROW is used outside of any CATCH
|
||||||
: DEFAULT-UNWIND ( k*x n -- i*x <noreturn> )
|
: DEFAULT-UNWIND ( k*x n -- i*x <noreturn> )
|
||||||
CASE
|
CASE
|
||||||
|
|
@ -446,7 +503,7 @@ CREATE CURRENT-SOURCE-ID -1 ,
|
||||||
: SAVE-INPUT ( -- xu ... x1 u ) >IN @ 1 ;
|
: SAVE-INPUT ( -- xu ... x1 u ) >IN @ 1 ;
|
||||||
: RESTORE-INPUT ( xu ... x1 u -- flag ) OVER >IN ! NDROP TRUE ;
|
: RESTORE-INPUT ( xu ... x1 u -- flag ) OVER >IN ! NDROP TRUE ;
|
||||||
|
|
||||||
: PARSE-AREA ( -- c-addr u ) SOURCE >IN @ DROP-PREFIX ;
|
: PARSE-AREA ( -- c-addr u ) SOURCE >IN @ /STRING ;
|
||||||
|
|
||||||
: PARSE-EMPTY? ( -- flag ) SOURCE NIP >IN @ = ;
|
: PARSE-EMPTY? ( -- flag ) SOURCE NIP >IN @ = ;
|
||||||
|
|
||||||
|
|
@ -457,12 +514,66 @@ CREATE CURRENT-SOURCE-ID -1 ,
|
||||||
|
|
||||||
: NEXT-CHAR ( -- c ) PEEK-CHAR SKIP-CHAR ;
|
: NEXT-CHAR ( -- c ) PEEK-CHAR SKIP-CHAR ;
|
||||||
|
|
||||||
: SKIPSPACE ( "<spaces?>" -- )
|
\ The size of this buffer will determine the maximum line length
|
||||||
|
4096 CONSTANT TERMINAL-BUFFER-SIZE
|
||||||
|
CREATE TERMINAL-BUFFER TERMINAL-BUFFER-SIZE ALLOT
|
||||||
|
|
||||||
|
\ If we read more than one line then these will refer to the rest of the data
|
||||||
|
CREATE TIB-LEFTOVER 0 ,
|
||||||
|
CREATE TIB-LEFTOVER-SIZE 0 ,
|
||||||
|
|
||||||
|
\ Attempt to replace the parse area with the next line from the current source
|
||||||
|
\ Return TRUE if the parse area was refilled, or FALSE otherwise
|
||||||
|
\ REFILL always fails if the current source is a string (from EVALUATE)
|
||||||
|
: REFILL ( -- flag )
|
||||||
|
SOURCE-ID 0< IF FALSE EXIT THEN
|
||||||
|
\ Shift any leftover characters after the previous line to the start of the buffer
|
||||||
|
TIB-LEFTOVER @ TERMINAL-BUFFER TIB-LEFTOVER-SIZE @ CMOVE
|
||||||
|
\ Look for the linefeed character which marks the end of the first line
|
||||||
|
TIB-LEFTOVER-SIZE @ 0 BEGIN
|
||||||
|
\ If at the end with room in the buffer, read more from the file descriptor
|
||||||
|
2DUP = IF
|
||||||
|
DUP TERMINAL-BUFFER-SIZE U< IF
|
||||||
|
\ SOURCE-ID is the file descriptor number to read from
|
||||||
|
SOURCE-ID OVER DUP TERMINAL-BUFFER + SWAP TERMINAL-BUFFER-SIZE SWAP -
|
||||||
|
( S: length idx src-id buff buff-size )
|
||||||
|
\ Repeat read if interrupted by a signal (returns -EINTR)
|
||||||
BEGIN
|
BEGIN
|
||||||
PARSE-EMPTY? 0= AND-THEN PEEK-CHAR SPACE? THEN
|
SYS_READ SYSCALL3
|
||||||
WHILE
|
DUP ERRNO_EINTR NEGATE <>
|
||||||
SKIP-CHAR
|
UNTIL
|
||||||
REPEAT ;
|
\ Any other negative (error) return value is fatal
|
||||||
|
DUP 0< IF EXCP-FILE-IO THROW THEN
|
||||||
|
( S: length idx u-read )
|
||||||
|
\ Add the amount of data read to the length; index is unchanged
|
||||||
|
ROT + SWAP
|
||||||
|
THEN
|
||||||
|
THEN
|
||||||
|
\ At this point if index equals length then buffer is full or read returned 0
|
||||||
|
\ Either way, we won't be reading any more into the buffer
|
||||||
|
2DUP = OR-ELSE
|
||||||
|
\ Check if the next character is a linefeed
|
||||||
|
1+ DUP 1- TERMINAL-BUFFER + C@ LF =
|
||||||
|
THEN
|
||||||
|
UNTIL
|
||||||
|
( S: length idx )
|
||||||
|
\ idx is the next location after the linefeed, if found, or else equal to length
|
||||||
|
\ Save the rest, if any, for the next REFILL
|
||||||
|
DUP TERMINAL-BUFFER + TIB-LEFTOVER !
|
||||||
|
TUCK - TIB-LEFTOVER-SIZE !
|
||||||
|
( S: idx )
|
||||||
|
\ The new input buffer is the first idx characters of the terminal buffer
|
||||||
|
TERMINAL-BUFFER INPUT-BUFFER !
|
||||||
|
DUP INPUT-BUFFER-SIZE !
|
||||||
|
DUP IF 0 >IN ! THEN
|
||||||
|
0<> ;
|
||||||
|
|
||||||
|
' TIB-LEFTOVER (HIDE)
|
||||||
|
' TIB-LEFTOVER-SIZE (HIDE)
|
||||||
|
' TERMINAL-BUFFER (HIDE)
|
||||||
|
|
||||||
|
: SKIP-SPACES ( "<spaces?>" -- )
|
||||||
|
BEGIN PARSE-EMPTY? OR-ELSE PEEK-CHAR SPACE? DUP IF SKIP-CHAR THEN 0= THEN UNTIL ;
|
||||||
|
|
||||||
\ Comments; ignore all characters until the next EOL or ) character, respectively
|
\ Comments; ignore all characters until the next EOL or ) character, respectively
|
||||||
: \ ( "ccc<eol>" -- ) IMMEDIATE BEGIN NEXT-CHAR LF = UNTIL ;
|
: \ ( "ccc<eol>" -- ) IMMEDIATE BEGIN NEXT-CHAR LF = UNTIL ;
|
||||||
|
|
@ -471,10 +582,15 @@ CREATE CURRENT-SOURCE-ID -1 ,
|
||||||
\ Skip whitespace; read and return the next word delimited by whitespace
|
\ Skip whitespace; read and return the next word delimited by whitespace
|
||||||
\ The delimiting whitespace character is left in the parse area
|
\ The delimiting whitespace character is left in the parse area
|
||||||
: WORD ( "<spaces>ccc" -- c-addr u )
|
: WORD ( "<spaces>ccc" -- c-addr u )
|
||||||
SKIPSPACE
|
BEGIN
|
||||||
|
SKIP-SPACES
|
||||||
|
PARSE-EMPTY?
|
||||||
|
WHILE
|
||||||
|
REFILL 0= IF 0 0 EXIT THEN
|
||||||
|
REPEAT
|
||||||
PARSE-AREA DROP
|
PARSE-AREA DROP
|
||||||
BEGIN
|
BEGIN
|
||||||
PARSE-EMPTY? OR-ELSE PEEK-CHAR SPACE? THEN 0=
|
PARSE-EMPTY? 0= AND-THEN PEEK-CHAR SPACE? 0= THEN
|
||||||
WHILE
|
WHILE
|
||||||
SKIP-CHAR
|
SKIP-CHAR
|
||||||
REPEAT
|
REPEAT
|
||||||
|
|
@ -500,7 +616,7 @@ CREATE CURRENT-SOURCE-ID -1 ,
|
||||||
|
|
||||||
' (DOES) (HIDE)
|
' (DOES) (HIDE)
|
||||||
|
|
||||||
: (MARK) TYPE ": " TYPE .DS EOL ;
|
: (MARK) "-- " TYPE TYPE " --\n" TYPE .S R> .RS >R ;
|
||||||
: MARK IMMEDIATE WORD POSTPONE SLITERAL POSTPONE (MARK) ;
|
: MARK IMMEDIATE WORD POSTPONE SLITERAL POSTPONE (MARK) ;
|
||||||
' (MARK) (HIDE)
|
' (MARK) (HIDE)
|
||||||
|
|
||||||
|
|
@ -555,7 +671,7 @@ CREATE CURRENT-SOURCE-ID -1 ,
|
||||||
CREATE CELLS 2* ALLOT DOES> SWAP [ 2 CELLS ] LITERAL * + ;
|
CREATE CELLS 2* ALLOT DOES> SWAP [ 2 CELLS ] LITERAL * + ;
|
||||||
|
|
||||||
\ Define a threaded word which also displays its name and the data stack when called
|
\ Define a threaded word which also displays its name and the data stack when called
|
||||||
: (TRACE) >NAME TYPE SPACE .DS EOL ;
|
: (TRACE) >NAME TYPE SPACE .S ;
|
||||||
: :TRACE : LATEST POSTPONE LITERAL POSTPONE (TRACE) ;
|
: :TRACE : LATEST POSTPONE LITERAL POSTPONE (TRACE) ;
|
||||||
' (TRACE) (HIDE)
|
' (TRACE) (HIDE)
|
||||||
|
|
||||||
|
|
@ -587,7 +703,7 @@ CREATE CURRENT-SOURCE-ID -1 ,
|
||||||
\ LATEST always refers to the innermost enclosing definition.
|
\ LATEST always refers to the innermost enclosing definition.
|
||||||
\
|
\
|
||||||
\ Example:
|
\ Example:
|
||||||
\ > : TIMES 0 DO DUP EXECUTE LOOP DROP ;
|
\ > : TIMES 0 ?DO DUP EXECUTE LOOP DROP ;
|
||||||
\ > : GREETINGS { "Hello" TYPE EOL } 3 TIMES ;
|
\ > : GREETINGS { "Hello" TYPE EOL } 3 TIMES ;
|
||||||
\ > GREETINGS
|
\ > GREETINGS
|
||||||
\ Hello
|
\ Hello
|
||||||
|
|
@ -630,6 +746,40 @@ CREATE CURRENT-SOURCE-ID -1 ,
|
||||||
( S: inner-xt )
|
( S: inner-xt )
|
||||||
THEN ;
|
THEN ;
|
||||||
|
|
||||||
|
\ Conditional compilation
|
||||||
|
\ No effect if flag is true, otherwise skips words until matching [ELSE] or [THEN]
|
||||||
|
\ Skips over nested [IF] … [THEN] or [IF] … [ELSE] … [THEN] structures
|
||||||
|
: [IF] IMMEDIATE RECURSIVE
|
||||||
|
0= IF
|
||||||
|
0 BEGIN
|
||||||
|
WORD 2>R
|
||||||
|
2R@ "[IF]" COMPARE 0= IF
|
||||||
|
1+
|
||||||
|
ELSE 2R@ "[THEN]" COMPARE 0= OR-ELSE 2R@ "[ELSE]" COMPARE 0= THEN IF
|
||||||
|
?DUP 0= IF 2RDROP EXIT THEN
|
||||||
|
1-
|
||||||
|
THEN THEN
|
||||||
|
2RDROP
|
||||||
|
AGAIN
|
||||||
|
THEN ;
|
||||||
|
|
||||||
|
\ Skips words until matching [THEN]
|
||||||
|
\ Skips over nested [IF] … [THEN] or [IF] … [ELSE] … [THEN] structures
|
||||||
|
: [ELSE] IMMEDIATE
|
||||||
|
0 BEGIN
|
||||||
|
WORD 2>R
|
||||||
|
2R@ "[IF]" COMPARE 0= IF
|
||||||
|
1+
|
||||||
|
ELSE 2R@ "[THEN]" COMPARE 0= IF
|
||||||
|
?DUP 0= IF 2RDROP EXIT THEN
|
||||||
|
1-
|
||||||
|
THEN THEN
|
||||||
|
2RDROP
|
||||||
|
AGAIN ;
|
||||||
|
|
||||||
|
\ [THEN] is just a placeholder to terminate [IF] or [ELSE]; no compilation effect
|
||||||
|
: [THEN] IMMEDIATE ;
|
||||||
|
|
||||||
4096 CONSTANT PAGESIZE
|
4096 CONSTANT PAGESIZE
|
||||||
|
|
||||||
0 CONSTANT PROT_NONE
|
0 CONSTANT PROT_NONE
|
||||||
|
|
@ -648,7 +798,7 @@ BUDDY-ORDERS 1- BUDDY-ORDER-BYTES CONSTANT BUDDY-MAX-BYTES
|
||||||
BUDDY-ORDERS ARRAY BUDDY-HEADS
|
BUDDY-ORDERS ARRAY BUDDY-HEADS
|
||||||
|
|
||||||
: INIT-BUDDY-HEADS ( -- )
|
: INIT-BUDDY-HEADS ( -- )
|
||||||
BUDDY-ORDERS 0 DO 0 I BUDDY-HEADS ! LOOP ;
|
BUDDY-ORDERS 0 ?DO 0 I BUDDY-HEADS ! LOOP ;
|
||||||
|
|
||||||
INIT-BUDDY-HEADS
|
INIT-BUDDY-HEADS
|
||||||
|
|
||||||
|
|
@ -666,14 +816,14 @@ INIT-BUDDY-HEADS
|
||||||
THEN
|
THEN
|
||||||
( S: order head-addr block-addr ) ( R: freed-addr )
|
( S: order head-addr block-addr ) ( R: freed-addr )
|
||||||
2 PICK 1+ BUDDY-ORDERS < AND-THEN
|
2 PICK 1+ BUDDY-ORDERS < AND-THEN
|
||||||
DUP 3 PICK BUDDY-ORDER-BYTES XOR R@ = AND-THEN
|
DUP 3 PICK BUDDY-ORDER-BYTES XOR R@ =
|
||||||
|
THEN AND-THEN
|
||||||
\ Found the buddy on the free list; coalesce
|
\ Found the buddy on the free list; coalesce
|
||||||
@ SWAP !
|
@ SWAP !
|
||||||
\ Pick the lower (naturally aligned) block address
|
\ Pick the lower (naturally aligned) block address
|
||||||
DUP BUDDY-ORDER-BYTES INVERT R> AND >R
|
DUP BUDDY-ORDER-BYTES INVERT R> AND >R
|
||||||
\ Repeat process with the next-higher order
|
\ Repeat process with the next-higher order
|
||||||
1+ DUP BUDDY-HEADS TRUE
|
1+ DUP BUDDY-HEADS TRUE
|
||||||
THEN
|
|
||||||
THEN 0= IF
|
THEN 0= IF
|
||||||
\ Insert before first item with address >= this addr
|
\ Insert before first item with address >= this addr
|
||||||
DUP R@ U>= IF R@ ! R> SWAP ! DROP EXIT THEN
|
DUP R@ U>= IF R@ ! R> SWAP ! DROP EXIT THEN
|
||||||
|
|
@ -723,7 +873,6 @@ VARIABLE TOTAL
|
||||||
|
|
||||||
: ALLOCATE ( size -- a-addr )
|
: ALLOCATE ( size -- a-addr )
|
||||||
CELL+ DUP BUDDY-MAX-BYTES U> IF
|
CELL+ DUP BUDDY-MAX-BYTES U> IF
|
||||||
MARK A
|
|
||||||
BEGIN
|
BEGIN
|
||||||
NULL OVER PROT_READ PROT_WRITE OR
|
NULL OVER PROT_READ PROT_WRITE OR
|
||||||
MAP_PRIVATE MAP_ANONYMOUS OR -1 0 SYS_MMAP2 SYSCALL6
|
MAP_PRIVATE MAP_ANONYMOUS OR -1 0 SYS_MMAP2 SYSCALL6
|
||||||
|
|
@ -733,7 +882,6 @@ MARK A
|
||||||
REPEAT
|
REPEAT
|
||||||
TUCK ! CELL+ EXIT
|
TUCK ! CELL+ EXIT
|
||||||
THEN
|
THEN
|
||||||
MARK B
|
|
||||||
NATURALLY-ALIGNED DUP BUDDY-MIN-BYTES U< IF DROP BUDDY-MIN-BYTES THEN
|
NATURALLY-ALIGNED DUP BUDDY-MIN-BYTES U< IF DROP BUDDY-MIN-BYTES THEN
|
||||||
BUDDY-ORDER-FROM-BYTES DUP BUDDY-ALLOCATE SWAP OVER ! CELL+ ;
|
BUDDY-ORDER-FROM-BYTES DUP BUDDY-ALLOCATE SWAP OVER ! CELL+ ;
|
||||||
|
|
||||||
|
|
@ -753,34 +901,6 @@ MARK B
|
||||||
: [CHAR] ( Compilation: "<spaces>ccc" -- ) ( Runtime: -- c ) IMMEDIATE
|
: [CHAR] ( Compilation: "<spaces>ccc" -- ) ( Runtime: -- c ) IMMEDIATE
|
||||||
CHAR POSTPONE LITERAL ;
|
CHAR POSTPONE LITERAL ;
|
||||||
|
|
||||||
\ Return -1, 0, or 1 if the left string is respectively
|
|
||||||
\ less than, equal to, or greater than the right string
|
|
||||||
: COMPARE ( c-addr1 u1 c-addr2 u2 -- -1 | 0 | 1 )
|
|
||||||
BEGIN
|
|
||||||
ROT ?DUP IF
|
|
||||||
( S: a1 a2 u2 u1 )
|
|
||||||
SWAP ?DUP IF
|
|
||||||
( S: a1 a2 u1 u2 )
|
|
||||||
2SWAP 2DUP C@ SWAP C@ - DUP IF
|
|
||||||
>R 4 NDROP R> SIGNUM EXIT
|
|
||||||
ELSE
|
|
||||||
DROP
|
|
||||||
( S: u1 u2 a1 a2 )
|
|
||||||
1+ SWAP 1+ 2SWAP 1- SWAP 1-
|
|
||||||
( S: a2' a1' u2' u1' )
|
|
||||||
SWAP -ROT 2SWAP
|
|
||||||
( S: a1' u1' a2' u2' )
|
|
||||||
THEN
|
|
||||||
ELSE
|
|
||||||
\ Return 1 since first string is longer
|
|
||||||
DROP 2DROP 1 EXIT
|
|
||||||
THEN
|
|
||||||
ELSE
|
|
||||||
\ If u2 is also zero return 0; else return -1 since first string is shorter
|
|
||||||
-ROT 2DROP 0<> EXIT
|
|
||||||
THEN
|
|
||||||
AGAIN ;
|
|
||||||
|
|
||||||
\ Field accessors for the search order linked list
|
\ Field accessors for the search order linked list
|
||||||
: ORDER>LINK ( a-addr1 -- a-addr2 ) ;
|
: ORDER>LINK ( a-addr1 -- a-addr2 ) ;
|
||||||
: ORDER>WID ( a-addr1 -- a-addr2 ) CELL+ ;
|
: ORDER>WID ( a-addr1 -- a-addr2 ) CELL+ ;
|
||||||
|
|
@ -962,61 +1082,6 @@ VARIABLE ORDER-FREELIST
|
||||||
: :REPLACE ( "<spaces>ccc" -- )
|
: :REPLACE ( "<spaces>ccc" -- )
|
||||||
: LATEST DUP >NAME FIND-OR-THROW DROP DUP (HIDE) DEFER! ;
|
: LATEST DUP >NAME FIND-OR-THROW DROP DUP (HIDE) DEFER! ;
|
||||||
|
|
||||||
\ The size of this buffer will determine the maximum line length
|
|
||||||
4096 CONSTANT TERMINAL-BUFFER-SIZE
|
|
||||||
CREATE TERMINAL-BUFFER TERMINAL-BUFFER-SIZE ALLOT
|
|
||||||
|
|
||||||
\ If we read more than one line then these will refer to the rest of the data
|
|
||||||
CREATE TIB-LEFTOVER 0 ,
|
|
||||||
CREATE TIB-LEFTOVER-SIZE 0 ,
|
|
||||||
|
|
||||||
: REFILL ( -- flag )
|
|
||||||
SOURCE-ID 0< IF FALSE EXIT THEN
|
|
||||||
\ Shift any leftover characters after the previous line to the start of the buffer
|
|
||||||
TIB-LEFTOVER @ TERMINAL-BUFFER TIB-LEFTOVER-SIZE @ CMOVE
|
|
||||||
\ Look for the linefeed character which marks the end of the first line
|
|
||||||
TIB-LEFTOVER-SIZE @ 0 BEGIN
|
|
||||||
\ If at the end with room in the buffer, read more from the file descriptor
|
|
||||||
2DUP = IF
|
|
||||||
DUP TERMINAL-BUFFER-SIZE U< IF
|
|
||||||
\ SOURCE-ID is the file descriptor number to read from
|
|
||||||
SOURCE-ID OVER DUP TERMINAL-BUFFER + SWAP TERMINAL-BUFFER-SIZE SWAP -
|
|
||||||
( S: length idx src-id buff buff-size )
|
|
||||||
\ Repeat read if interrupted by a signal (returns -EINTR)
|
|
||||||
BEGIN
|
|
||||||
SYS_READ SYSCALL3
|
|
||||||
DUP ERRNO_EINTR NEGATE <>
|
|
||||||
UNTIL
|
|
||||||
\ Any other negative (error) return value is fatal
|
|
||||||
DUP 0< IF EXCP-FILE-IO THROW THEN
|
|
||||||
( S: length idx u-read )
|
|
||||||
\ Add the amount of data read to the length; index is unchanged
|
|
||||||
ROT + SWAP
|
|
||||||
THEN
|
|
||||||
THEN
|
|
||||||
\ At this point if index equals length then buffer is full or read returned 0
|
|
||||||
\ Either way, we won't be reading any more into the buffer
|
|
||||||
2DUP = OR-ELSE
|
|
||||||
\ Check if the next character is a linefeed
|
|
||||||
1+ DUP 1- TERMINAL-BUFFER + C@ LF =
|
|
||||||
THEN
|
|
||||||
UNTIL
|
|
||||||
( S: length idx )
|
|
||||||
\ idx is the next location after the linefeed, if found, or else equal to length
|
|
||||||
\ Save the rest, if any, for the next REFILL
|
|
||||||
DUP TERMINAL-BUFFER + TIB-LEFTOVER !
|
|
||||||
TUCK - TIB-LEFTOVER-SIZE !
|
|
||||||
( S: idx )
|
|
||||||
\ The new input buffer is the first idx characters of the terminal buffer
|
|
||||||
TERMINAL-BUFFER INPUT-BUFFER !
|
|
||||||
DUP INPUT-BUFFER-SIZE !
|
|
||||||
DUP IF 0 >IN ! THEN
|
|
||||||
0<> ;
|
|
||||||
|
|
||||||
HIDE TIB-LEFTOVER
|
|
||||||
HIDE TIB-LEFTOVER-SIZE
|
|
||||||
HIDE TERMINAL-BUFFER
|
|
||||||
|
|
||||||
: ESCAPED-CHAR ( "<escapeseq>" | "c" -- c )
|
: ESCAPED-CHAR ( "<escapeseq>" | "c" -- c )
|
||||||
NEXT-CHAR DUP [CHAR] \ = IF
|
NEXT-CHAR DUP [CHAR] \ = IF
|
||||||
DROP NEXT-CHAR CASE
|
DROP NEXT-CHAR CASE
|
||||||
|
|
@ -1066,14 +1131,13 @@ HIDE TERMINAL-BUFFER
|
||||||
REPEAT
|
REPEAT
|
||||||
( S: neg-flag accum c-addr' ) ( R: c-addr u )
|
( S: neg-flag accum c-addr' ) ( R: c-addr u )
|
||||||
2RDROP DROP SWAP IF NEGATE THEN
|
2RDROP DROP SWAP IF NEGATE THEN
|
||||||
TRUE
|
TRUE ;
|
||||||
;
|
|
||||||
|
|
||||||
\ Read a word, number, or string and either execute it or compile it
|
\ Read a word, number, or string and either execute it or compile it
|
||||||
\ The stack effect depends on the input and the current value of STATE
|
\ The stack effect depends on the input and the current value of STATE
|
||||||
: INTERPRET ( i*x "<spaces>ccc" -- j*x )
|
: INTERPRET ( i*x "<spaces>ccc" -- j*x )
|
||||||
BEGIN
|
BEGIN
|
||||||
SKIPSPACE
|
SKIP-SPACES
|
||||||
PARSE-EMPTY? 0=
|
PARSE-EMPTY? 0=
|
||||||
WHILE
|
WHILE
|
||||||
PEEK-CHAR [CHAR] " = IF
|
PEEK-CHAR [CHAR] " = IF
|
||||||
|
|
@ -1103,6 +1167,15 @@ HIDE TERMINAL-BUFFER
|
||||||
DEFER SHOW-PROMPT
|
DEFER SHOW-PROMPT
|
||||||
{ "> " TYPE } IS SHOW-PROMPT
|
{ "> " TYPE } IS SHOW-PROMPT
|
||||||
|
|
||||||
|
36 CONSTANT STRUCT-TERMIOS-BYTES
|
||||||
|
21505 CONSTANT IOCTL_TCGETS
|
||||||
|
CREATE TERMIOS STRUCT-TERMIOS-BYTES ALLOT ALIGN
|
||||||
|
|
||||||
|
: TTY? ( fd -- flag )
|
||||||
|
IOCTL_TCGETS TERMIOS SYS_IOCTL SYSCALL3 0= ;
|
||||||
|
|
||||||
|
STDIN TTY? CONSTANT INTERACTIVE?
|
||||||
|
|
||||||
\ Redefine QUIT as a non-deferred word; update deferred references to point here
|
\ Redefine QUIT as a non-deferred word; update deferred references to point here
|
||||||
\ Empty the return stack, make stdin the input source, and enter interpretation state
|
\ Empty the return stack, make stdin the input source, and enter interpretation state
|
||||||
:REPLACE QUIT ( -- <noreturn> )
|
:REPLACE QUIT ( -- <noreturn> )
|
||||||
|
|
@ -1110,14 +1183,12 @@ DEFER SHOW-PROMPT
|
||||||
0 CURRENT-SOURCE-ID !
|
0 CURRENT-SOURCE-ID !
|
||||||
FALSE STATE !
|
FALSE STATE !
|
||||||
BEGIN
|
BEGIN
|
||||||
SHOW-PROMPT
|
[ INTERACTIVE? ] [IF] SHOW-PROMPT [THEN]
|
||||||
REFILL 0= IF
|
REFILL 0= IF BYE THEN
|
||||||
EOL BYE
|
|
||||||
THEN
|
|
||||||
INTERPRET
|
INTERPRET
|
||||||
STATE @ 0= IF
|
[ INTERACTIVE? ] [IF]
|
||||||
"OK\n" TYPE
|
STATE @ 0= IF "OK\n" TYPE THEN
|
||||||
THEN
|
[THEN]
|
||||||
AGAIN ;
|
AGAIN ;
|
||||||
|
|
||||||
: EVALUATE ( i*x c-addr u -- j*x )
|
: EVALUATE ( i*x c-addr u -- j*x )
|
||||||
|
|
@ -1208,9 +1279,6 @@ DEFINITIONS
|
||||||
\ From this point on we only execute threaded FORTH words defined in this file
|
\ From this point on we only execute threaded FORTH words defined in this file
|
||||||
\ *****************************************************************************
|
\ *****************************************************************************
|
||||||
|
|
||||||
\ Return the number of words on the data stack
|
|
||||||
: DEPTH ( -- n ) SP@ S0 SWAP - CELL / ;
|
|
||||||
|
|
||||||
\ Return TRUE if the given address is the execution token of a word in
|
\ Return TRUE if the given address is the execution token of a word in
|
||||||
\ the current search order or compilation word list, or FALSE otherwise
|
\ the current search order or compilation word list, or FALSE otherwise
|
||||||
\ The word's name may be hidden or shadowed by another definition
|
\ The word's name may be hidden or shadowed by another definition
|
||||||
|
|
@ -1259,7 +1327,7 @@ DEFINITIONS
|
||||||
|
|
||||||
\ Display a string in escaped (double-quoted) format, without the delimiters
|
\ Display a string in escaped (double-quoted) format, without the delimiters
|
||||||
: TYPE-ESCAPED ( c-addr u -- "<escapeseq*>" )
|
: TYPE-ESCAPED ( c-addr u -- "<escapeseq*>" )
|
||||||
0 DO DUP 1+ SWAP C@ CASE
|
0 ?DO DUP 1+ SWAP C@ CASE
|
||||||
0 OF "\\0" TYPE ENDOF
|
0 OF "\\0" TYPE ENDOF
|
||||||
7 OF "\\a" TYPE ENDOF
|
7 OF "\\a" TYPE ENDOF
|
||||||
8 OF "\\b" TYPE ENDOF
|
8 OF "\\b" TYPE ENDOF
|
||||||
|
|
@ -1362,7 +1430,10 @@ HIDE NONAME-LITERAL?
|
||||||
|
|
||||||
HIDE UNTHREAD
|
HIDE UNTHREAD
|
||||||
|
|
||||||
|
: WORDS ( -- )
|
||||||
|
GET-ORDER ?DUP IF 1- SWAP >R NDROP R> SHOW-WORDLIST THEN ;
|
||||||
|
|
||||||
: BANNER "JumpForth version " TYPE VERSION . ", by Jesse McDonald\n" TYPE ;
|
: BANNER "JumpForth version " TYPE VERSION . ", by Jesse McDonald\n" TYPE ;
|
||||||
|
|
||||||
BANNER
|
INTERACTIVE? [IF] BANNER [THEN]
|
||||||
QUIT
|
QUIT
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue