今度は逆に CASEを作ってみよう
FORTH DIMENSIONS II/3 の CASE Contest (Dr. Charles E. Eaker) を参考に
このような定義の場合、
: TEST
CASE
1 OF ." ONE" ENDOF
2 OF ." TWO" ENDOF
." OTHER"
ENDCASE ;
以下のようになってほしい
: TEST 1 OVER = ?BRANCH x1 DROP (.") ONE BRANCH x3
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^
CASE OF ENDOF
2 OVER = ?BRANCH x2 DROP (.") TWO BRANCH x3 (.") OTHER DROP ;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^
OF ENDOF ENDCASE
こうするためには、
CASE =>
OF => COMPILE OVER COMPILE = COMPILE ?BRANCH HERE 0 , COMPILE DROP
ENDOF => COMPILE BRANCH HERE 0 , SWAP HERE !
ENDCASE => HERE SWAP ! をすべてのOFに対して繰り返す
すべてのOFに対して繰り返すのは、回数が未定のためCASEで
フラグ(TRUE)を積んで置くことにする。
これらを考慮すると
: CASE TRUE ; IMMEDIATE
: OF COMPILE OVER COMPILE = COMPILE ?BRANCH HERE 0 , COMPILE DROP ; IMMEDIATE
: ENDOF COMPILE BRANCH HERE 0 , SWAP HERE SWAP ! ; IMMEDIATE
: ENDCASE COMPILE DROP BEGIN DUP TRUE <> WHILE
HERE SWAP ! REPEAT DROP ; IMMEDIATE
: TEST CASE 1 OF ." ONE" ENDOF 2 OF ." TWO" ENDOF ." OTHER" ENDCASE ;
確認すると、
SEE TEST
: TEST 1 OVER = ?BRANCH 14 DROP (.") ONE BRANCH 34 2 OVER = ?BRANCH 14
DROP (.") TWO BRANCH 12 (.") OTHER DROP ;
このままでも使えるが、F83らしく
HERE 0 , => >MARK
HERE SWAP ! => >RESOLVE
とすると、
: CASE TRUE ; IMMEDIATE
: OF COMPILE OVER COMPILE = COMPILE ?BRANCH >MARK COMPILE DROP ; IMMEDIATE
: ENDOF COMPILE BRANCH >MARK SWAP >RESOLVE ; IMMEDIATE
: ENDCASE COMPILE DROP BEGIN DUP TRUE <> WHILE
>RESOLVE REPEAT DROP ; IMMEDIATE
さらにチェック用のフラグを入れると
: CASE TRUE ; IMMEDIATE
: OF COMPILE OVER COMPILE = COMPILE ?BRANCH ?>MARK COMPILE DROP ; IMMEDIATE
: ENDOF COMPILE BRANCH ?>MARK 2SWAP ?>RESOLVE ; IMMEDIATE
: ENDCASE COMPILE DROP BEGIN DUP TRUE <> WHILE
?>RESOLVE REPEAT DROP ; IMMEDIATE
https://forth-standard.org/standard/core/CASE にある
テストで動くことが確認出来た。
: cs1 CASE 1 OF 111 ENDOF
2 OF 222 ENDOF
3 OF 333 ENDOF
>R 999 R>
ENDCASE
;
1 cs1 . 111 ok
2 cs1 . 222 ok
3 cs1 . 333 ok
4 cs1 . 999 ok
: cs2 >R CASE
-1 OF CASE R@ 1 OF 100 ENDOF
2 OF 200 ENDOF
>R -300 R>
ENDCASE
ENDOF
-2 OF CASE R@ 1 OF -99 ENDOF
>R -199 R>
ENDCASE
ENDOF
>R 299 R>
ENDCASE R> DROP ;
-1 1 cs2 . 100 ok
-1 2 cs2 . 200 ok
-1 3 cs2 . -300 ok
-2 1 cs2 . -99 ok
-2 2 cs2 . -199 ok
0 2 cs2 . 299 ok
注意
CASEワードを自分で書くまで気づかなかったが、ForthのCASEには微妙な点がある。
CASE 条件1 OF ワード1 ENDOF
条件2 OF ワード2 ENDOF
ワード3
ENDCASE
条件1、条件2に合致しない場合は、ワード3が実行される。ところがスタックトップの値は残ったままになり、
ENDCASE で DROP される。このためワード3でスタックに値を積んで残すには工夫が必要になる。
cs1の定義の以下の部分がそれに相当する。
>R 999 R>
FORTH DIMENSIONS II/3 の CASE Contest (Dr. Charles E. Eaker) を参考に
このような定義の場合、
: TEST
CASE
1 OF ." ONE" ENDOF
2 OF ." TWO" ENDOF
." OTHER"
ENDCASE ;
以下のようになってほしい
: TEST 1 OVER = ?BRANCH x1 DROP (.") ONE BRANCH x3
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^
CASE OF ENDOF
2 OVER = ?BRANCH x2 DROP (.") TWO BRANCH x3 (.") OTHER DROP ;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^
OF ENDOF ENDCASE
こうするためには、
CASE =>
OF => COMPILE OVER COMPILE = COMPILE ?BRANCH HERE 0 , COMPILE DROP
ENDOF => COMPILE BRANCH HERE 0 , SWAP HERE !
ENDCASE => HERE SWAP ! をすべてのOFに対して繰り返す
すべてのOFに対して繰り返すのは、回数が未定のためCASEで
フラグ(TRUE)を積んで置くことにする。
これらを考慮すると
: CASE TRUE ; IMMEDIATE
: OF COMPILE OVER COMPILE = COMPILE ?BRANCH HERE 0 , COMPILE DROP ; IMMEDIATE
: ENDOF COMPILE BRANCH HERE 0 , SWAP HERE SWAP ! ; IMMEDIATE
: ENDCASE COMPILE DROP BEGIN DUP TRUE <> WHILE
HERE SWAP ! REPEAT DROP ; IMMEDIATE
: TEST CASE 1 OF ." ONE" ENDOF 2 OF ." TWO" ENDOF ." OTHER" ENDCASE ;
確認すると、
SEE TEST
: TEST 1 OVER = ?BRANCH 14 DROP (.") ONE BRANCH 34 2 OVER = ?BRANCH 14
DROP (.") TWO BRANCH 12 (.") OTHER DROP ;
このままでも使えるが、F83らしく
HERE 0 , => >MARK
HERE SWAP ! => >RESOLVE
とすると、
: CASE TRUE ; IMMEDIATE
: OF COMPILE OVER COMPILE = COMPILE ?BRANCH >MARK COMPILE DROP ; IMMEDIATE
: ENDOF COMPILE BRANCH >MARK SWAP >RESOLVE ; IMMEDIATE
: ENDCASE COMPILE DROP BEGIN DUP TRUE <> WHILE
>RESOLVE REPEAT DROP ; IMMEDIATE
さらにチェック用のフラグを入れると
: CASE TRUE ; IMMEDIATE
: OF COMPILE OVER COMPILE = COMPILE ?BRANCH ?>MARK COMPILE DROP ; IMMEDIATE
: ENDOF COMPILE BRANCH ?>MARK 2SWAP ?>RESOLVE ; IMMEDIATE
: ENDCASE COMPILE DROP BEGIN DUP TRUE <> WHILE
?>RESOLVE REPEAT DROP ; IMMEDIATE
https://forth-standard.org/standard/core/CASE にある
テストで動くことが確認出来た。
: cs1 CASE 1 OF 111 ENDOF
2 OF 222 ENDOF
3 OF 333 ENDOF
>R 999 R>
ENDCASE
;
1 cs1 . 111 ok
2 cs1 . 222 ok
3 cs1 . 333 ok
4 cs1 . 999 ok
: cs2 >R CASE
-1 OF CASE R@ 1 OF 100 ENDOF
2 OF 200 ENDOF
>R -300 R>
ENDCASE
ENDOF
-2 OF CASE R@ 1 OF -99 ENDOF
>R -199 R>
ENDCASE
ENDOF
>R 299 R>
ENDCASE R> DROP ;
-1 1 cs2 . 100 ok
-1 2 cs2 . 200 ok
-1 3 cs2 . -300 ok
-2 1 cs2 . -99 ok
-2 2 cs2 . -199 ok
0 2 cs2 . 299 ok
注意
CASEワードを自分で書くまで気づかなかったが、ForthのCASEには微妙な点がある。
CASE 条件1 OF ワード1 ENDOF
条件2 OF ワード2 ENDOF
ワード3
ENDCASE
条件1、条件2に合致しない場合は、ワード3が実行される。ところがスタックトップの値は残ったままになり、
ENDCASE で DROP される。このためワード3でスタックに値を積んで残すには工夫が必要になる。
cs1の定義の以下の部分がそれに相当する。
>R 999 R>
※コメント投稿者のブログIDはブログ作成者のみに通知されます