Kevin Doyle
There are three main types of structure available in AMPLE:
a) Loops;
b) Conditionals;
c) Conditional loops.
b) Conditionals;
c) Conditional loops.
I am examining each of these in turn over the first few
issues of AMPLINEX and giving examples of their use. In this issue I will look
at conditional loops.
Conditional loops in AMPLE
In the first of these three articles I looked at simple
loops using the FOR(...)FOR structure. This allowed any AMPLE expression to be
performed a specified number of times. In many cases, however, the AMPLE
programmer may not want to specify the number of times the loop is to be
performed. For instance, in the early stages of composition it may be desirable
to play a repeating rhythm or bass line whilst trying different melodic lines on
another voice. In such cases the number of loops is not known in advance.
What is needed is an unlimited 'infinite' loop, to play the
rhythm or bassline as long as required.
To do this the REP(...)REP structure can be used. The AMPLE
expression between the two brackets is then repeated until the program is
stopped. So, to repeat a simple bass line the following word might be created:
"part1" [ % repeating bass line
REP( 48, -1: GGeeccDD )REP]
REP( 48, -1: GGeeccDD )REP]
which will continue until the ESCAPE key is pressed.
The REP(...)REP structure can also be given a conditional
section to allow exit from the loop.
This conditional loop uses a REP(...)UNTIL(...)REP
structure. The contents of the AMPLE expressions between the brackets is rather
more complex than with the conditionals discussed in the second article. This is
because the expression to be performed and the expression to be evaluated as ON
(true) or OFF (false) are both held within the structure and the expression to
be performed can be within either or both sets of brackets.
The form of the conditional loop can be described in more
detail as:
REP( action1 test )UNTIL( action2
)REP
where the presence of action1 and action2 is optional.
As with all the structures in AMPLE the action expressions
could be empty in which case the loop would merely serve a 'pausing' function.
For example, to provide a pause for a keypress the following
word could be defined:
"spacewait" [ % wait for space bar
"Press the space bar to continue" $OUT
REP( #IN 32 #= )UNTIL( )REP ]
"Press the space bar to continue" $OUT
REP( #IN 32 #= )UNTIL( )REP ]
which will print the message and wait for a keypress, test
if it equals 32 (i.e. a space) and then end if it does or wait for another
keypress if it doesn't.
Any expression placed before the test in the first set of
brackets will be performed at least once. So, to return to the earlier example
of a repeating bass line the structure could be changed so that the loop
repeats until the CTRL key is pressed:
"part1" [ % repeat bass line until
% CTRL key is pressed
REP( 48, -1: GGeeccDD
-2 QKEY )UNTIL( )REP ]
% CTRL key is pressed
REP( 48, -1: GGeeccDD
-2 QKEY )UNTIL( )REP ]
where -2 is the code for the CTRL key (see BBC User Guide
entry for BASIC word INKEY) and QKEY returns a ON if this key is being pressed
or OFF if not.
Because the key is only checked after each performance of
the bass line the CTRL key may have to pressed for a few seconds to cause the
loop to end.
As mentioned earlier, there is the opportunity with
conditional loops to have an AMPLE expression in the second part of the
structure, between the UNTIL(...)REP brackets. Any expression contained in this
part of the structure is performed whenever the result of the test preceding
the )UNTIL( is false. This can be useful when, for example, a simple error routine
needs to be incorporated into an input loop.
So, a word could be defined to accept a number from the
keyboard in the range 1-8 giving a beep if is outside this range:
"getnum" [ % get a number from 1 to 8
"Enter a number (1-8): " $OUT
REP( #IN #11 48 #> #12 57 #< AND
)UNTIL( 7#OUT )REP ]
"Enter a number (1-8): " $OUT
REP( #IN #11 48 #> #12 57 #< AND
)UNTIL( 7#OUT )REP ]
After printing the message, the loop waits for a keypress, tests
that it is greater than 0 (ASCII 48) and less than 9 (ASCII 57). If it is
within these limits the loop ends. If not then the second part of the structure
is performed, sounding a beep, and the loop starts again.
Structures in AMPLE - final points
In these articles I have discussed three types of AMPLE
structure:
1) Loops
FOR(...)FOR
2) Conditionals
IF(...)ELSE(...)IF;
3) Conditional loops
REP(...)UNTIL(...)REP.
Each of these can only be used within words and not as
commands entered at the '%' prompt.
When constructing complex, nested, structures the error '!
Bad structure' may occur. If this happens check carefully through the
definition to ensure that each structure is properly completed. Check that each
start word such as FOR(, IF(, and REP( has a matching finishing word of )FOR,
)IF and )REP and that no structures overlap thus:
REP(... FOR( ... )REP ...)FOR
Other errors associated with AMPLE structures are:
! Too many levels - this can occur
if a large number of nested FOR loops is used.
! Too many numbers - this can occur
if a loop is leaving an extra number each time round.
! Too many strings - this can occur
if a loop is leaving an extra string each time round.
This is the last of the three articles on structures in
AMPLE. If you have found these articles of use you may wish to suggest other
areas of AMPLE programming which you would like to see discussed in AMPLINEX.
Please send any suggestions via Feedback for the next issue.
Published in AMPLINEX 003, January 1988