One of the main differences between the PCs you find in your houses nowadays, and the 8 bit home computers that you found in the 1980s was that the latter machines tended to boot directly into a BASIC interperator when powered up. This was not only a programming language, but also your operating system.
One of the most popular home computers was the Sinclair ZX Spectrum which had a version of BASIC known as Sinclair BASIC. Named for its inventor Clive Sinclair, it was an updated version of that found in the earlier ZX80 and ZX81.
One of Clive Sinclair's main aims with his home computer range was to expose a whole generation of Britain's youth to an affordable computer on which to learn to program -- he was apparently a bit miffed that the focus of Spectrum users centred almost completely on the games. To help this goal, the spectrum came with, not only a fully functional BASIC interperator, but an actual manual which taught you how to program. This was my first foray into programming. As an aside, don't believe those who tell you that learning BASIC ruins programmers for life.
This writeup does not intend to teach a non-programmer how to teach in Sinclair BASIC from scratch. If you want to do that, the original manual is freely available online. Besides the fact: you're wasting your time; go and learn a useful living language like C, perl or Java. It is here as an historical reference and to give people an insight into the world of the Spectrum programmer.
Much of the design of Sinclair BASIC is directly influenced by the hardware it was to be run on. The first version was intended to fit into the 4KB ROM of the ZX80. Size efficiency, therefore, is everything. I am going to concentrate on the Spectrum 48K version, and update with many extra features which was squeezed, instead, into a 32K ROM.
The screen is a grid of 256x192 pixels which are either INK colour or PAPER colour. This grid is overlaid with a 33x22 grid of 8x8 pixel attribute squares in which the ink, paper, brightness, and flash attributes for that square are set. These squares are used in BASIC as the grid for printing text to the screen; text is always printed to align with the attribute squares.
The bottom two text lines of the screen is reserved for the keyboard. Typed text as well as error messages, prompts from INPUT commands and SCROLL?s appears here (internally text here is output to the keyboard stream instead of the output-only screen stream). If much text is written to the keyboard then this part of the screen is extended, but text appearing here is only temporary.
The editing environment
New lines are entered on the keyboard part of the screen. More than one statement can be entered on a line, separated by a colon. If the line has a line number then it will be checked for syntax errors and, if OK, stored in RAM and shown in the list at the top of the screen. Line numbers from 1 to 9999 are allowed. Lines which fail the syntax check are not entered. The computer beeps and the cursor flashes red and moves to the area of the error. Lines without a line number are executed immediately and not stored
One of the program will have a > characted between the line number and the first statement. This is the current line; it can be brought down for editing by pressing the EDIT key (or shift+1). The current line can be changed using the up and down cursors (shift+6 and shift+7) or by issuing a LIST linenumber command, which will change the current line to the line after linenumber.
Sinclair BASIC keywords are stored (for size efficency) in RAM as single characters. They are treated as such in the editing environment too. Which keyword was produced when a key is pressed depends on the cursor mode. The cursor could be in one of 5 modes, each identified by a letter:
- KEYWORD MODE
The cursor was in this mode before anything was typed, after a linenumber, after a colon or after a THEN token. In this mode, pressing any of the alphabet keys on the keyboard produced a keyword. For example pressing P would produce the keyword 'PRINT'. Most of Sinclair BASIC's common keywords were produced this way.
- LOWER-CASE MODE
This was the default mode in all situations when Keyword mode would not be normal and no other modes had been user set. In this mode, the P key would produce 'p'.
- CAPS MODE
Same as L mode, but Caps-Lock (shift+2) has been set. In this mode, pressing the P key would produce 'P'.
- EXTENDED MODE
Extended mode is accessed by pressing symbol-shift and caps-shift together. This makes available a whole host of extra function keywords and symbols. In this mode, pressing the P key would produce the keyword 'TAB'. With a shift key also pressed, the '©' symbol is produced.
- GRAPHICS MODE
In this mode, the number keys produce clunky graphics involving filling or not filling the 4x4 pixel corners of the attribute square. The keys A-G will produce user defined characters which can be POKEd directly into a RAM section of the character set. Pressing the P key in this mode will have no effect.
Now follows a reference of all commands, functions and statements in the Sinclair BASIC programming language. For each one I will describe the usage and, where appropriate, describe some concepts important to the use of the keyword. I've tried to put them into groups, but this could be a bit subjective.
Variables are either floating-pont or strings. Names are alphabetical, case-insensitive with arbitary length, with string names ending in $. Bots variables are assigned with the LET command which is not optional. Usual infix notation (+-*/) works with numbers and strings can be sliced as such:
LET b$=a$(5 TO 9), where b$ would take the value of the th through 9th characters of a$.
There are two types of Sinclair BASIC array. Numerical arrays hold floating point numbers and string arrays hold fixed-length strings. Both can be of arbitary size and arbitary dimensions. They are then used just like normal variables. They are declared using the DIM statement. Individual elements are accessed using the offsets in brackets after the variable name (which can only be one letter long):
10 DIM a(10,10)
20 LET a(1,1)=10
30 PRINT a(1,1)
With strings, the last dimension is the length of the strings. Longer stings are truncated, shorter ones padded with spaces. Arrays in Sinclair BASIC are indexed from 1; you cannot have the zeroth element of an array (which really confuses you in later programming life).
- LEN - Extend-mode K
Returns the length of a given string.
- VAL - Extend-mode J
- VAL$ - Extend-mode J
Returns the numerical value of a string. For example
VAL "3.4" would return the number3.4. VAL$ does this half way, takes the value but still returns it as a string (only makes sense if there a names of numerical values in the string).
- STR$ - Extend-mode Y
Like a VAL in reverse. Takes a numerical value and returns a string containing that value.
- CHR$ - Extend-mode U
- CODE - Extend-mode I
CHR$ given a character number, returns a string containing that character. CODE does the inverse: takes a string containing a character and returns its code.
- ABS - Extend-mode G
This is the ABSolute function. It basically rips off minus signs from a number and returns only the magnitude.
- BIN - Extend-mode B
Returns the decimal equivilent of its 8 bit binary argument. Note
that BIN will only work on constants.
- SIN - Extend-mode Q
- COS - Extend-mode W
- TAN - Extend-mode E
- ACS - Extend-mode Shift+Q
- ASN - Extend-mode Shift+W
- ATN - Extend-mode Shift+E
These are the trigonometric functions. They return the sine, cosine, tangent, arcsine, arccosine and arctangent respectively.
- LN - Extend-mode Shift+Z
- EXP - Extend-mode Shift+X
These functions return the logarithm to base e and ne respectively.
- PI - Extend-mode Shift+M
This returns a constant equal to π to 7 deximal places, or 3.1415927.
- RANDOMIZE - Keyword-mode T
- RND - Extend-mode T
RND is the random number generator. It generates pseudorandom numbers between 0 and 1 (but never actually reaching 1). The numbers are a sequence of 65536 numbers and RANDOMIZE n will set the seed to the nth number in the sequence. RANDOMIZE on its own sets the seed to a number based on the time since the computer was powered on to generate more randomness. The Sinclair BASIC manual describes how these numbers are generated as follows:
Let p be a (large) prime, and let a be a primitive root modulo p.
Then, if bi is the residue of ai modulo p (l ≤ bi ≤ p-l ), the sequence:
is a cyclical sequence of p-1 distinct numbers in the range 0 to 1 (excluding 1). By choosing a suitably, these can be made to look fairly random.
65537 is a Fermat prime, 2l6+1. Because the multiplicative group of non-zero residues modulo 65537 has a power of 2 as its order, a residue is a primitive root if and only if it is not a quadratic residue. Use Gauss' law of quadratic reciprocity to show that 75 is a primitive root modulo 65537.
The ZX Spectrum uses p=65537 and a=75, and stores some bi-1 in memory. RND entails replacing bi-1 in memory by bi+1 -1, and yielding the result (bi+1-l) (p-l). RANDOMIZE n (with 1<n<65535) makes bi equal to n+1.
RND is approximately uniformly distributed over the range 0 to 1.
- SGN - Extend-mode F
Returns the sign of its argument. Will return 1 if the argument is positive, -1 if it is negative and 0 if it is 0.
- SQR - Extend-mode H
Returns the square root of its argument
These statements set the defaults for the different attributes of the low-resolution grid. Printing and drawing commands after these will have the set attributes. They can also be used in conjunction with printing and drawing commands for temporary effect, for example: PRINT INK 5; "Hello!"
- INK - Extend-mode shift+X
- PAPER - Extend-mode shift+C
These set the paper and ink colours; these are used for the 0 and 1 bits on the bitmap for each attribute square. The colours are as follows:
0 Black 3 Magenta 6 Yellow
1 Dark Blue 4 Green 7 White
2 Red 5 Cyan 8 No Change
- BRIGHT - Extend-mode Shift+B
- INVERSE - Extend-mode Shift+M
- FLASH - Extend-mode Shift+V
- OVER - Extend-mode Shift+N
These all set attributes on individual low-res squares. BRIGHT makes that square slightly brighter, INVERSE swaps the PAPER and INK colours and FLASH keeps swapping the PAPER and INK colours over in irritating fashion. OVER is slightly different; normally, if you write text to a square it obliterates what was there before, but if it has its OVER attribute set it will write over the top of it.
- BORDER - Keyword-mode B
Changes the colour of the border area (which you cannot draw on). If you keep doing this fast enough, you can create stipes (which is basically what's happening during a LOAD or SAVE).
Screen and keyboard
CLS - Keyword-Mode V
- PRINT - Keyword-mode P
Syntax: PRINT a$;
Syntax: PRINT AT x, y; a$;
Syntax: PRINT TAB x; a$
PRINT is your all-purpose, write stuff to the screen. It can print literal numbers, literal strings and variables to the screen. PRINT AT moves to the specified x and y coordinates of the low-res grid first. PRINT TAB prints as many spaces as are needed to move to the give xcoordinate. Composite PRINT statements can be built up by using the separators:
' starts a new line,
, moves to x=16 or a new line if x is already > 16, ; continues from the last PRINT.
- PLOT - Keyword-mode Q
Syntax: PLOT x, y
Changes the pixel at point x,y to ink colour.
- DRAW - Keyword-mode W
Syntax: DRAW x, y
Syntax: DRAW x, y, z
The first form will draw a line from the current point (position of last PLOT or end of last DRAW) x pixels to the right and y pixels down - these values may be negative. The second
form has a third argument y which will produce a curve with the same start and end points. y is the number or radians that the curve will pass through as it goes.
- CIRCLE - Extend-mode Shift+H
Syntax: CIRCLE x, y, z
Draw a circle with centre at point x, y and with radius z.
Clears the screen. More specifically it wipes the bitmap to all 0s and sets the all the low-res attribute squares to the current default settings.
- INPUT - Keyword-mode I
Works just like PRINT except that it prints to the bottom (keyboard) lines of the screen and the variables given are asked for from the user. To protect variables from this and print them, they must be protected in parentheses. Is a string is requested then the prompt will contain quotes, which can be deleted by the user. Entering a STOP command will then exit the program. The variation INPUT LINE will prevent this.
- INKEY$ - Extend-mode N
Returns a string, length one, representing the currently pressed key.
- PAUSE - Keyword-mode M
Waits until either a key is pressed or a time is elapsed. The time is the argument in 50ths of a second. PAUSE 0 will wait for ever.
- POINT - Extend-mode Symbol-Shift+8
- SCREEN$ - Extend-mode Shift+K
- ATTR - Extend-Mode Shift+L
All these functions read information available on the screen. POINT returns 1 or 0 depending on the bitmap setting of the screen at the supplied x,y coordinates. SCREEN$ returns the character displayed at the supplied low-res coordinates. ATTR returns the colour attributes of the low-res square binary encoded in one byte.
- IF - Keyword-Mode U
Used in conjuntion with THEN and one or more tests combined with logical operators. If the test is true then statements up to the end of the line are executed, if it is false then the rest of the line is skipped. There is no ELSE.
- = - Symbol-Shift+L
- > - Symbol-Shift+T
- < - Symbol-Shift+R
- >= - Symbol-Shift+E
- <= - Symbol-Shift+Q
- <> - Symbol-Shift+W
The tests are the standard tests. They work on both strings and floats (but will not compare one type against the other). When working on strings they compare in alphabetical order.
- AND - Symbol-Shift+Y
- OR - Symbol-Shift+U
- NOT - Symbol-Shift+I
These peform the logical AND, OR and NOT functions, usually in conjunction with an IF...THEN statement.
- GO TO - Keyword-mode G
Execution of the program moves to the specified line number. This value can be dynamically calculated a run time.
- GO SUB - Keyword-mode H
- RETURN - Keyword-mode Y
GO SUB acts just like GO TO except the line (and statement) number before the jump is pushed to a stack and a RETURN statement will then pop the stack and return to the same point.
- RUN - Keyword-mode R
Usually used as a direct command. RUN n is the same as CLEAR:GO TO n. With no argument it starts execution from the first line.
- CONTINUE - Keyword-mode Shift+C
If BREAK has been used to interuppt the program, CONTINUE can be used to restart the program. The restart may either be just before, or just after the BREAK depending on the error message given.
- STOP - Symbol-shift A
Stops the program execution.
- FOR - Keyword-mode F
- NEXT - Keyword-mode N
- STEP - Symbol-shift D
For loops are the only loops available in Sinclair BASIC (Except for ones you make yourself with IFs and GO TOs). Internally they are simply implemented as variables which are checked at each NEXT statement. They
look rather like this:
10 FOR x=start TO end STEP s
20 REM do some stuff here
30 NEXT x
The counter runs from start to end counting up in steps of s. The STEP part can be omitted and a step of 1 in assumed.
By default the Spectrum uses audio tapes for storage. With the addition of an Interface One there is the possibility to use Microdrive storage as well as the Sinclair Network. 128K spectrums also have a ramdisk facility. The tokens OPEN #, CLOSE, ERASE, CAT, MOVE and FORMAT, whilst available, mean nothing to standard Sinclair BASIC and will produce a syntax error. An attatched Interface One will trap calls to these errors to insert its own ROM routines but they are not discussed here.
- LOAD - Keyword-mode J
Syntax: LOAD a$
Syntax: LOAD a$ CODE
Syntax: LOAD a$ CODE start
Syntax: LOAD a$ SCREEN$
Syntax: LOAD a$ DATA a()
Attempts to load a program from tape. It takes a string argument as a filename. If given the empty string it will load a program with any name. With the keyword CODE it will attempt to load machine code from the tape, optially at a given start address. The keyword SCREEN$ is a shortcut to load code into the video RAM. With the keyword DATA it will atttempt to load array data into the given array name.
- SAVE - Keyword-mode S
Syntax: SAVE a$
Syntax: SAVE a$ LINE n
Syntax: SAVE a$ CODE start, len
Syntax: SAVE a$ SCREEN$
Syntax: SAVE a$ DATA a()
Saves a program to tape. It takes a string argument as a filename, and optionally a linue number from which to begin execution on load. With the keyword CODE it will save machine code to the tape from a block defined by the start address and the length of the code. The keyword SCREEN$ is a shortcut to save the video RAM. With the keyword DATA it save array data from the given array name.
- VERIFY - Extend-mode shift+R
Takes all the same forms as LOAD but simply checks weather the data saved on tape matches that already in RAM.
- MERGE - Extend-mode shift+T
LOAD always clears the memory beforehand, whereas MERGE does not. It will attempt to replace lines or variables in memory with those on tape, but leaves the memory untouched where the tape has no new data.
- DATA - Extend-mode D
- READ - Extend-mode A
- RESTORE - Extend-mode S
Syntax: DATA 10,2,4,x,"plop",a$
Data lines hold lists of literals or variables. A each READ statement will read the next element in the list and store it in READ's list of variables. This is most often used to initialise an array using lots of DATA lines and a FOR...NEXT loop. RESTORE takes a line number and makes the next READ start from the first DATA element after that line. In execution, DATA lines have no effect.
- POKE - Keyword-mode O
- PEEK - Extend-mode O
These statements write and read directly to RAM. POKE takes teo arguments, an address and the value to write to it. PEEK takes just an address and reads the value there. These are usually of little use in BASIC programming, since variables and arrays offer a much easier way of storgin and retrieving data. There are two possible uses, though. One is to read an manipulate the Spectrum's system variables (housekeeping variables held between 23552 and 23734). You can use this to change the keyboard repeat, for example. Another is (usually in a loop reading DATA statements) to POKE a machine code program into memory byte-by-byte.
- CLEAR - Keyword-mode X
CLEAR does three separate things.
- It does a CLS
- It clears all variables from memory. This makes it a good thing to do before a SAVE.
- If given an argument, it sets the RAMTOP system variable. This variable holds the address of the highest part of RAM used for the BASIC program. Moving this up can make more space for BASIC, moving it down makes more space for machine-code programs that should run above RAMTOP.
- USR - Extend-mode L
This is a funtion with a side-effect. It begins machine-code execution at the address given as an argument. If the machine code routine returns to BASIC the function returns the contents of the BC register of the z80 chip.
- REM - Keyword-mode E
REM is short for REMark and is used for comments. The interperator ignores everything following a REM until the end of the line.
- NEW - Keywordd-mode A
Clears all memory below RAMTOP. This includes all BASIC program data.
Ready for your first Sinclair BASIC Program?
The Sinclair BASIC manual includes a number of example listings. This one is my favorite. It uses a couple of arrays to emulate a binary tree and uses this to play a game where it asks you yes or no questions to guess an animal you are thinking of. If it gets it wrong, you can add the animal so it will know next time. As a Spectrum-obssessed five-year-old I used to tinker with this all the time.
5 REM Pangolins
10 LET nq=100: REM number of questions and animals
15 DIM q$(nq,50): DIM a(nq,2): DIM r$(1)
20 LET qf=8
30 FOR n=1 TO qf/2 1
40 READ q$(n): READ a(n,1): READ a(n,2)
50 NEXT n
60 FOR n=n TO qf-1
70 READ q$(n): NEXT n
100 REM start playing
110 PRINT "Think of an animal.","Press any key to continue."
120 PAUSE 0
130 LET c=1: REM start with 1st question
140 IF a(c,1)=0 THEN GO TO 300
150 LET p$=q$(c): GO SUB 910
160 PRINT "?": GO SUB 1000
170 LET in=1: IF r$="y" THEN GO TO 210
180 IF r$="Y" THEN GO TO 210
190 LET in=2: IF r$="n" THEN GO TO 210
200 IF r$<>"N" THEN GO TO 150
210 LET c=a(c,in): GO TO 140
300 REM animal
310 PRINT "Are you thinking of"
320 LET P$=q$(c): GO SUB 900: PRINT "?"
330 GO SUB 1000
340 IF r$="y" THEN GO TO 400
350 IF r$="Y" THEN GO TO 400
360 IF r$="n" THEN GO TO 500
370 IF r$="N" THEN GO TO 500
380 PRINT "Answer me properly when I'm","talking to you.": GO TO 300
400 REM guessed it
410 PRINT "I thought as much.": GO TO 800
500 REM new animal
510 IF qf>nq-1 THEN PRINT "I'm sure your animal is very", "interesting,
but I don't have","room for it just now.": GO TO 800
520 LET q$(qf)=q$(c): REM move old animal
530 PRINT "What is it, then?": INPUT q$(qf+1)
540 PRINT "Tell me a question which dist ","inguishes between "
550 LET p$=q$(qf): GO SUB 900: PRINT " and"
560 LET p$=q$(qf+1): GO SUB 900: PRINT " "
570 INPUT s$: LET b=LEN s$
580 IF s$(b)="?" THEN LET b=b-1
590 LET q$(c)=s$(TO b): REM insert question
600 PRINT "What is the answer for"
610 LET p$=q$(qf+1): GO SUB 900: PRINT "?"
620 GO SUB 1000
630 LET in=1: LET io=2: REM answers for new and old animals
640 IF r$="y" THEN GO T0 700
650 IF r$="Y" THEN GO TO 700
660 LET in=2: LET io=1
670 IF r$="n" THEN GO TO 700
680 IF r$="N" THEN GO TO 700
690 PRINT "That's no good. ": GO TO 600
700 REM update answers
710 LET a(c,in)=qf+1: LET a(c,io)=qf
720 LET qf=qf+2: REM next free animal space
730 PRINT "That fooled me."
800 REM again?
810 PRINT "Do you want another go?": GO SUB 1000
820 IF r$="y" THEN GO TO 100
830 IF r$="Y" THEN GO TO 100
900 REM print without trailing spaces
905 PRINT " ";
910 FOR n=50 TO 1 STEP -1
920 IF p$(n)<>" " THEN GO TO 940
930 NEXT n
940 PRINT p$(TO n);: RETURN
1000 REM get reply
1010 INPUT r$: IF r$="" THEN RETURN
1020 LET r$=r$(1): RETURN
2000 REM initial animals
2010 DATA "Does it live in the sea",4,2
2020 DATA "Is it scaly",3,5
2030 DATA "Does it eat ants",6,7
2040 DATA "a whale", "a blancmange", "a pangolin", "an ant"
Notes on sources
Much of this comes from my many years as a youngster programming my own collection of spectrums, first in BASIC, later in Z80 code. I have used my original spectrum manual for fact-checking and memory-refreshing. The pangolins code is ripped directly from this manual. The manual is freely distributable but states that following notice must be included:
SINCLAIR ZX SPECTRUM
By Steven Vickers
Edited by Robin Bradbeer
Converted to ASCII text by
(Internet email: email@example.com)
Original edition published in 1982
by Sinclair Research Limited
This version published in 1995
by Chris Owen on behalf of Amstrad plc
© Amstrad plc 1995 - all rights reserved
This manual is freely distributable but must
not be distributed without this notice.