Post by Gnarlodioushttp://www.99-bottles-of-beer.net/f.html#Forth
Cute, but buggy.
Try
1 .bottles .s
oops! Nothing on the stack for the end of loop check in nbottles, so
make this change to avoid the underflow:
." Pass it around," CR
1-
\ ?dup \ WRONG !!!
dup \ RIGHT
IF
But its still not quite right. To see it fail, try:
0 nbottles ( or pass a negative # bottles)
Oops, that isn't what should result
So, we could make this change:
: nbottles ( n -- )
\ BEGIN .bottles ?dup NOT UNTIL
BEGIN .bottles dup 0> not UNTIL drop
Now it doesn't infinite loop, but 0 nbottles gives this respose:
0 bottles of beer on the wall,
0 bottles of beer,
Take one down,
Pass it around,
-1 bottles of beer on the wall;
Which isn't right either.
I decided it wasn't well factored:
.BOTTLES was displaying the initial state, decrementing the #bottles,
then redisplaying. This is what was mishandling "0 nbottles".
I decided to start over and after a few variants, I decided I like this
one:
\ 99 BOTTLES OF BEER REDUX
: ShowNumberBottles ( n -- )
dup 0 >
IF
dup 1 =
IF
drop
." One bottle"
ELSE
. ." bottles"
THEN
ELSE
drop
." No more bottles"
THEN
." of beer"
;
: DrinkAnotherBottle ( n -- n' )
\ also finishes displaying the stanza
\ dup 0 > \ we can skip this, if we KNOW that n will be positive
\ IF
cr dup ShowNumberBottles [char] , emit
cr ." Take "
dup 1 > IF ." one" ELSE ." it" THEN
." down, Pass it around,"
1- \ decrement N
cr dup ShowNumberBottles ." on the wall."
\ THEN
;
: ShowFirstLine ( n -- )
cr ShowNumberBottles ." on the wall"
;
: DRINK ( n -- )
BEGIN
dup 0 >
WHILE
cr
dup ShowFirstLine [char] , emit
DrinkAnotherBottle
REPEAT
drop
." :("
;
: DRUNK ( -- ) \ the way WE used to sing it
BEGIN
99 drink
cr
0 ShowFirstLine ." :("
0 ShowFirstLine ." :("
cr ." Let's get up and order some more!"
cr
99 ShowFirstLine ." :)"
cr cr
AGAIN
;
99 DRINK