BASICODE was a living standard that was updated and clarified with time in collaboration between listeners and broadcasters. Roughly, there have been 5 major versions, corresponding to books or other publications of the standard:
- BASICODE-1 (1980) consisted of the audio modulated transmission format only.
- BASICODE-2 (1983) added the language specification and standard subroutines for text and printing.
- BASICODE-3 (1986) added monochrome graphics and sound subroutines.
- BASICODE-3 second edition (1988) added user-defined functions.
- BASICODE-3C (1991) added colour.
The standard was not formally specified, but rather described as a limitation on existing 8-bit BASIC dialects, which were assumed to be known by the readers. Thus, many assumptions were never made explicit. This document aims to describe the BASICODE language in a more explicit way, so that it can be understood by those less familiar with classic BASIC dialects.
BASICODE programs consist of lines of ASCII text, separated by carriage returns. All program text except string literals and comments is uppercase.
Each line is no more than 60 characters long and consists of a line number, followed by a space and a compound statement.
The first line number is 1000
and following line numbers are whole numbers
in the range 1010
-32767
, inclusive.
A compound statement consists of one or more statements, separated by colons :
.
The first line of the program has line number 1000
and takes the following form:
1000 A = value: GOTO 20: REM program name
Here, the value of A
represents a number of bytes large enough
to store all string variables in the program, including arrays but
not counting string literals. GOTO 20
initialises the program.
By convention, the program name is given in a comment in line 1000
.
The second line of the program has number 1010
. This is where the program proper starts.
In Basicode-3 and -3C, programs should be explicitly terminated with GOTO 950
.
It is recommended to use line number ranges as follows:
Range | Purpose |
---|---|
1000 |
Initialisation line |
1010 -19999 |
Main program |
20000 -24999 |
Machine-specific subroutines |
25000 -29999 |
DATA lines |
30000 -31999 |
Comments: program description |
32000 -32767 |
Comments: author's name and contact details |
Keywords are any of the following:
- statement keywords;
- function keywords;
- operators;
- reserved words.
No spaces are required to separate keywords, except when ambiguity may arise.
For example, IFB=A THEN2000
requires no space between the keyword IF
and the variable
name B
or between the keyword THEN
and the numeric literal 2000
.
However, a space is required between the variable name A
and the
keyword THEN
to avoid the statement being interpreted as the syntactically
incorrect IF B= AT HEN 2000
.
There are two types of scalar variables: numerical and string.
Numerical variable names consist of a letter and optionally another letter or a number.
String variable names consist of a letter and optionally another letter or a number,
terminated by a dollar sign $
.
The following two-letter words are reserved words and must not be used as variable names:
- All words starting with
O
. AS
,AT
,FN
,GR
,IF
,PI
,ST
,TI
,TI$
,TO
(in BASICODE-2, -3 and -3C)LN
(in BASICODE-3 and -3C)DI
,EI
,GO
,SQ
(in BASICODE-3, 2nd edition and -3C)
The following variable names have a special meaning for use with BASICODE subroutines:
A
,CN
,CT
,FR
,HO
,IN$
,RV
,SR
,SR$
, andVE
(in BASICODE-2, -3 and -3C)HG
,IN
,NF
,NF$
,SD
,SP
,SV
, andVG
(in BASICODE-3 and -3C)CC()
(array, in BASICODE-3C)
Variables must be assigned a value before they may be used.
Arrays are lists of values of the same type. They must be declared first using
the DIM statement. The rules for array names are the same as for scalar variables,
i.e. a letter optionally followed by another letter or number, and the dollar sign
$
for string arrays. Arrays have a separate name space from scalar variables so
an array and a scalar variable with the same name may co-exist without confusion.
Arrays are indexed by a whole number enclosed in parentheses ()
. The first
index is 0
, the last index is the number specified in the DIM statement
which declared the array. At most two dimensions are allowed.
Numerical values are floating-point and single-precision: a precision of no more than 6 significant figures is guaranteed.
Strings must be no longer than 255 characters.
Numerical literals consist of an optional sign -
or +
, followed by
digits, optionally followed by a decimal point .
,
optionally followed by more digits.
String literals consist of a double quote "
, followed by the characters
of the string, followed by a double quote "
.
x AND y
returns the logical conjunction of its operands.
NOT x
returns the logical negation of its operand.
x OR y
returns the logical disjunction of its operands.
x = y
returns the equality of its operands.
x < y
returns x
less than y
.
x > y
returns x
greater than y
.
x <> y
returns the inequality of its operands.
x <= y
returns x
less than or equal to y
.
x >= y
returns x
greater than or equal to y
.
Boolean expressions may be used in an IF
statement and assigned to a
variable, but no assumptions should be made about the numerical value. When
assigning a boolean value to a variable, that value may only be used in an
IF
statement.
The order of precedence of Boolean operators is undefined and must be indicated with parentheses.
x$ + y$
returns the concatenation of its operands.
+ x
returns its operand.
- x
returns the negative of its operand.
x + y
returns the sum of its operands.
x - y
returns the difference of its operands.
x * y
returns the product of its operands.
x / y
returns the quotient of its operands.
x ^ y
returns x
raised to the power of y
.
Note that the arguments to the functions below are numeric expressions, unless the argument is denoted with a dollar sign.
ABS(x)
returns the absolute value of its argument.
ASC(x$)
returns the ordinal value of the first character of its argument.
Use with care as not all target platforms use ASCII.
ATN(x)
returns the arctangent of its argument, in radians.
CHR$(x)
returns the character with the ordinal value provided by its argument.
Use with care as not all target platforms use ASCII.
COS(x)
returns the cosine of its argument, which is interpreted as radians.
EXP(x)
returns the exponential of its argument.
FNa(x)
returns the value of the user-defined function a
with argument x
. BASICODE-3 and -3C only.
INT(x)
returns its argument as a whole number truncated towards negative infinity.
LEFT$(x$, n)
returns the n
leftmost characters of the string x$
.
n
must be in the range 1
- LEN(x$)
.
LEN(x$)
returns the length of its argument.
LOG(x)
returns the natural logarithm of its argument. x
must be greater than 0
.
MID$(x$, s [, n])
returns a substring of n
consecutive characters, starting with
position s
, where the first position is 1
. s
and n
must be in the
range 1
-LEN(x$)
.
In BASICODE-3 (2nd edition) and BASICODE-3C, the third
argument n
is optional, while in earlier versions it is mandatory.
If n
is omitted, the substring starting from position s
to the end of x$
is returned.
RIGHT$(x$, n)
returns the n
rightmost characters of the string x$
.
n
must be in the range 1
-255
.
SGN(x)
returns the sign of its argument: 1
for positive,
-1
for negative, 0
for zero.
SIN(x)
returns the sine of its argument, which is interpreted as radians.
SQR(x)
returns the square root of its argument. x
must be greater than or equal to 0
.
TAN(x)
returns the tangent of its argument, which is interpreted as radians.
VAL(x$)
returns the numerical value of the string representation of a number
given as its argument. x$
must be string representing a valid numerical literal.
DATA literal [, literal] ...
Declares data which can be read with READ
. No further statements are allowed on a line after a DATA statement.
DEF FNa(param) = expression
Defines the user-defined function a
with one numeric parameter param
.
param
is a numeric variable name.
expression
is a numeric or Boolean expression that may refer to param
.
It must not recursively call the newly defined function FNa
.
Function names follow the same rules as numerical variable names.
The space between DEF
and FN
is optional.
The DEF FN
statement must be the only statement on the program line; this
program line must not contain a colon.
After a DEF FNa
statement (and not before), the function FNa
may be used like other
numerical functions. Its return value will be the evaluation value of expession
after substituting the parameter.
BASICODE-3 (2nd edition) and -3C only.
DIM variable(max_index [, max_index_2])
Allocates an array (numerical or string) to be of length max_index+1
, with
an optional second dimension of length max_index_2+1
. Arrays must be declared by a
DIM
statement before they may be used, and re-dimensioning of the
same array is not allowed.
In BASICODE-3 (2nd edition) and -3C, DIM
initialises array values to zero
or the empty string. In earlier versions, they must be explicitly initialised.
END
Terminates the program. BASICODE-2 only; in BASICODE-3 and -3C use GOTO 950
.
FOR variable = start TO stop [STEP step]
Initiates a loop. variable
must be numeric. Statements between
this statement and the matching NEXT
statement will be executed at least once
and may be executed multiple times. In the first iteration, variable
will have the value start
.
Every next iteration it is incremented by step
or by one if the STEP
clause is omitted.
If variable
is greater than or equal to stop
, the loop exits at the NEXT
statement and
program execution continues from the statement after NEXT
.
GOSUB line_number
Jumps to a subroutine. If a subsequent RETURN
statement is encountered,
program execution continues at the statement after GOSUB
.
GOTO line_number
Jumps to a line number in the program.
IF condition THEN {line_number | compound_statement}
Executes compound_statement
or jumps to line_number
if condition
evaluates to true. condition
must be a Boolean expression. There is no ELSE
clause.
INPUT [string_literal;] variable
If string_literal
is given, prints this as a prompt.
Waits for user input and assigns the value provided by the user to variable
.
When in graphics mode (set by GOSUB 600
), INPUT
is not allowed.
The optional string_literal;
is only allowed in BASICODE-3 (2nd edition) and -3C.
[LET] variable = expression
Evaluates expression
and assigns its value to variable
.
The keyword LET
may be omitted.
NEXT variable
Iterates a loop. Loops may be nested but variable
must match the initiating FOR
statement (and must not be omitted).
ON expression {GOTO| GOSUB} line_number [, line_number] ...
Evaluates expression
and uses its
value to choose from a list of jumps. expression
is a numeric expression that must evaluate to a whole number. If the value is 1
,
the statement jumps to the first line_number
, etc. The expression may not evaluate to a number greater than the number of lines specified after GOTO or GOSUB.
PRINT {expression | TAB(n)} [{ ; } {expression | TAB(n)}] ...
Outputs the values of expression
to the screen.
If ;
is used, values may be separated by a space (depending on the platform).
The pseudo-function TAB(n)
may be used to move the next expression to position n
,
where the first position is 1
or 0
and implementation-dependent. n
must be greater than 0
.
When in graphics mode (set by GOSUB 600
), PRINT
is not allowed (use GOSUB 650
).
READ variable
Reads the next DATA
literal into variable
and increments the data pointer.
The types of the literal and the variable must match.
REM comment
Is a comment and ignored.
REM
must be the last statement on the line.
comment
must not contain the colon character :
.
RESTORE
Resets the data pointer to the start. Line numbers in a RESTORE statement are not allowed.
RETURN
Exits a subroutine; execution continues at the statement following the
GOSUB
that called the subroutine.
RUN
Clears all variables and restarts the program. BASICODE-2 only; in BASICODE-3 and -3C use GOTO 1000
.
STOP
Terminates the program. BASICODE-2 only; in BASICODE-3 and -3C use GOTO 950
.
Initialises the program. The variable A
should contain the
maximum total number of characters for all strings required by the program.
After initialisation, program execution continues in line 1010
.
Additionally, in BASICODE-3 and -3C:
- sets the variable
HO
to the highest column index andVE
to the highest row index on the text screen. - sets the variable
HG
to the number or horizontal pixels andVG
to the number of vertical pixels on the graphical screen. - if called from elsewhere in the program,
GOTO 20
clears all variables and restarts.
In BASICODE-3C only, does a DIM CC(1)
, sets CC(0)
to 7
(i.e. white), CC(1)
to 0
(i.e. black), and SV
to 35
as a version identifier.
Clears the screen, switches to text mode and places the cursor in the top left corner.
In BASICODE-3C, additionally, sets the foreground colour to CC(0) and background colour to CC(1). The colour values specified here will be used until the next GOSUB 100
.
The colour values for CC(0)
and CC(1)
are as follows:
Value | Colour |
---|---|
0 |
Black |
1 |
Blue |
2 |
Red |
3 |
Magenta |
4 |
Green |
5 |
Cyan |
6 |
Yellow |
7 |
White |
Places the cursor on the row given in VE
and the column given in HO
.
The top left cell has position HO=0
and VE=0
. HO
and VE
should be greater than or equal to zero.
The maximum values of HO
and VE
are machine-dependent. In BASICODE-3 and -3C, best practice is to save their values at the start of the program and adjust the screen output accordingly. As a minimum, a text screen of 24 lines and 40 columns may be assumed.
In BASICODE-2, additionally, HO
should be less than 40
and VE
should be less than 24
.
Returns the current cursor position in the variables HO
, VE
.
Basicode-3 and -3C only. Prints the contents of variable SR$
in an emphasised way, for example in reverse video.
Three spaces are printed before and three spaces are printed after the string.
In BASICODE-3C only, uses the foreground and background colours specified in CC(0)
and CC(1)
respectively, but SR$
is actually printed with the colours in reverse video. The colours specified here will be used during this call only; any PRINT
-statements hereafter will revert to the colours specified in the last GOSUB 100
.
Polls the keyboard; if a key was pressed, returns the corresponding character in
IN$
. If no key was pressed, returns the empty string in IN$
.
Additionally, in BASICODE-3 and -3C, returns in IN
the ordinal value of the
main character on the key pressed, ignoring the shift state. For letter keys,
the main value is the ordinal value of the uppercase character; for number keys,
it is the ordinal value of the digit character. The value returned is always
in the range 32
-95
. If no key is pressed, returns 0
in IN
.
The following codes are returned for special keys:
Key | IN$ |
IN |
---|---|---|
Return | CHR$(13) |
13 |
Delete | undefined | 127 |
Left | undefined | 28 |
Right | undefined | 29 |
Down | undefined | 30 |
Up | undefined | 31 |
Additionally, in BASICODE-3C only, function keys return negative values in IN
:
F1 returns -1, F2 returns -2, etc. In BASICODE-3 (2nd edition), control keys and
function keys return an undefined negative value in IN
.
In BASICODE-3 (2nd edition) and BASICODE-3C, the delete key and the arrow keys
return a single- or multiple-character string in IN$
such that PRINT IN$
reproduces the cursor-moving and character-removing effects of the key.
Waits for a keypress and returns it in IN$
. See GOSUB 200
for the
values returned in IN$
and, in BASICODE-3 and -3C, in IN
.
Basicode-3 and -3C only.
Sets IN
to the ordinal value of the character shown on the screen
at the position given by HO
, VE
. As in GOSUB 200
, this returns the main/uppercase character. The value returned is in the range 32
-95
.
If the position in those variables is outside the text screen, sets IN
to 0
.
IN$
is unaffected by this subroutine.
In BASICODE-3C only, an offset value is returned in CN
such that CHR$(IN+CN)
reproduces the character on the screen.
This is intended to make a screen dump possible on non-ASCII systems such as the Commodore 64.
The specification notes the expectation that CN
is set to zero on most systems,
which suggests it is not the intention to use the offset to produce case sensitive results.
Sound a beep. Pitch, volume and duration are implementation-dependent.
Sets RV
to a pseudorandom value greater than or equal to 0` and less than 1
.
Runs a garbage-collection cycle and sets FR
to the number of bytes of free memory.
Basicode-3 and -3C only.
If FR=1
, disable the Break key. If FR=0
, enable it.
Set SR$
to a string representation of the number stored in SR
.
The representation has no leading or trailing spaces.
Set SR$
to a string representation of the number stored in SR
. The representation is always fixed-point
with a total length of CT
characters and CN
digits after the radix point, rounding where necessary.
If the representation does not fit, a string of length CN
containing repeated * characters is returned.
Basicode-3 and -3C only.
Set SR$
to its value, converted to uppercase.
Prints the text contained in SR$
on the line printer.
No newline is printed (unless it is contained in the string).
Prints a newline on the printer.
Basicode-3 and -3C only.
Plays a tone of pitch SP
, duration SD
, and volume SV
, where:
SP
is in the range0
-127
where60
represents the middle C, 69 is standard pitch A (440 Hz). Every integer step represents a half-note difference so that an octave has 12 steps.SD
is the duration in tenths of a second.SV
is the volume, where0
represents silence,7
is normal volume and15
represents maximum volume.
Basicode-3 and -3C only.
Waits at most SD
tenths of a second or until a key is pressed. Returns any pressed key in the same way as GOSUB 200
.
Basicode-3 and -3C only.
Opens the file with name NF$
with source and mode determined by NF
as follows:
NF |
Mode | Medium |
---|---|---|
0 | input | BASICODE tape |
1 | output | |
2 | input | Native tape or disk |
3 | output | |
4 | input | Native disk, second file |
5 | output | |
6 | input | Native disk, third file |
7 | output |
Basicode-3 and -3C only.
Returns the next string from file open under NF
into IN$
A status code is returned in IN
:
IN |
Status |
---|---|
0 | OK |
1 | End of file |
-1 | Error |
If a error or end-of-file occurs, IN$
is set to the empty string.
Basicode-3 and -3C only.
Writes the string in SR$
to the file open under NF
.
See GOSUB 540
for status codes.
Basicode-3 and -3C only.
Closes the file open under NF
.
Basicode-3 and -3C only. Switch to graphics mode and clear the screen.
In BASICODE-3C only, the screen is cleared using the background colour specified in CC(1)
, which is also kept internally for use by the other graphics subroutines.
Basicode-3 and -3C only.
Plot a point at coordinate (HO,VE)
, where HO
and VE
are in the interval [0,1[
, (0, 0)
is the top left pixel and (1, 1)
is just outside the bottom right screen corner.
If CN
equals 0, plot in foreground colour; if CN
equals 1, plot in background colour.
In BASICODE-3C, the foreground colour is the current value of CC(0)
while the background colour is the value CC(1)
had at the time GOSUB 600
was last called.
Basicode-3 and -3C only.
Draw a line to coordinate (HO,VE)
. If CN
equals 0, draw in foreground colour; if CN
equals 1, draw in background colour.
In BASICODE-3C, the foreground colour is the current value of CC(0)
while the background colour is the value CC(1)
had at the time GOSUB 600
was last called.
Basicode-3 and -3C only.
Draw text on the graphical screen, where coordinate (HO,VE)
is the top left of the text box.
If CN
equals 0, draw in foreground colour; if CN
equals 1, draw in background colour.
In BASICODE-3C, the foreground colour is the current value of CC(0)
while the background colour is the value CC(1)
had at the time GOSUB 600
was last called.
Basicode-3 and -3C only. End the program.
Files on BASICODE cassettes are stored as frequency-modulated sound. BASICODE bits all have the same duration of 1/1200 s.
- A 1-bit is represented by two wave periods at 2400 Hz.
- A 0-bit is represented by a single wave period at 1200 Hz.
Bits | Value | Function |
---|---|---|
1 | 0 | Start bit |
7 | ASCII payload, least significant bit first. | |
1 | 1 | Inverted most-significant bit of payload (for 7-bit ASCII, always 1) |
2 | 1 | Stop bits |
Bytes | Format | Meaning |
---|---|---|
5s at 2400Hz | Leader wave | |
1 | 02 |
STX |
BASICODE payload: ASCII with CR line separators. |
||
1 | 03 |
ETX |
1 | Checksum: bitwise XOR of STX , payload and ETX bytes. |
|
5s at 2400Hz | Trailer wave |
Data files are split into blocks of 1024 bytes each. The stated reason for this is to avoid needing a sentinel value to indicate the end of the block; however, the header information does not include the number of blocks nor the length of the last block.
Therefore, the end of the file needs to be indicated with an ETH
(04
) byte.
All further bytes in the block after ETH
are unspecified.
This means that, despite the 1024-byte block structure of the files, this protocol
is not suited to transfer binary files, since it is not possible to transmit a 04
without indicating the end of the file. In practice, all files in BASICODE-3 format
are ASCII files, so this problem does not arise.
Bytes | Format | Meaning |
---|---|---|
5s at 2400Hz | Leader wave | |
1 | 01 |
STH |
1 | Block sequential number; first block is 0. | |
1024 | Data payload. | |
1 | 03 |
ETX |
1 | Checksum: bitwise XOR of STH , block number, payload and ETX bytes. |
|
5s at 2400Hz | Trailer wave |
The last block will have 0 – 1023 payload bytes; the rest of the block
is filled with ETH
(04
) bytes. These bytes are included in that
block's checksum but otherwise ignored.
- Hans G. Janssen (ed.), BASICODE Hobbyscoop 2, Nederlandse Omroep Stichting, Hilversum, 1983.
- Jacques Haubrich (ed.), Het BASICODE-3 Boek, Kluwer Technische Boeken, Deventer, 1986.
- Jacques Haubrich (ed.), Het BASICODE-3 Boek (2e druk), Kluwer Technische Boeken, Deventer, 1988.
- Speciaal bulletin BASICODE-3 Verzamelcassette 5, Stichting BASICODE, 1989.
- Jacques Haubrich, Toelichting BASICODE-3C, Stichting BASICODE, 1991.