Any programming language gives to the programmer a set of instructions that allow computer programs to make decisions: they are called “control structures”. This section will give you a quick overview on the topic.
One way of forcing programs to jump to a specified locations is to use the GOTO
instruction, followed by a specific target destination. In ugBASIC destinations can be a literal label or a line number. Label markers can consist of names that use any string of letters or numbers, as well as the underscore character (_
), and they must be ended with the colon character :
.
Take a look at this example1):
label: COLOR BORDER YELLOW WAIT 100 MS COLOR BORDER BLACK WAIT 100 MS GOTO label
Like any BASIC, also numbers may be used to identify specific lines, and the program can be commanded to GOTO one of these optional markers, like this:
10 COLOR BORDER YELLOW 20 WAIT 100 MS 30 COLOR BORDER BLACK 40 WAIT 100 MS 50 GOTO 10
Note that line numbers could be different from identification numbers, and labels are much easier to remember and to locate.
Routines can be packaged to perform a specific task, and such routines could be split into smaller set of instructions as “sub-routines”. GOSUB
is another, also if a bit antiquated, command used to perform a jump to a sub-routine. As with GOTO
, there are two alternative targets for a GOSUB
instruction: labels and line numbers. To make sub-routines easier to spot in your program listings, it is good practice to place them at the end of the main
start: GOSUB yellowBorder WAIT 1000 MS GOSUB blackBorder WAIT 1000 MS GOTO start yellowBorder: COLOR BORDER YELLOW RETURN blackBorder: COLOR BORDER BLACK RETURN
When a program execute a GOSUB
instruction, it must be instructed to RETURN
to the main program after the subroutine has been executed. A single GOSUB
statement can be linked to several RETURN
commands, allowing exits from any number of different points in the routine.
x = 0 start: GOSUB incrementX COLOR BORDER x WAIT 500 MS GOTO start incrementX: x = x + 1 IF x > 16 THEN : x = 0 : RETURN : ENDIF RETURN
There is no fixed rule. After the RETURN
, a jump is made back to the instruction immediately after the original GOSUB
.
Normally, you cannot exit from a GOSUB
statement using a standard GOTO
. To avoid this limitation you can use the POP
command:
x = 0 y = 0 start: x = x + 1 COLOR BORDER x + y GOSUB incrementX GOTO start nextCycle: y = y + 1 IF y > 7 THEN : y = 0 : ENDIF GOTO start incrementX: IF x > 7 THEN : POP : x = 0 : GOTO nextCycle : ENDIF RETURN
It removes the return address generated by a GOSUB
, allowing you to leave the subroutine not using a RETURN statement. In the above example, when the color index in x is greater than 7, y is incremented but outside the original subroutine.
The most used command to implement the decision making process is the IF…THEN…ENDIF
structure. It allows simple decisions to be made within a program, so IF
a condition is true THEN
the computer decides to take a particular course of action, up to reach ENDIF
. If the condition is not true, the machine does something else. The list of condition in an IF … THEN … ENDIF
structure can be any list of tests, including the use of AND
and OR
keywords. Another keyword understood is ELSE
. This is the “alternative” choice. Remember that an IF … THEN … ELSE … ENDIF
statement is not limited to a single line so you can build a “structured test”.
x = 0 y = 0 start: IF x > 16 THEN y = 0 ENDIF IF x == 0 THEN y = 1 ENDIF IF y == 1 THEN : x = x + 1 : ELSE : x = x - 1 : ENDIF COLOR BORDER y + x WAIT x * 50 MS GOTO start
In a structured test, each test is set up with an IF
and a THEN
, and ended with a matching ENDIF
. The statements in a structured test are separated by colons on any particular line, as usual, but can extend over any number of lines in your listing, as required.
x = 0 y = 0 start: IF x > 16 THEN y = 0 ELSE IF x == 0 THEN y = 1 ELSE REM does nothing! ENDIF IF y == 1 THEN : x = x + 1 : ELSE : x = x - 1 : ENDIF COLOR BORDER y + x WAIT x * 50 MS GOTO start
Moreover, there is the capability to allow multiple tests to be performed. The keyword is ELSE IF
, and it must be used within a normal IF…ENDIF
statement, and the only rule to remember is that there must be one ELSE
just before the ENDIF
. This sort of test waits for an expression, and if the expression is true, then what comes after it is executed.
About logical decisions, ugBASIC understands the following character symbols, which are used as a form of short-hand function:
==
is used as “equal to” (note the double equals!);<>
is used as “not equal to”;>
is used as “greater than”;<
is used as “less than”;>=
is used as “greater than or equal to”⇐
is used as “less than or equal to”There are also three special functions that can be called during the decision making process:
TRUE
that returns 255;FALSE
that returns 0;NOT
that returns the logical inverse of the given value.
In all the conditional operations such as IF…THEN
and REPEAT…UNTIL
, the value of not zero is used to represent TRUE
, and the value of 0 is used to represent FALSE
. A value of either 255 (TRUE
) or 0 (FALSE
) is produced every time a test is made to satisfy a condition. Instead, NOT
is used to swap over every digit in a binary number from a 0 to a 1, and vice versa. Since 255 (TRUE
) can be expressed in binary as %11111111, then NOT TRUE
must be equal to FALSE
, and a logical NOT
operation is achieved.
ugBASIC offers all of the expected programming short-cuts to allow sections of code to be repeated as often as necessary. These repeated parts of programs are known as “loops”. In particular, loops can be defined using the pair DO…LOOP
, and it will loop a list of statements forever, with DO
acting as the marker
position for the LOOP
to return to.
DO COLOR BORDER YELLOW WAIT 500 MS COLOR BORDER BLACK WAIT 500 MS LOOP
The instruction EXIT
forces the program to leave a loop immediately, and it can be used to escape from all the types of loop, such as FOR … NEXT
, REPEAT … UNTIL
, WHILE … WEND
and DO … LOOP
.
DO COLOR BORDER YELLOW WAIT 500 MS COLOR BORDER BLACK WAIT 500 MS DO COLOR BORDER RED WAIT 1000 MS EXIT REM The border will never be green! COLOR BORDER GREEN WAIT 1000 MS LOOP LOOP
You can nest any number of loops, and when used on its own, EXIT will “short-circuit” the innermost loop only. By including the number after EXIT, that number of nested loops will be taken into account before the EXIT
is made.
DO COLOR BORDER YELLOW WAIT 500 MS COLOR BORDER BLACK WAIT 500 MS DO COLOR BORDER RED WAIT 1000 MS COLOR BORDER GREEN WAIT 1000 MS DO COLOR BORDER RED WAIT 1000 MS EXIT 2 : REM EXIT 2 = skip 1 more loop, because "EXIT" == "EXIT 1"! REM The border will never be green, REM and the secondo loop will be skiped COLOR BORDER GREEN WAIT 1000 MS LOOP LOOP LOOP
In this way, the program will jump directly to the instruction immediately after the relevant loop.
If you need to leave a loop as a result of a specific set of conditions, this can be made by using the EXIT IF
instruction. As explained above, in conditional operations, the value 255 represents TRUE
, whereas a zero
represents FALSE
. After using EXIT IF
, an expression is given which consists of one or more tests. The EXIT
will only be performed IF
the result is found to be 255 (TRUE). As with the command EXIT
, an optional number can be given to specify the number of loops to be jumped from, otherwise only the
current loop will be aborted.
The WHILE…WEND
commands provides a convenient way of making the program repeat a group of instructions all the time a particular condition is true.
For example, this program will show a decrement number from 10 to 1 and restart from 10 again:
DO x = (8BIT) 10 WHILE x > 0 DEBUG x x = x - 1 WEND LOOP
WHILE
marks the start of this loop, and the condition is checked for a value of 255 (TRUE) from this starting position through to the end position, which is marked by a WEND
. The condition is then checked again at every turn of the loop, until it is no longer true. You are, obviously, free to use AND
, OR
and NOT
to qualify the conditions to be checked.
DO x = (8BIT) 10 REPEAT DEBUG x x = x - 1 UNTIL x == 0 LOOP
Instead of checking if a condition is true or false at the start of a loop, REPEAT…UNTIL
makes its check at the end of a loop. REPEAT
marks the start and UNTIL
the end of the loop to be checked. This means that if a condition is false at the beginning of a WHILE … WEND
structure, that loop will never be performed at all, but if it is true at the beginning of a REPEAT…UNTIL
structure, the loop will be performed at least once.
Control can be made much more definite than relying on whether conditions are true or false. In particular, when deciding how many times a loop is to be repeated, you can use the FOR…NEXT
control structure. For example, this sample program will print numbers from 1 to 100:
i = 0 FOR i = 1 TO 100 DEBUG i NEXT HALT
Each FOR
statement must be matched by a single NEXT
, and pairs of FOR…NEXT
loops can be nested inside one another. Each loop repeats a list of instructions for a specific number of times, governed by an index which counts the number of times the loop is repeated. Once inside the loop, this index can be read by the program as if it is a normal variable.
i = 0 : j = 0 FOR i = 1 TO 100 FOR j = 1 TO 5 DEBUG i * j NEXT NEXT HALT
Normally, the index counter is increased by 1 unit at every turn of a FOR…NEXT
loop. When the current value
exceeds that of the last number specified, the loop is terminated. STEP
is used to change the size of increase in the index value.
Jumps can be made whenever a particular variable is recognised, in other words, regardless of any other conditions. GOTO
and GOSUB
are examples of a “forced” jump. ON
can be used to force the program to jump to a pre-defined position when it recognises a specified variable and against a choice of several positions, depending on what value is held by the variable at the time it is spotted.
For example, this program will print repeatly the sequence “1, 2, 3”:
times = 1 start: ON times GOSUB first, second, third times = times + 1 IF times > 3 THEN times = 1 ENDIF GOTO start first: DEBUG 1 RETURN second: DEBUG 2 RETURN third: DEBUG 3 RETURN
ON
can force a unconditional jump (GOTO
) or with returning (GOSUB
). To work properly, the expression must have a value from 1 up to the number of the highest possible destination. If the expression has a value of 0 or greater than the highest possibile destination, no jump will be performed.
Take this example:
IF level==1 THEN GOTO level1 IF level==2 THEN GOTO level2 IF level==2 THEN GOTO level3
Can be rewritten as:
ON level GOTO level1, level2, level3
The use of an ON GOSUB
structure is identical to ON … GOTO
, except that it must employ a RETURN
(or a POP
!) to jump back to the instruction immediately after the ON … GOSUB
statement. Destinations may be given as the name of a label, or the identification number of a line between 1 and the maximum number of possible destinations.
The EVERY
statement is used to call up a sub-routine or a procedure at regular intervals, without interfering with the main program. By specifying the length of time between every call, measured in TICKS
, you can call a sub-routine.
colorIndex = 0 EVERY 50 TICKS GOSUB changeBorderColor EVERY ON HALT changeBorderColor: COLOR BORDER colorIndex colorIndex = colorIndex + 1 IF colorIndex > 16 THEN colorIndex = 0 ENDIF EVERY ON RETURN
Note that the sub execution time should be less than the interval time, or the main program timings will be affected. After a sub-routine has been entered, the EVERY
system is automatically disabled. This means that, in order to call this feature continuously, an EVERY ON
command must be inserted into a sub-routine before the final RETURN
statement.
So, EVERY ON
should be used before the relevant sub-routine has finished executing, while EVERY OFF
is the default condition, and is used to disable the automatic calling process altogether.