RISC OS Build EnvironmentROBE

Appendix40Appendix F: Tokenised BBC BASIC file format

Overview

This appendix describes the tokenised BBC BASIC file format used by the environment's BASIC conversion tools. It is separated from the general naming appendix so that runtime BASIC representation can be referenced on its own.

Tokenised file structure

Tokenised BBC BASIC file format

The riscos-basictokenise tool writes a tokenised BBC BASIC file as a sequence of line records followed by a fixed trailer. The editable source form should still normally be kept as textual ,fd1 files in Git, but it is useful to know the runtime format when detokenising, packaging, or inspecting generated BASIC programs.

Overall file structure

The file structure emitted by the tokeniser is:

OffsetSizeContents
0variableOne or more tokenised line records.
end-12Trailer bytes &0D &FF, marking end of file.

If the textual source does not include explicit line numbers, the tokeniser numbers lines automatically from 10 in steps of 10 before encoding them.

Line record structure

Each BASIC line is stored with a four-byte header followed by the tokenised text of the line:

OffsetSizeContents
01Line introducer byte &0D.
11High byte of the line number.
21Low byte of the line number.
31Total record length in bytes, including the four-byte header.
4variableTokenised line content.

Unlike the other multi-byte fields described in this book, which are little-endian, this line-number field is big-endian (high byte first). The single-byte total-record-length field bounds a tokenised line to 255 bytes in total, leaving at most 251 bytes for the tokenised content after the four-byte header. The two-byte line-number field can represent 0-65535, though conventional BBC BASIC interpreters restrict usable line numbers to a narrower range (typically 0-65279); this tokeniser itself performs no range check on the value supplied.

The tokeniser copies variable names, most punctuation, and quoted strings through unchanged. A line that begins with a * command is copied verbatim rather than tokenised.

Special encodings

Some items are encoded specially rather than by a simple keyword token:

BytesMeaning
0D FFEnd-of-file trailer.
8D xx xx xxEncoded line-number constant, used after keywords such as GOTO, GOSUB, RESTORE, THEN, or ELSE when they are followed by a line number.
CCBare ELSE when it appears alone on a line.
CFStatement-form PTR used as a left-value.
F4 + textA REM token followed by the remainder of the line copied without further tokenisation.
THEN/ELSE + *commandIf a * command follows THEN or ELSE, the command tail is copied verbatim.
C6 xxTwo-byte function-style token sequence.
C7 xxTwo-byte directive-style token sequence.
C8 xxTwo-byte statement-style token sequence.

The three bytes following the &8D introducer encode the target line number (0-65535) using the same bit-shuffled transformation as the classic Acorn tokenisers:

  1. Split the line number into hi (bits 8-15) and lo (bits 0-7).
  2. Build a third value from the top two bits of each: top = ((hi >> 6) << 2) | ((lo >> 6) << 4) (bits 6-7 of hi become bits 2-3 of top; bits 6-7 of lo become bits 4-5).
  3. Mask hi and lo down to their low 6 bits each.
  4. Emit three bytes, in this order: top XOR &54, then lo XOR &40, then hi XOR &40 (the low byte of the line number is emitted before the high byte).

To decode, XOR each of the three bytes back with the same constant (&54, &40, &40 respectively) to recover top, lo, and hi, then reconstruct: hi |= ((top >> 2) & 3) << 6, lo |= ((top >> 4) & 3) << 6, and the line number is (hi << 8) | lo. This matches the algorithm originally described by Matt Godbolt's analysis of the BBC BASIC line-number format, which the tokeniser's own source comments cite directly.

Direct one-byte tokens

These tokens appear directly in the line stream without a leading prefix byte:

ByteKeyword or form
7FOTHERWISE
80AND
81DIV
82EOR
83MOD
84OR
85ERROR
86LINE
87OFF
88STEP
89SPC
8ATAB(
8BELSE
8CTHEN
8EAPPEND or OPENIN
8FAUTO or PTR in expression form
90CRUNCH or PAGE
91DELETE or TIME
92EDIT or LOMEM
93HIMEM
94ABS or LIST
95ACS or LOAD
96ADVAL
97ASC
98ASN
99ATN or RENUMBER
9ABGET or SAVE
9BCOS or TEXTLOAD
9CCOUNT or TEXTSAVE
9DDEG
9EERL or TWINO
9FERR or INSTALL
A0EVAL
A1EXP
A2EXT
A3FALSE
A4FN
A5GET
A6INKEY
A7INSTR(
A8INT
A9LEN
AALN
ABLOG
ACNOT
ADOPENUP
AEOPENOUT
AFPI
B0POINT(
B1POS
B2RAD
B3RND
B4SGN
B5SIN
B6SQR
B7TAN
B8TO
B9TRUE
BAUSR
BBVAL
BCVPOS
BDCHR$
BEGET$
BFINKEY$
C0LEFT$(
C1MID$(
C2RIGHT$(
C3STR$
C4STRING$(
C5EOF
C9WHEN
CAOF
CBENDCASE
CDENDIF
CEENDWHILE
D4SOUND
D5BPUT
D6CALL
D7CHAIN
D8CLEAR
D9CLOSE
DACLG
DBCLS
DCDATA
DDDEF
DEDIM
DFDRAW
E0END
E1ENDPROC
E2ENVELOPE
E3FOR
E4GOSUB
E5GOTO
E6GCOL
E7IF
E8INPUT
E9LET
EALOCAL
EBMODE
ECMOVE
EDNEXT
EEON
EFVDU
F0PLOT
F1PRINT
F2PROC
F3READ
F4REM
F5REPEAT
F6REPORT
F7RESTORE
F8RETURN
F9RUN
FASTOP
FBCOLOUR
FCTRACE
FDUNTIL
FEWIDTH
FFOSCLI

Prefixed two-byte tokens

The tokeniser also emits these prefixed token sequences:

BytesKeyword or form
C6 8ESUM
C6 8FBEAT
C7 93HELP
C7 96LVAR or WAIT
C7 97NEW
C7 98OLD or QUIT
C7 9DTWIN
C8 8ECASE
C8 8FCIRCLE
C8 90FILL
C8 91ORIGIN
C8 92POINT
C8 93RECTANGLE
C8 94SWAP
C8 95WHILE
C8 97MOUSE
C8 99SYS
C8 9BLIBRARY
C8 9CTINT
C8 9DELLIPSE
C8 9EBEATS
C8 9FTEMPO
C8 A0VOICES
C8 A1VOICE
C8 A2STEREO
C8 A3OVERLAY

Conversion workflow

Tokenising and detokenising a program

riscos-basictokenise and riscos-basicdetokenise convert between textual and tokenised BASIC:

riscos-basictokenise program.bas program,ffb
riscos-basicdetokenise -i program,ffb

For a program using only ordinary statements, the round trip is exact: the detokenised text matches the original line for line.

riscos-basicdetokenise does not decode the &8D line-number constant token described above: it prints the three raw transformed bytes as characters under an unlistable token label rather than recovering the original line number. Programs that use GOTO, GOSUB, or similar with a literal line-number target should be checked by eye against the source, not assumed to round-trip cleanly through this tool.