Renumber 1

Date: 198x
Type: Program
Platform(s): TS 2068

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:

  1. Machine code installation (lines 1–18): 120 bytes are READ from DATA statements and POKEd into RAM immediately below the VARS area.
  2. Parameter collection (lines 9991–9996): The user is prompted for the old starting line, new starting line, step increment, and stopping line number.
  3. 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 OffsetParameterLine POKEd
VARS-120 / VARS-119Old starting line number9992
VARS-86 / VARS-85Address returned by first USR call9993
VARS-83 / VARS-82New starting line number9994
VARS-48 / VARS-47Step value9995
VARS-80 / VARS-79Old stopping line number9996

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 variable b (value 0) as a zero placeholder in DATA statements is an unusual approach; it relies on b not 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 b in DATA statements (lines 7, 11–15) is potentially fragile. If b were ever assigned a non-zero value before line 3 executes, the machine code bytes would be corrupted. In practice this works because b is never assigned, but it is not robust.
  • Line 9996 ends with STOP rather than transitioning to 9997 automatically, meaning the user must manually continue (e.g., with CONTINUE) to trigger the renumber. This appears intentional, giving the user a chance to abort.
  • Line 9997 uses IF USR (VARS-87) THEN with 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

Appears On

Library tape of the Indiana Sinclair Timex User’s Group.

Related Products

Related Articles

Related Content

Image Gallery

Renumber 1

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.

People

No people associated with this content.

Scroll to Top