--- title: "Line Renumber Routine" id: 56809 type: "computer_media" slug: "renumber-routine" url: "http://localhost/computer_media/renumber-routine/" markdown_url: "http://localhost/computer_media/renumber-routine.md" published_at: "2024-09-29T02:23:28+00:00" modified_at: "2026-04-03T07:58:51+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/09/299_LRS.png" excerpt: "A pure-BASIC line renumbering subroutine that directly manipulates memory headers to reassign line numbers across any range of your program — no machine code needed." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" genre: - name: "Programming" slug: "programming" taxonomy: "genre" url: "http://localhost/type/programming/" media_contents: - id: 56738 title: "Timex Sinclair Public Domain Library Tape 1007" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-1007/" media_type: "Program" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/09/299_LRS.png" media_type_tags: "Programming" --- This BASIC subroutine renumbers a specified range of program lines in memory without requiring any machine code. It works by directly manipulating the BASIC program area starting at address 16509, walking the linked-list structure of BASIC lines (each line header stores its number in two bytes and its length in the following two bytes) to locate user-specified start and end lines, then POKEing new line numbers into memory. The routine accepts three inputs: the last line to renumber, the first line to renumber, and a new starting line number with an increment value. A boundary check prevents renumbering into the reserved 9970–9999 range used by the subroutine itself. *** ## Program Analysis ### Program Structure The listing is a self-contained subroutine occupying lines 9950–9999. Lines 9950–9970 are housekeeping/setup lines (SAVE, LIST, REM, STOP) intended to be deleted before the subroutine is embedded in a host program. The operative logic runs from line 9971 onward and divides into three phases: 1. **Line-search subroutine (9971–9979):** Starting at the BASIC program area, walks the program’s line headers to find a user-specified line number. 2. **Input phase (9980–9989):** Prompts the user for the last line to renumber, the first line to renumber, a new starting number, and an increment. 3. **Renumber loop (9990–9999):** Iterates from the first to the last line, POKEing the new line numbers into the two-byte line-number field of each line header. ### BASIC Line Memory Layout The ZX81 BASIC program area begins at address 16509 (system variable PROG). Each line is stored as a 4-byte header followed by the tokenised statement bytes: | Offset | Content | | --- | --- | | +0 | High byte of line number | | +1 | Low byte of line number | | +2 | Low byte of line length | | +3 | High byte of line length | | +4… | Tokenised BASIC text | Note that the length bytes are stored in little-endian order (low byte at +2, high byte at +3), which is reflected in the pointer-advance expression at line 9977: `A+4+PEEK (A+2)+256*PEEK (A+3)`. ### Line-Search Subroutine (9971–9979) The inner subroutine at line 9971 is a reusable routine called twice via `GOSUB 9971`. It reads a target line number `S` from INPUT, then walks the program area starting at address `A` (initialised to 16509). At each header it reconstructs the stored line number as `256*PEEK A + PEEK (A+1)` and compares it with `S`. If the current line number reaches or exceeds 9970 without a match, the subroutine reports “NOT FOUND” and terminates at line 9979 (falling through without a RETURN, which will cause an error — see Bugs section). ### Renumber Loop (9990–9996) The renumber loop uses pointer `A` (set to the first line to renumber) and `AE` (set to just past the last line: `AE = A+3` after the last-line search). Each iteration: - Checks `A > AE` to detect completion (line 9990). - Guards against the new line number exceeding 9969 (line 9991). - POKEs the high byte of `N` at address `A` (line 9992) and the low byte at `A+1` (line 9993). - Advances `A` to the next line header (line 9994). - Increments `N` by `I` (line 9995). ### Notable Techniques - **No machine code:** The entire renumber operation is performed in pure BASIC using PEEK/POKE, making it portable and easy to embed. - **Self-protection guard:** Line 9976 and line 9991 both prevent the routine from renumbering its own lines (above 9969), avoiding self-corruption. - **Reusable inner subroutine:** The GOSUB at 9971 is called twice with different prompts, cleanly factoring out the line-search logic. - **Boundary pointer `AE`:** Set to `A+3` after finding the last line (line 9982), so the loop condition `A > AE` correctly terminates after the final line is processed. ### Bugs and Anomalies - **“NOT FOUND” path lacks RETURN:** If a searched line number is not found, lines 9979–9979 print an error message but do not RETURN or STOP, causing execution to fall through into the input phase at line 9980, which is likely unintended behaviour. - **Spelling error:** Line 9999 contains `CANT COMPLEAT` — “COMPLEAT” is a misspelling of “COMPLETE”. - **Variable `A` reuse:** After the first GOSUB (finding the last line), `A` is saved into `AE`, but then the second GOSUB reinitialises `A` to 16509 at line 9971. This is correct behaviour but relies on the programmer re-entering a line number that falls before `AE` — no validation is performed to ensure the first line precedes the last line. - **No GO TO adjustment:** The routine renumbers line-number headers only. Any `GO TO` or `GO SUB` targets embedded within the tokenised lines are not updated, which can break program flow after renumbering. ## Source Code ``` 9950 SAVE "1029%9" 9960 LIST 9965 REM DELETE LINES 9950-9960 B4 USING THIS SUBROUTINE 9970 STOP 9971 LET A=16509 9972 INPUT S 9973 PRINT S 9974 LET L=256*PEEK A+PEEK (A+1) 9975 IF L=S THEN RETURN 9976 IF L>=9970 THEN GOTO 9979 9977 LET A=A+4+PEEK (A+2)+256*PEEK (A+3) 9978 GOTO 9974 9979 PRINT S;"NOT FOUND" 9980 PRINT "LAST LINE TO BE RENUMBERED="; 9981 GOSUB 9971 9982 LET AE=A+3 9983 PRINT "1ST LINE TO BE RENUMBERED="; 9984 GOSUB 9971 9985 PRINT "1ST NEW LINE NUMBER="; 9986 INPUT N 9987 PRINT N,"INCREMENT LINES BY:"; 9988 INPUT I 9989 PRINT I 9990 IF A>AE THEN GOTO 9997 9991 IF N>9969 THEN GOTO 9999 9992 POKE A,INT (N/256) 9993 POKE (A+1),N-256*INT (N/256) 9994 LET A=A+4+PEEK (A+2)+256*PEEK (A+3) 9995 LET N=N+I 9996 GOTO 9990 9997 PRINT ,,"RENUMBER COMPLETE" 9998 STOP 9999 PRINT ,,"CANT COMPLEAT. LINE NR>9969." ```