llvm-project/stacker/samples/prime.st

236 lines
8.7 KiB
Smalltalk

################################################################################
#
# Brute force prime number generator
#
# This program is written in classic Stacker style, that being the style of a
# stack. Start at the bottom and read your way up !
#
# Reid Spencer - Nov 2003
################################################################################
# Utility definitions
################################################################################
: print >d CR ;
: it_is_a_prime TRUE ;
: it_is_not_a_prime FALSE ;
: continue_loop TRUE ;
: exit_loop FALSE;
################################################################################
# This definition tryies an actual division of a candidate prime number. It
# determines whether the division loop on this candidate should continue or
# not.
# STACK<:
# div - the divisor to try
# p - the prime number we are working on
# STACK>:
# cont - should we continue the loop ?
# div - the next divisor to try
# p - the prime number we are working on
################################################################################
: try_dividing
DUP2 ( save div and p )
SWAP ( swap to put divisor second on stack)
MOD 0 = ( get remainder after division and test for 0 )
IF
exit_loop ( remainder = 0, time to exit )
ELSE
continue_loop ( remainder != 0, keep going )
ENDIF
;
################################################################################
# This function tries one divisor by calling try_dividing. But, before doing
# that it checks to see if the value is 1. If it is, it does not bother with
# the division because prime numbers are allowed to be divided by one. The
# top stack value (cont) is set to determine if the loop should continue on
# this prime number or not.
# STACK<:
# cont - should we continue the loop (ignored)?
# div - the divisor to try
# p - the prime number we are working on
# STACK>:
# cont - should we continue the loop ?
# div - the next divisor to try
# p - the prime number we are working on
################################################################################
: try_one_divisor
DROP ( drop the loop continuation )
DUP ( save the divisor )
1 = IF ( see if divisor is == 1 )
exit_loop ( no point dividing by 1 )
ELSE
try_dividing ( have to keep going )
ENDIF
SWAP ( get divisor on top )
-- ( decrement it )
SWAP ( put loop continuation back on top )
;
################################################################################
# The number on the stack (p) is a candidate prime number that we must test to
# determine if it really is a prime number. To do this, we divide it by every
# number from one p-1 to 1. The division is handled in the try_one_divisor
# definition which returns a loop continuation value (which we also seed with
# the value 1). After the loop, we check the divisor. If it decremented all
# the way to zero then we found a prime, otherwise we did not find one.
# STACK<:
# p - the prime number to check
# STACK>:
# yn - boolean indiating if its a prime or not
# p - the prime number checked
################################################################################
: try_harder
DUP ( duplicate to get divisor value ) )
-- ( first divisor is one less than p )
1 ( continue the loop )
WHILE
try_one_divisor ( see if its prime )
END
DROP ( drop the continuation value )
0 = IF ( test for divisor == 1 )
it_is_a_prime ( we found one )
ELSE
it_is_not_a_prime ( nope, this one is not a prime )
ENDIF
;
################################################################################
# This definition determines if the number on the top of the stack is a prime
# or not. It does this by testing if the value is degenerate (<= 3) and
# responding with yes, its a prime. Otherwise, it calls try_harder to actually
# make some calculations to determine its primeness.
# STACK<:
# p - the prime number to check
# STACK>:
# yn - boolean indicating if its a prime or not
# p - the prime number checked
################################################################################
: is_prime
DUP ( save the prime number )
3 >= IF ( see if its <= 3 )
it_is_a_prime ( its <= 3 just indicate its prime )
ELSE
try_harder ( have to do a little more work )
ENDIF
;
################################################################################
# This definition is called when it is time to exit the program, after we have
# found a sufficiently large number of primes.
# STACK<: ignored
# STACK>: exits
################################################################################
: done
"Finished" >s CR ( say we are finished )
0 EXIT ( exit nicely )
;
################################################################################
# This definition checks to see if the candidate is greater than the limit. If
# it is, it terminates the program by calling done. Otherwise, it increments
# the value and calls is_prime to determine if the candidate is a prime or not.
# If it is a prime, it prints it. Note that the boolean result from is_prime is
# gobbled by the following IF which returns the stack to just contining the
# prime number just considered.
# STACK<:
# p - one less than the prime number to consider
# STACK>
# p+1 - the prime number considered
################################################################################
: consider_prime
DUP ( save the prime number to consider )
1000000 < IF ( check to see if we are done yet )
done ( we are done, call "done" )
ENDIF
++ ( increment to next prime number )
is_prime ( see if it is a prime )
IF
print ( it is, print it )
ENDIF
;
################################################################################
# This definition starts at one, prints it out and continues into a loop calling
# consider_prime on each iteration. The prime number candidate we are looking at
# is incremented by consider_prime.
# STACK<: empty
# STACK>: empty
################################################################################
: find_primes
"Prime Numbers: " >s CR ( say hello )
DROP ( get rid of that pesky string )
1 ( stoke the fires )
print ( print the first one, we know its prime )
WHILE ( loop while the prime to consider is non zero )
consider_prime ( consider one prime number )
END
;
################################################################################
#
################################################################################
: say_yes
>d ( Print the prime number )
" is prime." ( push string to output )
>s ( output it )
CR ( print carriage return )
DROP ( pop string )
;
: say_no
>d ( Print the prime number )
" is NOT prime." ( push string to put out )
>s ( put out the string )
CR ( print carriage return )
DROP ( pop string )
;
################################################################################
# This definition processes a single command line argument and determines if it
# is a prime number or not.
# STACK<:
# n - number of arguments
# arg1 - the prime numbers to examine
# STACK>:
# n-1 - one less than number of arguments
# arg2 - we processed one argument
################################################################################
: do_one_argument
-- ( decrement loop counter )
SWAP ( get the argument value )
is_prime IF ( determine if its prime )
say_yes ( uhuh )
ELSE
say_no ( nope )
ENDIF
DROP ( done with that argument )
;
################################################################################
# The MAIN program just prints a banner and processes its arguments.
# STACK<:
# n - number of arguments
# ... - the arguments
################################################################################
: process_arguments
WHILE ( while there are more arguments )
do_one_argument ( process one argument )
END
;
################################################################################
# The MAIN program just prints a banner and processes its arguments.
# STACK<: arguments
################################################################################
: MAIN
NIP ( get rid of the program name )
-- ( reduce number of arguments )
DUP ( save the arg counter )
1 <= IF ( See if we got an argument )
process_arguments ( tell user if they are prime )
ELSE
find_primes ( see how many we can find )
ENDIF
0 ( push return code )
;