This program dumps and decodes the entire variable area in human-readable form, walking through memory starting at the address stored in system variables VARS (23627–23628). It identifies all seven variable types — single-letter numerics, multi-character named numerics, numeric arrays, FOR-NEXT loop control blocks, strings, and string arrays — by inspecting the high three bits of each entry’s first byte. Numeric values are decoded from the Spectrum’s five-byte floating-point format, including the sign bit, biased exponent (offset 128), and mantissa reconstruction across bytes 2–5. The FOR-NEXT loop handler extracts the current value, limit, step, line number, and statement counter from the control block, displaying them with labeled column alignment using TAB.
Program Structure
The program is organized as a dispatcher with a main loop and a set of subroutines. Lines 10–70 form the main loop: they read the current byte at pointer p, determine the variable type from the upper three bits, and branch to one of six handlers. Line 25 detects the end-of-variable-area sentinel byte (128). Lines 100–650 are the six type handlers, and lines 800–940 are shared utility subroutines.
| Lines | Role |
|---|---|
| 1–5 | Initialization: screen colors, dimension work array |
| 10–70 | Main dispatch loop |
| 100–120 | Handler: single-letter numeric variable (type 3) |
| 200–270 | Handler: multi-character numeric variable (type 5) |
| 300–330 | Handler: numeric array (type 4) |
| 400–465 | Handler: FOR-NEXT loop control block (type 7) |
| 500–550 | Handler: string variable (type 2) |
| 600–650 | Handler: string array (type 6) |
| 800–875 | Subroutine: read and decode 5-byte float/integer |
| 900–945 | Subroutine: read array header (dimensions and total element count) |
Variable Area Navigation
The starting address is fetched via PEEK 23627+256*PEEK 23628, which reads the two-byte system variable VARS. The pointer p is advanced manually after each field is consumed. This byte-by-byte traversal mirrors what the Spectrum ROM itself does when searching for variables.
Type Dispatch Mechanism
At line 30, p2 = INT(p1/32) extracts the top three bits of the first byte (equivalent to a right-shift by 5). The resulting value identifies the variable type:
p2=3— single-letter numeric (bits 011)p2=5— multi-character numeric name (bits 101)p2=4— numeric array (bits 100)p2=7— FOR-NEXT loop control (bits 111)p2=2— string variable (bits 010)p2=6— string array (bits 110)
Five-Byte Floating-Point Decoder (Lines 800–875)
The Spectrum stores all numeric variables in a five-byte format. Subroutine 800 first reads five bytes into array b(). If b(1) is zero, the value is a short integer stored in b(3) and b(4), with b(2)=255 signaling a negative value (two’s complement adjusted by subtracting 65536).
For true floating-point values, b(1) holds the biased exponent (bias 128), b(2) holds the sign in its high bit plus the implicit leading mantissa bit, and bytes 3–5 hold the remaining mantissa. The reconstruction at line 855 iterates j=2 TO 5, accumulating b(j)/256^(j-1). After restoring the implicit bit and adjusting the exponent at line 860, the result is scaled by 2^b(1). The sign flag m is applied last.
Multi-Character Variable Name Decoding (Lines 200–260)
In the Spectrum variable area, multi-character names encode the first letter with bit 6 set (adding 64) and the last letter with bit 7 set (adding 128), while intermediate letters are stored as plain ASCII. The handler subtracts 64 from the first byte and 128 from the last byte to recover the original characters, printing them in sequence.
FOR-NEXT Loop Block Handler (Lines 400–465)
A FOR-NEXT control block stores five values in sequence: the current loop value, the limit (TO value), the step, the line number (two bytes), and the statement number within that line. The handler calls subroutine 800 three times to decode the floating-point current, limit, and step values, then reads the two-byte line number and one-byte statement index directly with PEEK.
Array Header Subroutine (Lines 900–940)
Subroutine 900 reads the two-byte total byte-length field, then the dimension count d, then iterates over each dimension’s two-byte element count. It computes the total number of elements t as a running product (line 920), and prints the dimension sizes separated by commas before the closing parenthesis. The pointer is left one byte before the first element so that subsequent loops calling subroutine 800 (which pre-increments p) land correctly.
Notable Techniques
- The array
b(5)(line 5) is reused on every call to subroutine 800, avoiding repeated variable declarations. TABcolumns are used consistently for value alignment: column 16 for numeric values, column 22 for labels, giving the output a structured columnar appearance.- The main loop uses
GO TO 20rather than aFORloop, since the step between entries is variable-length and depends on the type just processed.
Bugs and Anomalies
- String array elements (lines 610–640): The handler reads only one byte per element (
CHR$ PEEK p), which is incorrect for multi-character string array elements. Each element in a string array occupies a fixed number of characters defined by the last array dimension, so only the first character of each element is shown. - Typo at line 60: The REM comment reads “string aray” (missing ‘r’), which is cosmetic only.
- Floating-point sign bit handling (line 850): When
b(2)is less than 128 the sign flagmis set to 0 (positive) and 128 is added back tob(2)to restore the implicit leading mantissa bit. This logic is inverted from what the comment might suggest but is arithmetically correct for the Spectrum’s format.
Content
Source Code
1 PAPER 0:BORDER 0:INK 9
5 DIM b(5)
10 LET p= PEEK 23627+256* PEEK 23628
20 PRINT p; TAB 6;:LET p1= PEEK p
25 IF p1=128 THEN PRINT TAB 7;"END OF VARIABLE AREA":STOP
30 LET p2= INT (p1/32)
35 IF p2=3 THEN GO TO 100:REM number (single-letter name)
40 IF p2=5 THEN GO TO 200:REM number (multi-character name)
45 IF p2=4 THEN GO TO 300:REM number array
50 IF p2=7 THEN GO TO 400:REM loop control
55 IF p2=2 THEN GO TO 500:REM string
60 IF p2=6 THEN GO TO 600:REM string aray
70 STOP :REM error if this line is reached
100 REM number:-
105 PRINT CHR$ p1;
110 GO SUB 800
115 PRINT TAB 16;n
120 LET p=p+1:GO TO 20
200 PRINT CHR$ (p1-64);:REM first letter
210 LET p=p+1
220 LET p1= PEEK p
230 IF p1 >=128 THEN GO TO 260
240 PRINT CHR$ p1;:REM middle letters (if any)
250 GO TO 210
260 PRINT CHR$ (p1-128);:REM last letter
270 GO TO 110
300 PRINT CHR$ (p1-32);"(";
305 GO SUB 900
310 FOR k=1 TO t
315 GO SUB 800
320 PRINT TAB 3;"element #";k; TAB 16;n
325 NEXT k
330 LET p=p+1:GO TO 20
400 PRINT CHR$ (p1-128);
410 GO SUB 800
420 PRINT TAB 9;"(LOOP)"; TAB 16;n; TAB 22;"Current"
425 GO SUB 800
430 PRINT TAB 16;n; TAB 22;"Limit (TO)"
435 GO SUB 800
440 PRINT TAB 16;n; TAB 22;"STEP"
450 LET l= PEEK (p+1)+256* PEEK (p+2):LET s= PEEK (p+3):LET p=p+4
455 PRINT TAB 16;l; TAB 22;"Line No."
460 PRINT TAB 16;s; TAB 22;"Statement"
465 GO TO 20
500 PRINT CHR$ p1;"$"; TAB 16;
510 LET l= PEEK (p+1)+256* PEEK (p+2):LET p=p+2
520 FOR j=1 TO l
530 PRINT CHR$ PEEK (p+j);
540 NEXT j:PRINT
550 LET p=p+j:GO TO 20
600 PRINT CHR$ (p1-128);"$(";
605 GO SUB 900
610 FOR k=1 TO t
620 LET p=p+1
630 PRINT TAB 3;"element #";k; TAB 16; CHR$ PEEK p
640 NEXT k
650 LET p=p+1:GO TO 20
800 REM integer
805 FOR j=1 TO 5
810 LET p=p+1:LET b(j)= PEEK p
815 NEXT j
820 IF b(1) THEN GO TO 845
825 LET n=b(3)+256*b(4):IF b(2)=255 THEN LET n=n-65536
830 RETURN
845 REM floating point
850 LET m=1:IF b(2)<128 THEN LET m=0:LET b(2)=b(2)+128
855 LET n=0:FOR j=2 TO 5:LET n=n+b(j)/256^(j-1):NEXT j
860 LET b(1)=b(1)-128
865 LET n=n*2^b(1)
870 IF m THEN LET n=-n
875 RETURN
900 REM arrays
905 LET p1= PEEK (p+1)+256* PEEK (p+2):LET p=p+3
910 LET d= PEEK p:LET p=p+1
915 LET t=1:FOR j=1 TO d
920 LET el= PEEK p+256* PEEK (p+1):LET t=t*el:PRINT el
925 IF d <>1 AND j <>d THEN PRINT ",";
930 LET p=p+2:NEXT j:PRINT ")"
940 LET p=p-1
945 RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
