chitselb wrote:
Code:
: CASE[ ( -- ADR ) COMPILE (CASE#) HERE 0 , ; IMMEDIATE
: ]END-CASE ( ADR -- ) HERE SWAP ! ; IMMEDIATE
pretty sure this should be :
: CASE[ ( -- ADR ) COMPILE (CASE#) HERE 0 C, ; IMMEDIATE
: ]END-CASE ( ADR -- ) HERE SWAP C! ; IMMEDIATE
No, that is for another variation on
(CASE#) that uses an inline branch address
instead of an inline byte count. It, like the other version, allows 127 compiled cases, 0 - 126. In both versions, any case number on the stack that falls outside the range of cases defaults to case 0.
Code:
SCR# 93
// (CASE#) -- INLINE BRANCH ADDRESS
HEX
CODE (CASE#) ( N -- )
CLC,
IP )Y LDA, IP SBC,
.A LSR, N STA,
0 ,X LDA, N CMP,
CS IF, TYA, THEN,
.A ASL, TAY, INY, INY,
IP )Y LDA, W STA, INY,
IP )Y LDA, W 1+ STA, 1 # LDY,
IP )Y LDA, PHA, DEY,
IP )Y LDA, IP STA,
PLA, IP 1+ STA,
INX, INX, W 1- JMP,
END-CODE
SCR# 94
// CASE[ ]END-CASE
HEX
: CASE[ ( -- ADR )
COMPILE (CASE#)
HERE 0 , ; IMMEDIATE
: ]END-CASE ( ADR -- )
HERE SWAP ! ; IMMEDIATE
Using
>MARK and
>RESOLVE makes
CASE[ and
]END-CASE smaller. Renaming
CASE[ to
CASE# and using it with
THEN makes it smaller still (
]END-CASE is no longer needed as it is an alias for
THEN). However, this assumes your
>MARK and
>RESOLVE behave similarly to this:
Code:
: >MARK ( -- ADR 1 )
HERE 0 , 1 ;
: >RESOLVE ( ADR 1 -- )
?COMP
1 ?PAIRS HERE SWAP ! ;
?COMP just aborts with a message if not compiling and
?PAIRS aborts with a message if the two numbers it consumes are not equal. A different compiler security number could be used. Here are the versions without compiler security ( at least on my system ).
Code:
: >MARK ( -- ADR )
HERE 0 , ;
: >RESOLVE ( ADR -- )
HERE SWAP ! ;
And here is
THEN:
Code:
: THEN ( ADR CS -- )
>RESOLVE ; IMMEDIATE
CASE[ is renamed
CASE# and becomes:
Code:
: CASE# ( -- ADR CS )
COMPILE (CASE#)
>MARK ; IMMEDIATE
And
]END-CASE is an alias for
THEN, so it is not needed.
The demo then becomes:
Code:
SCR# 98
// TEST OF CASE#
HEX
: POWER ." POWERING UP SYSTEMS." ;
: TAKEOFF ." VERTICAL ASCENT." ;
: HOVER ." AIRWOLF HOVERING." ;
: TURBO ." TURBOS ENGAGED!" ;
: LAND ." LANDING AIRWOLF." ;
VARIABLE HELICOPTER
: AIRWOLF ( -- )
HELICOPTER @ CASE#
POWER TAKEOFF HOVER TURBO
LAND
THEN
CR .S ;
: TEST ( -- ) 6 -1 DO
I HELICOPTER ! CR AIRWOLF
LOOP ;
On my system, the version which takes an inline branch is about 27 bytes smaller than the version which takes an inline byte count, including the compiler words, while each use of the mini case structure requires one more byte for the version that takes an inline branch. If I were to use it 27 times the memory usage would be even. If I use it less than 27 times, the branch address version wins out. If I use it more than 27 times, the byte count version wins out.
IIRC you plan to remove the headers for your final application ( you'll probably find a way to strip out the compiler words as well, since they will no longer be needed ). In that event, the first version, the one that takes an inline byte count would be more memory efficient for you.
Here are the two versions in high level Forth.
Here is the version of
(CASE#) that takes an inline byte count in high level Forth:
Code:
SCR# 99
// (CASE#) -- HIGH LEVEL BYTE COUNT
HEX
: (CASE#) ( N -- )
R> COUNT 2DUP 2* + >R
ROT TUCK SWAP
U< AND
2* +
@ EXECUTE ;
: CASE[ ( -- ADR )
COMPILE (CASE#) HERE 0 C, ;
IMMEDIATE
: ]END-CASE ( ADR -- )
HERE OVER - 1- 2/ SWAP C! ;
IMMEDIATE
And here is the version that takes an inline branch address in high level Forth:
Code:
SCR# 9B
// (CASE#) -- HIGH LEVEL BRANCH
HEX
: (CASE#) ( N -- )
R> 2DUP DUP @ DUP>R
SWAP - 2/ 1-
U< ROT AND
1+ 2* +
@ EXECUTE ;
: CASE# ( -- ADR CS )
COMPILE (CASE#)
>MARK ; IMMEDIATE
If you don't have
DUP>R, just replace it with
DUP >R.
And here are some notes about memory size.
Code:
All versions of mini case structure default to case 0 if the number is outside the range of cases.
The two code level versions of (CASE#) allow a maximum of 127 compiled cases, 0 - 126
The high level version of (CASE#) with inline byte count allows a maximum of 255 cases, 0 - 254.
The high level version of (CASE#) with inline branch allows as many cases as will fit in available memory.
Here are some statistics about the sizes. The bodies tally includes the code fields of the words.
(CASE#) with inline count ( 1 byte )
Size of bodies: Whole word:
(CASE#) 41 bytes 51 bytes
CASE[ 14 bytes 22 bytes
]END-CASE 18 bytes 30 bytes
-------------------------------
Total: 73 bytes 103 bytes
(CASE#) with inline branch address ( 2 bytes )
Size of bodies: Whole word:
(CASE#) 48 bytes 58 bytes
CASE[ 14 bytes 22 bytes
]END-CASE 10 bytes 22 bytes
-------------------------------
Total: 72 bytes 102 bytes
(CASE#) with inline branch address
using >MARK and >RESOLVE
Size of bodies: Whole word:
(CASE#) 48 bytes 58 bytes
CASE[ 10 bytes 18 bytes
]END-CASE 6 bytes 18 bytes
-------------------------------
Total: 64 bytes 94 bytes
(CASE#) with inline branch address
using CASE# and THEN
Size of bodies: Whole word:
(CASE#) 48 bytes 58 bytes
CASE# 10 bytes 18 bytes
-------------------------------
Total 58 bytes 76 bytes
High level (CASE#) with inline count ( 1 byte )
Size of bodies: Whole word:
(CASE#) 34 bytes 44 bytes
CASE[ 14 bytes 22 bytes
]END-CASE 18 bytes 30 bytes
-------------------------------
Total: 66 bytes 96 bytes
High level (CASE#) with inline branch address with DUP>R
Size of bodies: Whole word:
(CASE#) 38 bytes 48 bytes
CASE# 10 bytes 18 bytes
-------------------------------
Total: 48 bytes 66 bytes
Cheers,
Jim
BTW this is for a Forth-83 ITC system with 16 bit addressing.