Path: utzoo!censor!geac!torsqnt!news-server.csri.toronto.edu!bonnie.concordia.ca!thunder.mcrcim.mcgill.edu!snorkelwacker.mit.edu!usc!wuarchive!zaphod.mps.ohio-state.edu!unix.cis.pitt.edu!pitt!willett!ForthNet From: ForthNet@willett.pgh.pa.us (ForthNet articles from GEnie) Newsgroups: comp.lang.forth Subject: CASE Message-ID: <2303.UUL1.3#5129@willett.pgh.pa.us> Date: 4 Feb 91 12:35:38 GMT Organization: (n.) to be organized. But that's not important right now. Lines: 98 Category 10, Topic 9 Message 16 Sun Feb 03, 1991 W.BADEN1 [Wil] at 13:21 PST Here is one of the many ways to portably implement the Eaker CASE statement without using control flow extension words. It does not matter what the control flow stack is, but structures must be properly nested. VARIABLE Cases : CASE Cases @ ( oldCases) 0 Cases ! ; IMMEDIATE : CASE? ( N1 n2 -- true, or N1 false) OVER = DUP IF NIP THEN ; : OF COMPILE CASE? [COMPILE] IF 1 Cases +! ; IMMEDIATE : ENDOF [COMPILE] ELSE ; IMMEDIATE : ENDCASE Cases @ 0= ABORT" No cases." COMPILE DROP Cases @ 0 DO [COMPILE] THEN LOOP Cases ! ; IMMEDIATE Alternatively OF could be expanded in full. : OF COMPILE OVER COMPILE = [COMPILE] IF COMPILE DROP 1 Cases +! ; IMMEDIATE When I first became involved with Forth a dozen years ago I could not understand why Forth does not have a case statement, since all the profane languages do. With experience there came the understanding why a case structure is superfluous in Forth. A case structure takes a single value and makes a series of tests for equality. Without a case statement a profane language would have to specify or evaluate the subject of the test for each test explicitly. In Forth this can be done with DUP or OVER. An even worse "defect" was the lack of ELSIF for a series of tests. With more than two alternatives nesting of IFs becomes intolerable. Eventually I appreciated good Forth coding style, which factors complexity. Any series of tests worthy of ELSIF deserves its own definition. ( "Thirty days hath September,....") : days ( Month -- days) : days ( Month -- days) CASE Sep CASE? IF 30 EXIT THEN Sep OF 30 ENDOF Apr CASE? IF 30 EXIT THEN Apr OF 30 ENDOF Jun CASE? IF 30 EXIT THEN Jun OF 30 ENDOF Nov CASE? IF 30 EXIT THEN Nov OF 30 ENDOF Feb CASE? IF Feb OF Year @ 4 MOD IF 28 ELSE 29 THEN Year @ 4 MOD IF 28 ELSE 29 THEN EXIT THEN ENDOF DROP 31 ; 31 SWAP ENDCASE ; : Craps : Craps Dice ( Point) CR DUP . Dice ( Point) CR DUP . CASE 2 CASE? IF Lose EXIT THEN 2 OF Lose ENDOF 3 CASE? IF Lose EXIT THEN 3 OF Lose ENDOF 7 CASE? IF Win EXIT THEN 7 OF Win ENDOF 11 CASE? IF Win EXIT THEN 11 OF Win ENDOF 12 CASE? IF Lose EXIT THEN 12 OF Lose ENDOF BEGIN ( Point) BEGIN ( Point) Dice ( Point throw) DUP . Dice ( Point throw) DUP . 7 CASE? IF DROP Lose EXIT THEN 7 CASE? IF DROP Lose EXIT THEN CASE? CASE? UNTIL ( ) Win ; UNTIL ( ) Win ENDCASE ; The CASE statement takes fewer words and more lines. It is also constrictive. If you want to extend the tests you can make then you have to make more and more special-case CASE-definitions. The classical Forth CASE? is just enough semantic sugar, but if you think even this is too sweet, "foo CASE? IF" could be replaced by "DUP foo = IF DROP". A range can be done "DUP first limit WITHIN IF DROP". Drop DROP if the value is needed. Here is some more semantic sugar. : ANDIF COMPILE DUP [COMPILE] IF [COMPILE] DROP ; IMMEDIATE : ORIF COMPILE DUP COMPILE 0= [COMPILE] IF [COMPILE] DROP ; IMMEDIATE : days ( Month -- days) Sep CASE? ORIF Apr CASE? ORIF Jun CASE? ORIF Nov THEN THEN THEN IF 30 EXIT THEN Feb CASE? (and the rest as before) : Craps 2 CASE? ORIF 3 CASE? ORIF 12 CASE? THEN THEN IF Lose EXIT THEN 7 CASE? ORIF 11 CASE? THEN IF Win EXIT THEN BEGIN ( and the rest as before.) ----- This message came from GEnie via willett. You cannot Reply to the author using email. Please post a follow-up article, or use any instructions the author may have included (USMail addresses, telephone #, whatever). Report problems to: dwp@willett.pgh.pa.us or uunet!willett!dwp