This program is a BASIC line renumbering utility that operates on the program area in RAM. It loads 120 bytes of Z80 machine code into memory just below the VARS area (using PEEK 23627/23628 to locate it), then uses that code — invoked via USR calls — to scan the program’s line table, relocate line numbers, and patch internal GO TO/GO SUB targets. The user is prompted for the old starting line number, a new starting line number, a step value, and an ending line number; these parameters are POKEd as 16-bit little-endian values into fixed offsets relative to VARS. Line 9999 contains a dense REM statement whose bytes encode additional Z80 machine code or data used by the renumbering engine. The SAVE at line 9989 preserves the program with auto-run from line 1.
Program Analysis
Program Structure
The program is organized into three phases:
- Machine code installation (lines 1–18): 120 bytes are READ from DATA statements and POKEd into RAM immediately below the VARS area.
- Parameter collection (lines 9991–9996): The user is prompted for the old starting line, new starting line, step increment, and stopping line number.
- Execution (line 9997): The renumber routine is triggered via
USR (VARS-87); on completion line 9998 prints a confirmation message.
Lines 9988–9990 form a save/stop guard: GO TO 9991 skips the SAVE on normal runs, while deliberately running from line 9988 would trigger the SAVE command.
Machine Code Installation
Lines 2–5 compute the load address as PEEK 23627 + 256*PEEK 23628 - 121, which is 121 bytes below the start of the VARS area. This makes the code position-independent with respect to program size — wherever VARS sits in RAM, the machine code lands just beneath it. The 120 bytes are loaded by a simple FOR/READ/POKE loop. The letter b appearing in the DATA lines (e.g., lines 7, 11, 12, 13, 14, 15) is unusual: as a BASIC variable it would evaluate to whatever b currently holds (likely 0), making those bytes effectively zero — these are likely placeholder addresses or zero-valued operands in the Z80 code that are patched at runtime via the POKE statements in lines 9992–9996.
Parameter Passing via Memory Offsets
All parameters are communicated to the machine code through fixed negative offsets from VARS, stored as 16-bit little-endian values. The offsets used are summarized below:
| VARS Offset | Parameter | Line POKEd |
|---|---|---|
| VARS-120 / VARS-119 | Old starting line number | 9992 |
| VARS-86 / VARS-85 | Address returned by first USR call | 9993 |
| VARS-83 / VARS-82 | New starting line number | 9994 |
| VARS-48 / VARS-47 | Step value | 9995 |
| VARS-80 / VARS-79 | Old stopping line number | 9996 |
Line 9992 also calls USR (VARS-121) to locate the first matching line in the program, storing the resulting address for subsequent renumbering operations. Line 9997 calls USR (VARS-87) to actually perform the renumbering pass.
The REM at Line 9999
Line 9999 contains a long REM statement filled with BASIC keyword tokens and symbol characters. On the Spectrum, REM contents are stored verbatim as bytes in the program area; this REM likely encodes additional Z80 machine code or lookup tables used by the renumbering engine, accessed by the machine code routines at known offsets from the line’s position in memory. This is a standard technique for embedding data or code in a REM without it being executed as BASIC.
Notable Techniques
- VARS-relative addressing: By anchoring all code and data to VARS, the utility works regardless of where the program sits in RAM or how long it is.
- 16-bit little-endian POKE idiom:
Q - 256*INT(Q/256)extracts the low byte;INT(Q/256)extracts the high byte — the standard Spectrum BASIC technique for storing integers wider than one byte. - DATA bytes with variable
b: Using the uninitialized variableb(value 0) as a zero placeholder in DATA statements is an unusual approach; it relies onbnot being set before the READ loop executes. - Two-stage USR invocation: The first USR call (line 9993) performs a search/locate pass; the second (line 9997) performs the actual renumbering, allowing the address of the target line to be verified before modification.
- PRINT with double newline
'': Lines 9993–9995 use the''idiom (two consecutive newline characters in PRINT) to add blank lines between prompts for readability.
Bugs and Anomalies
- The use of
bin DATA statements (lines 7, 11–15) is potentially fragile. Ifbwere ever assigned a non-zero value before line 3 executes, the machine code bytes would be corrupted. In practice this works becausebis never assigned, but it is not robust. - Line 9996 ends with
STOPrather than transitioning to 9997 automatically, meaning the user must manually continue (e.g., withCONTINUE) to trigger the renumber. This appears intentional, giving the user a chance to abort. - Line 9997 uses
IF USR (VARS-87) THENwith no consequent statement, which is legal BASIC (the line simply does nothing visible on a true result) but unusual — the renumber routine’s return value is effectively ignored, and the fall-through to 9998 always occurs.
Content
Source Code
1 REM "renumber"-TSUG of Las Vegas
2 LET j=PEEK 23627+256*PEEK 23628-121
3 FOR n=0 TO 119: READ b
4 POKE j+n,b
5 NEXT n
6 GO TO 9991
7 DATA 1,0,b,33,83,92,94,35,86,235
8 DATA 167,126,184,35,56,10,32,4,126,185,56,4
9 DATA 43,77,68,201
10 DATA 35,94,35,86,25,35,24,232
11 DATA 33,0,b,17,0,b
12 DATA 1,0,b,167,126,35,184,56,4,192,126,185,208
13 DATA 43,1,5,39,167,126,35,184,56,4,192,126,185,208
14 DATA 43,114,35,115,235,1,0,b,9,235,35,78,35,70,229,9,68,77,225,35
15 DATA 62,14,190,32,5,35,b,b,b,b
16 DATA 62,236,190,40,4,60,190,32,3
17 DATA 35,54,143
18 DATA 35,229,167,237,66,225,56,226,35,24,175
9988 GO TO 9991
9989 SAVE "RENUMBER" LINE 1
9990 STOP
9991 CLS : PRINT "old starting line number:";: INPUT q: PRINT q
9992 LET VARS=PEEK 23627+256*PEEK 23628: POKE VARS-120,Q-256*INT (Q/256): POKE VARS-119,INT (Q/256)
9993 LET Q=USR (VARS-121): POKE VARS-86,Q-256*INT (Q/256): POKE VARS-85,INT (Q/256): PRINT "ADDRESS: ";Q,: PRINT "LENGTH; ";PEEK (Q+2)+256*PEEK (Q+3)+4''
9994 PRINT "NEW STARTING LINE NUMBER: ";: INPUT Q: POKE VARS-83,Q-256*INT (Q/256): POKE VARS-82,INT (Q/256): PRINT Q''
9995 PRINT "STEP: ";: INPUT Q: POKE VARS-48,Q-256*INT (Q/256): POKE VARS-47,INT (Q/256): PRINT Q''
9996 PRINT "OLD LINE STOPPING NUMBER: ": INPUT Q: POKE VARS-80,Q-256*INT (Q/256): POKE VARS-79,INT (Q/256): PRINT Q: STOP
9997 IF USR (VARS-87) THEN
9998 PRINT AT 13,5;"RENUMBERING COMPLETE.": STOP
9999 REM 5555!S\^#V FOR PI~LN #8 ~EXP 8+MD<>#^#V# CONTINUE !PI~#LN 8USR ~EXP FORMAT +'PI~#LN 8USR ~EXP FORMAT +r#s FOR FOR #N#F RESTORE DM LLIST #>###> GO TO PEEK (<PEEK #6\::# RESTORE PI GO SUB B LLIST 8 STOP #CODE
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
