TRS-80 DOS - NEWDOS/80 v2.0 for the Model III - SYS11/SYS Disassembled

Page Customization

Introduction / Summary

The handler operates in two passes over the BASIC program text, both driven by the dual-purpose byte-fetch routine at 5120H. The byte at self-modifying location 5121H selects the pass: 00H for the first pass (read-only scan) and 01H for the second pass (read-and-copy to output buffer).

First pass (5121H = 00H): The scanner walks the BASIC linked-list line by line. For each line it reads the four-byte line header (link pointer and line number) via four calls to 5120H. It then feeds every token through a 19-entry dispatch table at 4E8AH. The table routes each token to a specialised handler: quoted strings are skipped, USING and DEFSTR are skipped to end-of-statement, parenthesised argument lists (for NAME, KILL, LOAD, MERGE) are walked with a depth counter, and tokens that introduce a line-number argument (“GOTO-range” tokens, THEN, GET, PUT, CLOSE, FIELD) set a “line number found” flag at 4E81H before entering the line-number parser at 4E4CH. The parser accumulates a decimal value in DE using DE = DE × 10 + digit and records the digit count at 515EH. Every parsed line-number reference is looked up in a cross-reference table at 64A3H (128 two-byte entries, built by 5073H) using a binary search at 4EC3H followed by a linear-scan fallback at 4EEBH. When a match is found the replacement line number is written directly into the cross-reference table.

Concurrently with scanning, the first pass accumulates the maximum per-reference expansion (in decimal digits) at 5168H and counts unresolvable references at 515AH. At the end of the first pass, if any references are out of range, their source line numbers are displayed preceded by an ‘X’ marker; if a reference overflows the 65529 limit the marker is ‘S’.

Memory relocation (4FABH–4FFAH): Between passes the handler calculates how many extra bytes the renamed line numbers will require (worst-case expansion × estimated count), reserves that space, and uses LDDR to slide the BASIC program text upward in memory. The stack pointer is temporarily moved to the top of free memory during the block move to prevent overwriting the stack. After relocation the 128 entries in the cross-reference table at 64A3H are each incremented by the relocation delta.

Second pass (5121H = 01H): The byte-fetch routine at 5120H now copies each byte it reads into the output buffer (tracked by the self-modifying BC operand at 4EF6H) as well as returning it to the scanner. Line-number references are replaced in-place: the replacement value from the cross-reference table is formatted as a decimal string by 5153H/5D00H and spliced into the output stream. After the second pass, two further block moves (LDDR then LDIR) compact the program back to its original start address, and a final walk at 5050H rebuilds every line’s forward link pointer. The handler then displays DONE and re-enters BASIC via 1AE9H.

If at any stage the computed memory requirement exceeds available free memory the handler aborts with “Not Enough Memory” (error 0CH). If the program text is damaged during a second-pass block move the handler aborts with “FATAL ERROR. TEXT NOW BAD”.

SYS11 — Variables and Self-Modifying Code

RAM locations written at runtime, and operand bytes within SYS11 that are overwritten by the program itself during execution

4D4CH
Cross-Reference Table Pointer
Two-byte LE operand of LD HL,nnnnH at 4D4BH. Initialized to 64A3H (start of the cross-reference table). Written by 4D65H (advance to next entry) and 4FEAH (reset for second pass). Read implicitly each time 4D4BH executes.
4DE4H
Token Context Flag
One-byte operand of LD A,nnH at 4DE3H. Written 00H by 4DA8H (no line-number context) and 01H by 4DC3H (PUT/CLOSE context active). Read by the FIELD handler at 4DC5H and by 4DE3H. Controls whether comma-separated arguments following PUT, CLOSE, and FIELD are treated as line-number references.
4DEDH
Current Line Number
Two-byte LE operand of LD DE,nnnnH at 4DECH. Written by 4D78H from the line header read (four calls to 5120H). Read by 4DECH when displaying the error line number. Holds the BASIC line number of the line currently being scanned, used in error output.
4E81H
Line Number Found Flag
One-byte operand of OR nnH at 4E80H. Written 00H by 4DA4H (clear at start of each statement) and 01H by 4DD1H (GET handler) and 4DCDH (FIELD handler). Read by 4E80H: when 00H the OR produces Z (no line-number context); when 01H it produces NZ (a line-number reference is expected).
4EF6H
Output Position (BC Copy)
Two-byte LE operand of LD BC,nnnnH at 4EF5H. Written by 4D34H (position store at start of each line) and 5007H (updated after each block copy segment). Read by 4EF5H. Tracks the current write position in the output buffer during the second pass.
4F01H
Current Line Pointer
Two-byte LE operand of LD HL,nnnnH at 4F00H. Written by 4D38H (stored from HL at the start of each line). Read by 4F00H in the linear-scan fallback at 4EEBH. Holds the address of the start of the BASIC line currently being scanned.
4FA6H
Error Header Printed Flag
One-byte operand of LD A,nnH at 4FA5H, also accessed directly via HL=4FA6H with BIT 0,(HL) at 4F61H and SET 0,(HL) at 4F65H. Initialized 00H; set to 01H the first time an error line is displayed. Controls whether the “ERROR LINES” header has been printed.
5014H
Block-Copy Source Address
Two-byte LE operand of LD HL,nnnnH at 5013H. Written by 507BH (from binary search result). Read by 5013H at the start of each second-pass block-copy segment. Holds the address of the next source byte to be copied into the output buffer.
5035H
Range-Start Destination (Reverse Copy)
Two-byte LE operand of LD DE,nnnnH at 5034H. Written by 50CAH (insertion point extracted from BASIC line scan). Read by 5034H in the final LDDR at 502FH. Holds the destination address for the reverse block move that compacts the output back to the program start area.
50C0H
End Boundary
Two-byte LE operand of LD DE,nnnnH at 50BFH. Written by 5087H (from binary search for end of renumber range). Read by 50BFH. Holds the address of the last byte of the renumber range within the BASIC program text.
50C8H
Insertion Point
Two-byte LE operand of LD DE,nnnnH at 50C7H. Written by 50AFH (from linear scan of BASIC lines). Read by 50C7H. Holds the address within the BASIC program where the renumbered text is to be written back.
50F2H
Block Size (Expansion Reserve)
Two-byte LE operand of LD DE,nnnnH at 50F1H. Written by 50CDH (computed from maximum expansion × line count). Read by 50F1H in the memory-size calculator at 50F9H. Holds the number of extra bytes to reserve above the existing program for worst-case line-number expansion.
50F7H
Memory Size Result
Two-byte LE operand of LD DE,nnnnH at 50F6H. Written by 5117H (result of free-memory fit loop). Read by 50F6H. Holds the computed value that is compared against available memory to determine whether enough space exists for the relocation.
5121H
Pass-Select / Copy-Enable Flag
One-byte operand of LD A,nnH at 5120H. Written 01H by 4FDBH when the second pass is activated. Read by 4D42H, 4F44H, 4F57H, 4EEFH, and 50DCH to distinguish first pass from second pass; read by 5120H itself to decide whether to copy the fetched byte to the output buffer. 00H = first pass (scan only); 01H = second pass (scan and copy).
515AH
Error Count Accumulator
Two-byte LE operand of LD HL,nnnnH at 5159H. Initialized 0000H by 4D30H; incremented by 5163H each time a line-number reference cannot be resolved. Read by 5159H. Counts the total number of out-of-range references found during the first pass.
515EH
Digit Count
Two-byte LE operand of LD DE,nnnnH at 515DH. Written by 4E73H from the line-number parser after each reference is parsed. Read by 515DH. Holds the number of decimal digits in the most recently parsed line-number reference, used to calculate expansion or contraction relative to the replacement value’s digit count.
5168H
Maximum Expansion Size
Two-byte LE operand of LD DE,nnnnH at 5167H. Updated by 516CH whenever a new maximum is found. Read by 4FB7H and 5167H. Tracks the worst-case increase in bytes across all line-number references in the program, used by the memory-reservation calculation at 50F9H.

Major Routine Reference

Functional summary of every named entry point in SYS11, in address order

4D0CH
Renum Entry Point
Command entry from NEWDOS/80. Stores the caller-supplied DE (new start line) and HL (first line of range) parameters into the BASIC program text, counts lines in the renumber range via the loop at 4D16H, then falls through to 4D25H.
4D25H
Initialize Renumber Variables
Calls 5073H to validate the range and build the cross-reference table at 64A3H. Loads HL from the BASIC program start pointer at 40A4H, copies it to BC, clears the error-count self-mod at 515AH, and falls into the main scanner loop at 4D34H.
4D34H
Position Store + Next Line
Saves the current BC (output position) to self-mod at 4EF6H and the current HL (line address) to self-mod at 4F01H, then falls into the main line scanner at 4D3BH.
4D3BH
Main Line Scanner
Reads the two-byte link pointer at (HL). If zero, the program end has been reached; jumps to 4F97H. Otherwise, if the second-pass flag at 5121H is set, calls the cross-reference fixup at 4D48H to update the link field. Then falls to 4D6AH to read the line header.
4D48H
Cross-Reference Address Fixup
Searches the cross-reference table at 64A3H (self-mod pointer at 4D4CH) for the current line address DE. When found, overwrites the table entry with the replacement BC value and advances the self-mod pointer. Called only during the second pass.
4D6AH
Read Line Header
Calls 5120H four times to fetch the two-byte link pointer and two-byte line number, storing the line number in DE and then to self-mod at 4DEDH. Jumps to 4DA3H to begin statement-level scanning.
4D7EH
Using / Defstr Skip
Fetches bytes via 5120H until a non-NZ result (end-of-statement byte 00H) is found, then jumps to 4D34H for the next line. Used for USING and DEFSTR tokens that take no line-number arguments.
4D85H
Quoted String Skip
Saves the return address 4DADH on the stack, then calls the quote-match subroutine at 4D89H. On return, execution falls into the main dispatch re-entry at 4DADH, effectively resuming the token dispatch loop after the closing quote.
4D89H
Quote Match Subroutine
Saves the opening quote character (22H) in E. Calls 5120H repeatedly until the same byte is returned (closing quote found) or until a 00H (end-of-line) terminates the scan. Returns to the caller when the string boundary is located.
4D95H
General Statement Scanner
Checks the current byte: if 22H (double-quote), calls the quote-match subroutine at 4D89H; if 3AH (colon), exits to 4D34H for the next statement; otherwise fetches the next byte and loops. This is the fallback scanner for tokens with no line-number arguments.
4D9AH
Goto-Range Statement Scanner
Fetches a byte via 5120H. If 00H or 3AH (end of statement/line), returns to 4D34H. Otherwise falls into the general statement scanner at 4D95H. Entry point for tokens in the GOTO range of the dispatch table.
4DA3H
Token Dispatch Init
Clears the line-number-found flag at 4E81H and the token-context flag at 4DE4H (both to 00H), then falls into the dispatch fetch-and-lookup sequence at 4DADH.
4DADH
Byte Fetch + Dispatch Entry
Calls 5120H to read the next byte, then falls into the dispatch table lookup at 4DB0H.
4DB0H
Dispatch Table Lookup
Saves HL, loads HL with the base of the 19-entry dispatch table at 4E8AH. Reads each three-byte entry (handler address + threshold token), compares the current token A against the threshold: less-than skips via JR C back to 4DACH; equal dispatches to the handler address; greater advances to the next entry.
4DC1H
Put / Close Handler
Loads A with 01H and jumps to 4DA8H, setting the token-context flag at 4DE4H to indicate that a PUT or CLOSE statement has been seen. This enables line-number parsing on subsequent comma-delimited arguments.
4DC5H
Field Handler
Reads the token-context flag at 4DE4H. If 00H (no PUT/CLOSE context), jumps back to the dispatch loop at 4DADH. If 01H, loads A with 01H and jumps to 4DA4H to set the line-number-found flag, enabling line-number parsing for the FIELD argument list.
4DCFH
Get Handler
Loads A with 01H and stores it to the line-number-found flag at 4E81H, signalling that the next numeric token should be treated as a line-number reference. Falls through to the digit-check and parse loop at 4DD4H.
4DD4H
Line Number Check and Parse Loop
Calls the digit-check at 513BH. If no digit found, re-enters the dispatch loop at 4DB0H. If a digit is found, calls the line-number parser at 4E4CH, then skips whitespace via 511DH. If a comma follows, loops to parse the next argument; otherwise re-enters dispatch.
4DE8H
Error Line Number Output Setup
Pushes AF, pops it (no-op pair preserving AF), loads A with 58H (‘X’), loads DE from self-mod at 4DEDH (current line number), and calls the error-output routine at 4F54H. Then decrements BC and HL and enters the EOS-check loop at 4E40H to skip remaining bytes on the line.
4DF9H
Line Number Overflow Error
Pops HL, BC, and AF from the stack (unwinding the nested call chain), loads A with 53H (‘S’), and jumps to 4DECH to display the error using the self-mod DE (current line number) and the ‘S’ overflow marker.
4E00H
Then Handler
Calls the line-number parser at 4E4CH to read the THEN target, then calls the digit-check at 513BH. If a digit follows (another line number in a multi-target THEN), loops. If the next token is in the range D2H–D6H (function tokens), skips it and loops. Otherwise re-enters dispatch at 4DB0H.
4E12H
General Token Handler
Calls the digit-check at 513BH. If a digit is present, parses the line number via 4E4CH and skips whitespace via 511DH. Then checks for token CEH (ON ERROR GOTO); if found, jumps to the THEN handler at 4DD4H. Otherwise re-enters dispatch.
4E23H
Name / Kill / Load / Merge Parenthesis Handler
Initialises a paren-depth counter in D (02H) and a comma counter in E (FFH). Fetches bytes via 4E40H, tracking open-paren depth increments, close-paren decrements, and commas. Exits when the depth returns to 01H and a comma is seen at the outermost level, then falls to the line-number check at 4DD4H.
4E40H
Byte Fetch with EOS Check
Calls 5120H. If A is 00H or 3AH (end of statement), discards the top-of-stack return address and jumps to 4E10H (re-enter dispatch). Otherwise returns to the caller with the byte in A.
4E4CH
Line Number Parser
Calls the digit-check at 513BH; if no digit, jumps to 4DE9H (error). Pushes BC. Accumulates a decimal value in DE using DE = DE × 10 + (A−30H), incrementing a digit counter in BC, until a non-digit is read. Overflow beyond 1998H (6552) jumps to the overflow error at 4DF9H. On completion, stores the digit count to 515EH, then calls 5153H to perform the cross-reference lookup and replacement.
4E8AH
Token Dispatch Table
19-entry data table, 57 bytes (4E8AH–4EC2H). Each entry is a two-byte handler address (little-endian) followed by a one-byte token threshold. The dispatch loop at 4DB0H walks this table to route each BASIC token to the correct handler. See the token dispatch table in the continuation instructions for the full entry listing.
4EC3H
Binary Search for Line Number
Searches the 128-entry cross-reference table at 64A3H for the line number in DE, using a halving algorithm. Computes the midpoint, reads the two-byte entry, compares with DE, and halves the search range. When the range collapses, falls through to the linear-scan fallback at 4EEBH.
4EEBH
Linear Scan Fallback
After the binary search converges, walks BASIC lines sequentially from the self-mod line pointer at 4F01H (loaded by 4F00H), comparing each line number against DE until a match or end-of-program is found. On match, falls to 4F1CH to extract the line address into DE.
4F00H
Second-Pass Position Match
Entry point that loads HL from the self-mod operand at 4F01H (the current line’s start address). Falls immediately into the linear-scan loop body at 4F03H.
4F03H
Linear Scan Loop Body
Reads the two-byte forward link from (HL), tests for end-of-program (00H link), reads the two-byte line number, compares against DE, and either loops or falls to the match exit at 4F1CH.
4F18H
End-of-Program Handler
Sets the carry flag and extracts the end-of-program boundary address into DE from HL. Used when the binary/linear search reaches the program end without finding the target line.
4F1CH
Search Exit
Extracts the matched line’s address from HL into DE, clearing the carry flag. Returns to the line-number parser at 4E4CH with DE = address of the matched BASIC line.
4F22H
Line Number Replacement
Performs a binary search for the parsed DE line number in the cross-reference table, checks that it is within the renumber range, then calls 5159H (error-count accumulator) and 5153H (number-string copy) to splice the replacement number into the output. Out-of-range references jump to the error output at 4DE8H.
4F43H
Output Unchanged Line Number
Dispatches on the pass-select flag at 5121H: during the first pass calls 5153H to record the number without replacement; during the second pass calls 5156H to copy the original digit string verbatim into the output buffer.
4F54H
Error Line Number Output Routine
Entry from 4DE8H with the error-marker character in A. Calls the screen-position check at 4F70H, displays the marker character, a space, and the line number in DE using 5D00H/5D3DH. Increments the error count at 515AH.
4F57H
Pass Check + Error Output
Reads the pass-select flag at 5121H. During the first pass, continues to the screen-position check at 4F70H. During the second pass, calls the fatal-error handler at 50E4H (an error on the second pass means the text is irreparably damaged).
4F70H
Screen Position Check + Error Display
Reads the screen cursor position from 4020H. If the column is past 60 (3CH), outputs a carriage return via 5D52H and resets the column. Then checks whether the “ERROR LINES” header at 518CH has been printed (flag at 4FA6H); if not, prints it and sets the flag.
4F97H
End-of-Scan Handler
Reached when the forward link pointer is 00H (end of BASIC program). During the first pass, falls to the memory-relocation setup at 4FABH. During the second pass, falls to the second-pass completion handler at 4FFDH.
4FABH
Memory Relocation
Calculates the size of the BASIC program (end minus start), calls 50F1H to compute the expansion reserve, checks memory overflow, then uses LDDR to move the entire program text upward by the expansion amount. Temporarily relocates SP to the top of free memory during the block move to protect the stack.
4FC1H
Expansion Padding
Adds a 256-byte safety margin to the expansion reserve before the memory-overflow check, ensuring that rounding errors in the digit-count arithmetic do not cause the output to overrun the reserved area.
4FD1H
Memory Overflow Check
Compares the computed post-relocation top address against the BASIC memory ceiling at 40B1H. If the relocated program would exceed available memory, jumps to the “Not Enough Memory” error at 50EDH.
4FDBH
Second Pass Activation
Writes 01H to the pass-select self-mod byte at 5121H, switching the byte-fetch routine at 5120H into copy mode. Then jumps to 4D2DH to restart the main scanner loop for the second pass.
4FEDH
Cross-Reference Table Update Loop
Walks all 128 two-byte entries in the cross-reference table at 64A3H, adding the relocation delta (in DE) to each entry. This adjusts every recorded BASIC line address to reflect the program’s new position in memory after the LDDR block move.
4FFAH
Restart Main Scan
Jumps to 4D2DH to begin the second pass. The BASIC program pointer at 40A4H is re-read and BC/HL are re-initialised from the (now relocated) program start.
4FFDH
Second-Pass Completion Handler
After the second-pass scan finishes, calculates the size of the renumbered output, performs a final LDDR (reverse) block move to bring the output back to the original program start address, then an LDIR (forward) move to align the remainder. Falls through to the re-link routine at 5050H.
5013H
Block Copy Loop
Self-modifying loop used during the second pass. Loads HL from self-mod at 5014H (source address), calls 5120H-based copy for each segment between line-number replacements, and updates the self-mod pointer after each segment. Recalculates the remaining byte count before calling the LDIR at 502FH.
502FH
Final Block Copy
Executes the final LDDR (decrementing) block move of the completed second-pass output, followed immediately by an LDIR (incrementing) block move to copy any trailing program bytes that were not part of the renumber range.
5050H
Re-link Basic Lines
Walks the BASIC program from its start address at 40A4H, rewriting each line’s two-byte forward link pointer to point to the start of the next line. Continues until a 00H link is found (end of program), then updates the BASIC memory-top pointer at 40B1H.
5063H
Display “Done” + Exit
Calls the message-display routine at 5147H with the pointer to the “DONE” string at 5198H, outputs a carriage return via 5D52H, then jumps to 1AE9H (ROM BASIC warm-restart) to return control to BASIC.
5073H
Range Calculation and Error Checking
Performs two binary searches in the BASIC program to locate the first and last lines of the renumber range. Validates that the range is non-empty and that the new line numbers do not overlap with existing lines outside the range. Fills the cross-reference table at 64A3H with the addresses of all line link fields within the range. Errors jump to 50D9H.
5092H
Insertion Point Scan
Walks the BASIC linked list from the program start, comparing each line number against the range-start target. Stops at the first line whose number meets or exceeds the target. Falls through to 50ACH to store the result.
50ACH
Insertion Point Extract
Stores the current HL (address of the located insertion-point line) to the self-mod operand at 50C8H. Returns to the range-calculation routine at 5073H.
50D9H
Range Error Handler
Issues NEWDOS/80 error code 8CH. During the first pass this exits cleanly via 4409H. During the second pass this jumps to the fatal-error handler at 50E4H because the program text is partially modified.
50E4H
Fatal Error Handler
Displays the message “FATAL ERROR. TEXT NOW BAD” from 5170H via 5147H, then exits via 4409H. Called when an unrecoverable error is detected during the second pass, after the program text has already been partially rewritten.
50EDH
“Not Enough Memory” Error
Issues NEWDOS/80 error code 0CH (insufficient memory) and exits via 4409H. Reached from the memory-overflow check at 4FD1H when the relocated program would exceed the BASIC memory ceiling.
50F1H
Memory Size Calculator Entry 1
Loads DE from the self-mod operand at 50F2H (the expansion reserve in bytes), then falls into entry 2 at 50F6H.
50F6H
Memory Size Calculator Entry 2
Loads DE from the self-mod operand at 50F7H (the previously computed memory-size result), then falls into the calculator body at 50F9H.
50F9H
Memory Size Calculator Body
Computes the amount of free memory between the current program end and the BASIC memory ceiling at 40B1H. Subtracts the expansion reserve. If the result is negative (insufficient memory), sets the carry flag, which the caller tests to branch to the overflow error.
511DH
Whitespace Skip
Calls the raw-whitespace-skip routine at 512EH, then returns. A wrapper entry point used in contexts where the caller needs whitespace consumed before the next significant byte is examined.
5120H
Dual-Purpose Byte Fetch
Reads the next byte from (HL) and increments HL. The self-modifying byte at 5121H selects the mode: 00H returns the byte in A with NZ set for non-zero bytes (first-pass, read-only); 01H additionally writes the byte to (BC) and increments BC (second-pass, copy mode). Sets Z if the byte is 00H.
512BH
Whitespace Consume Loop
Reads the byte at (HL), checks it against the whitespace set (20H, 09H, 0AH, 0BH) using the raw-skip at 512EH, and loops if whitespace is found. Returns with the first non-whitespace byte in A.
512EH
Raw Whitespace Skip
Compares A against 20H (space), 09H (tab), 0AH (line feed), and 0BH (vertical tab). If a match is found, calls 5120H to advance past the whitespace byte and returns. If no match, returns without consuming the byte.
513BH
Digit Check
Calls the whitespace-skip at 512EH to skip any leading whitespace, then tests whether A is in the range 30H–39H (ASCII digits ‘0’–‘9’). Returns with the carry flag set if A is a digit, clear otherwise.
5147H
Message Display
Displays a 03H-terminated string pointed to by HL, calling the ROM character-output routine at 0033H for each byte until the 03H terminator is reached.
5153H
Number Output First Pass
Loads BC with 5D2AH (the BASIC number string buffer) and calls the number-string copy routine at 5D00H to convert the line number in DE to a decimal ASCII string. Then falls to 5156H.
5156H
Number-String Copy
Calls 5D00H to copy the formatted decimal string, then calls 516CH to compare the new digit count against the running maximum at 5168H and update if a new maximum is found.
5159H
Error Count Accumulator
Loads HL from the self-mod operand at 515AH (the running error count), increments it, and writes the new count back to 515AH. Called each time an unresolvable reference is encountered.
5170H
String: “Fatal Error. Text Now Bad”
03H-terminated ASCII message used by the fatal-error handler at 50E4H. Occupies 5170H–518BH.
518CH
String: “Error Lines”
03H-terminated ASCII message printed as the header before the first error line number is displayed. Occupies 518CH–5197H.
5198H
String: “Done”
03H-terminated ASCII message displayed on successful completion. Occupies 5198H–519CH.
519DH
16-Bit Comparison Utility
Subtracts BC from HL using SBC HL,BC (with carry cleared first), then calls RST 18H to set the standard comparison flags (carry if HL < BC, zero if HL = BC). Returns with flags set for a signed 16-bit comparison of the original HL vs. BC.
51A2H
Nop Padding
82 × NOP (00H) bytes filling 51A2H–51F3H. Unused space at the end of SYS11.

Disassembly

4D0CH - RENUM Entry Point (Parameter Store and Line Count Loop)

RENUM Entry Point. SYS11 implements the RENUM (renumber) command for NEWDOS/80 BASIC. The entry point receives the parsed RENUM parameters in registers: HL = pointer to the BASIC program text start address (stored at 40A4H), DE = first new line number, BC = line count and increment. The code first stores these parameters into the BASIC program's line link pointers, then walks forward through the program lines, counting down the number of lines to renumber. When the count reaches zero or the program ends, the code falls through to the main renumbering pass.

4D0C
EX DE,HL EB
Exchange Register Pairs DE and HL. On entry, DE held the first new line number and HL held the pointer to the current line's link field. After the exchange, HL = first new line number, DE = pointer to the link field.
4D0D
LD (HL),E 73
Store the low byte of the link field pointer (Register E) at the address pointed to by HL. This writes the low byte of the new line number destination into the parameter area.
4D0E
INC HL 23
INCrement Register Pair HL by 1, advancing to the next byte of the parameter storage.
4D0F
LD (HL),D 72
Store the high byte of the link field pointer (Register D) at (HL). The 16-bit link address is now stored.
4D10
INC HL 23
INCrement Register Pair HL by 1, advancing past the stored link address.
4D11
PUSH HL E5
Save Register Pair HL (pointer to the next parameter position) onto the stack.
4D12
EX DE,HL EB
Exchange Register Pairs DE and HL again. HL now points to the line link field in BASIC program text, and DE holds the saved parameter pointer.
4D13
LD E,C 59
Copy the line count (Register C, the number of lines to renumber) into Register E. E serves as the loop counter for the line-counting walk.
4D14
Unconditional JUMP forward to 4D1CH to begin the line-counting loop by checking the current line's link pointer.

LOOP START
Line-counting loop
This loop walks through the BASIC program text, following line link pointers, counting down E lines. Each BASIC line begins with a 2-byte link pointer (address of the next line), followed by a 2-byte line number, followed by the tokenized statement text, terminated by 00H.

4D16
GOSUB to 5CCCH (line skip in BASIC/CMD). This routine advances HL past the current BASIC line by following the line link pointer. On return, HL points to the start of the next line.
4D19
DEC E 1D
DECrement Register E by 1 (the remaining line count). When E reaches zero, all requested lines have been counted.
4D1A
If the Z FLAG has been set (E reached zero - all lines counted), JUMP forward to 4D22H to exit the loop and begin processing.
4D1C
LD A,(HL) 7E
Fetch the low byte of the line link pointer from (HL) into Register A. The link pointer is the first 2 bytes of each BASIC line; if both bytes are 00H, this is the end of the program.
4D1D
INC HL 23
INCrement Register Pair HL by 1, advancing to the high byte of the line link pointer.
4D1E
OR (HL) B6
OR the high byte of the line link pointer (at (HL)) into Register A (which holds the low byte). If both bytes are zero, the result is zero and the Z flag is set, indicating end-of-program.

LOOP - continue counting lines

4D1F
If the NZ FLAG has been set (link pointer is non-zero - more lines exist), JUMP back to 4D16H to skip to the next line and continue counting.
4D21
DEC HL 2B
DECrement Register Pair HL by 1, backing up to point at the low byte of the zero link pointer (the program end marker). This ensures HL points to the start of the end-of-program marker.
4D22
POP DE D1
Restore Register Pair DE from the stack (the parameter pointer saved at 4D11H).
4D23
DECrement Register B by 1 and, if B is not zero, JUMP back to 4D0CH. Register B holds the iteration counter for the parameter storage loop. If more parameters need to be stored, the loop repeats with the next set of values. When B reaches zero, all parameters have been processed and execution falls through.

LOOP END

4D25H - Initialize Renumber Variables

Initialize Renumber Variables. After the parameter loop completes, this section calls 5073H to calculate the line number ranges, then loads the BASIC program start address from 40A4H and initializes several self-modifying code locations that track state throughout the renumbering process. The main variables are: 515AH (error count), 4EF6H (current position in program), and 4F01H (line pointer for the current scan).

4D25
GOSUB to 5073H (range calculation routine). This routine computes the renumbering range boundaries by looking up the start and end line numbers in the BASIC program. It stores results at 5014H (start line address), 50C0H (end boundary), and other self-modifying locations.
4D28
LD HL,(40A4H) 2A A4 40
Fetch the BASIC program start address from ROM address 40A4H into Register Pair HL. 40A4H contains the address of the first line of the BASIC program in memory. HL now points to the beginning of the program text.
4D2B
LD B,H 44
Copy the high byte of the program start address (Register H) into Register B.
4D2C
LD C,L 4D
Copy the low byte of the program start address (Register L) into Register C. Register Pair BC now holds a copy of the BASIC program start address.
4D2D
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H (zero). DE is initialized to zero, representing the error/line counter reset value.
4D30
Store 0000H (Register Pair DE) into address 515AH. This is self-modifying code - 515AH is the operand of a LD HL instruction at 5159H. It holds the accumulated error count (lines that could not be renumbered). Initializing to zero clears any previous error state.
4D34
Store the current program position (Register Pair BC) into address 4EF6H. This is self-modifying code - 4EF6H is the operand of a LD BC instruction at 4EF5H. It tracks the current position in the BASIC program during the line-by-line scan, starting at the program beginning.
4D38
Store Register Pair HL (the current line pointer) into address 4F01H. This is self-modifying code - 4F01H is the operand of a LD HL instruction at 4F00H. It stores the address of the line currently being examined for line number references.

4D3BH - Main Line Scanner Loop

Main Line Scanner Loop. This is the outer loop that processes the BASIC program line by line. For each line, it checks the link pointer to detect end-of-program, then checks the cross-reference flag at 5121H (which is non-zero during the second pass when the program has been relocated). If the cross-reference flag is set, it performs the optional line address fixup. Otherwise, it falls through to the token-by-token scanning of the line's statement text, reading four bytes (link low, link high, line number low, line number high) via 5120H before entering the token dispatcher.

MAIN LOOP START
Process Each BASIC line

4D3B
LD A,(HL) 7E
Fetch the low byte of the current line's link pointer from (HL) into Register A.
4D3C
INC HL 23
INCrement Register Pair HL by 1, advancing to the high byte of the link pointer.
4D3D
OR (HL) B6
OR the high byte of the link pointer (at (HL)) into Register A (which holds the low byte). If both are zero, the Z flag is set - end of program.
4D3E
DEC HL 2B
DECrement Register Pair HL by 1, restoring the pointer to the start of the link field (low byte).
4D3F
If the Z FLAG has been set (link pointer is 0000H - end of program), JUMP to 4F97H (end-of-scan handler). All lines have been processed; the code proceeds to the finalization phase.

The line has a non-zero link pointer, so it is a valid BASIC line. Check whether the cross-reference fixup pass is active.

4D42
LD A,(5121H) 3A 21 51
Fetch the cross-reference flag from address 5121H into Register A. This is self-modifying code - 5121H is the operand of an LD A instruction at 5120H. A value of 00H means first pass (scan only), non-zero means second pass (program has been relocated and line addresses need fixup).
4D45
OR A B7
OR Register A with itself to set the flags based on the cross-reference flag value.
4D46
If the Z FLAG has been set (cross-reference flag is 00H - first pass), JUMP forward to 4D6AH to skip the address fixup and go directly to reading the line header bytes. On the first pass, no relocation has occurred, so no fixup is needed.

4D48H - Cross-Reference Address Fixup (Second Pass)

Cross-Reference Address Fixup. During the second pass (5121H is non-zero), the BASIC program text has been relocated in memory and the line link pointers need to be updated. This section searches through the cross-reference table at 64A3H (the SYS jump table area) to find entries whose old addresses match the current line's link pointer, and replaces them with the new address from BC. The search walks through the table entries comparing the stored old address (DE) against each entry, replacing matches with the current address (BC).

4D48
PUSH HL E5
Save Register Pair HL (pointer to the current line's link field) onto the stack.
4D49
PUSH DE D5
Save Register Pair DE (the old line address to search for) onto the stack.
4D4A
EX DE,HL EB
Exchange Register Pairs DE and HL. DE now holds the current line pointer, and HL is free for the search.
4D4B
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H. This is self-modifying code - the operand at 4D4CH is written by 4D65H and 4FEAH to hold the current position in the cross-reference table. On the first call, it starts at 0000H (will be set to 64A3H during initialization).

LOOP START
Cross-Reference Search

4D4E
INC HL 23
INCrement Register Pair HL by 1, advancing to the high byte of the table entry's stored address.
4D4F
LD A,(HL) 7E
Fetch the high byte of the stored address from the cross-reference table at (HL) into Register A.
4D50
CP D BA
Compare Register A against Register D (the high byte of the old line address from DE). If they match, the Z flag is set.
4D51
If the NZ FLAG has been set (high bytes do not match), JUMP forward to 4D68H to restore registers and continue. This table entry does not match the old address.
4D53
DEC HL 2B
DECrement Register Pair HL by 1, moving back to the low byte of the stored address.
4D54
LD A,(HL) 7E
Fetch the low byte of the stored address from (HL) into Register A.
4D55
CP E BB
Compare Register A against Register E (the low byte of the old line address). If both bytes match, the entry's address equals the old line address.
4D56
If the NZ FLAG has been set (low bytes do not match), JUMP forward to 4D68H. The full 16-bit address does not match.

Both bytes match - this table entry's old address matches the current line. Replace it with the new address from BC.

4D58
LD (HL),C 71
Store the low byte of the new address (Register C) at (HL), replacing the old low byte.
4D59
INC HL 23
INCrement Register Pair HL by 1, advancing to the high byte position.
4D5A
LD (HL),B 70
Store the high byte of the new address (Register B) at (HL), replacing the old high byte. The cross-reference entry now points to the new line address.
4D5B
INC HL 23
INCrement Register Pair HL by 1, advancing past the replaced entry.
4D5C
LD DE,65A3H 11 A3 65
Load Register Pair DE with 65A3H. This is the end-of-table boundary address. The cross-reference table extends from 64A3H to 65A2H (256 bytes, 128 entries of 2 bytes each).
4D5F
OR A B7
OR Register A with itself to clear the CARRY flag, preparing for the 16-bit subtraction.
4D60
SBC HL,DE ED 52
SUBtract Register Pair DE (65A3H, end of table) from Register Pair HL (current table position). If HL >= 65A3H, the result is non-negative (Z or positive) - the table has been fully scanned.
4D62
If the Z FLAG has been set (HL was exactly at the end of the table), JUMP forward to 4D68H to restore registers. The search is complete.

LOOP END

4D64
ADD HL,DE 19
ADD Register Pair DE (65A3H) back to Register Pair HL, restoring HL to the actual table position (undoing the SBC).
4D65
Store the updated table position (Register Pair HL) into the operand at 4D4CH. This is self-modifying code - updating the LD HL at 4D4BH so the next call to the fixup routine starts from where the last one left off, rather than re-scanning from the beginning.
4D68
POP DE D1
Restore Register Pair DE from the stack (the old line address saved at 4D49H).
4D69
POP HL E1
Restore Register Pair HL from the stack (the pointer to the current line's link field saved at 4D48H).

4D6AH - Read Line Header and Enter Token Scanner

Read Line Header. This section reads the four header bytes of the current BASIC line (link pointer low, link pointer high, line number low, line number high) using the byte-fetch routine at 5120H. The line number is stored at 4DEDH as a self-modifying operand for later comparison. After reading the header, execution falls through to the main token dispatch loop at 4DA3H.

4D6A
GOSUB to 5120H (byte fetch with optional output). This routine reads the next byte from the BASIC program text at (HL), advances HL, and optionally copies it to the output buffer at (BC) if the cross-reference flag at 5121H is set. Returns with A = the fetched byte and Z flag set if the byte is 00H.
4D6D
GOSUB to 5120H. Fetch the second header byte (link pointer high byte). Two calls read the complete 2-byte link pointer.
4D70
GOSUB to 5120H. Fetch the third header byte (line number low byte). Register A now holds the low byte of the current line's line number.
4D73
LD E,A 5F
Copy the line number low byte (Register A) into Register E.
4D74
GOSUB to 5120H. Fetch the fourth header byte (line number high byte). Register A now holds the high byte of the current line's line number.
4D77
LD D,A 57
Copy the line number high byte (Register A) into Register D. Register Pair DE now holds the complete 16-bit line number of the current line.
4D78
Store the current line number (Register Pair DE) into address 4DEDH. This is self-modifying code - 4DEDH is the operand of a LD DE instruction at 4DECH. The stored line number is used later for range checking when processing line number references within the program text.
4D7C
Unconditional JUMP forward to 4DA3H (token dispatch initialization). After reading the line header, the code enters the token-by-token scanning loop that processes each token in the line's statement body.

4D7EH - USING/DEFSTR Skip Handler (Token 92H-93H)

USING/DEFSTR Skip Handler. Dispatched from the token table for tokens 92H-93H (TROFF and DEFSTR). These tokens do not contain line number references, so the handler simply skips bytes until a 00H end-of-statement or 3AH colon statement separator is found, then re-enters the main scanner loop.

LOOP START
Skip until end-of-statement

4D7E
GOSUB to 5120H (byte fetch). Read the next byte from the BASIC text.
4D81
If the NZ FLAG has been set (the byte is not 00H), JUMP back to 4D7EH to read the next byte. This loops until a 00H end-of-statement marker is found.

LOOP END

4D83
Unconditional JUMP back to 4D34H (store current position and process next line header). The end-of-statement has been reached; update the position and move to the next line.

4D85H - Quoted String Skip Handler (Token <= 22H)

Quoted String Skip Handler. Dispatched from the token table for characters up to 22H (the ASCII double-quote). When a quoted string is encountered, the handler reads bytes until the matching closing quote (22H) is found, or until end-of-statement. This prevents line number references inside string literals from being renumbered.

4D85
LD DE,4DADH 11 AD 4D
Load Register Pair DE with 4DADH (the address of the main token dispatch entry point). This is pushed as the return address for the quote-matching subroutine at 4D89H.
4D88
PUSH DE D5
Save 4DADH onto the stack as the return address. When the subroutine at 4D89H returns, execution will continue at 4DADH (fetch next byte and dispatch).
4D89
LD E,A 5F
Copy the current character (Register A, which is 22H for a double-quote) into Register E. E holds the target character to match (the closing quote).

LOOP START
Scan for matching quote

4D8A
GOSUB to 5120H (byte fetch). Read the next byte from the BASIC text.
4D8D
CP E BB
Compare Register A (the fetched byte) against Register E (the target quote character 22H). If they match, the Z flag is set - the closing quote has been found.
4D8E
RET Z C8
If the Z FLAG has been set (matching quote found), RETURN. The return address on the stack is 4DADH, so execution continues at the main dispatch entry.
4D8F
OR A B7
OR Register A with itself to check if the byte is 00H (end-of-statement).
4D90
If the NZ FLAG has been set (not end-of-statement and not the matching quote), JUMP back to 4D8AH to read the next byte.

End-of-statement (00H) reached without finding a closing quote. The string was unterminated. Discard the return address and go back to the main loop.

LOOP END

4D92
POP AF F1
Discard the return address (4DADH) from the stack by popping it into AF. Since end-of-statement was reached, we need to process the end-of-line rather than continue scanning tokens.
4D93
Unconditional JUMP back to 4D34H (store current position and process next line). The unterminated string has been skipped; advance to the next line.

4D95H - General Statement Scanner (Token <= 88H / GOTO)

General Statement Scanner. Dispatched from the token table for tokens 3BH through 88H (which includes GOTO at 88H). This handler scans through the statement text looking for tokens that contain line number references. It checks for quoted strings (22H) and colon separators (3AH). Quoted strings are handled by calling the string skip subroutine at 4D89H. Colons cause a re-entry to the main dispatch loop. All other bytes are skipped by the byte-fetch loop.

LOOP START
Statement scan

4D95
CP 22H FE 22
Compare Register A against 22H (ASCII double-quote "). If Register A equals 22H, the Z FLAG is set.
4D97
If the Z FLAG has been set (the character is a double-quote), GOSUB to 4D89H (quote skip subroutine). This reads bytes until the closing quote is found, preventing string contents from being treated as line number references.
4D9A
GOSUB to 5120H (byte fetch). Read the next byte from the BASIC text.
4D9D
If the Z FLAG has been set (the byte is 00H - end-of-statement), JUMP back to 4D34H to store the position and process the next line.
4D9F
CP 3AH FE 3A
Compare Register A against 3AH (ASCII colon :). A colon is a statement separator in BASIC.
4DA1
If the NZ FLAG has been set (the character is not a colon), JUMP back to 4D95H to check for quotes and continue scanning. [LOOP - continue scanning statement]

4DA3H - Token Dispatch Initialization

Token Dispatch Initialization. This section initializes the token dispatch state variables and enters the dispatch table lookup. It clears the “line number found” flag at 4E81H and the “token context” flag at 4DE4H, then fetches the next byte from the BASIC text and looks it up in the dispatch table at 4E8AH. The table maps token ranges to handler addresses. If the token falls below an entry’s threshold, that entry’s handler is called; if it matches exactly, the handler is also called; if it is above the threshold, the next entry is checked.

4DA3
XOR A AF
Set Register A to zero and clear all flags.
4DA4
Store 00H (Register A) into address 4E81H. This is self-modifying code - 4E81H is the operand of an OR instruction at 4E80H. Clearing it to 00H resets the “line number found” flag, which is set to non-zero when a valid line number reference is detected and needs renumbering.
4DA7
XOR A AF
Set Register A to zero again (redundant but ensures clean state).
4DA8
Store 00H (Register A) into address 4DE4H. This is self-modifying code - 4DE4H is the operand of an LD A instruction at 4DE3H. Clearing it resets the “token context” flag, which tracks whether the current context requires line number processing (set to 01H when a GOTO, GOSUB, or similar token is encountered).

The PUSH HL / POP HL sequence at 4DABH-4DACH is a deliberate no-operation. It serves as a JR target (4DACH) from the dispatch table scanner at 4DBAH: when a token falls below the current entry's threshold, execution jumps here to re-enter the main byte-fetch loop without dispatching.

4DAB
PUSH HL E5
Save Register Pair HL onto the stack. This is part of a PUSH/POP no-op sequence that serves as a jump target for the table scanner's “token below threshold” path.
4DAC
POP HL E1
Restore Register Pair HL from the stack (immediately cancelling the PUSH). HL is unchanged. This address (4DACH) is the target of JR C at 4DBAH - when a token is below the current table entry's threshold, the scanner jumps here to skip the dispatch and fetch the next byte.
4DAD
GOSUB to 5120H (byte fetch). Read the next byte from the BASIC text into Register A. On return, the Z flag is set if A is 00H (end-of-statement).
4DB0
PUSH HL E5
Save Register Pair HL (the current BASIC text pointer, now past the fetched byte) onto the stack. This will be restored after the dispatch table lookup.
4DB1
LD HL,4E8AH 21 8A 4E
Point Register Pair HL to 4E8AH, the start of the token dispatch table. The table contains 19 entries of 3 bytes each: address low, address high, maximum token value.

LOOP START
Table Lookup

4DB4
LD E,(HL) 5E
Fetch the dispatch address low byte from the table at (HL) into Register E.
4DB5
INC HL 23
INCrement Register Pair HL by 1, advancing to the dispatch address high byte.
4DB6
LD D,(HL) 56
Fetch the dispatch address high byte from (HL) into Register D. Register Pair DE now holds the handler address for this table entry.
4DB7
INC HL 23
INCrement Register Pair HL by 1, advancing to the maximum token value byte.
4DB8
CP (HL) BE
Compare Register A (the current token/character) against the maximum token value at (HL). If A < (HL), the CARRY flag is set (token is below this entry's threshold). If A = (HL), the Z flag is set (exact match). If A > (HL), neither flag is set (token is above this entry's range).
4DB9
INC HL 23
INCrement Register Pair HL by 1, advancing to the start of the next table entry.
4DBA
If the CARRY FLAG has been set (token is below this entry's threshold - the token falls within this entry's range), JUMP back to 4DACH (POP HL, then fetch next byte). The token does not need special handling; skip it and continue scanning.

LOOP - continue table search

4DBC
If the NZ FLAG has been set (token is above this entry's threshold - try the next entry), JUMP back to 4DB4H to read the next table entry.

LOOP END
The token exactly matches this entry's threshold value (Z flag set). Dispatch to the handler address in DE.

4DBE
POP HL E1
Restore Register Pair HL (the BASIC text pointer saved at 4DB0H) from the stack.
4DBF
PUSH DE D5
Save the handler address (Register Pair DE) onto the stack. This sets up a RET-based dispatch - the next RET instruction will jump to the handler.
4DC0
RET C9
RETURN. Since the handler address was just pushed onto the stack, this RET transfers control to the handler. The handler will process the token and eventually return to the main loop at 4DB0H or 4D34H.

4DC1H - PUT/CLOSE Handler (Tokens A0H-A1H)

PUT/CLOSE Handler. Dispatched for tokens A0H-A1H (PUT and CLOSE). These statements may be followed by line number expressions (e.g., ON ERROR GOTO context). The handler sets the “line number found” flag at 4E81H to 01H and re-enters the dispatch initialization at 4DA8H, which then proceeds to scan for line numbers in the statement's arguments.

4DC1
LD A,01H 3E 01
Load Register A with 01H (flag value indicating a line number context is active).
4DC3
Unconditional JUMP back to 4DA8H. Store 01H into 4DE4H (token context flag) and re-enter the dispatch loop. This tells the line number parser that the next numeric value should be treated as a potential line number reference.

4DC5H - FIELD Handler (Tokens 96H-9EH)

FIELD Handler. Dispatched for tokens 96H-9EH (DEFDBL through FIELD). These statements are checked for whether the token context flag at 4DE4H is already set (from a prior GOTO/GOSUB/THEN). If it is set, the code treats the content as a potential line number and routes to the line number check at 4DA4H. If not set, it sets the flag and falls through to the main dispatch at 4DADH.

4DC5
LD A,(4DE4H) 3A E4 4D
Fetch the token context flag from 4DE4H into Register A. This is self-modifying code - 4DE4H is the operand of a LD A instruction at 4DE3H. The flag is 00H if no line-number-producing token has been seen, or 01H if one has.
4DC8
OR A B7
OR Register A with itself to set the flags based on the context flag value.
4DC9
If the Z FLAG has been set (context flag is 00H - no prior line number token), JUMP to 4DADH to fetch the next byte and continue scanning. These tokens don't introduce line number references on their own.
4DCB
LD A,01H 3E 01
Load Register A with 01H.
4DCD
Unconditional JUMP back to 4DA4H. Store 01H into 4E81H (line number found flag), then re-enter the dispatch loop. This marks the current context as expecting a line number, so the next numeric token will be processed as a line reference.

4DCFH - GET Handler (Token 9FH)

GET Handler. Dispatched for token 9FH (GET). Sets the line number found flag at 4E81H to 01H and enters the line number check routine at 4DD4H. GET statements can contain file number and line number references.

4DCF
LD A,01H 3E 01
Load Register A with 01H (line number found flag).
4DD1
Store 01H into 4E81H (line number found flag). This is self-modifying code .

4DD4H - Line Number Check (REM/GOTO/GOSUB Common Entry)

Line Number Check. This is the common entry point for tokens that may be followed by line number references (GOTO, GOSUB, THEN, RUN, RESTORE, RESUME, ON...GOTO, ON...GOSUB, etc.). It calls 513BH (digit check) to determine if the next character is a digit. If it is a digit, the code enters the line number parser at 4E4CH. If not a digit, it calls 511DH (whitespace skip) and checks for a comma separator. If a comma is found, the loop continues to look for the next potential line number.

4DD4
GOSUB to 513BH (digit check). This routine reads the next byte, skips whitespace, and tests if it is an ASCII digit (30H-39H). Returns with CARRY set if the byte is a digit, NO CARRY if not.
4DD7
If the NO CARRY FLAG has been set (the byte is not a digit - no line number follows), JUMP back to 4DB0H to enter the dispatch table lookup with the current byte. The token is not followed by a line number reference.

The next character IS a digit. Parse it as a line number.

4DD9
GOSUB to 4E4CH (line number parser). This routine parses a decimal line number from the BASIC text, validates it against range limits, and stores the result. On return, BC = number of digits consumed, DE = the parsed line number (or reference to the lookup result).
4DDC
GOSUB to 511DH (whitespace skip). This routine skips whitespace and returns with the next non-whitespace character in Register A.
4DDF
CP 2CH FE 2C
Compare Register A against 2CH (ASCII comma ,). If Register A equals 2CH, the Z FLAG is set. A comma indicates another line number follows (e.g., ON GOTO 100,200,300).
4DE1
If the NZ FLAG has been set (not a comma - no more line numbers in this list), JUMP back to 4DB0H to dispatch the current byte through the table. The line number list has ended.

A comma was found. Check the token context flag to see if more line numbers are expected.

4DE3
LD A,00H 3E 00
Load Register A with the token context flag. This is self-modifying code - the operand at 4DE4H is written by 4DA8H and 4DC3H. When 00H, no more line numbers are expected; when 01H, the comma-separated list continues.
4DE5
OR A B7
OR Register A with itself to set the flags based on the context flag value.
4DE6
If the NZ FLAG has been set (context flag is 01H - more line numbers expected after the comma), JUMP back to 4DD9H to parse the next line number. This handles comma-separated line number lists like ON GOTO 100,200,300.

4DE8H - Error Line Number Output Setup

Error Line Number Output Setup. When a line number reference cannot be resolved (the target line does not exist), this section sets up the error reporting. It saves the current state, loads the error format code 58H (ASCII 'X'), and calls the line number output routine at 4F54H to display the error. After output, it continues scanning the BASIC text to find the next line number or end of statement.

4DE8
PUSH AF F5
Save Register Pair AF (the current flags and accumulator state) onto the stack. This is a no-op placeholder - the POP AF at 4DE9H immediately restores it.
4DE9
POP AF F1
Restore Register Pair AF from the stack (cancelling the PUSH). This PUSH/POP pair is a 2-byte no-op used as alignment or a patch point.
4DEA
LD A,58H 3E 58
Load Register A with 58H (ASCII X). This is the error format code used in the line number output to mark unresolvable line references with an 'X'.
4DEC
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H. This is self-modifying code - the operand at 4DEDH is written by 4D78H to hold the current line number. When this instruction executes, DE will contain the line number of the line where the unresolvable reference was found.
4DEF
GOSUB to 4F54H (line number output routine). This routine formats and displays the error line number with the 'X' marker, outputting it to the screen as part of the error reporting. The line number in DE and format code in A are used to produce the display.
4DF2
DEC BC 0B
DECrement Register Pair BC by 1. BC tracks the output buffer position; backing up by one prepares for the next byte fetch.
4DF3
DEC HL 2B
DECrement Register Pair HL by 1, backing up the BASIC text pointer by one byte.

LOOP START
Skip remaining tokens after error

4DF4
GOSUB to 4E40H (byte fetch with end-of-statement check). This reads the next byte and checks for 00H (end-of-statement) or 3AH (colon). If end-of-statement, it pops the return address and goes to 4E10H; otherwise it returns with the byte in A.
4DF7
Unconditional JUMP back to 4DF4H. This is an infinite loop that reads bytes until 4E40H detects end-of-statement or colon and exits via the POP/JR path.

LOOP END
Continue skipping until end-of-statement

4DF9H - Line Number Overflow Error

Line Number Overflow Error. Reached when the line number parser detects that the parsed number exceeds the maximum allowed value (65529, or 19998 in some configurations). The code unwinds the stack (three POPs to discard the parser's saved state) and falls through to output the error with format code 53H (ASCII 'S' for overflow/size error).

4DF9
POP HL E1
Discard the first saved value from the stack (parser state cleanup).
4DFA
POP BC C1
Discard the second saved value from the stack.
4DFB
POP AF F1
Discard the third saved value from the stack. The parser's state has been unwound.
4DFC
LD A,53H 3E 53
Load Register A with 53H (ASCII S). This is the error format code for a size/overflow error in the line number.
4DFE
Unconditional JUMP back to 4DECH (load the current line number from the self-modifying operand and call the error output routine at 4F54H).

4E00H - THEN/Token Check with Digit Scan (Tokens B6H-C2H)

THEN/Token Check. Dispatched for tokens B6H through C2H, which includes THEN (C2H). The THEN token is significant because THEN can be followed by a line number (GOTO-like behavior). The handler calls the line number parser (4E4CH) and the digit checker (513BH) in a loop, processing line numbers found after THEN. Tokens in the range D2H-D6H are function tokens that do not contain line numbers and are re-routed to the scanner.

LOOP START
THEN line number check

4E00
GOSUB to 4E4CH (line number parser). Parse the next line number from the BASIC text.
4E03
GOSUB to 513BH (digit check). Skip whitespace and test if the next character is a digit.

LOOP
Parse next line number

4E06
If the CARRY FLAG has been set (next character IS a digit), JUMP back to 4E00H to parse another line number. Multiple line numbers can follow THEN in an ON...GOTO/GOSUB list.

The next character is not a digit. Check if it is a function token (D2H-D6H range) that should be skipped.

4E08
CP D2H FE D2
Compare Register A against D2H. If A < D2H, CARRY is set (the token is below the function range).
4E0A
If the CARRY FLAG has been set (token is below D2H), JUMP forward to 4E10H (re-enter the main dispatch loop). The token is not a function token.
4E0C
CP D7H FE D7
Compare Register A against D7H. If A < D7H (i.e., A is in the range D2H-D6H), CARRY is set.
4E0E
If the CARRY FLAG has been set (token is in the D2H-D6H function range), JUMP back to 4E03H to skip the function token and check for the next digit. Function tokens in this range are skipped because they don't contain line number references.

LOOP END

4E10
Unconditional JUMP back to 4DB0H (enter dispatch table with current byte). The current token is re-dispatched through the table for standard handling.

4E12H - General Line Number Token Handler (Tokens A6H-B5H)

General Line Number Token Handler. Dispatched for tokens A6H through B5H (LSET through CSAVE). These statements may optionally contain line number references. The handler calls the digit checker and, if a digit is found, parses the line number via 4E4CH and skips whitespace. It then checks for the GOTO/GOSUB token CEH to handle constructs like ON ERROR GOTO, routing to the line number check at 4DD4H if found.

4E12
GOSUB to 513BH (digit check). Skip whitespace and test if the next character is a digit.
4E15
If the NO CARRY FLAG has been set (next character is NOT a digit), JUMP forward to 4E1DH to check for the GOTO/GOSUB token. No line number follows immediately.
4E17
GOSUB to 4E4CH (line number parser). Parse the line number that follows the token.
4E1A
GOSUB to 511DH (whitespace skip). Returns with the next non-whitespace character in Register A.
4E1D
CP CEH FE CE
Compare Register A against CEH. In NEWDOS/80 BASIC, CEH is a token that can introduce a GOTO target (used in ON ERROR GOTO constructs).
4E1F
If the Z FLAG has been set (token is CEH - GOTO context), JUMP back to 4DD4H (line number check). This handles the GOTO portion of ON ERROR GOTO and similar constructs.
4E21
Unconditional JUMP to 4E10H (re-enter dispatch at 4DB0H). No GOTO token found; continue scanning the statement normally.

4E23H - NAME/KILL Parenthesis Handler (Tokens A2H-A5H)

NAME/KILL Parenthesis Handler. Dispatched for tokens A2H through A5H (LOAD, MERGE, NAME, KILL). These statements can have parenthesized arguments that contain commas. The handler counts parentheses to correctly identify when a comma is a list separator (outside parentheses) rather than part of an argument expression. Register D counts the number of commas to expect (initialized to 02H for NAME which has two arguments), and Register E tracks parenthesis nesting depth.

4E23
LD D,02H 16 02
Load Register D with 02H (decimal 2). D is the expected comma count for NAME-style statements that take two filename arguments separated by a comma (e.g., NAME “OLD” AS “NEW”).
4E25
LD E,FFH 1E FF
Load Register E with FFH (-1 in signed arithmetic). E is the parenthesis nesting depth counter. Starting at FFH means the first INC E will bring it to 00H, representing zero nesting depth.
4E27
INC E 1C
INCrement Register E by 1 (increase parenthesis nesting depth). Called when an opening parenthesis is found.

LOOP START
Parenthesis scan

4E28
GOSUB to 4E40H (byte fetch with end-of-statement check). Read the next byte; if 00H or 3AH, exit via the POP path.
4E2B
CP 28H FE 28
Compare Register A against 28H (ASCII opening parenthesis ().
4E2D
If the Z FLAG has been set (opening parenthesis found), JUMP back to 4E27H to increment the nesting depth and read the next byte.
4E2F
DEC E 1D
DECrement Register E by 1 (tentatively decrease parenthesis depth, assuming closing parenthesis).
4E30
CP 29H FE 29
Compare Register A against 29H (ASCII closing parenthesis )).
4E32
If the Z FLAG has been set (closing parenthesis found), JUMP back to 4E28H. The DEC at 4E2FH correctly decreased the depth.
4E34
INC E 1C
INCrement Register E by 1, undoing the tentative DEC at 4E2FH since the character was not a closing parenthesis.
4E35
If the NZ FLAG has been set (nesting depth is non-zero - still inside parentheses), JUMP back to 4E28H. While inside parentheses, commas are part of the argument expression and should not be treated as list separators.

Nesting depth is zero (E = 00H after INC restored it). We are outside parentheses. Check if the character is a comma.

4E37
CP 2CH FE 2C
Compare Register A against 2CH (ASCII comma ,).
4E39
If the NZ FLAG has been set (not a comma), JUMP back to 4E28H to continue scanning.

A comma was found outside parentheses. Decrement the expected comma count.

4E3B
DEC D 15
DECrement Register D by 1 (the expected comma count). If D reaches zero, all expected commas have been consumed.
4E3C
If the NZ FLAG has been set (D is not zero - more commas expected), JUMP back to 4E28H to continue scanning for the next comma.

LOOP END

4E3E
Unconditional JUMP back to 4DD4H (line number check). After all expected commas have been consumed, the remaining text may contain a line number reference.

4E40H - Byte Fetch with End-of-Statement Check

This subroutine fetches the next byte from BASIC program text via the dual-purpose byte-fetch routine at 5120H and checks whether it is an end-of-statement marker (00H for end-of-line or 3AH for colon separator). If the byte IS an end-of-statement marker, the routine pops the caller's return address off the stack (discarding the immediate caller) and jumps to 4E10H to re-enter the dispatch table lookup, effectively abandoning the current token handler. If the byte is NOT an end-of-statement marker, it returns normally to the caller with the byte in Register A.

4E40
GOSUB to 5120H, the dual-purpose byte-fetch routine. This reads the next byte from the BASIC program text pointed to by Register Pair HL (the current scan position) into Register A, advances HL past it, and - if the cross-reference flag at 5121H is set to 01H (second pass) - also copies the byte to the output buffer pointed to by Register Pair BC.
4E43
OR A B7
OR Register A with itself. This sets the Z FLAG if Register A is 00H (end-of-line marker in BASIC program text), or clears it otherwise. The byte just fetched is being tested to see if it is a null terminator marking the end of the current BASIC statement line.
4E44
If the Z FLAG has been set (the fetched byte is 00H, an end-of-line marker), JUMP forward to 4E49H to pop the return address and re-enter the dispatch loop. [END OF LINE - abandon current handler]
4E46
CP 3AH FE 3A
Compare Register A against 3AH (ASCII colon :). The colon is the BASIC statement separator. If Register A equals 3AH, the Z FLAG is set; otherwise the NZ FLAG is set.
4E48
RET NZ C0
If the NZ FLAG has been set (the byte is neither 00H nor 3AH, meaning it is not an end-of-statement marker), RETURN to the caller with Register A holding the fetched byte. The caller continues processing this byte normally.

If execution reaches 4E49H, the fetched byte IS an end-of-statement marker (either 00H from the check at 4E43H, or 3AH from the compare at 4E46H). The routine discards its caller's return address and re-enters the dispatch loop.

4E49
POP DE D1
Pop the top value from the stack into Register Pair DE, discarding the return address of the subroutine that called this routine. This prevents returning to the current token handler, which is no longer relevant since the statement has ended.
4E4A
JUMP back to 4E10H, which is the re-entry point for the token dispatch table lookup. This sends execution back to the main dispatcher at 4DB0H to begin processing the next statement's tokens.

4E4CH - Line Number Parser (Decimal Accumulator)

This routine parses a decimal line number from the BASIC program text. It accumulates the value digit-by-digit into Register Pair DE using the formula DE = DE × 10 + digit. Before each multiply, it checks for overflow against 1998H (decimal 6552); if DE exceeds this threshold, the next multiply-by-10 would overflow a 16-bit value, so the routine branches to the overflow error handler at 4DF9H. After the number is fully parsed, the routine stores the digit count at 515EH, checks whether the parsed number is zero, and tests the self-modifying “line number found” flag at 4E81H to determine whether this number is a line reference (requiring lookup/replacement) or just a numeric literal (to be skipped).

4E4C
GOSUB to 513BH, the digit-check routine. This skips whitespace in the BASIC program text, then checks whether Register A contains an ASCII digit (30H-39H). If it IS a digit, the CARRY FLAG is set and Register A holds the digit character. If it is NOT a digit, the NO CARRY FLAG is set.
4E4F
If the NO CARRY FLAG has been set (the first character is not a digit, meaning there is no line number to parse here), JUMP back to 4DE9H, the error line-number output setup routine. This handles the case where a line number was expected but not found.
4E51
PUSH BC C5
Save Register Pair BC (the current output buffer position) onto the stack. BC will be repurposed as a digit counter during the parsing loop.
4E52
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H, initializing the decimal accumulator to zero. DE will hold the running total of the parsed line number as each digit is processed.
4E55
LD B,D 42
Load Register B with Register D (which is 00H). This clears Register B to zero as part of initializing Register Pair BC as a digit counter.
4E56
LD C,E 4B
Load Register C with Register E (which is 00H). Together with the previous instruction, Register Pair BC is now 0000H - the digit counter is initialized to zero.
4E57
PUSH HL E5
Save Register Pair HL (the current BASIC program text pointer) onto the stack. HL will be temporarily repurposed inside the accumulation loop.

LOOP START - Decimal Digit Accumulation Loop
Each iteration processes one ASCII digit: it checks for overflow, multiplies DE by 10, adds the new digit, and fetches the next character. The loop continues as long as the next character is a digit.

4E58
INC BC 03
INCrement Register Pair BC (the digit counter) by 1. This counts how many decimal digits have been parsed so far.
4E59
LD HL,1998H 21 98 19
Load Register Pair HL with 1998H (decimal 6552). This is the overflow threshold: if the current accumulated value in DE exceeds 6552, then multiplying by 10 and adding a digit could produce a value greater than 65529 (the maximum valid BASIC line number), which would overflow a 16-bit register.
4E5C
OR A B7
Clear the CARRY FLAG by ORing Register A with itself. This prepares for the 16-bit subtraction that follows, ensuring SBC does not subtract an extra 1 from a stale carry.
4E5D
SBC HL,DE ED 52
Subtract Register Pair DE (the current accumulated line number value) from Register Pair HL (the overflow threshold 1998H) with borrow. If DE > 1998H, the result is negative and the CARRY FLAG is set, indicating overflow.
4E5F
If the CARRY FLAG has been set (DE exceeds 1998H, meaning the next multiply-by-10 would overflow), JUMP to 4DF9H, the line number overflow error handler. That routine unwinds the stack and outputs an S-type error marker. [OVERFLOW ERROR EXIT]

The overflow check passed. Now multiply DE by 10 using the shift-and-add method: DE × 10 = DE × 2 × 2 + DE) × 2 = ((DE << 2) + DE) << 1. The code implements this by loading HL with DE, then computing HL = HL × 4 + DE, then HL = HL × 2.

4E61
LD H,D 62
Load Register H with Register D (high byte of the accumulated value). This copies DE into HL so the multiply-by-10 can be performed using HL arithmetic.
4E62
LD L,E 6B
Load Register L with Register E (low byte of the accumulated value). Register Pair HL now holds a copy of the accumulated line number value from DE.
4E63
ADD HL,HL 29
ADD Register Pair HL to itself, doubling it. HL is now DE × 2.
4E64
ADD HL,HL 29
ADD Register Pair HL to itself again, doubling it. HL is now DE × 4.
4E65
ADD HL,DE 19
ADD Register Pair DE (the original accumulated value) to HL. HL is now DE × 4 + DE = DE × 5.
4E66
ADD HL,HL 29
ADD Register Pair HL to itself, doubling it. HL is now DE × 5 × 2 = DE × 10. The multiply-by-10 is complete.
4E67
SUB 30H D6 30
SUBtract 30H (ASCII 0) from Register A, converting the ASCII digit character in Register A to its binary value (0-9).
4E69
LD E,A 5F
Load Register E with Register A (the binary digit value 0-9). This places the digit in the low byte of DE for the addition.
4E6A
LD D,B 50
Load Register D with Register B. Since B was set to 00H earlier and is not modified in this loop (only BC as a 16-bit pair is incremented), D is loaded with 00H, making DE hold just the single digit value.
4E6B
ADD HL,DE 19
ADD Register Pair DE (the single digit value) to Register Pair HL (which holds the old accumulated value × 10). HL now equals (old_DE × 10) + new_digit.
4E6C
EX DE,HL EB
Exchange Register Pairs DE and HL. DE now holds the updated accumulated line number value. HL gets the digit value (no longer needed).
4E6D
POP HL E1
Restore Register Pair HL from the stack. HL now points back to the current position in the BASIC program text (saved at 4E57H or by the EX (SP),HL at 4E70H from the previous iteration).
4E6E
PUSH HL E5
Save Register Pair HL (the BASIC text pointer) back onto the stack, preserving it for the next iteration or for after the loop exits.
4E6F
RST 10H D7
Call the ROM routine at 0010H (RST 10H), which fetches the next non-space character from the BASIC program text pointed to by HL. On return, Register A holds the next non-space character and HL points past it. The CARRY FLAG is set if the character is a digit (30H-39H).
4E70
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack. The updated BASIC text pointer (from RST 10H) goes onto the stack, and the previous saved text pointer comes into HL. This preserves the advanced pointer for later retrieval.
4E71
If the CARRY FLAG has been set (RST 10H found another digit), JUMP back to 4E58H to accumulate this digit into the running total. [LOOP - continue parsing digits]

LOOP END - Decimal Digit Accumulation Loop
All digits have been parsed. DE holds the complete line number value. BC holds the digit count. The stack holds the updated BASIC text pointer.

4E73
LD (515EH),BC ED 43 5E 51
Store Register Pair BC (the digit count - number of decimal digits that were parsed) to memory location 515EH, the self-modifying operand that records how many digits the parsed line number contains. This is used later during output to determine how many bytes of program text to replace. [SELF-MODIFYING CODE TARGET at 515EH]
4E77
POP BC C1
Restore Register Pair BC from the stack. BC now holds the output buffer position that was saved at 4E51H before the parsing loop began.
4E78
INC HL 23
INCrement Register Pair HL by 1. This advances the saved text pointer past the last digit that was parsed, positioning it at the first non-digit character.
4E79
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack. The incremented text pointer goes onto the stack, and the previous stack value (the original text pointer saved at 4E6EH) comes into HL. HL now points to the current scan position.
4E7A
PUSH HL E5
Save Register Pair HL (the current text pointer) onto the stack. This balances the stack for the upcoming POP HL at the caller.
4E7B
LD A,D 7A
Load Register A with Register D (the high byte of the parsed line number in DE). This prepares to check if the parsed number is zero.
4E7C
OR E B3
OR Register A with Register E (the low byte of the parsed line number). If DE is 0000H (the user typed line number 0), the Z FLAG is set. Otherwise the NZ FLAG is set.
4E7D
If the NZ FLAG has been set (the parsed line number is not zero), JUMP to 4F22H, the line number replacement routine. That routine looks up the parsed line number in the cross-reference table and replaces it with the renumbered value if it falls within the renumber range.

The parsed line number is zero. Now check the self-modifying “line number found” flag at 4E81H to determine whether this zero was expected as a line number reference.

4E80
OR 00H F6 00
OR Register A with the immediate operand at 4E81H. The operand byte at 4E81H is a self-modifying code target: when set to 00H, this instruction is OR 00H which has no effect and the Z FLAG remains set. When set to 01H (written by the GET handler at 4DD1H or the FIELD handler at 4DCBH), this becomes OR 01H which clears the Z FLAG, signaling that a line number reference was found and needs processing. [SELF-MODIFYING CODE at 4E81H]
4E82
If the NZ FLAG has been set (the line-number-found flag at 4E81H was 01H, meaning a line number reference context is active), JUMP to 4F43H, the skip/output routine. Even though the line number is zero, the context flag indicates this is a deliberate line number reference (e.g., GOTO 0) that must be output.
4E85
LD A,53H 3E 53
Load Register A with 53H (ASCII S). This is the error type marker for a “syntax” or “special” error - a line number of zero was found outside of a line-number-reference context, which is invalid.
4E87
JUMP to 4F56H, the error output routine entry point. This outputs the error marker with the current line number information.

4E8AH - Token Dispatch Table (19 Entries, 57 Bytes)

This is a data table, not executable code. It contains 19 three-byte entries used by the dispatch table lookup loop at 4DB4H. Each entry consists of a 16-bit handler address (low byte first, little-endian) followed by a 1-byte maximum token value. The scanner at 4DB4H reads each entry sequentially: if the current token in Register A is less than the max_token, the token falls below this entry’s range and is skipped via JR C,4DACH; if equal, the handler is dispatched; if greater, the next entry is checked. The table is terminated by an FFH sentinel entry that catches all remaining tokens.

4E8A-4E8C
DEFW 4D34H / DEFB 00H 34 4D 00
Entry 0
Handler: 4D34H (Position Store + Next Line). Max Token: 00H (end-of-statement null byte). When the scanner encounters a 00H byte, it dispatches to 4D34H to store the current position and advance to the next BASIC line.
4E8D-4E8F
DEFW 4D85H / DEFB 22H 85 4D 22
Entry 1
Handler: 4D85H (Quoted String Skip). Max Token: 22H (double-quote). When the scanner encounters a 22H byte (ASCII "), it dispatches to 4D85H to skip past the quoted string without scanning its contents for line number references.
4E90-4E92
DEFW 4DA3H / DEFB 3AH A3 4D 3A
Entry 2
Handler: 4DA3H (Token Dispatch Init). Max Token: 3AH (colon). Tokens/characters in the range 23H-39H (ASCII punctuation and digits that are not token codes) are skipped. When a 3AH colon (statement separator) is reached, dispatch to 4DA3H resets the context flags and begins scanning the next statement.
4E93-4E95
DEFW 4D9AH / DEFB 88H 9A 4D 88
Entry 3
Handler: 4D9AH (GOTO Range Statement Scanner). Max Token: 88H (GOTO token). Tokens 3BH-87H are below the threshold and are skipped. Token 88H (GOTO) dispatches to the scanner that processes line number arguments for GOTO statements.
4E96-4E98
DEFW 4DD9H / DEFB 8DH D9 4D 8D
Entry 4
Handler: 4DD9H (Line Number Call). Max Token: 8DH (RETURN token). Tokens 89H-8CH (GOSUB through RESUME) are below threshold and skipped. Token 8DH (RETURN) dispatches to 4DD9H which calls the line number parser at 4E4CH for statements like RUN, RESTORE, and RESUME that take line number arguments.
4E99-4E9B
DEFW 4DD4H / DEFB 8EH D4 4D 8E
Entry 5
Handler: 4DD4H (Line Number Check). Max Token: 8EH (REM token). Token 8EH (REM) dispatches to 4DD4H. Since REM causes the rest of the line to be treated as a comment, the digit-check at 513BH fails immediately and control falls through to skip the remainder.
4E9C-4E9E
DEFW 4DD9H / DEFB 91H D9 4D 91
Entry 6
Handler: 4DD9H (Line Number Call). Max Token: 91H (TRON token). Tokens 8FH-90H (STOP, ELSE) are below threshold. Token 91H (TRON) dispatches to 4DD9H for line number parsing.
4E9F-4EA1
DEFW 4D7EH / DEFB 93H 7E 4D 93
Entry 7
Handler: 4D7EH (USING/DEFSTR Skip). Max Token: 93H (DEFSTR token). Tokens 92H (TROFF) is below threshold. Token 93H (DEFSTR) dispatches to 4D7EH which skips to the end of the statement without scanning for line numbers.
4EA2-4EA4
DEFW 4DD4H / DEFB 95H D4 4D 95
Entry 8
Handler: 4DD4H (Line Number Check). Max Token: 95H (DEFSNG token). Token 94H (DEFINT) is below threshold. Token 95H (DEFSNG) dispatches to the line number check handler.
4EA5-4EA7
DEFW 4DC5H / DEFB 9EH C5 4D 9E
Entry 9
Handler: 4DC5H (FIELD Handler). Max Token: 9EH (FIELD token). Tokens 96H-9DH (DEFDBL through LINE) are below threshold. Token 9EH (FIELD) dispatches to 4DC5H which checks the context flag to determine whether to parse line numbers in a comma-separated list.
4EA8-4EAAH
DEFW 4DCFH / DEFB 9FH CF 4D 9F
Entry 10
Handler: 4DCFH (GET Handler). Max Token: 9FH (GET token). Token 9FH dispatches to 4DCFH which sets the line-number-found flag at 4E81H to 01H, enabling line number reference detection in subsequent parsing.
4EAB-4EADH
DEFW 4DC1H / DEFB A1H C1 4D A1
Entry 11
Handler: 4DC1H (PUT/CLOSE Handler). Max Token: A1H (CLOSE token). Token A0H (PUT) is below threshold. Token A1H (CLOSE) dispatches to 4DC1H which sets the token context flag and re-enters the scanner.
4EAE-4EB0
DEFW 4E23H / DEFB A4H 23 4E A4
Entry 12
Handler: 4E23H (NAME/KILL Parenthesis Handler). Max Token: A4H (NAME token). Tokens A2H-A3H (LOAD, MERGE) are below threshold. Token A4H (NAME) dispatches to 4E23H which tracks parenthesis depth and comma positions for multi-argument statements.
4EB1-4EB3
DEFW 4E23H / DEFB A5H 23 4E A5
Entry 13
Handler: 4E23H (NAME/KILL Parenthesis Handler). Max Token: A5H (KILL token). Token A5H dispatches to the same parenthesis handler as NAME.
4EB4-4EB6
DEFW 4E12H / DEFB B4H 12 4E B4
Entry 14
Handler: 4E12H (General Token Handler). Max Token: B4H (CLOAD token). Tokens A6H-B3H (LSET through MID$) are below threshold. Token B4H (CLOAD) dispatches to 4E12H which checks for digits (ON ERROR GOTO pattern) and the CEH token (ERROR).
4EB7-4EB9
DEFW 4E12H / DEFB B5H 12 4E B5
Entry 15
Handler: 4E12H (General Token Handler). Max Token: B5H (CSAVE token). Token B5H dispatches to the same general handler as CLOAD.
4EBA-4EBC
DEFW 4E03H / DEFB C2H 03 4E C2
Entry 16
Handler: 4E03H (THEN post-handler). Max Token: C2H (THEN token). Tokens B6H-C1H are below threshold. Token C2H (THEN) dispatches to 4E03H which checks the next character for digits (implicit GOTO line number after THEN).
4EBD-4EBF
DEFW 4DD4H / DEFB CAH D4 4D CA
Entry 17
Handler: 4DD4H (Line Number Check). Max Token: CAH (TO token). Tokens C3H-C9H are below threshold. Token CAH (TO) dispatches to the line number check handler.
4EC0-4EC2
DEFW 4DADH / DEFB FFH AD 4D FF
Entry 18 (Sentinel)
Handler: 4DADH (Byte Fetch + Dispatch Entry). Max Token: FFH. This is the catch-all sentinel entry. Any token with a value above CAH that has not matched a previous entry will match FFH here and dispatch to 4DADH, which simply fetches the next byte and re-enters the dispatch loop. This ensures all unrecognized tokens are consumed without error.

4EC3H - Binary Search for Line Number in Cross-Reference Table

This routine searches for a target line number (in Register Pair DE) within the cross-reference table at 64A3H. The table contains 128 two-byte entries (256 bytes total), where each entry holds the address of a BASIC line’s link field. The search uses a binary approach: it starts with an offset of 80H (128 bytes = 64 entries), halves the offset each iteration, and adjusts the table pointer up or down depending on whether the target is greater or less than the candidate. When the offset shrinks below 02H (one entry), the search switches to a linear scan of consecutive lines. The routine returns with DE holding the address of the matching line (or the insertion point), and the flags set: CARRY FLAG set if the line was not found (past end of program), Z FLAG set if an exact match was found.

4EC3
LD HL,64A3H 21 A3 64
Load Register Pair HL with 64A3H, the base address of the cross-reference table. This table resides in high memory and contains 128 two-byte pointers to BASIC program line link fields, sorted by line number.
4EC6
LD BC,0080H 01 80 00
Load Register Pair BC with 0080H (decimal 128). This is the initial binary search offset in bytes, corresponding to 64 table entries (each entry is 2 bytes). The offset will be halved after each comparison.

LOOP START - Binary Search Loop
Each iteration: add offset to HL, dereference the table entry to get a BASIC line address, read the line number from that address, compare against the target in DE, and adjust HL accordingly.

4EC9
ADD HL,BC 09
ADD Register Pair BC (the current binary search offset) to Register Pair HL (the current table position). This moves the table pointer forward by the offset amount to check the middle candidate.
4ECA
PUSH HL E5
Save Register Pair HL (the current table position after adjustment) onto the stack, preserving it for later adjustment based on the comparison result.
4ECB
LD A,(HL) 7E
Load Register A with the byte at the address pointed to by HL. This reads the low byte of the table entry, which is the low byte of a pointer to a BASIC line’s link field.
4ECC
INC HL 23
INCrement Register Pair HL by 1, advancing to the high byte of the table entry.
4ECD
LD H,(HL) 66
Load Register H with the byte at the address pointed to by HL. This reads the high byte of the pointer from the table entry.
4ECE
LD L,A 6F
Load Register L with Register A (the low byte of the pointer read at 4ECBH). Register Pair HL now holds the full 16-bit address of a BASIC line’s link field.

HL now points to a BASIC line in program memory. The first two bytes at this address are the link pointer (address of the next line). The next two bytes (at HL+2 and HL+3) are the line number. First, check if this is a valid line (link pointer is not 0000H).

4ECF
LD A,(HL) 7E
Load Register A with the byte at the address pointed to by HL. This reads the low byte of the BASIC line’s link pointer (the address of the next line).
4ED0
INC HL 23
INCrement Register Pair HL by 1, advancing to the high byte of the link pointer.
4ED1
OR (HL) B6
OR Register A (the low byte of the link pointer) with the byte at HL (the high byte of the link pointer). If both bytes are 00H, the link pointer is 0000H and the Z FLAG is set, indicating this is the end of the program (no valid line here).
4ED2
INC HL 23
INCrement Register Pair HL by 1, advancing past the link pointer to the line number field (low byte).
4ED3
SCF 37
Set the CARRY FLAG. This pre-sets carry as a “not found / past end” indicator. If the link pointer was 0000H (Z FLAG set at 4ED1H), the following conditional jump will branch and carry will remain set, signaling failure.
4ED4
If the Z FLAG has been set (the link pointer is 0000H, meaning this table entry points past the end of the program), JUMP to 4EDEH to adjust the search position downward. The CARRY FLAG remains set from the SCF at 4ED3H, indicating “target is below this position”. [END OF PROGRAM - search too high]

The link pointer is valid (non-zero). HL now points to the line number low byte. Compare this line’s number against the target in DE.

4ED6
INC HL 23
INCrement Register Pair HL by 1, advancing to the line number high byte. The line number is stored low-byte-first, so the high byte is at the higher address.
4ED7
LD A,D 7A
Load Register A with Register D (the high byte of the target line number in DE).
4ED8
CP (HL) BE
Compare Register A (high byte of target line number) against the byte at HL (high byte of the candidate line number). If they differ, the NZ FLAG is set and the comparison is resolved.
4ED9
DEC HL 2B
DECrement Register Pair HL by 1, moving back to the line number low byte. This positions HL for the low-byte comparison if the high bytes matched.
4EDA
If the NZ FLAG has been set (the high bytes of the target and candidate line numbers differ), JUMP to 4EDEH. The CARRY FLAG from the CP at 4ED8H indicates the direction: set if the target is less than the candidate (search too high), clear if greater (search too low).
4EDC
LD A,E 7B
Load Register A with Register E (the low byte of the target line number in DE). The high bytes matched, so the low bytes must be compared to determine the exact relationship.
4EDD
CP (HL) BE
Compare Register A (low byte of target line number) against the byte at HL (low byte of the candidate line number). The Z FLAG is set if the line numbers are identical (exact match found). The CARRY FLAG is set if the target is less than the candidate.
4EDE
POP HL E1
Restore Register Pair HL from the stack (saved at 4ECAH). HL now holds the table position before dereferencing.
4EDF
If the NO CARRY FLAG has been set (the target line number is greater than or equal to the candidate), JUMP to 4EE4H to halve the offset without adjusting HL downward. The table pointer stays at or above the current position.

The target is less than the candidate (or past end of program). Move the table pointer back down by subtracting the current offset.

4EE1
OR A B7
Clear the CARRY FLAG by ORing Register A with itself. This prepares for the 16-bit SBC instruction that follows.
4EE2
SBC HL,BC ED 42
Subtract Register Pair BC (the current binary search offset) from Register Pair HL (the table position), with borrow (but carry was just cleared). This moves the table pointer back down to compensate for the overshoot, since the target is below the current candidate.
4EE4
SRL C CB 39
Shift Register C right logically by one bit, halving the offset. Since Register B is 00H (unchanged from the initial load at 4EC6H), only C holds the offset value. The offset shrinks from 80H to 40H to 20H to 10H to 08H to 04H to 02H to 01H across successive iterations.
4EE6
LD A,C 79
Load Register A with Register C (the halved offset value).
4EE7
CP 02H FE 02
Compare Register A against 02H. If the offset is still 02H or greater (at least one table entry), the binary search has not yet converged and another iteration is needed. If below 02H, the search has narrowed to a single entry and must switch to linear scanning.
4EE9
If the NO CARRY FLAG has been set (the offset is 02H or greater), JUMP back to 4EC9H for the next binary search iteration. [LOOP - continue binary search]

LOOP END - Binary Search Loop
The binary search has converged. HL points to the table entry nearest the target. Now switch to a linear scan through BASIC program lines to find the exact match.

4EEB
LD A,(HL) 7E
Load Register A with the byte at the address pointed to by HL. This reads the low byte of the table entry (the low byte of the pointer to the nearest BASIC line).
4EEC
INC HL 23
INCrement Register Pair HL by 1, advancing to the high byte of the table entry.
4EED
LD H,(HL) 66
Load Register H with the byte at HL (the high byte of the pointer).
4EEE
LD L,A 6F
Load Register L with Register A (the low byte of the pointer). Register Pair HL now holds the address of the BASIC line identified by the converged binary search.

Check the cross-reference flag at 5121H to determine whether we are on the first pass (scan only) or second pass (scan and copy). On the second pass, the program text has been relocated, so we need to compare against the output position to detect when the scan has caught up to the current write position.

4EEF
LD A,(5121H) 3A 21 51
Load Register A with the value at memory location 5121H, the cross-reference flag. This flag is 00H during the first pass (scan only) and 01H during the second pass (scan and copy to output buffer). [SELF-MODIFYING CODE at 5121H]
4EF2
OR A B7
OR Register A with itself. Sets the Z FLAG if the cross-reference flag is 00H (first pass), or clears it if 01H (second pass).
4EF3
If the Z FLAG has been set (first pass, cross-reference flag is 00H), JUMP forward to 4F03H to begin the linear scan without the output-position check. [FIRST PASS - skip position comparison]

Second pass. Check if the current line pointer (HL) has caught up to the output buffer position stored at 4EF6H. If so, all remaining lines have already been processed.

4EF5
LD BC,0000H 01 00 00
Load Register Pair BC with the value at 4EF6H. The operand bytes at 4EF6H-4EF7H are a self-modifying code target, written at 4D34H and 5007H with the current output buffer position. During execution, this loads BC with the output position, not literal 0000H. [SELF-MODIFYING CODE at 4EF6H]
4EF8
LD A,H 7C
Load Register A with Register H (the high byte of the current line address in HL).
4EF9
CP B B8
Compare Register A (high byte of current line address) against Register B (high byte of output position). If they differ, the comparison is resolved.
4EFA
If the NZ FLAG has been set (the high bytes of the line address and output position differ, meaning the current line is not at the output position), JUMP to 4F03H to continue the linear scan.
4EFC
LD A,L 7D
Load Register A with Register L (the low byte of the current line address).
4EFD
CP C B9
Compare Register A (low byte of current line address) against Register C (low byte of output position). If they are equal (and the high bytes also matched), the line address matches the output position exactly.
4EFE
If the NZ FLAG has been set (the low bytes differ, meaning the addresses do not match), JUMP to 4F03H to continue the linear scan.

The current line address exactly matches the output buffer position. This means the scan has caught up to the write point. Load HL from the self-modifying operand at 4F01H, which holds the actual line pointer for the current position.

4F00
LD HL,0000H 21 00 00
Load Register Pair HL with the value at 4F01H. The operand bytes at 4F01H-4F02H are a self-modifying code target, written at 4D38H with the address of the line currently being scanned. During execution, this loads HL with the actual line pointer, not literal 0000H. [SELF-MODIFYING CODE at 4F01H]

LOOP START - Linear Scan Loop
Walk through consecutive BASIC lines starting from the position resolved by the binary search. For each line, check if it is the end of the program (link pointer is 0000H), then compare its line number against the target in DE.

4F03
LD A,(HL) 7E
Load Register A with the byte at the address pointed to by HL. This reads the low byte of the current BASIC line’s link pointer.
4F04
INC HL 23
INCrement Register Pair HL by 1, advancing to the high byte of the link pointer.
4F05
OR (HL) B6
OR Register A (low byte of link pointer) with the byte at HL (high byte of link pointer). If both are 00H, the Z FLAG is set, indicating end of program.
4F06
If the Z FLAG has been set (the link pointer is 0000H, meaning end of the BASIC program), JUMP to 4F18H, the end-of-program handler. [END OF PROGRAM - target line not found]
4F08
INC HL 23
INCrement Register Pair HL by 1, advancing past the high byte of the link pointer to the line number low byte.
4F09
LD C,(HL) 4E
Load Register C with the byte at HL (the low byte of this line’s line number).
4F0A
INC HL 23
INCrement Register Pair HL by 1, advancing to the line number high byte.
4F0B
LD A,(HL) 7E
Load Register A with the byte at HL (the high byte of this line’s line number).
4F0C
CP D BA
Compare Register A (high byte of candidate line number) against Register D (high byte of target line number). If they differ, the comparison is resolved.
4F0D
If the NZ FLAG has been set (the high bytes of the candidate and target line numbers differ), JUMP to 4F11H. The CARRY FLAG from the CP indicates direction: set if candidate is greater than target.
4F0F
LD A,C 79
Load Register A with Register C (the low byte of the candidate line number, read at 4F09H).
4F10
CP E BB
Compare Register A (low byte of candidate line number) against Register E (low byte of target line number). The Z FLAG is set if the line numbers match exactly. The CARRY FLAG is set if the candidate is less than the target.
4F11
If the NO CARRY FLAG has been set (the candidate line number is greater than or equal to the target), JUMP to 4F1CH. The search has found either an exact match (Z set) or the first line past the target (NZ set). [MATCH OR PAST - exit linear scan]
4F13
GOSUB to 5CCEH, the line-skip alternate entry in BASIC/CMD. This advances HL past the current BASIC line to the start of the next line, using the link pointer to jump directly without scanning the line contents.
4F16
JUMP back to 4EEFH to repeat the linear scan with the next line. On the first pass, the cross-reference flag check at 4EEFH-4EF3H will branch directly to 4F03H. On the second pass, the output position comparison is performed first. [LOOP - continue linear scan]

LOOP END - Linear Scan Loop

End-of-program path: the link pointer was 0000H. Advance HL past the null link and null line number to the body area, set carry to indicate “not found,” then extract the line address from the position just before the end marker.

4F18
INC HL 23
INCrement Register Pair HL by 1. HL was pointing at the high byte of the null link pointer; this advances to the first byte of the line number field.
4F19
INC HL 23
INCrement Register Pair HL by 1 again, advancing to the second byte of the line number field. HL now points past both the null link and the line number field.
4F1A
INC A 3C
INCrement Register A by 1. Register A was 00H from the OR (HL) at 4F05H that detected the null link. Incrementing to 01H clears the Z FLAG, indicating “no exact match found.”
4F1B
SCF 37
Set the CARRY FLAG. Combined with the cleared Z FLAG from the INC A, this signals “target line number not found in program; HL points past the end.”
4F1C
DEC HL 2B
DECrement Register Pair HL by 1. This moves back from the line number high byte to the line number low byte position.
4F1D
DEC HL 2B
DECrement Register Pair HL by 1 again, moving back to the high byte of the link pointer. HL now points to the start of the line’s link field.
4F1E
LD D,(HL) 56
Load Register D with the byte at HL (the high byte of the link pointer of the line BEFORE the current position). Actually, after the two DECs, HL points to the link high byte of the matched or boundary line. This loads the high byte of the matched line’s link address into D.
4F1F
DEC HL 2B
DECrement Register Pair HL by 1, moving to the low byte of the link pointer.
4F20
LD E,(HL) 5E
Load Register E with the byte at HL (the low byte of the link pointer). Register Pair DE now holds the address extracted from the line boundary.
4F21
RET C9
RETURN to the caller. Flags indicate the search result: Z FLAG set = exact match found, DE holds the matching line address. CARRY FLAG set = not found (past end of program). NZ + NC = target falls between two lines, DE holds the boundary address.

4F22H - Line Number Replacement (Range Check and Output)

This routine is called when a non-zero line number has been parsed from the BASIC program text (from 4E7DH). It calls the binary search routine at 4EC3H to look up the line number in the program, then checks whether the line falls within the user-specified renumber range (stored at 4D04H-4D07H). If the line is within range, it is replaced with the new renumbered value; if outside the range, the original number is output unchanged. The routine also handles the case where the line number was not found in the program.

4F22
PUSH DE D5
Save Register Pair DE (the parsed line number value from the decimal accumulator) onto the stack. This preserves the original line number for later comparison or output.
4F23
GOSUB to 4EC3H, the binary search routine. This searches the cross-reference table at 64A3H for the line number in DE. On return, the Z FLAG indicates whether an exact match was found, and DE holds the address of the matching or boundary line.
4F26
POP BC C1
Restore the original parsed line number from the stack into Register Pair BC. The binary search used DE, so the original value was saved on the stack at 4F22H.
4F27
If the Z FLAG has been set (the binary search did not find an exact match for the line number in the program), JUMP to 4F43H to output the line number unchanged. The line number references a nonexistent line, so no renumbering is needed. [LINE NOT FOUND - output as-is]

The line number was found in the program. Now check whether it falls within the user-specified renumber range. The “from” line number is stored at 4D04H-4D05H and the “to” line number is at 4D06H-4D07H. If the line is outside this range, output it unchanged.

4F29
LD D,B 50
Load Register D with Register B (the high byte of the original parsed line number, restored from the stack into BC at 4F26H). This copies the line number back into DE for the range comparison.
4F2A
LD E,C 59
Load Register E with Register C (the low byte of the original parsed line number). Register Pair DE now holds the original line number for range checking.
4F2B
LD A,55H 3E 55
Load Register A with 55H (ASCII U). This is the error type marker for “unreferenced” or “unchanged” - it will be used if the line number is outside the renumber range.
4F2D
PUSH AF F5
Save Register A (the error marker 55H) and the flags onto the stack. The error marker is saved in case the range check fails and it needs to be output.
4F2E
LD A,(4D0BH) 3A 0B 4D
Load Register A with the value at memory location 4D0BH. This byte is a flag that indicates whether a renumber range was specified by the user. If 00H, no range was specified (renumber the entire program). If non-zero, a specific range was given.
4F31
OR A B7
OR Register A with itself. Sets the Z FLAG if the range flag is 00H (no range specified), or clears it if a range was specified.
4F32
If the Z FLAG has been set (no renumber range was specified - the entire program is being renumbered), JUMP to 4F57H. Since all lines are in range, the error marker path is skipped and the replacement proceeds for every line. [NO RANGE - renumber everything]

A renumber range was specified. Check if the parsed line number falls within the “from” to “to” boundaries.

4F34
LD HL,(4D06H) 2A 06 4D
Load Register Pair HL with the 16-bit value at memory location 4D06H, the “to” (ending) line number of the renumber range specified by the user.
4F37
RST 18H DF
Call the ROM routine at 0018H (RST 18H), which performs a 16-bit comparison of HL vs DE. This compares the “to” line number (HL) against the parsed line number (DE). The CARRY FLAG is set if HL < DE (the parsed line is above the range end).
4F38
If the CARRY FLAG has been set (the parsed line number is greater than the “to” boundary, meaning it is above the renumber range), JUMP to 4F42H to pop the error marker and output the line unchanged. [ABOVE RANGE - skip renumber]
4F3A
LD HL,(4D04H) 2A 04 4D
Load Register Pair HL with the 16-bit value at memory location 4D04H, the “from” (starting) line number of the renumber range.
4F3D
EX DE,HL EB
Exchange Register Pairs DE and HL. DE now holds the “from” line number and HL holds the parsed line number. This sets up for RST 18H to compare them in the correct order.
4F3E
RST 18H DF
Call RST 18H for a 16-bit comparison of HL vs DE. This compares the parsed line number (HL) against the “from” boundary (DE). The CARRY FLAG is set if HL < DE (the parsed line is below the range start).
4F3F
EX DE,HL EB
Exchange Register Pairs DE and HL again, restoring DE to the parsed line number and HL to the “from” value.
4F40
If the NO CARRY FLAG has been set (the parsed line number is greater than or equal to the “from” boundary, meaning it is within the renumber range), JUMP to 4F57H to proceed with the replacement. [IN RANGE - renumber this line]
4F42
POP AF F1
Restore Register A (the error marker 55H, ASCII U) and flags from the stack (saved at 4F2DH). The line is outside the renumber range, so it will be output unchanged with the U error marker.

The line number is either not found in the program, outside the renumber range, or the line-number-found flag was active with a zero value. Output the original line number digits without modification.

4F43
POP BC C1
Restore Register Pair BC from the stack. This retrieves the output buffer position that was saved earlier by the line number parser.
4F44
LD A,(5121H) 3A 21 51
Load Register A with the value at memory location 5121H, the cross-reference flag. 00H = first pass (display only), 01H = second pass (write to program text). [SELF-MODIFYING CODE at 5121H]
4F47
OR A B7
OR Register A with itself. Sets the Z FLAG if first pass (00H), clears it if second pass (01H).
4F48
If the Z FLAG has been set (first pass - display only), JUMP to 4F4FH to call the first-pass display routine. [FIRST PASS - display number]
4F4A
GOSUB to 5156H, the number-string copy routine. This converts the line number in DE to ASCII digits and copies them to the output buffer pointed to by BC (second pass). The original digits in the program text are replaced with the new number string.
4F4D
JUMP to 4F52H to skip the first-pass call and proceed to the common exit.
4F4F
GOSUB to 5153H, the first-pass number display routine. This displays the line number on screen for the user to see the cross-reference report, without modifying the program text.
4F52
POP HL E1
Restore Register Pair HL from the stack. HL now holds the updated BASIC text pointer, positioned after the parsed line number digits.
4F53
RET C9
RETURN to the caller (the line number check routine at 4DD4H or the THEN handler at 4E00H). The line number has been output (either unchanged or renumbered) and HL points past it in the program text.

4F54H - Error Line Number Output Routine

This routine outputs a line number that could not be renumbered (error/warning output). On the first pass (cross-reference flag at 5121H is 00H), it formats the display output showing the error type marker, the line number, and its context. On the second pass (flag is 01H), it jumps to the fatal error handler at 50E4H. The error type marker character is passed in Register A (58H=X for syntax errors, 53H=S for overflow, 55H=U for out-of-range). Register Pair DE holds the line number being reported.

4F54
PUSH HL E5
Save Register Pair HL (the current BASIC text pointer) onto the stack.
4F55
PUSH BC C5
Save Register Pair BC (the output buffer position) onto the stack.
4F56
PUSH AF F5
Save Register A (the error type marker character) and flags onto the stack. This entry point at 4F56H is used by the jump from 4E87H (line number zero error).
4F57
LD A,(5121H) 3A 21 51
Load Register A with the value at memory location 5121H, the cross-reference flag. 00H = first pass (display cross-reference report on screen), 01H = second pass (fatal error during program rewrite). [SELF-MODIFYING CODE at 5121H]
4F5A
OR A B7
OR Register A with itself. Sets the Z FLAG if first pass (00H), clears it if second pass (01H).
4F5B
If the NZ FLAG has been set (second pass is active - the cross-reference flag is 01H), JUMP to 50E4H, the fatal error handler. Finding an unreferenced or invalid line number during the second pass (when the program text is actually being rewritten) is a fatal condition that corrupts the program. [FATAL ERROR ON SECOND PASS]

First pass. Display the error/warning line on the screen. The format is: error marker / old line number / slash / error type character, followed by two spaces.

4F5E
LD HL,4FA6H 21 A6 4F
Load Register Pair HL with 4FA6H, the address of a one-byte flag that tracks whether the “ERROR LINES” header has been printed. This flag is initialized to 00H and set to 01H after the first error line is output.
4F61
BIT 0,(HL) CB 46
Test bit 0 of the byte at the address pointed to by HL (the error-header-printed flag at 4FA6H). If bit 0 is 0 (header has not been printed yet), the Z FLAG is set. If bit 0 is 1 (header already printed), the NZ FLAG is set.
4F63
If the NZ FLAG has been set (the “ERROR LINES” header has already been printed), JUMP to 4F70H to skip the header and go directly to outputting the error line details.
4F65
SET 0,(HL) CB C6
Set bit 0 of the byte at the address pointed to by HL (the error-header-printed flag at 4FA6H) to 1. This marks the header as having been printed so it is not repeated for subsequent error lines.
4F67
GOSUB to 5D52H, the carriage-return output routine in BASIC/CMD. This outputs a CR/LF to start a new line on the display before printing the error header.
4F6A
LD HL,518CH 21 8C 51
Load Register Pair HL with 518CH, the address of the “ERROR LINES” text string (terminated by 03H).
4F6D
GOSUB to 5147H, the message display routine. This outputs the 03H-terminated string at HL to the screen character by character, displaying “ERROR LINES” as the header before the first error line is shown.

Now output the specific error line information. First check if the display cursor is near the right edge of the screen (column 56 or beyond, since the screen is 64 columns wide) and output a CR/LF if needed to prevent wrapping mid-entry.

4F70
LD A,(4020H) 3A 20 40
Load Register A with the value at memory location 4020H, the screen cursor position (low byte). The cursor position tracks where the next character will be displayed on the 64-column screen.
4F73
AND 3FH E6 3F
AND Register A with 3FH (binary 00111111). This masks the cursor position to extract the column number (0-63) by clearing the row bits. The result is the current column position within the 64-column screen row.
4F75
CP 38H FE 38
Compare Register A against 38H (decimal 56). If the current column is at position 56 or beyond, there are fewer than 8 characters remaining on the line, which may not be enough space for the error entry.
4F77
If the NO CARRY FLAG has been set (the current column is 38H or greater, meaning fewer than 8 columns remain on the line), GOSUB to 5D52H to output a CR/LF and move to the start of the next screen line.
4F7A
LD BC,(4020H) ED 4B 20 40
Load Register Pair BC with the 16-bit value at memory location 4020H, the current cursor position. This saves the cursor position before the line number is printed, so it can be restored afterward.
4F7E
GOSUB to 5156H, the number-string copy routine. This converts the line number in DE to decimal ASCII digits and displays them on the screen, advancing the cursor.
4F81
LD (4020H),BC ED 43 20 40
Store Register Pair BC (the saved cursor position from before the number display) back to memory location 4020H. This restores the cursor to its previous position. The line number was displayed but the cursor is reset, which is used for overwrite-style display formatting.
4F85
LD A,2FH 3E 2F
Load Register A with 2FH (ASCII /). This is the separator character between the line number and the error type marker in the error display format.
4F87
GOSUB to 5D3FH, the display-character routine in BASIC/CMD. This outputs the slash separator / to the screen.
4F8A
POP AF F1
Restore Register A (the error type marker character: X=58H, S=53H, or U=55H) from the stack (saved at 4F56H).
4F8B
GOSUB to 5D3FH to display the error type marker character on screen. The display now shows something like “1000/X” or “500/U”.
4F8E
GOSUB to 5D3DH, the display-with-space routine in BASIC/CMD. This outputs a space character after the error marker to visually separate entries.
4F91
GOSUB to 5D3DH again to output a second space character, providing wider visual separation between error entries on the display line.
4F94
POP BC C1
Restore Register Pair BC (the output buffer position) from the stack (saved at 4F55H).
4F95
POP HL E1
Restore Register Pair HL (the BASIC text pointer) from the stack (saved at 4F54H).
4F96
RET C9
RETURN to the caller. The error line has been displayed, and the scan continues with the next token in the BASIC program text.

4F97H - End-of-Scan Handler (First/Second Pass Router)

This routine is reached when the main line scanner at 4D3BH detects the end of the BASIC program (the link pointer is 0000H via the JP Z,4F97H at 4D3FH). It checks the cross-reference flag at 5121H to determine which pass just completed. On the first pass (00H), it checks for errors and proceeds to the memory relocation phase. On the second pass (01H), it jumps to the second-pass completion handler at 4FFDH. The routine also manages the transition between passes: after the first pass, it relocates the program text in memory to make room for the renumbered line numbers, then starts the second pass.

4F97
LD A,(5121H) 3A 21 51
Load Register A with the value at memory location 5121H, the cross-reference flag. 00H = first pass just completed, 01H = second pass just completed. [SELF-MODIFYING CODE at 5121H]
4F9A
OR A B7
OR Register A with itself. Sets the Z FLAG if first pass (00H), clears it if second pass (01H).
4F9B
If the NZ FLAG has been set (the second pass has completed), JUMP to 4FFDH to handle the second-pass completion, which includes the final output and re-linking of BASIC lines. [SECOND PASS COMPLETE - finalize]

First pass just completed. Check the error flag at 4D0AH to see if any renumber errors were encountered during the scan.

4F9E
LD A,(4D0AH) 3A 0A 4D
Load Register A with the value at memory location 4D0AH, the error flag. This byte is set to a non-zero value if any errors were detected during the first-pass scan (unresolvable line references, overflow, etc.).
4FA1
OR A B7
OR Register A with itself. Sets the Z FLAG if no errors (00H), clears it if errors were found.
4FA2
If the NZ FLAG has been set (errors were found during the first pass), JUMP to 5063H, which displays the “DONE” message and exits without performing the renumber. The program text is left unmodified. [ERRORS FOUND - abort renumber]

No errors on the first pass. Now check the error-header-printed flag at 4FA6H (bit 0 of the byte at 4FA5H+1). If any error lines were displayed, this flag is non-zero.

4FA5
LD A,00H 3E 00
Load Register A with the immediate operand at 4FA6H. The byte at 4FA6H is the error-header-printed flag (written by 4F65H via SET 0,(HL)). If 00H, no error lines were displayed. If 01H, the “ERROR LINES” header was printed. [SELF-MODIFYING CODE at 4FA6H]
4FA7
OR A B7
OR Register A with itself. Sets the Z FLAG if no error lines were displayed (00H), clears it if the error header was printed (01H).
4FA8
If the NZ FLAG has been set (error lines were displayed during the first pass), JUMP to 5069H. This outputs a CR/LF after the error report, loads the BASIC program start address, and exits to the ROM at 1AE9H without performing the renumber. [ERROR LINES DISPLAYED - abort renumber]

No errors at all. Proceed with memory relocation. The program text must be moved in memory to make room for any expansion caused by renumbered line numbers that require more digits than the originals. Calculate the new program size and perform the block move.

4FAB
LD HL,(40F9H) 2A F9 40
Load Register Pair HL with the 16-bit value at memory location 40F9H, the string space start address. This marks the current boundary between the BASIC program area and the string/variable storage area.
4FAE
LD DE,(40A4H) ED 5B A4 40
Load Register Pair DE with the 16-bit value at memory location 40A4H, the BASIC program start address. This is the base address where the tokenized BASIC program begins in memory.
4FB2
OR A B7
Clear the CARRY FLAG by ORing Register A with itself, preparing for the 16-bit subtraction that follows.
4FB3
SBC HL,DE ED 52
Subtract Register Pair DE (program start) from Register Pair HL (string space start). The result in HL is the size of the current BASIC program text in bytes.
4FB5
LD B,H 44
Load Register B with Register H (high byte of the program size).
4FB6
LD C,L 4D
Load Register C with Register L (low byte of the program size). Register Pair BC now holds the current program text size in bytes.
4FB7
LD HL,(5168H) 2A 68 51
Load Register Pair HL with the 16-bit value at memory location 5168H, the expansion size calculated during the first pass. This is the number of additional bytes needed to accommodate the renumbered line numbers (which may be longer or shorter than the originals). A negative value means the program will shrink. [SELF-MODIFYING CODE at 5168H]
4FBA
BIT 7,H CB 7C
Test bit 7 of Register H (the sign bit of the expansion size). If bit 7 is 1, the expansion size is negative (the program will shrink), and the NZ FLAG is set. If bit 7 is 0, the expansion is zero or positive (program grows or stays the same).
4FBC
If the Z FLAG has been set (the expansion size is zero or positive), JUMP to 4FC1H to proceed with the memory calculation using the actual expansion value.
4FBE
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H. If the expansion size was negative (program shrinks), force it to zero for the memory boundary calculation. The shrinkage will be handled during the actual copy phase, but the new memory boundary must not be set lower than the current one.
4FC1
INC H 24
INCrement Register H by 1, adding 256 bytes (one page) of padding to the expansion size. This provides a safety margin for the memory relocation to ensure the program does not collide with the string space.
4FC2
PUSH HL E5
Save Register Pair HL (the padded expansion size) onto the stack.
4FC3
ADD HL,DE 19
ADD Register Pair DE (the BASIC program start address from 40A4H) to Register Pair HL (the padded expansion size). This calculates the new base address where the relocated program will start.
4FC4
ADD HL,BC 09
ADD Register Pair BC (the current program size) to Register Pair HL. This calculates the end address of the relocated program (new base + program size = new end).
4FC5
If the CARRY FLAG has been set (the 16-bit addition overflowed, meaning the relocated program would exceed the 64K address space), JUMP to 4FD1H which leads to the “Not enough memory” error at 50EDH. [OVERFLOW - not enough memory]
4FC7
EX DE,HL EB
Exchange Register Pairs DE and HL. DE now holds the end address of the relocated program. HL holds the BASIC program start address.
4FC8
ADD HL,BC 09
ADD Register Pair BC (program size) to Register Pair HL (program start). HL now holds the end address of the ORIGINAL program (start + size).
4FC9
PUSH DE D5
Save Register Pair DE (the end address of the relocated program) onto the stack.
4FCA
EXX D9
Exchange the primary register set (BC, DE, HL) with the alternate register set (BC’, DE’, HL’). The primary registers are saved and the alternate set becomes active. This preserves BC (program size) and HL (original program end) for later use.
4FCB
POP DE D1
Pop the relocated program end address from the stack into Register Pair DE (now in the alternate register set context). After EXX, this DE is actually DE’.
4FCC
LD HL,(40B1H) 2A B1 40
Load Register Pair HL with the 16-bit value at memory location 40B1H, the BASIC memory top (the highest usable address). This is the upper boundary of available memory.
4FCF
DEC H 25
DECrement Register H by 1, subtracting 256 bytes from the memory top. This provides a safety margin at the top of memory for stack and system use.
4FD0
RST 18H DF
Call RST 18H for a 16-bit comparison of HL vs DE. This compares the adjusted memory top (HL) against the relocated program end (DE). The CARRY FLAG is set if HL < DE, meaning the relocated program would exceed available memory.
4FD1
If the CARRY FLAG has been set (the relocated program exceeds available memory), JUMP to 50EDH, the “Not enough memory” error handler. [OUT OF MEMORY ERROR]

Memory check passed. Now set up the stack pointer for the relocation operation and perform the LDDR block move to copy the program text to its new location.

4FD4
INC H 24
INCrement Register H by 1, restoring the 256-byte margin that was subtracted at 4FCFH. HL now holds the memory top address again.
4FD5
POP BC C1
Pop the padded expansion size from the stack into Register Pair BC (saved at 4FC2H). This is the distance the program will be moved upward in memory.
4FD6
LD SP,HL F9
Load the Stack Pointer with Register Pair HL (the memory top). This temporarily relocates the stack to the top of memory, well above the program area, to prevent the LDDR block move from overwriting the stack. [CRITICAL - stack relocated for safety]
4FD7
PUSH BC C5
Save Register Pair BC (the padded expansion size / relocation delta) onto the new stack at the top of memory.
4FD8
EXX D9
Exchange back to the primary register set. BC now holds the program size, HL holds the original program end address, and DE holds the relocated program end address (from before the EXX at 4FCAH).
4FD9
LD A,01H 3E 01
Load Register A with 01H, the value to set the cross-reference flag for the second pass.
4FDB
LD (5121H),A 32 21 51
Store Register A (01H) to memory location 5121H, setting the cross-reference flag to indicate the second pass is now active. From this point on, the byte-fetch routine at 5120H will copy bytes to the output buffer in addition to reading them. [SELF-MODIFYING CODE WRITE to 5121H]
4FDE
LDDR ED B8
Execute the LDDR (Load, Decrement, Repeat) block transfer instruction. This copies BC bytes from the address pointed to by HL (the original program end, moving downward) to the address pointed to by DE (the relocated program end, moving downward). The BASIC program text is moved upward in memory by the expansion delta. After completion, HL and DE both point to the byte before the start of the respective copies.
4FE0
LD A,(HL) 7E
Load Register A with the byte at the address pointed to by HL. After LDDR, HL points one byte below the original program start. This reads the byte at the original start position (which was not copied by LDDR since LDDR copies BC bytes starting from HL, decrementing).
4FE1
LD (DE),A 12
Store Register A to the address pointed to by DE. This copies the first byte of the program (missed by LDDR’s off-by-one) to the relocated position.
4FE2
POP BC C1
Restore Register Pair BC (the padded expansion size / relocation delta) from the stack (saved at 4FD7H).

The program text has been relocated. Now update all 128 entries in the cross-reference table at 64A3H by adding the relocation delta (BC) to each entry. This ensures the table pointers still correctly reference their respective BASIC lines at the new locations.

4FE3
PUSH DE D5
Save Register Pair DE (the new program start address after relocation) onto the stack.
4FE4
LD E,80H 1E 80
Load Register E with 80H (decimal 128). This is the loop counter for updating all 128 entries in the cross-reference table (each entry is 2 bytes, totaling 256 bytes).
4FE6
PUSH HL E5
Save Register Pair HL onto the stack.
4FE7
LD HL,64A3H 21 A3 64
Load Register Pair HL with 64A3H, the base address of the cross-reference table. HL will be used to walk through all 128 table entries.
4FEA
LD (4D4CH),HL 22 4C 4D
Store Register Pair HL (64A3H) to memory location 4D4CH, resetting the self-modifying operand at 4D4BH to the table base. This reinitializes the cross-reference table position for the second pass. [SELF-MODIFYING CODE WRITE to 4D4CH]

LOOP START - Cross-Reference Table Update Loop
For each of the 128 entries, add the relocation delta (BC) to the 16-bit pointer value.

4FED
LD A,(HL) 7E
Load Register A with the byte at the address pointed to by HL (the low byte of the current cross-reference table entry).
4FEE
ADD A,C 81
ADD Register C (the low byte of the relocation delta) to Register A. This adds the low byte of the delta to the low byte of the table entry, with carry propagating to the next byte.
4FEF
LD (HL),A 77
Store Register A (the updated low byte) back to the address pointed to by HL, replacing the original low byte in the table entry.
4FF0
INC HL 23
INCrement Register Pair HL by 1, advancing to the high byte of the current table entry.
4FF1
LD A,(HL) 7E
Load Register A with the byte at HL (the high byte of the current cross-reference table entry).
4FF2
ADC A,B 88
ADD Register B (the high byte of the relocation delta) plus the carry from the low-byte addition to Register A. This completes the 16-bit addition of the delta to the table entry.
4FF3
LD (HL),A 77
Store Register A (the updated high byte) back to the address pointed to by HL.
4FF4
INC HL 23
INCrement Register Pair HL by 1, advancing to the low byte of the next table entry.
4FF5
DEC E 1D
DECrement Register E (the loop counter) by 1.
4FF6
If the NZ FLAG has been set (the loop counter has not reached zero, meaning more table entries remain), JUMP back to 4FEDH to update the next entry. [LOOP - continue updating table]

LOOP END - Cross-Reference Table Update Loop
All 128 table entries have been adjusted. Restore the saved registers and restart the main scan loop for the second pass.

4FF8
POP BC C1
Restore Register Pair BC from the stack (saved at 4FE6H as HL).
4FF9
POP HL E1
Restore Register Pair HL from the stack (saved at 4FE3H as DE, the new program start after relocation).
4FFA
JUMP to 4D2DH to restart the main scan loop. This begins the second pass with DE=0000H already loaded (from the initialization at 4D2DH), HL pointing to the relocated program text, and the cross-reference flag set to 01H so that the byte-fetch routine at 5120H now copies bytes to the output buffer as it reads them.

4FFDH - Second-Pass Completion Handler

This routine handles the completion of the second pass of the RENUM operation. At this point, the BASIC program text has been scanned and all line number references have been replaced with renumbered values. The routine reads two bytes from the program text to advance past the final null link, stores the output buffer position as the new string space start (40F9H), and then calls the range calculation routine at 5073H to determine the block move parameters. It then enters a loop that copies the renumbered program text back to its final location, inserting and removing bytes as needed to account for line number expansions and contractions.

4FFD
GOSUB to 5120H, the dual-purpose byte-fetch routine. Since the cross-reference flag at 5121H is 01H (second pass), this reads a byte from the BASIC program text AND copies it to the output buffer. This reads the first byte of the end-of-program marker.
5000
GOSUB to 5120H again, reading and copying the second byte of the end-of-program marker. The two null bytes (0000H link pointer) marking the end of the program have been processed.
5003
LD (40F9H),BC ED 43 F9 40
Store Register Pair BC (the current output buffer position, which is the byte after the last written byte of the renumbered program) to memory location 40F9H, the string space start address. This updates the boundary between the BASIC program area and string/variable storage to reflect the new program size.
5007
LD (4EF6H),BC ED 43 F6 4E
Store Register Pair BC to memory location 4EF6H, updating the self-modifying operand at 4EF5H (the output position for the binary search second-pass check). [SELF-MODIFYING CODE WRITE to 4EF6H]
500B
GOSUB to 5073H, the range calculation and error-checking routine. This determines the block move parameters for copying the renumbered text back to its final position.
500E
GOSUB to 50F1H, the memory size calculator. This calculates the available memory and returns with the Z FLAG set if there is no room for the block move, or NZ FLAG if sufficient memory is available. Register Pair BC holds the block size.
5011
If the Z FLAG has been set (no memory available for the block move, meaning BC is zero), JUMP to 5050H to skip the copy loop and proceed directly to the re-link phase. [NO COPY NEEDED - proceed to re-link]

LOOP START - Block Copy Loop
Copy blocks of renumbered program text from the relocated buffer back to the final program area. Each iteration copies one block using LDIR, then checks if more blocks remain.

5013
LD HL,0000H 21 00 00
Load Register Pair HL with the value at 5014H. The operand bytes at 5014H-5015H are a self-modifying code target, written at 507BH with the source address for the block copy. During execution, HL holds the actual source address. [SELF-MODIFYING CODE at 5014H]
5016
PUSH HL E5
Save Register Pair HL (the source address for the block copy) onto the stack.
5017
LD DE,(40F9H) ED 5B F9 40
Load Register Pair DE with the 16-bit value at memory location 40F9H, the current string space start (which is the destination for the block copy - the end of the program area).
501B
LDIR ED B0
Execute the LDIR (Load, Increment, Repeat) block transfer. This copies BC bytes from the address in HL (source) to the address in DE (destination), incrementing both pointers after each byte. The renumbered program text is copied back to the final program area.
501D
EX DE,HL EB
Exchange Register Pairs DE and HL. After LDIR, DE points past the last destination byte. HL now holds the destination end address, and DE holds the source end address.
501E
OR A B7
Clear the CARRY FLAG by ORing Register A with itself, preparing for the 16-bit subtraction.
501F
SBC HL,DE ED 52
Subtract Register Pair DE from Register Pair HL. This calculates the difference between the destination end and source end addresses, determining how much the program area has shifted.
5021
LD B,H 44
Load Register B with Register H (high byte of the shift amount).
5022
LD C,L 4D
Load Register C with Register L (low byte of the shift amount). Register Pair BC now holds the remaining copy size for the next iteration.
5023
EX DE,HL EB
Exchange Register Pairs DE and HL, restoring DE to the shift amount and HL to the source end address.
5024
POP DE D1
Restore Register Pair DE from the stack (the original source address saved at 5016H).
5025
LDIR ED B0
Execute LDIR again, copying the remaining BC bytes from the source to the destination. This handles any overlap or additional data that needs to be moved.
5027
GOSUB to 50F6H, the memory size calculator entry point (with DE already loaded). This recalculates the available memory after the copy operation.
502A
If the NZ FLAG has been set (more memory/data remains to be copied), JUMP back to 5013H for the next iteration of the block copy loop. [LOOP - continue copying]
502C
GOSUB to 50F1H, the memory size calculator. This performs a final check after all block copies are complete.

Now handle the final block: copy any remaining data using LDDR (reverse direction) to avoid overwrite conflicts when the source and destination overlap.

502F
LD HL,(40F9H) 2A F9 40
Load Register Pair HL with the 16-bit value at memory location 40F9H, the string space start (current program end boundary).
5032
PUSH HL E5
Save Register Pair HL (string space start) onto the stack.
5033
PUSH BC C5
Save Register Pair BC (the block size from the memory calculator) onto the stack.
5034
LD DE,0000H 11 00 00
Load Register Pair DE with the value at 5035H. The operand bytes at 5035H-5036H are a self-modifying code target, written at 50CAH with the destination address for the reverse block copy. [SELF-MODIFYING CODE at 5035H]
5037
PUSH DE D5
Save Register Pair DE (the reverse-copy destination address) onto the stack.
5038
PUSH HL E5
Save Register Pair HL (string space start) onto the stack again.
5039
PUSH BC C5
Save Register Pair BC (block size) onto the stack.
503A
OR A B7
Clear the CARRY FLAG in preparation for the subtraction.
503B
SBC HL,DE ED 52
Subtract Register Pair DE (the reverse-copy destination) from Register Pair HL (string space start). The result is the size of the data segment to be moved.
503D
LD B,H 44
Load Register B with Register H (high byte of the segment size).
503E
LD C,L 4D
Load Register C with Register L (low byte of the segment size). BC now holds the byte count for the LDDR operation.
503F
POP HL E1
Restore Register Pair HL from the stack (the block size).
5040
POP DE D1
Restore Register Pair DE from the stack (the string space start address).
5041
DEC DE 1B
DECrement Register Pair DE by 1. LDDR copies from HL downward to DE downward, so DE must point to the last byte of the destination area, which is one byte before the string space start.
5042
ADD HL,DE 19
ADD Register Pair DE (adjusted destination end) to Register Pair HL (the block size). This calculates the source end address for the LDDR operation.
5043
EX DE,HL EB
Exchange Register Pairs DE and HL. DE now holds the source end and HL holds the destination end, set up correctly for LDDR.
5044
LDDR ED B8
Execute the LDDR (Load, Decrement, Repeat) block transfer. This copies BC bytes from HL (moving downward) to DE (moving downward), performing the reverse block move to place the remaining program data in its final position without overwrite conflicts.
5046
POP DE D1
Restore Register Pair DE from the stack (the reverse-copy destination address).
5047
POP BC C1
Restore Register Pair BC from the stack (the block size).
5048
POP HL E1
Restore Register Pair HL from the stack (the original string space start).
5049
LDIR ED B0
Execute LDIR, copying BC bytes from HL upward to DE upward. This handles the forward copy phase of the data rearrangement.
504B
GOSUB to 50F6H, the memory size calculator. Check if more data needs to be moved.
504E
If the NZ FLAG has been set (more data remains to be moved), JUMP back to 502FH for another iteration. [LOOP - continue final copy]

All data has been copied to its final position. Now re-link the BASIC program lines. The line numbers have been renumbered but the link pointers between lines still point to the old locations. Walk through all lines and rebuild the link chain.

5050
LD HL,(40A4H) 2A A4 40
Load Register Pair HL with the 16-bit value at memory location 40A4H, the BASIC program start address. HL now points to the first line of the BASIC program.
5053
LD E,(HL) 5E
Load Register E with the byte at HL (the low byte of the current line’s link pointer - the address of the next line).
5054
INC HL 23
INCrement Register Pair HL by 1, advancing to the high byte of the link pointer.
5055
LD D,(HL) 56
Load Register D with the byte at HL (the high byte of the link pointer). Register Pair DE now holds the old link pointer (address of the next line in the pre-renumber layout).
5056
LD A,D 7A
Load Register A with Register D (the high byte of the link pointer).
5057
OR E B3
OR Register A with Register E. If the link pointer is 0000H, the Z FLAG is set, indicating this is the end of the program.
5058
If the Z FLAG has been set (the link pointer is 0000H, end of program), JUMP to 5063H to output the “DONE” message and exit. [END OF PROGRAM - re-link complete]
505A
INC HL 23
INCrement Register Pair HL by 1, advancing past the link pointer to the line number low byte.
505B
LD (HL),E 73
Store Register E (low byte of the old link pointer, which in the re-linked structure becomes the new line number low byte) to the current position. Actually, this writes the new link pointer for this line: HL+2 and HL+3 hold the renumbered line number, and the code at 505A-505D stores the OLD link as the line number field. This re-links the chain.
505C
INC HL 23
INCrement Register Pair HL by 1.
505D
LD (HL),D 72
Store Register D (high byte of the old link pointer) to the current position.
505E
GOSUB to 5CCEH, the line-skip alternate entry in BASIC/CMD. This advances HL past the current line to the start of the next BASIC line, using the line contents to find the null terminator.
5061
JUMP back to 5053H to process the next line in the re-link loop. [LOOP - continue re-linking]

Re-linking complete (or error exit). Display the “DONE” message and exit RENUM.

5063
LD HL,5198H 21 98 51
Load Register Pair HL with 5198H, the address of the “DONE” text string (terminated by 03H).
5066
GOSUB to 5147H, the message display routine. This displays “DONE” on the screen.
5069
GOSUB to 5D52H, the CR output routine. This outputs a carriage return / line feed to end the RENUM output display.
506C
LD DE,(40A4H) ED 5B A4 40
Load Register Pair DE with the 16-bit value at memory location 40A4H, the BASIC program start address. This is loaded into DE as the parameter expected by the ROM exit routine.
5070
JUMP to the ROM routine at 1AE9H, the BASIC warm-restart entry point. This returns control to the BASIC interpreter, which re-initializes its state and displays the “Ready” prompt. The RENUM command is complete.

5073H - Range Calculation and Error Checking

This routine calculates the renumber range boundaries by looking up the user-specified start and end line numbers in the BASIC program. It calls the binary search routine at 4EC3H twice: once for the “from” line number (at 4D04H) and once for the “to” line number (at 4D06H, incremented by 1 to make it exclusive). The results are stored in self-modifying code locations for use by the block copy routines. The routine also validates the ranges and checks for overlap conditions that would prevent the renumber from proceeding.

5073
LD DE,(4D04H) ED 5B 04 4D
Load Register Pair DE with the 16-bit value at memory location 4D04H, the “from” (starting) line number of the renumber range specified by the user on the RENUM command line.
5077
GOSUB to 4EC3H, the binary search routine. This searches for the “from” line number in the cross-reference table and returns with DE holding the address of the matching or nearest line, and HL pointing to the table entry.
507A
PUSH DE D5
Save Register Pair DE (the start-range line address from the binary search) onto the stack.
507B
LD (5014H),HL 22 14 50
Store Register Pair HL (the table entry address for the start-range line) to memory location 5014H, the self-modifying operand at 5013H. This sets the source address for the block copy in the second-pass completion handler. [SELF-MODIFYING CODE WRITE to 5014H]
507E
PUSH HL E5
Save Register Pair HL (the table entry address) onto the stack.
507F
LD DE,(4D06H) ED 5B 06 4D
Load Register Pair DE with the 16-bit value at memory location 4D06H, the “to” (ending) line number of the renumber range.
5083
INC DE 13
INCrement Register Pair DE by 1, making the search look for the first line AFTER the “to” boundary. This makes the “to” line inclusive in the renumber range.
5084
GOSUB to 4EC3H, the binary search routine. This searches for the line number one past the “to” boundary. DE returns with the address of the first line outside the renumber range.
5087
LD (50C0H),DE ED 53 C0 50
Store Register Pair DE (the end-boundary line address) to memory location 50C0H, the self-modifying operand for the end boundary check. [SELF-MODIFYING CODE WRITE to 50C0H]
508B
POP BC C1
Restore Register Pair BC from the stack (the table entry address for the start-range line, saved at 507EH).
508C
OR A B7
Clear the CARRY FLAG in preparation for the subtraction.
508D
SBC HL,BC ED 42
Subtract Register Pair BC (the start-range table entry) from Register Pair HL (the end-range table entry). The result is the size (in bytes) of the table entries spanned by the renumber range.
508F
POP DE D1
Restore Register Pair DE from the stack (the start-range line address from the first binary search, saved at 507AH).
5090
PUSH BC C5
Save Register Pair BC (the start-range table entry address) onto the stack.
5091
PUSH HL E5
Save Register Pair HL (the table range size) onto the stack.

Walk through the BASIC program from the start to find the insertion point for the renumbered lines. This linear scan finds the first line whose line number is greater than or equal to the start-range address.

5092
LD HL,(40A4H) 2A A4 40
Load Register Pair HL with the 16-bit value at memory location 40A4H, the BASIC program start address.
5095
LD A,(HL) 7E
Load Register A with the byte at HL (the low byte of the current line’s link pointer).
5096
INC HL 23
INCrement Register Pair HL by 1.
5097
OR (HL) B6
OR Register A with the byte at HL (high byte of the link pointer). If both bytes are 00H, Z FLAG is set (end of program).
5098
If the Z FLAG has been set (end of program reached without finding the range start), JUMP to 50ACH. [END OF PROGRAM]
509A
INC HL 23
INCrement HL, advancing to the line number low byte.
509B
LD C,(HL) 4E
Load Register C with the line number low byte.
509C
INC HL 23
INCrement HL, advancing to the line number high byte.
509D
LD A,(HL) 7E
Load Register A with the line number high byte.
509E
CP D BA
Compare Register A (line number high byte) against Register D (high byte of start-range address).
509F
If the NZ FLAG has been set (high bytes differ), JUMP to 50A3H to check the carry flag for direction.
50A1
LD A,C 79
Load Register A with Register C (the line number low byte).
50A2
CP E BB
Compare Register A against Register E (low byte of start-range address).
50A3
If the NO CARRY FLAG has been set (this line’s number is greater than or equal to the start range), JUMP to 50AAH. The insertion point has been found.
50A5
GOSUB to 5CCEH to skip past the current BASIC line and advance to the next one.
50A8
JUMP back to 5095H to check the next line. [LOOP - continue scanning]
50AA
DEC HL 2B
DECrement HL by 1 (back from line number high to low byte).
50AB
DEC HL 2B
DECrement HL again (back to link pointer high byte).
50AC
LD D,(HL) 56
Load Register D with the byte at HL (high byte of the link pointer at the insertion point).
50AD
DEC HL 2B
DECrement HL (to link pointer low byte).
50AE
LD E,(HL) 5E
Load Register E with the byte at HL (low byte of the link pointer). DE holds the insertion point address.
50AF
LD (50C8H),DE ED 53 C8 50
Store Register Pair DE (the insertion point address) to memory location 50C8H, the self-modifying operand for the insertion point. [SELF-MODIFYING CODE WRITE to 50C8H]
50B3
POP BC C1
Restore Register Pair BC from the stack (the table range size, saved at 5091H).
50B4
POP DE D1
Restore Register Pair DE from the stack (the start-range table entry address, saved at 5090H).
50B5
RST 18H DF
Call RST 18H for a 16-bit comparison of HL vs DE. This compares the current line position against the start-range table entry to determine the relative positioning.
50B6
If the CARRY FLAG has been set (HL < DE), JUMP to 50C7H.
50B8
GOSUB to 519DH, the 16-bit comparison utility. This performs an additional range validation check.
50BB
If the CARRY FLAG has been set, JUMP to 50BFH.
50BD
If the NZ FLAG has been set, JUMP to 50C7H.
50BF
LD DE,0000H 11 00 00
Load Register Pair DE with the value at 50C0H. The operand bytes at 50C0H-50C1H are a self-modifying code target, written at 5087H with the end-boundary line address. [SELF-MODIFYING CODE at 50C0H]
50C2
LD BC,0000H 01 00 00
Load Register Pair BC with 0000H. This clears BC to zero as part of the range adjustment when the insertion point overlaps the range.
50C5
JUMP to 50CAH to store the adjusted range values and continue.
50C7
LD DE,0000H 11 00 00
Load Register Pair DE with the value at 50C8H. The operand bytes at 50C8H-50C9H are a self-modifying code target, written at 50AFH with the insertion point address. [SELF-MODIFYING CODE at 50C8H]
50CA
LD (5035H),HL 22 35 50
Store Register Pair HL to memory location 5035H, the self-modifying operand for the reverse-copy destination address used in the second-pass completion handler at 5034H. [SELF-MODIFYING CODE WRITE to 5035H]
50CD
LD (50F2H),BC ED 43 F2 50
Store Register Pair BC to memory location 50F2H, the self-modifying operand for the block size in the memory size calculator at 50F1H. [SELF-MODIFYING CODE WRITE to 50F2H]
50D1
LD HL,(4D08H) 2A 08 4D
Load Register Pair HL with the 16-bit value at memory location 4D08H, the increment value for the renumber operation (the step size between consecutive renumbered line numbers).
50D4
RST 18H DF
Call RST 18H for a 16-bit comparison of HL vs DE. This compares the increment value against DE to check for a valid configuration.
50D5
RET C D8
If the CARRY FLAG has been set (HL < DE), RETURN to the caller. The range calculation is complete and the parameters are stored.
50D6
LD A,D 7A
Load Register A with Register D (high byte of DE).
50D7
OR E B3
OR Register A with Register E. If DE is 0000H, the Z FLAG is set.
50D8
RET Z C8
If the Z FLAG has been set (DE is 0000H), RETURN. No further validation is needed.

The range parameters indicate an error condition (overlap or invalid range). Load the error code and check which pass we are on.

50D9
LD A,8CH 3E 8C
Load Register A with 8CH. This is the error code for “RENUM range error” (decimal 140). This code will be passed to the error handler if we are on the first pass.
50DB
LD B,A 47
Load Register B with Register A (save the error code 8CH in B).
50DC
LD A,(5121H) 3A 21 51
Load Register A with the cross-reference flag at 5121H. 00H = first pass, 01H = second pass. [SELF-MODIFYING CODE at 5121H]
50DF
OR A B7
OR Register A with itself.
50E0
LD A,B 78
Load Register A with Register B (restore the error code 8CH).
50E1
If the Z FLAG has been set (first pass), JUMP to 5DE2H, the error store routine in BASIC/CMD. This stores the error code and returns to the BASIC error handler. On the first pass, the error is non-fatal and can be reported to the user. [FIRST PASS ERROR - report and continue]

Second pass. A range error during the second pass is fatal because the program text is already being modified.

50E4
LD HL,5170H 21 70 51
Load Register Pair HL with 5170H, the address of the “FATAL ERROR. TEXT NOW BAD” message string (terminated by 0DH + 03H).
50E7
GOSUB to 5147H, the message display routine. This displays “FATAL ERROR. TEXT NOW BAD” on the screen, warning the user that the BASIC program text has been corrupted.
50EA
JUMP to 4030H, the error-already-displayed DOS error exit in BASIC/CMD. This is a dead-end routine that halts the current operation and returns to the DOS command prompt. The BASIC program is left in a corrupted state.

50EDH - “Not Enough Memory” Error Handler

This short routine loads the error code for “Not enough memory” and branches to the error check at 50DBH, which determines whether to report the error (first pass) or trigger the fatal error message (second pass).

50ED
LD A,0CH 3E 0C
Load Register A with 0CH (decimal 12). This is the error code for “Not enough memory” / “Out of memory”.
50EF
JUMP to 50DBH to check the pass number and route to the appropriate error handler (first pass: store error code; second pass: display fatal error).

50F1H - Memory Size Calculator

This routine calculates the available memory for block copy operations. It has two entry points: 50F1H loads DE from the self-modifying operand at 50F2H (the block size), while 50F6H assumes DE is already loaded. The routine calculates the difference between the BASIC memory top (40B1H minus one page) and the string space start (40F9H), then iteratively adjusts BC to fit within the available space. Returns with Z FLAG set if BC is zero (no room), or NZ FLAG if BC is non-zero (room available).

50F1
LD DE,0000H 11 00 00
Load Register Pair DE with the value at 50F2H. The operand bytes at 50F2H-50F3H are a self-modifying code target, written at 50CDH with the block size. [SELF-MODIFYING CODE at 50F2H]
50F4
JUMP to 50F9H to continue with the calculation using the loaded DE value.
50F6
LD DE,0000H 11 00 00
Load Register Pair DE with the value at 50F7H. The operand bytes at 50F7H-50F8H are a self-modifying code target, written at 5117H with the memory size result from the previous calculation. [SELF-MODIFYING CODE at 50F7H]
50F9
LD HL,(40B1H) 2A B1 40
Load Register Pair HL with the 16-bit value at memory location 40B1H, the BASIC memory top (highest usable address).
50FC
DEC H 25
DECrement Register H by 1, subtracting 256 bytes (one page) from the memory top as a safety margin for stack and system use.
50FD
LD BC,(40F9H) ED 4B F9 40
Load Register Pair BC with the 16-bit value at memory location 40F9H, the string space start address (current program end boundary).
5101
SBC HL,BC ED 42
Subtract Register Pair BC (string space start) from Register Pair HL (adjusted memory top). The result in HL is the available free memory between the program end and the memory ceiling.
5103
LD B,H 44
Load Register B with Register H (high byte of available memory).
5104
LD C,L 4D
Load Register C with Register L (low byte of available memory). BC now holds the available free memory size.
5105
EX DE,HL EB
Exchange Register Pairs DE and HL. HL now holds the block size (from DE), and DE holds the available memory (from HL).
5106
LD A,D 7A
Load Register A with Register D (high byte of the block size, now in HL after the EX but actually this is DE from the exchange - checking the high byte of the original block size).
5107
DEC A 3D
DECrement Register A by 1. This tests whether the high byte is 00H or greater. If it was 00H, A becomes FFH and the subtraction at 5108H will detect this.
5108
CP F0H FE F0
Compare Register A against F0H. If A ≥ F0H (which includes the FFH case from decrementing 00H), the block size is either negative or extremely large (more than 61440 bytes), which is invalid.
510A
If the NO CARRY FLAG has been set (A ≥ F0H, indicating an invalid or impossibly large block size), JUMP to 50EDH, the “Not enough memory” error handler. [OUT OF MEMORY]

LOOP START - Memory Fit Loop
Iteratively halve BC until it fits within the available block size, or reaches zero.

510D
OR A B7
Clear the CARRY FLAG in preparation for the subtraction.
510E
SBC HL,BC ED 42
Subtract Register Pair BC (the available memory / adjusted block size) from Register Pair HL (the target block size). If BC ≤ HL, the block fits and NC is set.
5110
If the NO CARRY FLAG has been set (the block fits within available memory), JUMP to 5117H to store the result and return. [FITS - done]
5112
ADD HL,BC 09
ADD Register Pair BC back to HL, restoring the original block size (undoing the failed subtraction).
5113
LD B,H 44
Load Register B with Register H.
5114
LD C,L 4D
Load Register C with Register L. BC now holds the original block size value.
5115
JUMP back to 510DH to try again with the current BC value. [LOOP - retry fit]

LOOP END - Memory Fit Loop

5117
LD (50F7H),HL 22 F7 50
Store Register Pair HL (the remaining block size after subtracting BC) to memory location 50F7H, the self-modifying operand at 50F6H. This saves the result for the next call to 50F6H. [SELF-MODIFYING CODE WRITE to 50F7H]
511A
LD A,B 78
Load Register A with Register B (high byte of the fit-adjusted block size in BC).
511B
OR C B1
OR Register A with Register C. Sets the Z FLAG if BC is 0000H (no room available for copy), or NZ FLAG if BC is non-zero (room available). The Z/NZ flag is the return value used by callers to decide whether to proceed with the copy.
511C
RET C9
RETURN to the caller with the Z/NZ flag indicating the result. BC holds the block size to use for the copy operation.

511DH - Whitespace Skip Routine

This routine skips whitespace characters in the BASIC program text. It calls the raw whitespace skip at 512EH, which advances past spaces (20H), tabs (09H), and line-feed/vertical-tab (0AH/0BH). Used by the line number check and other token handlers to find the next significant character after parsing.

511D
GOSUB to 512EH, the raw whitespace skip routine. This reads bytes from the BASIC program text at HL, skipping over space (20H), tab (09H), and control characters 0AH-0BH. On return, Register A holds the first non-whitespace character and HL points past it.

5120H - Dual-Purpose Byte Fetch (Self-Modifying)

This is the central byte-fetch routine used throughout SYS11. It reads a byte from the BASIC program text at HL and advances HL. On the second pass (when the self-modifying flag at 5121H is 01H), it also copies the byte to the output buffer at BC and advances BC. On the first pass (flag is 00H), the byte is read but not copied. The dual behavior is controlled by the LD A,00H instruction at 5120H, whose immediate operand at 5121H is modified to 01H when the second pass begins.

5120
LD A,00H 3E 00
Load Register A with the immediate operand at 5121H. The byte at 5121H is a self-modifying code target: when 00H (first pass), Register A is loaded with 00H. When modified to 01H at 4FDBH (second pass activation), Register A is loaded with 01H. [SELF-MODIFYING CODE at 5121H]
5122
OR A B7
OR Register A with itself. Sets the Z FLAG if Register A is 00H (first pass - read only), or clears it if 01H (second pass - read and copy).
5123
LD A,(HL) 7E
Load Register A with the byte at the address pointed to by HL (the next byte in the BASIC program text). This is the actual byte-fetch operation.
5124
INC HL 23
INCrement Register Pair HL by 1, advancing the program text pointer past the byte just read.
5125
If the Z FLAG has been set (first pass - the flag at 5121H was 00H), JUMP to 5129H to skip the copy-to-buffer step. On the first pass, bytes are read but not copied. [FIRST PASS - skip copy]
5127
LD (BC),A 02
Store Register A (the byte just read from the program text) to the address pointed to by Register Pair BC (the output buffer write position). This copies the byte to the output buffer during the second pass.
5128
INC BC 03
INCrement Register Pair BC by 1, advancing the output buffer write position past the byte just written.
5129
OR A B7
OR Register A with itself. This sets the flags based on the FETCHED byte (not the pass flag). The Z FLAG is set if the byte is 00H (end-of-line marker), which callers use to detect end-of-statement.
512A
RET C9
RETURN to the caller. Register A holds the fetched byte, HL points past it, and BC has been advanced if on the second pass. The Z/NZ flags reflect the fetched byte value.

512BH - Whitespace Consume Loop (Internal)

This is an internal entry point for the whitespace skip loop. It calls the byte-fetch routine at 5120H to read and optionally copy a whitespace character, then falls through to 512EH to check if the next character is also whitespace.

512B
GOSUB to 5120H, the dual-purpose byte-fetch routine. This reads the next byte from the program text (which is a whitespace character identified by the check at 512EH) and copies it to the output buffer if on the second pass.

Fall through to the raw whitespace skip routine at 512EH to check the next byte.

512E
LD A,(HL) 7E
Load Register A with the byte at the address pointed to by HL (the next byte in the BASIC program text, without advancing HL).
512F
CP 20H FE 20
Compare Register A against 20H (ASCII space). If the byte is a space, the Z FLAG is set.
5131
If the Z FLAG has been set (the byte is a space), JUMP back to 512BH to consume it and check the next character. [LOOP - skip spaces]
5133
CP 0BH FE 0B
Compare Register A against 0BH (vertical tab). If the byte is 0BH or greater (not a whitespace control character), the NO CARRY FLAG is set.
5135
RET NC D0
If the NO CARRY FLAG has been set (the byte is 0BH or greater and is not a space - it is a significant character), RETURN. Register A holds the non-whitespace character and HL points to it (not past it, since this routine peeks without advancing).
5136
CP 09H FE 09
Compare Register A against 09H (horizontal tab). If the byte is less than 09H, the CARRY FLAG is set (the byte is a control character below tab, which is not whitespace).
5138
RET C D8
If the CARRY FLAG has been set (the byte is below 09H - a non-whitespace control character), RETURN. This exits for control codes 00H-08H, which include the end-of-line null (00H).
5139
JUMP back to 512BH. The byte is 09H or 0AH (tab or line feed), which are whitespace characters. Consume them and check the next byte. [LOOP - skip tab/LF]

513BH - Digit Check Routine

This routine checks whether the next non-whitespace character in the BASIC program text is an ASCII digit (30H-39H). It first skips whitespace by calling 512EH, then tests the character against the digit range. Returns with CARRY FLAG set if the character IS a digit, or NO CARRY FLAG if it is not. If the character is not a digit and is also below 30H, the routine falls through to 5120H for additional processing.

513B
GOSUB to 512EH, the raw whitespace skip routine. This skips past any spaces, tabs, and control characters in the BASIC program text. On return, Register A holds the first non-whitespace character.
513E
CP 30H FE 30
Compare Register A against 30H (ASCII 0). If Register A < 30H, the CARRY FLAG is set (the character is below the digit range). If Register A ≥ 30H, the NO CARRY FLAG is set.
5140
If the CARRY FLAG has been set (the character is below 30H, meaning it is not a digit and is some control or punctuation character), JUMP to 5145H. [NOT A DIGIT - below range]
5142
CP 3AH FE 3A
Compare Register A against 3AH (one past ASCII 9). If Register A < 3AH, the CARRY FLAG is set (the character is in the range 30H-39H, confirming it is a digit). If Register A ≥ 3AH, the NO CARRY FLAG is set (the character is 3AH or above, which is a colon or token).
5144
RET C D8
If the CARRY FLAG has been set (the character is an ASCII digit in the range 30H-39H), RETURN. Register A holds the digit character, HL points to it in the program text. The caller knows a digit was found.
5145
JUMP to 5120H, the byte-fetch routine. The character is not a digit. By jumping to the byte-fetch, the character is consumed (read and optionally copied to the output buffer), and control returns to the caller with the character in Register A and the NO CARRY FLAG indicating “not a digit.”

5147H - Message Display Routine

This routine displays a 03H-terminated message string on the screen. It reads characters one at a time from the address in HL, sends each to the display routine at 5D3FH, and stops when it encounters a 03H terminator, at which point it calls the CR output routine at 5D52H.

5147
LD A,(HL) 7E
Load Register A with the byte at the address pointed to by HL (the next character of the message string).
5148
CP 03H FE 03
Compare Register A against 03H, the string terminator. If the byte is 03H, the Z FLAG is set, indicating the end of the message.
514A
INC HL 23
INCrement Register Pair HL by 1, advancing to the next character. This is done before the conditional jump so that HL is positioned correctly whether the loop continues or exits.
514B
If the Z FLAG has been set (the terminator 03H was reached), JUMP to 5D52H, the CR output routine. This outputs a carriage return/line feed to end the message display, and then returns to the caller via 5D52H’s own RET.
514E
GOSUB to 5D3FH, the display-character routine in BASIC/CMD. This outputs the character in Register A to the screen at the current cursor position.
5151
JUMP back to 5147H to fetch and display the next character. [LOOP - continue displaying]

5153H - Number Output (First Pass) / Number-String Copy

These two entry points handle the output of a line number. 5153H is the first-pass entry, which displays the number on screen. 5156H is the second-pass entry, which copies the number string to the output buffer. Both use the number-string conversion routine at 5D00H (via 5D2AH) to convert the binary line number in DE to ASCII digits.

5153
LD BC,5D2AH 01 2A 5D
Load Register Pair BC with 5D2AH, the address of the number-to-string conversion entry point in BASIC/CMD. This sets up BC as the parameter for the CALL at 5156H.
5156
GOSUB to 5D00H, the number-string copy routine in BASIC/CMD. This converts the line number in DE to a decimal ASCII string and writes it to the output destination (screen for first pass, buffer for second pass). BC controls the conversion mode.
5159
LD HL,0000H 21 00 00
Load Register Pair HL with the value at 515AH. The operand bytes at 515AH-515BH are a self-modifying code target, written at 4D30H (initialized to 0000H) and at 5163H (updated with the running count). This holds the current error count. [SELF-MODIFYING CODE at 515AH]
515C
ADD HL,DE 19
ADD Register Pair DE to Register Pair HL. This adds the line number value (or an increment) to the error count accumulator.
515D
LD DE,0000H 11 00 00
Load Register Pair DE with the value at 515EH. The operand bytes at 515EH-515FH are a self-modifying code target, written at 4E73H with the digit count from the line number parser. [SELF-MODIFYING CODE at 515EH]
5160
OR A B7
Clear the CARRY FLAG in preparation for the subtraction.
5161
SBC HL,DE ED 52
Subtract Register Pair DE (the digit count of the old line number) from Register Pair HL (the accumulated expansion). This calculates the net expansion: positive if the new number has more digits than the old, negative if fewer, zero if the same.
5163
LD (515AH),HL 22 5A 51
Store Register Pair HL (the updated expansion accumulator) to memory location 515AH, updating the self-modifying operand at 5159H for the next call. [SELF-MODIFYING CODE WRITE to 515AH]
5166
RET M F8
If the SIGN FLAG (Minus) has been set (the accumulated expansion is negative, meaning the program is shrinking), RETURN. A shrinking program does not need additional memory.
5167
LD DE,0000H 11 00 00
Load Register Pair DE with the value at 5168H. The operand bytes at 5168H-5169H are a self-modifying code target, written at 516CH with the maximum expansion size encountered so far. [SELF-MODIFYING CODE at 5168H]
516A
RST 18H DF
Call RST 18H for a 16-bit comparison of HL vs DE. This compares the current expansion (HL) against the previous maximum expansion (DE). The CARRY FLAG is set if HL < DE (the current expansion is not a new maximum).
516B
RET C D8
If the CARRY FLAG has been set (the current expansion is less than the previous maximum), RETURN. The maximum does not need to be updated.
516C
LD (5168H),HL 22 68 51
Store Register Pair HL (the new maximum expansion size) to memory location 5168H, updating the self-modifying operand at 5167H. This tracks the worst-case expansion across all line numbers, which determines how much memory must be reserved for the relocation. [SELF-MODIFYING CODE WRITE to 5168H]
516F
RET C9
RETURN to the caller.

5170H - Text Strings (Message Data)

This section contains three message strings used by the RENUM command for display output. Each string is terminated by 03H (with the fatal error string having an additional 0DH carriage return before the terminator).

5170-518B
DEFM "FATAL ERROR. TEXT NOW BAD" + 0DH + 03H 46 41 54 41 4C 20 45 52 52 4F 52 2E 20 54 45 58 54 20 4E 4F 57 20 42 41 44 0D 03
28-byte message string: “FATAL ERROR. TEXT NOW BAD” followed by a carriage return (0DH) and terminator (03H). Displayed by the routine at 50E4H when a fatal error occurs during the second pass, indicating the BASIC program text has been corrupted.
518C-5197
DEFM "ERROR LINES" + 03H 45 52 52 4F 52 20 4C 49 4E 45 53 03
12-byte message string: “ERROR LINES” followed by terminator (03H). Displayed by the routine at 4F6DH as the header before the first error line is shown during the first-pass cross-reference report.
5198-519C
DEFM "DONE" + 03H 44 4F 4E 45 03
5-byte message string: “DONE” followed by terminator (03H). Displayed by the routine at 5063H when the RENUM command completes successfully (or when errors were found and the operation was aborted without modifying the program).

519DH - 16-Bit Comparison Utilities

Two utility routines for 16-bit comparisons, used by the range calculation routine at 5073H for validating renumber range boundaries.

519D
SBC HL,BC ED 42
Subtract Register Pair BC from Register Pair HL with borrow. The CARRY FLAG is set if HL < BC, and the Z FLAG is set if HL equals BC. This provides a signed comparison of the two 16-bit values.
519F
RET C D8
If the CARRY FLAG has been set (HL < BC), RETURN immediately. The caller uses this to determine relative ordering.
51A0
RST 18H DF
Call RST 18H for a 16-bit comparison of HL vs DE. This performs an additional comparison after the SBC.
51A1
RET C9
RETURN to the caller. The flags from RST 18H indicate the comparison result: CARRY FLAG set if HL < DE, Z FLAG set if HL equals DE.

51A2H - NOP Padding

Unused space at the end of the SYS11 overlay module, filled with NOP (00H) bytes. This padding brings the overlay file to its full allocated size.

51A2-51F3
NOP × 82 00 × 82
82 bytes of 00H NOP padding. This fills the remainder of the SYS11/SYS overlay file from 51A2H through 51F3H (the end of the allocated overlay space). The overlay loader expects a fixed-size file; this padding ensures the file meets the required length.