In part ten of this series, David Matthewman looks at embedding data in a program and tackles the subject of line numbers.
Programmers often wish to include long lists of data in their programs. For example, if you were trying to plot a complicated shape on the screen, the program would need to know the coordinates of all the points to be plotted.
One way of doing this would be to use an array, as described in the January issue. This involves having a long list of lines setting up the values of the individual elements of the array, as follows:
coordinate(1,1) = 100 coordinate(1,2) = 100 coordinate(2,1) = 0 coordinate(2,2) = 100 coordinate(3,1) = 0 coordinate(3,2) = 0 coordinate(4,1) = 100 coordinate(4,2) = 0
which will set up a 100 by 100 square.
This gets very tedious to type in and can also occupy a lot of unnecessary space. It would be very simple to set up a loop to cycle through values in the array, so what we need is some way of storing the coordinates and reading them one by one. Basic provides two commands for doing just this, DATA and READ.
A DATA statement, like a REM statement, is ignored if Basic tries to execute one when running the program. Its purpose is to mark the position of a block of data within the program.
DATA statements are followed by a list of data; this list can have many forms, a string, a number, even a numeric expression. A READ statement is followed by a list of variables. When Basic executes a READ statement it copies the data after the DATA statement to the variables after the READ statement.
The data is read, starting from the first DATA statement in the program, with following READs working through the next DATA statements in order.
A READ statement may access the same DATA statement several times and values for one READ statement may also be split across two DATA statements.
The following program shows how we could read the 100 by 100 square into an array using DATA statements:
FOR i%=1 TO 4 FOR y%=1 TO 2 READ coordinate(i%,j%) NEXT i% NEXT j% : DATA 100,100,0,100 DATA 0,0,100,0
As you can see, this can easily be changed to read any number of coordinates, simply by adding more DATA statements and increasing the number of times the outer loop is executed.
In the example above, the loop read eight items of data, which was the same number as we provided in the DATA statements. More would have been ignored, but if we had provided fewer the program would have stopped with an 'Out of data' error.
This is easy to avoid if we know in advance how many data-values we want to read, but what if this is not the case?
The easiest way to avoid running off the end of a list of data is to make the last data set have some predetermined value.
Usually this value is one that would not occur normally in the data, such as coordinates of (-999,-999) or a string "This is the end", otherwise the program might accidentally finish reading the list early.
Listing 1 puts all this into practice by writing a simple program which tests knowledge of the symbols of some of the chemical elements. As we may want to add other elements to the list we have a data value which signals the end of the list.
REM >Listing1 REM Here, we test knowledge of the symbols for elements. score%=0:total%=0 READ element$,symbol$ WHILE element$<>"End" PRINT "What is the chemical symbol for ";element$;"?"; INPUT " "answer$ IF answer <> symbol$ THEN PRINT "Wrong, it is ";symbol$;"."' ELSE PRINT "Correct."' score%=score%+1 ENDIF total%=total%+1 READ element$,symbol$ ENDWHILE PRINT "You scored ";score%;" out of ";total%;"." DATA Hydrogen, H, Oxygen, O, Sulphur, S DATA Calcium, Ca, Aluminium, Al, Magnesium DATA Mg, Copper, Cu, Zinc, Zn, Lead, Pb DATA Tungsten, W, End, E END
In this case we stop when we read the string 'End'. Note that we need to invent a symbol for this string, otherwise we will get an 'Out of data' error.
By using a WHILE - ENDWHILE loop we ensure that the program does not enter the loop at all if there are no elements to be read. This also explains the READ statement on line five outside the loop; if this reads an 'End' string the loop is never entered.
Assuming that there are some elements in the list of data, the program repeatedly reads them with the READ statement on line 16, leaving the loop when it reads the string 'End'. It then prints out the user's score, runs straight through the four DATA statements on lines 19-22 which it ignores, and ends normally.
If we need to read the data again, perhaps because we want the user to keep taking the test until all the answers are correct, we can use the RESTORE command.
RESTORE on its own ensures that the next READ statement will read values from the first DATA statement in the program, but it can also be used to jump directly to a DATA statement later in the program.
This is a subject that we have carefully avoided so far. For the last nine parts of the course we have treated Basic programs as unnumbered lines of text.
When we have referred to 'line 5' we have meant `the fifth line down' rather than 'the line that starts with a "5".' In fact, Basic program lines are numbered.
When we load a Basic program into an editor such as Risc OS 3's Edit, DBEdit, StrongEd or Zap, the editor strips off the line numbers, replacing them when the file is saved. This is normally fine, as neither the programmer nor the program needs to know what the actual line numbers are.
Suppose we have a long list of DATA statements but actually want to get at some of the data in the middle. We can use the RESTORE command to jump directly to a given DATA statement but the RESTORE command needs the line number of the DATA statement to jump to.
Listing 2 contains such a RESTORE command and in order to load it you must turn off the 'strip line numbers' option in your editor. This will give you a screen similar to the listing below.
10 REM >Listing 2 20 REM most DATA statements missed here for space reasons 30 score%=0:total%=0 40 PRINT "Do you want to be tested on:" 50 PRINT "1 - Element atomic numbers" 60 PRINT "2 - Facts about certain elements" 65 REPEAT 70 INPUT choice% 71 UNIL choice%=1 OR choice%=2 72 IF choice%=1 RESTORE 1000 ELSE RESTORE 2000 73 READ ask$,end$ 80 READ question$,element$,symbol$ 90 WHILE question$<>end$ 100 PRINT ask$;question$;"?"; 110 INPUT " "answer$ 120 IF answer$ <> symbol$ AND answer$ <> element$ THEN 130 PRINT "Wrong, it is ";element$;", ";symbol$;"."' 140 ELSE 150 PRINT "Correct."' 160 score%=score%+1 170 ENDIF 180 total%=total%+1 190 READ question$,element$,symbol$ 200 ENDWHILE 220 END 1000 DATA "Which element has the atomic number ", 0 .............. 2000 DATA "Which element ", "End" ..............
The details of Basic line numbering need not concern us here, it is enough to know that each line has a higher number than the one before, but the numbers do not need to be consecutive. In fact, it is usually a good idea to number lines in multiples of 10, at least, so that it is easier to insert extra lines.
The DATA statements in Listing 2 may be thought of as being in two blocks: one starting at line 1000 and one at line 2000. The user selects which block should be read.
The first values in each block are different from all the others and are a 'header' for the block. Data blocks often contain such headers, giving information about the block, which in this case is the question associated with the data and the last value in the block. These are read first, and the behaviour of the program modified accordingly.
There are two further points to note about Listing 2. Firstly, the DATA statements are after the END statement, emphasising that they can occur anywhere in the program. Secondly, strings need to be enclosed within double quotes if they are more than one word long.
Listing 3 (on the cover disc) gives an extended version of Listing 2 with much more data and questions asked in a random order. Again, you'll need to turn 'strip line numbers' off on your editor to look at it.
Next month we'll look at reading data from another source - files.
Click here to download the example files
|Source:||Acorn User 142 - May 1994|