Renumber

Developer(s): Charles Stelding
Date: 1982
Type: Program
Platform(s): TS 2068

This program is a BASIC renumbering utility that rewrites line number references (GO TO, GO SUB, ON ERR GO TO, RESTORE, etc.) throughout a BASIC program. The bulk of the work is performed by 383 bytes of Z80 machine code, loaded into RAM at address 64986 via a hex-string DATA loader in lines 9943–9991. The DATA loader decodes pairs of ASCII hex digits from 48 DATA strings into raw bytes using the expression (CODE a$(k)-48-(7 AND a$(k)>"9"))*16+..., a standard technique for embedding machine code in BASIC. At runtime, line 9998 prompts for a starting line number and step value, stores them into memory-mapped variables at addresses 23297–23299, then transfers control to the machine code with RANDOMIZE USR 64986. The utility is designed to be MERGEd into the target program, used once, then removed.


Program Analysis

Program Structure

The program divides cleanly into four parts:

  1. Lines 10–12: REM documentation describing the utility’s purpose and usage instructions.
  2. Line 9943: The DATA loader — reads 48 hex strings and POKEs decoded bytes to address 64986 onward.
  3. Lines 9944–9991: 48 DATA statements, each containing 16 hex-encoded bytes (8 bytes per string × 2 chars each = 16 chars, actually 16 hex digits = 8 bytes per line, giving 48 × 8 = 384 bytes, though the header states 383).
  4. Lines 9998–9999: The user-facing entry point: prompts for start line and step, stores parameters, invokes machine code, then LISTs the result.

Machine Code Loader (Line 9943)

The loader at line 9943 uses a compact but well-known hex-decode idiom:LET num=(CODE a$(k)-48-(7 AND a$(k)>"9"))*16+(CODE a$(k+1)-48-(7 AND a$(k+1)>"9"))

This converts each pair of ASCII hex characters to a byte value. Subtracting 48 converts digits ‘0’–’9′ to 0–9. The extra -7 adjustment (applied when the character is greater than ‘9’) handles the gap between ‘9’ (57) and ‘A’ (65) in ASCII, correctly converting hex letters A–F to 10–15. The result is POKEd sequentially from address 64986.

The loader iterates with FOR j=1 TO 48 (one iteration per DATA string) and an inner FOR k=1 TO LEN a$ STEP 2 walking character pairs. After loading, a LIST is executed, which is an unusual choice — it may be intended to confirm loading completed, or it is a leftover artifact.

Parameter Passing (Line 9998)

Line 9998 stores the user-supplied renumbering parameters into fixed memory locations before invoking the machine code routine:

AddressContentHow stored
23297Low byte of starting line numberL-(INT(L/256))*256
23298High byte of starting line numberINT(L/256)
23299Step valueDirect POKE of L

Addresses 23297–23299 fall in the system variables area (RAMTOP and surrounding bytes on the standard Spectrum/TS2068 map). The machine code reads these three bytes as its configuration inputs. The low/high byte split uses integer division rather than bitwise operations, which is the idiomatic BASIC approach on this platform.

Note that the step value is stored as a single byte (POKE accepts 0–255), limiting the renumbering step to a maximum of 255.

Machine Code Routine

The 383-byte Z80 routine at 64986 performs the actual renumbering. Based on the DATA content and the described behaviour, it walks the BASIC program area (whose start address is read from system variable PROG at 23635, i.e., 2A 53 5C = LD HL,(5C53h)) and scans each line for keyword tokens that are followed by line number arguments. Tokens handled include GO TO, GO SUB, RESTORE, and ON ERR GO TO. For each such reference it finds, it calculates the new line number and overwrites the relevant bytes in place.

The routine uses ROM calls (visible as CD 4C FF, CD 41 FF, CD EE 0A, CD E2 FE, CD D4 FE, etc.), leveraging existing ROM floating-point and display routines rather than implementing them from scratch. The RANDOMIZE USR 64986 call in line 9998 is the standard method for invoking machine code from BASIC.

Notable Techniques

  • Hex DATA loader: Encoding machine code as hex strings in DATA statements avoids the need for a separate binary file or POKE-per-byte listings, and is resilient to line re-ordering.
  • MERGE workflow: The utility is designed to be MERGEd into the target program at high line numbers (9943–9999), used, then deleted with DELETE, keeping the utility self-contained and non-destructive to the user’s code below line 9943.
  • ROM call reuse: The machine code delegates number parsing and display to existing ROM routines, keeping the routine compact at under 400 bytes.
  • RESTORE 9944 at the start of line 9943 ensures the DATA pointer is correctly positioned regardless of prior BASIC execution state.

Potential Issues and Anomalies

  • The header claims 383 bytes but 48 DATA strings × 8 bytes = 384 bytes. This is a minor discrepancy; the machine code likely ends one byte short of the full 384, with the last byte unused or the count off by one.
  • The step value is limited to a single byte (0–255) due to the direct POKE at address 23299, which may be too restrictive for programs with widely spaced line numbers if a step larger than 255 is desired.
  • The LIST at the end of line 9943 causes the screen to scroll through the program after loading, which may be disorienting but is not harmful.
  • Line 9999 executes LIST after renumbering completes, providing immediate visual confirmation of the result.

Content

Appears On

One of a series of library tapes. Programs on these tapes were renamed to a number series. This tape contained

Related Products

Related Articles

Related Content

Image Gallery

Renumber

Source Code

   10 REM RENUMBER UTILITY       from "40 Best Machine Code Routines for the ZX Spectrum" by John Hardman & Andrew Hewson, 1982  adapted to the Timex 2068 by    Charles Stelding                1415 S. Baxter                  Tyler TX 75701                  214 593-3331   
   11 REM This utility will renumber GOSUBS, ON ERR GOTO, GOTO, RESTORE, etc. within the BASIC line.
   12 REM To use this routine, enter RUN, SAVE the code as SAVE "RENUMBER"CODE 64986,383, DELETE 10,9996 and MERGE line 9998 into your program you wish to renumber. Type goto 9998 and you will be prompted to enter the new line number and how you wish it to be renumbered.
 9943 RESTORE 9944: LET addr=64986: PRINT "Loading   DATA lines...": FOR j=1 TO 48: READ a$: FOR k=1 TO LEN a$ STEP 2: LET num=(CODE a$(k)-48-(7 AND a$(k)>"9"))*16+(CODE a$(k+1)-48-(7 AND a$(k+1)>"9")): POKE addr,num: LET addr=addr+1: NEXT k: NEXT j: LIST 
 9944 DATA "2A015B7CB5C82A03"
 9945 DATA "5B7CB5C82A535CED"
 9946 DATA "5B015BCD4CFF3016"
 9947 DATA "4672234E73237123"
 9948 DATA "7023E52A035B19EB"
 9949 DATA "E1CD41FF18E52A53"
 9950 DATA "5C23232323CDEBFE"
 9951 DATA "D2B8FE545D060004"
 9952 DATA "237EFE2E2003EB18"
 9953 DATA "ECFE0E20F2232323"
 9954 DATA "2323237EFE3A2804"
 9955 DATA "FE0D20EA78FE0428"
 9956 DATA "1030E3D5626BF53E"
 9957 DATA "30CDEE0AF13CD118"
 9958 DATA "EC424BD521000011"
 9959 DATA "E803CDE2FE116400"
 9960 DATA "CDE2FE1E0ACDE2FE"
 9961 DATA "0AD6305F19444D2A"
 9962 DATA "535C2323CD4CFF38"
 9963 DATA "03E118997EB93007"
 9964 DATA "2323CD41FF18EB23"
 9965 DATA "7EB838F52B2B4E2B"
 9966 DATA "6669C1C5E511E803"
 9967 DATA "CDD4FE116400CDD4"
 9968 DATA "FE1E0ACDD4FE1E01"
 9969 DATA "CDD4FE0397020302"
 9970 DATA "03E17D02037C0203"
 9971 DATA "9702E1C30FFE2A53"
 9972 DATA "5C2323CD4CFFD054"
 9973 DATA "5D2323CD41FFE537"
 9974 DATA "ED522BEB732372E1"
 9975 DATA "18E73E30A7ED5238"
 9976 DATA "033C18F8190203C9"
 9977 DATA "0A03D62F3DC81918"
 9978 DATA "FB7ECD4CFFD0FEEA"
 9979 DATA "200D237EFE0D20FA"
 9980 DATA "232323232318EAFE"
 9981 DATA "222009237EFE2220"
 9982 DATA "FA2318DDFE0D28E8"
 9983 DATA "CD021628D4FEED28"
 9984 DATA "1BFEEC2817FEF728"
 9985 DATA "13FEF0280FFEE528"
 9986 DATA "0BFEE12807FECA28"
 9987 DATA "032318B5237EFE30"
 9988 DATA "38AFFE3A30ABC97E"
 9989 DATA "CD021628FBFE0D23"
 9990 DATA "20F5E5D5ED5B4B5C"
 9991 DATA "A7ED52D1E1C97E00"
 9998 INPUT "BEGINNING NEW LINE #? ";L: POKE 23298,INT (L/256): POKE 23297,L-(INT (L/256))*256: INPUT "STEP? ";L: POKE 23299,L: RANDOMIZE USR 64986
 9999 LIST 

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

Scroll to Top