|Home||QL User index|
|Holy Structures ... |
Zap, Pow, Blam ... just when you thought it was safe to get back to unstructured waters, along came the Cambridge Joker in his QL-Mobile with a surprise present - SuperBasic - to threaten an imprecise programming world. Andrew Pennell battles to explain ...
The subtly named SuperBasic on the
QL appears to have interesting features, particularly its ability to use
Pascal- like structures, similar to BBC
Basic. I say 'appears' because at the
time of writing (some weeks after the
28-day expiry) no QLs have been
manufactured; this article is based
mainly on information given in the
provisional User Guide and therefore no guarantees can be given as to
its total accuracy. |
Having thus 'copped out', let's first of all consider the subject of structured programming. Different people have different views, but for me it's programming in such a way as to be 'self- documenting' - that is, you're able to work out what a section of program does without too much effort. The much maligned GO TO and GO SUB statements have long come under attack by purists - certainly they make program flow more difficult to follow on paper. The QL manual says that the extra SuperBasic commands make these statements superfluous, and there's a lot of truth in it. When I was taught Pascal, I remember the lecturer putting a total ban on the GO TO statement, which horrified me at the time. But she was right - you don't need it in Pascal, and you shouldn't need it in SuperBasic, if you use the control structures efficiently; none of the QL programs in this article have it.
There are four major enhancements to bog- standard Basic in the QL that relate to structured programming - functions, procedures, REPEAT loops and the SELECT command. They are very similar to certain Pascal statements, except that SELECT in SuperBasic is known as CASE in Pascal. I shall endeavour to show you each of them in use, and compare them to their 'equivalent' in Spectrum Basic.
LOOKING AT FUNCTIONSQL-type functions are a great improvement on Spectrum types allowing as they do multi- line definitions and the use of local variables. On the Spectrum, DEF FN statements could only be followed by an
expression, with no other statement
types allowed. Any attempts at recursion (ie. the function calling itself)
resulted in an 'Out of memory' error,
after a delay while the machine stack
filled. SuperBasic functions, on the
other hand, do allow recursion, as
well as single- line definitions with
the normal syntax. |
An example of a recursive function is shown in Listing 1a, where a function called 'fact' calculates the factorial of a number. (The factorial of a number is the result of all integers up to and including it being multiplied together - eg. factorial 4 = 1x2x3x4 = 24.) Lines 1010-1020 check first for factorial zero, which by definition
The Spectrum version is shown in Listing 1b and it has several disadvantages when compared to the QL version - and that's apart from its lack of structure. In particular, the variable i is corrupted by the routine, and the 'input' variable must always be a, and the 'output' variable is always fact. With the QL version, there are no variable restrictions - if you wish to make zz equal to the factorial of b, then you could use zz=fact(b).
As you can see, to use a QL function you don't need the FN of other Basics - you just use it like any of the built-in functions.
Listing 2a shows another QL function, which is used for a 'live' string
input routine called 'getstring$'. It
shows several of the QL's features,
the first of which is LOCAL. If you
want to use variables in a function
definition (or in procedures, shown
later) and you don't want them to
affect any variables in the rest of the
program, then the use of LOCAL will
ensure that the values of any existing
variables with the same name are
preserved through the function or
procedure, then restored afterwards. |
Another 'structured' feature is the REPEAT command, used for looping. Basically, if you want a loop of some sort, put 'REPEAT some name' at the start, and 'END REPEAT somename' at the end. Then, where you want to put a test to leave it, use 'IF condition THEN EXIT somename' and the named loop will no longer execute. Unfortunately, this is not very similar to either Pascal or BBC Basic's REPEAT ... UNTIL construct, making conversion more difficult.
The final, rather neat, feature used is the SELECT statement, which allows easy choices to be made without unwieldy IF ... THEN statements - something which has not been implemented on any previous Basic. Line 1010 ensures first that any variables called a$ or b$ in the calling program are not affected, and then it enters the main loop, 'getloop'. The two REPEATs in lines 1030 and 1040 are short forms of the statement, and execute the multi- statements that come after them automatically without END REPEAT commands; they're used in the function to scan the keyboard.
Lines 1050-1170 consist of SELECT statements for taking a number of different actions, depending on the key used. If Newline (CHR$ 13) is pressed, then the main loop, 'getloop', is left. If backspace (CHR$ 8) is pressed, then (if allowed) a backspace is printed and a character removed from the end of b$. Note that QL string handling is conducted in the same (non- standard but neat) way as the Spectrum and ZX81. If it's a non- control character (lines 1120- 1160) it's printed, then added to b$.
Finally line 1190 ensures that the
value returned from the function is
For reference, the Spectrum equivalent is shown in Listing 2b and it displays similar disadvantages to Listing 1b. I've made one assumption in the QL version, and that is that backspace is CHR$8 (it should be as it's the ASCII standard code).
As well as functions, the other major structure addition is that of procedures. A procedure is a sequence
of instructions, optionally using
parameters, which is basically just an
upmarket GO SUB. They each must
have a different name, and are invoked by simply using their names,
unlike fussy BBC Basic which requires PROCname. This allows extra
commands to be added, without
resort to the machine code that's
required when adding commands to
the Spectrum - and the BBC Micro
for that matter. |
In Listing 3a, a QL procedure
called 'box' is defined which, not surprisingly, draws a box that's defined
by its bottom left-hand corner, its
width and height. The QL has an improved version of DRAW, which can
cope with many parameters, each
separated with TO. To use it, for example, to draw a box at (10,20), size
300x200, is simply: box 10,20,300,
Note that unlike DEF PROC no brackets are required when the procedures are actually used. The Spectrum
|SuperBasic - A Spectral Comparison|
1000 DEF FN fact(a) 1010 IF a=0 THEN 1020 RETURN 1 1030 ELSE 1040 RETURN a*fact(a-1) 1050 END IF 1060 END DEF
1000 LET fact=1 1010 IF a=0 THEN RETURN 1020 FOR i=1 TO a 1030 LET fact=fact*i 1040 NEXT i 1050 RETURN
|This is an example of recursion, where the function 'fact' calculates the factorial of a number. Note the use of QL keywords IF ... THEN ... ELSE.||The Spectrum Basic version of Listing 1a - you can see that there are a number of variable restrictions; ie. the variable i is corrupted by the routine.|
1000 DEF FN getstring$ 1010 LOCAL a$,b$ 1020 LET b$="" 1025 REPEAT getloop 1030 REPEAT getpause: IF INKEY$="" THEN EXIT getpause 1040 REPEAT getkey: LET a$=INKEY$: IF a$<>"" THEN EXIT getkey 1050 SELECT ON CODE a$ 1060 ON CODE a$=13 1070 PRINT : EXIT getloop 1080 ON CODE a$=8 1090 IF b$<>"" THEN 1095 b$=b$( TO LEN b$-1) 1100 PRINT CHR$ 8;" ";CHR$ 8; 1110 ENDIF 1120 ON CODE a$=32 TO 127 1130 IF LEN b$<32 THEN 1140 b$=b$+a$ 1150 PRINT a$; 1160 ENDIF 1170 END SELECT 1180 END REPEAT getloop 1190 RETURN b$ 1200 END DEF
1000 LET b$="" 1010 PAUSE 0: LET a$=INKEY$ 1020 IF CODE a$>127 THEN GO TO 1010 1030 IF a$=CHR$ 13 THEN PRINT : RETURN 1040 IF a$<>CHR$ 12 THEN GO TO 1100 1049 REM backspace 1050 IF b$="" THEN GO TO 1010 1060 LET b$=b$( TO LEN b$-1) 1070 PRINT CHR$ 8;" ";CHR$ 8; 1080 GO TO 1010 1100 IF LEN b$=32 OR CODE a$<32 THEN GO TO 1010 1110 LET b$=b$+a$ 1120 PRINT a$; 1130 GO TO 1010
|This program example illustrates a 'live' string input routine called 'getstring$'. Notable QL features to watch out for are the LOCAL, REPEAT and SELECT commands.||The equivalent Spectrum Basic to Listing 2a, although seemingly shorter, is somewhat lacking in structure. The problem of variable restriction is also present.|
1000 DEF PROCbox(x,y,width,height) 1010 PLOT x,y 1020 DRAW x+width,y TO x+width,y+height 1030 DRAW x,y+height TO x,y 1040 END DEF
1000 PLOT x,y: DRAW width,0 1010 DRAW 0,height: DRAW -width,0 1020 DRAW 0,-height 1030 RETURN
|This QL procedure draws a box by defining its bottom left- hand corner, width and height. More complex parameters may be included, separated by the keyword TO.||Spectrum Basic allows the routine in Listing 3a to be written in a simpler fashion - it uses a DRAW statement that is relative, rather than the QL's absolute equivalent.|
1000 DEF PROCpformat(b) 1010 LOCAL a,a$ 1020 a=(INT (b*100))/100 1030 IF a<.01 THEN PRINT " 0.00";: RETURN 1040 IF a>1e6 THEN PRINT " ?.??";: RETURN 1050 a$=STR$ a 1060 IF a$(1)="." THEN a$="0"+a$ 1070 IF a$(LEN a$-1)="." THEN a$=a$+"0" 1080 IF a$(LEN a$-2)<>"." THEN a$=a$+".00" 1090 REPEAT strlen 1100 IF LEN a$=9 THEN EXIT strlen 1110 a$=" "+a$ 1120 END REP strlen 1130 PRINT a$; 1140 END DEF
1000 LET a=(INT (a*100))/100 1010 IF a<.01 THEN PRINT " 0.00";: RETURN 1020 IF a>1e6 THEN PRINT " ?.??";: RETURN 1030 LET a$=STR$ a 1040 IF a$(1)="." THEN LET a$="0"+a$ 1050 IF a$(LEN a$-1)="." THEN LET a$=a$+"0" 1060 IF a$(LEN a$-2)<>"." THEN LET a$=a$+".00" 1070 IF LEN a$<9 THEN LET a$=" "+a$: GO TO 1070 1080 PRINT a$; 1090 RETURN
|This procedure is suitable for a financial package in which you wish to right- justify a series of numbers on the decimal point. Again, use is made of the LOCAL and REPEAT commands.||To simulate Listing 4a in Spectrum Basic, you come up against the same problem experienced in Listing 1b - namely, that of variable restrictions; ie. you lose the old values of the variables a and a$.|
version, in Listing 3b, is a bit
simpler than the QL version because
it uses a relative DRAW statement,
whereas the QL's is absolute. |
Listing 4a shows another QL procedure called 'pformat', which prints a number right- justified on the decimal point and therefore it's for printing currency. It's probably called 'pformat' because format is a reserved word; there's already a Basic statement with that name. It uses a LOCAL statement, as well as a REPEAT loop to finally right- justify the output string, a$. It uses the STR$ command, found on most other Basics but missing from the SuperBasic manual. Because of the variable coercion on the QL, it may well be possible to replace it with: 1050 a$=a.
The equivalent Spectrum program is shown in Listing 4b, and its main disadvantage is again the loss of the old value of variables, a and a$.
The use of procedures greatly enhances the readability of programs if
is much more understandable than a possible Spectrum equivalent of:
100 GO SUB 9000
110 GO SUB 2300
120 GO SUB 4200
130 GO SUB 1200
The way that functions and procedures add features to QL Basic is extremely useful, so much so that on switching on your QL, it will ask you if you want to LOAD any from Microdrive.
I hope this has given an insight into the 'structured' aspects of SuperBasic on the QL; you can all practice now while waiting for one to be delivered. Who knows, if it really catches on, it could be the end of the GO TO for good!
[continued overleaf ...]
|Home||QL User index|