NEW OWNERS COLUMN
Lesson 6: Subroutines
by DAVID PLOTKIN, Antic Contributing Editor
This series, which started in the March, 1986 issue, teaches beginners how to program in BSSIC on all Atari 8-bit computers such as the 800XL and 130XE. Antic Contributing Editor David Plotkin is a chemical engineer.
Up to this point, all our programming examples have RUN in the order shown by their line numbers. Line number 10 will execute before line number 20, and so on. When you use the LIST command to put the program on the screen, the order in which the lines are displayed is also the order in which the program will execute.
Sometimes, however it is advantageous to "skip around" a program, executing statements in a different order than the line numbers specify. For example, you might need to execute different groups of statements based on a condition in the program. This is often tested for by an IF/THEN Statement.
Skipping around is also useful when you need to execute the same set of statements many times from different parts of the main program because these statements do something particularly useful.
The technical name for "skipping around" in a program is branching. Two commands enable you to branch from one section of a program to another: the GOTO command and the GOSUB/RETURN command. The GOTO command will be discussed next month.
When you need to execute the same task many times from different places in your program, you have two choices. The first is to put the section of BASIC lines that performs the task everywhere you need it. The alternative is to use a subroutine. A subroutine is a module (part) of a BASIC program that can be accessed from anywhere in the program.
Before branching to your subroutine, your Atari makes a note of its current place in your program. Once the subroutine is complete, your Atari refers back to this note and returns to the proper place in your program. This process is like marking your place with a bookmark before flipping ahead to read another chapter. Every time your program processes a GOSUB, it adds another entry into its list of "bookmarks." Every time your program processes a RETURN, it jumps back to the corresponding GOSUB statement and removes it from its list.
Subroutines are extremely useful, and calling and defining subroutines is quite easy. To call a subroutine, you use the format GOSUB line number. Thus, to call a subroutine beginning at line 100, you would type GOSUB 100. The subroutine itself can be anywhere in the program. But it must end with a RETURN statement. This causes the program to branch back to the next statement after the GOSUB.
This is shown in the following short example of the use of subroutines to compute the square and square root of a number:
10 DIM ANSWR$(1)
20 PRINT "WHAT NUMBER ":INPUT A:GOSUB 100
30 PRINT "THE SQUARE OF THE NUMBER IS ";X
40 GOSUB 200:PRINT "SQUARE ROOT OF THE NUMBER IS ";Y
50 A=Y:GOSUB 200:PRINT FOURTH ROOT OF THE NUMBER IS ";Y
60 PRINT "ANOTHER NUMBER (Y OR N)": INPUT ANSWER$
70 IF ANSWR$="Y" THEN GOSUB 20
100 X=A*A:REM SQUARE SUBROUTINE
200 Y=SQR(A):REM SQUARE ROOT SUBROUTINE
Note that when you GOSUB 100 in line 20, the RETURN at line 110 branches back to the next statement after the GOSUB, which is the first statement in line 30. When you GOSUB 200 in line 40, the RETURN at line 210 branches back to the next statement after the GOSUB which is still on line 40. The program remembers the location of the GOSUB statement that called the subroutine.
Subroutines are usually grouped at the end of the program's main body. Normally this makes the program easier to read and use. However, sometimes you don't want to place suhroutines at the end of the program. In the example above, the END statement at line 90 is also important. It separates the main program from the subroutines. If you answer N to the question at line 70, then the program will not branch back to line 20. Instead it will "fall through" to line 90 and stop. If line 90 wasn't there, the program would enter the subroutine at line 100. An error would occur when the RETURN at line 120 is encountered, since the program doesn't know where to RETURN to.
A powerful variation of GOSUB is the ON GOSUB command. This command branches to one of the line numbers, in a list of line numbers, based on the value of a variable or expression:
10 ON A GOSUB 100,200,300,400,100,100
The variable A must evaluate to an integer. The statement above will GOSUB line 100 if A= 1, line 200 if A = 2, line 300 if A = 3, and so on. The portion of the statement between ON and GOSUB may be a simple variable (such as an A) or it may be a complex expression such as INT(A*2).
The list of line numbers following GOSUB should have as many elements as there are possible values of the variable or expression. Note that the same line number can be used several times if you want the program to GOSUB the same place for several different values of the variable or expression.
If the variable or expression has a value exceeding the number of line numbers listed, the ON GOSUB statement will be ignored. And even if the variable or expression will never have certain values within a series, you must still include line numbers for those values. For example, suppose A could be 2,4 or 6:
10 ON A GOSUB 10,100,10,200,10,300
This statement will branch to lines :100, 200 or 300 based on A having the values of 2, 4, or 6. But notice that numerical "place holders" for A equal to 1, 3 or 5 must still be used, even though you will never execute those branches. Here I have used 10 as a "dummy" line number--the line number of the ON GOSUB statement itself works just fine. If A ever equals 7 or more, this whole statement will be ignored.
10 GRAPHICS 0:PRINT :PRINT
20 PRINT "TYPE A NUMBER BETWEEN 5 AND 10, THEN PRESS RETURN"
30 INPUT A:IF A,5 THEN PRINT "NAUGHTY NAUGHTY!":GOSUB 20
40 ON INT(A)-4 GOSUB 100,110,120,130,140,150
50 PRINT "A IS GREATER THEN 10!":GOSUB 20
100 PRINT "A=5":GOSUB 20
110 PRINT "A=6":GOSUB 20
120 PRINT "A=7":GOSUB 20
130 PRINT "A=8":GOSUB 20
140 PRINT "A=9":GOSUB 20
150 PRINT "A=10":GOSUB 20
The above demo program shows the power of the ON GOSUB command. Obviously each of the lines that the program GOSUBs to could be the beginning of a whole block of statements. A prime example of ON GOSUB would be making a choice from a menu.
As explained earlier, subroutines can be called from anywhere in the program. In fact, a subroutine may even call itself. This is a powerful technique known as recursion. Unfortunately, this technique also uses plenty of memory. Every time a subroutine calls itself, it adds another "bookmark" entry to the list of places it must return to when complete. Each bookmark represents another level of recursion. If the size of this list exceeds the memory capacity of your computer, your program will crash.
Recursion can be a difficult concept to understand, so examine this month's listing carefully, especially line 1000. Line 1000 is the first line of a subroutine which GOSUBs to itself. That is, the subroutine beginning at line 1000 calls itself over and over again.
The program is very short, but it demonstrates GOSUB in quite an interesting way. It fills any closed shape with color.
Type in listing 1, NEWOWN6.BAS, check it with TYPO II and SAVE a copy before you RUN it. When RUN, the program draws a closed shape on your screen. Press the [START] key and a small dot will begin filling in the shape. The plotting routines are in a recursive subroutine beginning at line 1000.
A line of text at the bottom of the screen tells you how many times this routine has called itself (which recursion it is working on) and whether the computer is beginning a new level of recursion, or RETURNing from a previous level. If you plug a joystick into port one, you may draw your own shapes for filling. Move the blinking-dot cursor with the joystick while pressing the joystick button. Erase by moving the cursor without holding the button down. Then place the cursor anywhere inside the shape and press the [START] key.
Line 10 sets up the arrays and colors. Line 15 draws a border in blue around the outside of the screen. Lines 20 through 50 allow you to use your joystick to draw a shape on the screen. The PEEK(53279) statement in line 40 reads the console keys. When the [START] key is being held down, this value will be 6. The main subroutine, beginning at line 1000, won't RETURN to line 210 until the shape is completely filled with color. Basically, the subroutine works by using, the LOCATE command to examine a dot on the screen and filling each dot with color (if it isn't already filled).
The subroutine calls itself each time it discovers a point which hasn't been filled. It's fascinating to watch the shape being filled in on the screen. There will be long periods of time, both before and after the shape is completely filled, when nothing appears to be happening on the screen. The subroutine may have been called several hundred times, and it can take awhile for the program to execute that many RETURNs! Just be patient, and watch the text window telling you what the computer is doing.