Miser's CASE - A general purpose Forth CASE statement

Revision 3  2008-11-30

This CASE statement offers the following features:

It is called Miser's CASE because it immodestly claims to 'do everything yet cost nothing'.


Implementation

The following high-level implementation is intended as a guide only. Please note the comments regarding portability and performance optimization.


\ Miser's CASE
\
\ A general purpose Forth case statement.
\
\ Revision 3  2008-11-30
\
\ -------------------------------------------------------------
\ History
\ - RANGE changed to use recent BETWEEN proposal.
\   Add CONTINUE for C-style switching.
\ - Examples revised. Minor text changes
\ -------------------------------------------------------------
\
\ Sample implementation only.
\
\ The provided code is NOT portable. It makes assumptions
\ about the control flow stack which may not be applicable
\ to your forth.
\
\ Run-time code should be replaced by machine-code primitives
\ for maximum performance.
\
\ Tested on SwiftForth, VFX, Win32Forth, Gforth and others.
\
\ This code is public domain. Use at your own risk.
\
\ Keywords:
\
\   CASE ENDCASE COND WHEN EQUAL RANGE CONTINUE IF ELSE
\
\   OF ENDOF ( for backward compatibility )
\
\ Syntax:
\
\   CASE ( x1 )
\      COND  <tests>  WHEN    ... ELSE
\            <test>   IF DROP ... ELSE
\            x2       OF      ... ENDOF
\      ...   ( default )
\   ENDCASE
\
\ All clauses are optional.
\
\ <tests> may consist of one or more of the following:
\
\    x2    EQUAL  ( test if x1 x2 equal )
\    x2 x3 RANGE  ( test if x1 in the range x2..x3 )
\
\ <test> can be any code that leaves x1 and a zero|non-zero
\ value.
\
\ CONTINUE may be placed anywhere within:
\
\   WHEN ... ELSE
\   IF ( DROP ) ... ELSE
\   OF ... ENDOF
\
\ CONTINUE redirects program flow from previously matched
\ clauses that would otherwise pass to ENDCASE. It provides
\ "fall-through" capability akin to C's switch statement.
\
\ IF ... ELSE is for expansion allowing user-defined tests.
\
\ OF ... ENDOF is largely obsolete but is retained for
\ backward compatibility with Forth-94.
\

0 constant CASE  immediate
0 constant COND  immediate

: thens
  begin  ?dup while  postpone then  repeat ;

: ENDCASE
  postpone drop  thens ; immediate

cr .( Are you using SwiftForth or VFX? Y/N )
key dup emit cr dup char Y = swap char y = or
[if]

: WHEN
  postpone else  >r  thens  r>  postpone drop ; immediate

: CONTINUE
  >r  thens  0  r> ; immediate

[else]

cr .( Are you using gForth Y/N )
key dup emit cr dup char Y = swap char y = or
[if]

: WHEN
  postpone else  >r >r >r  thens  r> r> r>  postpone drop ;
  immediate

: CONTINUE
  >r >r >r thens  0  r> r> r> ; immediate

[else]

: WHEN
  postpone else  2>r  thens  2r>  postpone drop ; immediate

: CONTINUE
  2>r  thens  0  2r> ; immediate

[then]
[then]

: EQUAL
  postpone over  postpone -  postpone if ; immediate

\ Range is based on  : BETWEEN over - -rot - u< 0= ;
\ Values may be signed or unsigned.
: (range)
  2>r dup 2r> over - -rot - u< ;

: RANGE
  postpone (range)  postpone if ; immediate

\ OF ENDOF provided for backward compatibility
: ENDOF  postpone else ; immediate

: OF  postpone over  postpone =  postpone if
  postpone drop ; immediate

\
\ Examples
\

hex

: TEST1 ( n )  space
  case
    cond
          00 1F range
          7F    equal  when  ." Control char "       else
    cond
          20 2F range
          3A 40 range
          5B 60 range
          7B 7E range  when  ." Punctuation "        else
    cond  30 39 range  when  ." Digit "              else
    cond  41 5A range  when  ." Upper case letter "  else
    cond  61 7A range  when  ." Lower case letter "  else
      ." Not a character "
  endcase ;

decimal

cr cr .( Running TEST1...)

cr  char a  .(   ) dup emit  test1
cr  char ,  .(   ) dup emit  test1
cr  char 8  .(   ) dup emit  test1
cr  char ?  .(   ) dup emit  test1
cr  char K  .(   ) dup emit  test1
cr  0              dup 3 .r  test1
cr  127            dup 3 .r  test1
cr  128            dup 3 .r  test1

\ end

Top    Home    Forth

em.gif (457 bytes)


web stats

Page updated: 30 Nov 2008