This program is a BASIC renumbering utility that operates in two distinct parts. Lines 9949–9956 implement a line-listing display routine that walks through program memory using the system variable at address 23635–23636 (PROG, the start-of-BASIC pointer) to read and print each line number and its tokenised source. Lines 9957–9998 form the renumbering engine: it prompts for a start number and step, then scans the program body from address 26710 (stored in `bs`) to patch line headers via direct POKE operations and resolve all GO TO and GO SUB targets (token bytes 236 and 237) by scanning the ASCII digits before the embedded five-byte floating-point literal (token 14). The renumberer searches backward through digit characters to reconstruct the referenced line number, locates it in the program, calculates its new number, and prints the updated value — notably it prints rather than POKEs the GO TO/GO SUB arguments, meaning the user sees what needs changing rather than having them automatically rewritten. The program saves itself with SAVE “BASRENUM” at line 9999.
Program Structure
The listing splits cleanly into two functional sections, both residing at the top of the line-number space (9949–9999) so they can coexist with any user program loaded below them:
- Lister (9949–9956): Reads the
PROGsystem variable from addresses 23635–23636, iterates through the tokenised program body, and prints each line with its line number right-aligned at column4-LEN STR$ l. - Renumberer (9957–9998): Accepts a start number and step, walks the program from the hard-coded base address stored in
bs(26710), rewrites line-header bytes withPOKE, and identifies but only prints GO TO / GO SUB targets rather than patching them automatically.
Key Variables
| Variable | Role |
|---|---|
g | Byte pointer into program memory; also reused as new start line number |
l | Current line number (lister) / decimal place accumulator (renumberer) |
bs | Hard-coded base address of the program to renumber (26710) |
ff | Renumber step size |
m | Running new line number counter |
i | Byte pointer used by the renumberer scan loop |
j, k, n | Offset counter, target line number, and ordinal index of matched line |
h | Token discriminator: 1 = GO TO (236), 2 = GO SUB (237) |
Memory Layout Assumptions
The lister uses the standard system variable PROG held as a 16-bit little-endian word at 23635–23636. Each BASIC line in memory follows the layout: [high byte of line no.][low byte of line no.][length low][length high][tokens…][0x0D]. The lister reconstructs the line number as PEEK g * 256 + PEEK (g+1) (big-endian), advances g by 4 to skip the header, then prints tokens until it encounters a newline byte (13).
The renumberer hard-codes bs = 26710 as the start of the target program. This means the utility and the program being renumbered must coexist in memory at a known layout; the constant would need manual adjustment for a different host address.
Token Detection Idioms
The five-byte floating-point embedded number is detected by token byte 14. The renumberer skips these literals in the lister (line 9952) and uses their presence as an anchor when reconstructing a GO TO / GO SUB argument (line 9974–9977).
GO TO and GO SUB are identified by their token codes 236 and 237 respectively. The boolean expression on line 9965 exploits the fact that 1 AND condition evaluates to 1 or 0, giving h the value 1, 2, or 0 — a compact multi-way flag without IF chains.
The keyword strings on line 9969 use string multiplication by a boolean: (" GO TO " AND h=1) produces the string when true, or an empty string when false — a classic Spectrum BASIC string-selection idiom.
Renumbering Algorithm
- Walk lines from
bs; at each newline (byte 13), check whether the following byte exceeds 34 (i.e., the line number MSB is in range). If above 34, branch to the POKE phase (9990). - For each GO TO / GO SUB found, scan forward up to 5 bytes to locate the embedded float marker (14), then read the ASCII digit characters backward to reconstruct the decimal target line number
k. - Count how many lines from
bshave a header value less thankto find ordinaln, then compute the new target asg + n * ff. - Print (do not POKE) the new target value — the user must manually correct GO TO / GO SUB arguments or use a companion editor.
- The POKE phase (9990–9998) iterates all lines and rewrites the two-byte big-endian line number in each header, splitting the new value into high byte (
j) and low byte (gafter repeated subtraction of 256).
Notable Techniques
- Right-aligning line numbers in the lister via
AT PI,4-LEN STR$ l— usingPI(truncated to 3) as the row avoids a separate row variable. - Skipping floating-point literals with
IF PEEK g=14 THEN LET g=g+6(line 9952) — the token plus 5 bytes of IEEE-like mantissa/exponent. - The digit-reconstruction loop (9978–9982) walks right-to-left through ASCII digit bytes, accumulating
kusing an explicit powers-of-ten multiplierl. PAUSE 0on line 9956 halts the lister between pages, consistent with the keypress-wait idiom.
Bugs and Anomalies
- The renumberer only prints GO TO / GO SUB new targets; it does not patch them. The program is therefore a semi-automatic aid rather than a fully automatic renumberer — the user must act on the printed output.
Content
Image Gallery
Source Code
9949 LET g=PEEK 23635+PEEK 23636*256
9950 LET l=PEEK g*256+PEEK (g+1): LET g=g+4
9951 PRINT AT PI,4-LEN STR$ l;l;
9952 IF PEEK g=14 THEN LET g=g+6
9953 IF PEEK g=13 THEN LET l=0
9954 PRINT CHR$ PEEK g;: LET g=g+1
9955 IF l THEN GO TO 9952
9956 PAUSE 0: CLS : GO TO 9950
9957 LET bs=26710: REM RENUM STARTS HERE
9958 INPUT " INPUT start no. ";g: INPUT " THEN INPUT STEP ";ff
9959 LET m=g: CLS
9960 PRINT "Change these lines": LET i=bs+4
9961 IF PEEK i<>13 THEN GO TO 9965
9962 IF PEEK (i+1)>34 THEN GO TO 9990
9963 LET m=m+ff
9964 LET i=i+5
9965 LET h=(1 AND PEEK i=236)+(2 AND PEEK i=237)
9966 IF PEEK i=14 THEN LET i=i+5
9967 IF h THEN GO SUB 9969
9968 LET i=i+1: GO TO 9961
9969 PRINT m;(" GO TO " AND h=1)+(" GO SUB " AND h=2);
9970 LET h=0
9971 IF PEEK (i+1)>=48 AND PEEK (i+1)<58 THEN GO TO 9973
9972 PRINT " * ": RETURN
9973 LET j=2
9974 IF PEEK (i+j)=14 THEN GO TO 9978
9975 LET j=j+1
9976 IF j>5 THEN GO TO 9972
9977 GO TO 9974
9978 LET l=1: LET k=0
9979 LET k=k+(PEEK (i+j-1)-48)*l
9980 LET j=j-1
9981 IF PEEK (i+j-1)=236 OR PEEK (i+j-1)=237 THEN GO TO 9983
9982 LET l=l*10: GO TO 9979
9983 LET j=bs: LET n=0
9984 IF PEEK j*256+PEEK (j+1)>=k THEN GO TO 9988
9985 LET n=n+1
9986 LET j=j+(PEEK (j+2)+PEEK (j+3)*256)+4
9987 GO TO 9984
9988 LET k=g+n*ff
9989 PRINT k: RETURN
9990 LET j=0: LET i=bs
9991 GO SUB 9994
9992 LET i=i+PEEK (i+2)+PEEK (i+3)*256+4
9993 GO TO 9991
9994 IF PEEK i>34 THEN STOP
9995 IF g<256 THEN GO TO 9997
9996 LET j=j+1: LET g=g-256
9997 POKE i,j: POKE (i+1),g
9998 LET g=g+ff: RETURN
9999 SAVE "BASRENUM"
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.