TRS-80 DOS - LDOS 5.3.1 for the Model I - BASIC/OV1 Disassembled

Page Customization

Summary:

LDOS 5.3.1 BASIC/OV1 Disassembly - The LBASIC Line-Renumber Overlay (Model I)

BASIC/OV1 is the line-renumbering overlay of LBASIC, the LDOS Disk BASIC extension. It implements the CMD"N ..." statement, which renumbers the program currently in memory and, unlike the DOS-level MOVE command, correctly adjusts every internal line-number reference in GOTO, GOSUB, THEN, ELSE, RESUME, RUN, ON...GOTO/GOSUB and ERL. The MISOSYS BASIC Reference Manual (M-40-061) gives the syntax CMD"N ! line,newline,inc,last": line and last bound the old line range to renumber, newline is the new starting number, inc the increment, and the optional leading ! skips the pre-renumber error scan.

The overlay is a transient program, not a resident module. When the interpreter meets CMD"N ..." its CMD dispatcher builds the filespec BASIC/OV1, loads the overlay with the resident @RUN service so it replaces BASIC/CMD's own image at 5200H, and enters it at 5200H with Register Pair HL pointing at the text that followed the N. Because the file overlays the interpreter, the overlay finishes by reloading BASIC/CMD with @RUN, passing the command * so the interpreter returns quietly to its Ready prompt. Both BASIC/CMD and BASIC/OV1 must therefore be present on the disk.

Renumbering is done in stages. A first pass over the program stores each line's new number in that line's two-byte link word (the field that normally holds the address of the next line), assigning the running newline, newline+inc, ... sequence to lines inside the range and leaving lines outside it with their own numbers, while validating that the result stays in ascending order and within the 65529 line-number ceiling. A validation pass then scans every line for reference tokens and confirms each referenced line exists, printing Can not find line for any that do not (the ! option skips this pass). A rewrite pass rebuilds each line in a work buffer, replacing the ASCII digits of each reference with the new number read from the target line's link word, and splices the rebuilt line back into the program, growing or shrinking the text as the digit counts change. Finally each line's new number is copied from its link word into its line-number field, all link words are rebuilt to point at the following line, and VARTAB, ARYTAB and STREND are reset just past the renumbered program.

The overlay was byte-verified for this disassembly: the memory image rebuilt from the LDOS load records in BASIC/OV1 (1189 bytes over 5200H-56A4H, transfer address 5200H) matches the listing exactly, with full coverage and no gaps.

File and Memory Map

Address RangeContents
5200H-55C6H
966 bytes
Executable code: entry and parameter parsing, the new-number assignment pass, the reference validation and rewrite passes, the commit and link-rebuild passes, and the numeric and display helpers.
55C7H-569AH
212 bytes
The BASIC/CMD reload filespec, the sign-on banner, and the six status and error message strings.
569BH-56A4H
10 bytes
The four-entry parameter table (with its default values) and the work-buffer pointer.
5700H upward
(above the image)
The line work buffer in which each line is rebuilt; not part of the loaded file.

Variables and Self-Modified Cells

Address RangePurpose
569BH-56A2H
8 bytes
Parameter table: line (569BH, default 1), newline (569DH, default 20, also the running new-number counter), inc (569FH, default 20), last (56A1H, default 65529).
56A3H-56A4H
2 bytes
Work-buffer pointer, initialized to 5700H.
56A5H-56A6H
2 bytes
Scratch above the loaded image: it first saves the newline start so the counter can be reset, then serves as the per-line "reference was rewritten" flag during the reference passes.
56A7H
1 byte
Pass flag: 0 selects the validation pass, non-zero the rewrite pass. The ! option presets it to 1 to skip validation.
56A9H
1 byte
In-string-literal flag, toggled by each double-quote so tokens inside quoted strings are not mistaken for references.
5696H
1 byte
Self-Modifying Code
The terminator of the "Error in line " message. The empty-program path at 5545H overwrites it (and the byte after) with "0" and a carriage return to produce "Error in line 0".

Major Routines

AddressRoutine
5200HEntry, Banner, and Setup
Skip blanks in the parameter text, show the banner and "Checking for errors", reject an empty program, move the stack to HIGH$, and read the optional !.
5237HParse Parameters
Read up to four comma-separated decimal numbers into the parameter table, each field defaulting to its baked-in value.
527BHResolve the last Boundary
Use ROM FNDLIN to turn the last parameter into an actual program boundary, and validate its range.
5295HPass 0: Assign New Numbers
Walk every line, storing its new number in its link word: the assigned sequence for lines in range, unchanged numbers otherwise, with ordering and overflow checks.
5333HReference Pass
Scan each line for reference tokens outside quoted strings; validate targets on the first pass and rebuild the line on the second.
53FBHReference Handler
Accumulate the old target number, find its line, read the new number from that line's link word, and write the new digits into the rebuilt line.
5479HCommit New Numbers
Copy each line's new number from its link word into its line-number field.
54C7HRebuild Links and Exit
Relink every line to its successor, reset VARTAB/ARYTAB/STREND, and reload BASIC/CMD.
54EFHNumeric Helpers
Parse a decimal number (54EFH), test a digit (54FFH), and multiply-by-ten-and-add (5506H).
557EHLine Number to ASCII
Convert a 16-bit line number to an ASCII digit string via the ROM number-formatter.
558EHLine-Record Helpers
Advance to the next line record (558EH) and test for end of program (559EH).
55A8HReference-Token Test
Recognize the seven tokens a line-number reference can follow: THEN, ELSE, RESUME, GOTO, GOSUB, RUN, ERL.
5520HMessage Helpers
Print "Error in line NNNN. " (5520H) and the IY/DE-preserving @DSPLY wrapper (5538H/553BH).

Cross-References

Entered from: the CMD dispatcher of BASIC/CMD (LBASIC), which loads BASIC/OV1 to 5200H with the resident @RUN service and enters it at 5200H with Register Pair HL at the parameter string.

LDOS resident services used: @DSPLY (4467H) to display the banner and messages, and @RUN (4433H) to reload BASIC/CMD on exit.

Level II ROM routines used: FNDLIN (1B2CH) to find a line, LINPRT (0FAFH) to print a line number, MAKINT (0A9AH), FOUINI (1034H) and FOUT2 (0FD9H) to format a number to ASCII, and DCOMPR (RST 18H, 0018H) to compare line numbers.

BASIC workspace touched: TXTTAB (40A4H), HIGH$ (4049H), VARTAB (40F9H), ARYTAB (40FBH), STREND (40FDH), INBUF$ (4318H) and CFCB$ (4480H).

Disassembly:

5200H - Entry: Skip Blanks and Show the Banner

The renumber overlay is entered here at 5200H after BASIC/CMD's CMD dispatcher loads it over the interpreter image with @RUN. Register Pair HL points at the parameter text that followed the N in CMD"N ..."; leading blanks are skipped and the sign-on banner is displayed.

5200H
LD A,(HL) 7E
Read a byte of the parameter text into Register A. Register Pair HL points at the character following the N in the CMD string.
5201H
CP 20H FE 20
Compare it with a blank (20H).
5203H
On the first non-blank, jump to the banner display.
5205H
INC HL 23
Otherwise advance Register Pair HL past the blank.
5206H
Loop back to test the next character.
5208H
PUSH HL E5
Save the parameter pointer; Register Pair HL now points at the first non-blank of the parameter list.
5209H
LD HL,55D2H 21 D2 55
Point Register Pair HL at the sign-on banner text at 55D2H.
520CH
Display it through @DSPLY.
520FH
LD HL,5637H 21 37 56
Point Register Pair HL at the "Checking for errors" message at 5637H.
5212H
Display it through the IY/DE-preserving helper at 553BH.

5215H - Verify a Program Is Present

The first program line's line-number word is tested; an empty program (or a program whose first line is line 0) is rejected to the empty-program error at 5545H.

5215H
LD HL,(40A4H) 2A A4 40
Load Register Pair HL from TXTTAB 40A4H, the start of program text (the first line's link word).
5218H
INC HL 23
Advance toward the line-number field of the first line.
5219H
INC HL 23
Second byte of the advance, leaving Register Pair HL at TXTTAB+2.
521AH
LD A,(HL) 7E
Read the low byte of the first line's number into Register A.
521BH
INC HL 23
Advance to the high byte.
521CH
OR (HL) B6
OR in the high byte, so the Zero flag is set only when the first line number is 0000H.
521DH
POP DE D1
Recover the saved parameter pointer into Register Pair DE.
521EH
With no first line (or a line 0), abort to the empty-program error at 5545H.

5221H - Switch Stacks and Read the "!" Option

The stack is moved to the top of protected memory (HIGH$) and the optional leading ! is detected. The ! presets the pass flag 56A7H so the error-checking pass is skipped.

5221H
LD HL,(4049H) 2A 49 40
Load Register Pair HL from HIGH$ 4049H, the top of memory protected from BASIC.
5224H
LD SP,HL F9
Move the stack pointer there; the overlay runs on its own stack at the top of memory.
5225H
EX DE,HL EB
Return the parameter pointer to Register Pair HL.
5226H
XOR A AF
Clear Register A.
5227H
LD (56A7H),A 32 A7 56
Clear the pass flag 56A7H (0 = run the error-checking pass before rewriting).
522AH
LD A,(HL) 7E
Read the first parameter character.
522BH
CP 21H FE 21
Compare it with ! (21H).
522DH
If it is not !, go straight to parameter parsing.
522FH
LD A,01H 3E 01
Load 01H.
5231H
LD (56A7H),A 32 A7 56
Set the pass flag 56A7H to 1, so the error-checking pass is skipped and rewriting begins at once.
5234H
Skip the ! and any following blanks (helper at 55BEH).

5237H - Parse the Four Numeric Parameters

Up to four comma-separated decimal numbers - line,newline,inc,last - are parsed into the parameter table at 569BH, each field defaulting to the value already stored there. A malformed field aborts to the Bad parameters error.

5237H
LD B,04H 06 04
Set Register B to 4, the maximum number of parameters.
5239H
LD IX,569BH DD 21 9B 56
Point Register IX at the parameter table 569BH (line, newline, inc, last).
523DH
LD A,(HL) 7E
Read the next parameter character.
523EH
CP 0DH FE 0D
Compare it with a carriage return (0DH), the end of the parameter line.
5240H
At end of line, stop parsing and resolve the boundary at 527BH.
5242H
LD E,(IX+00H) DD 5E 00
Load the current table entry's low byte into Register E (its default value).
5245H
LD D,(IX+01H) DD 56 01
Load its high byte into Register D, so Register Pair DE holds the default for this field.
5248H
LD A,(HL) 7E
Read the current character.
5249H
CP 2CH FE 2C
Compare it with a comma (2CH).
524BH
An immediate comma means the field was omitted; keep the default and store it at 525DH.
524DH
PUSH BC C5
Save the parameter count.
524EH
PUSH IX DD E5
Save the table pointer.
5250H
Parse a decimal number at (HL) into Register Pair DE (helper at 54EFH).
5253H
POP IX DD E1
Restore the table pointer.
5255H
POP BC C1
Restore the parameter count.
5256H
A parse overflow (Carry) aborts to Bad parameters.
5259H
LD A,D 7A
Test the parsed value: copy Register D...
525AH
OR E B3
...OR Register E, setting the Zero flag when the value is zero.
525BH
A zero value is dropped: the table keeps its default and the pointer is not advanced.
525DH
LD (IX+00H),E DD 73 00
Store the value's low byte into the current table slot.
5260H
INC IX DD 23
Advance the table pointer.
5262H
LD (IX+00H),D DD 72 00
Store the value's high byte.
5265H
INC IX DD 23
Advance to the next table slot.
5267H
LD A,(HL) 7E
Read the character that follows the number.
5268H
CP 0DH FE 0D
Compare it with a carriage return.
526AH
At end of line, stop parsing.
526CH
CP 2CH FE 2C
Compare it with a comma.
526EH
Anything other than a comma between fields is a Bad parameters error.
5271H
Skip the comma and any following blanks.
5274H
LD A,(HL) 7E
Read the next character.
5275H
CP 0DH FE 0D
Compare it with a carriage return.
5277H
A trailing comma at end of line ends parsing.
5279H
Otherwise loop for the next of the four parameters.

527BH - Resolve the "last" Line Boundary

The last parameter is resolved against the actual program with ROM FNDLIN, so renumbering can stop at the correct line even when last falls between two existing line numbers.

527BH
LD DE,(56A1H) ED 5B A1 56
Load Register Pair DE with the last parameter from 56A1H.
527FH
Search the program for that line number with ROM FNDLIN; Carry set means the exact line exists.
5282H
If it does not exist, leave last as given and go on to 5295H.
5284H
LD A,(HL) 7E
Read the low byte of the following line's link word into Register A (HL was left at the next line by FNDLIN).
5285H
INC HL 23
Advance to the high byte.
5286H
OR (HL) B6
OR it in; the Zero flag is set when that link word is 0000H (no following line).
5287H
LD DE,0FFF9H 11 F9 FF
Preload Register Pair DE with 65529 (FFF9H), the highest usable line number.
528AH
If there is no following line, keep 65529 as the effective last.
528CH
INC HL 23
Otherwise advance to the following line's number.
528DH
LD E,(HL) 5E
Read its low byte into Register E.
528EH
INC HL 23
Advance.
528FH
LD D,(HL) 56
Read its high byte into Register D.
5290H
DEC DE 1B
Decrement, so Register Pair DE is one below the next line's number.
5291H
LD (56A1H),DE ED 53 A1 56
Store the resolved value back into last 56A1H.

5295H - Pass 0: Assign a New Number to Every Line

Every line record is walked once. The 16-bit link word of each record - normally the address of the next line - is overwritten with the line's NEW number: its own old number for lines outside the selected range, and the running newline, newline+inc, ... sequence for lines inside it. Ordering and 16-bit overflow are validated; any violation aborts to Bad parameters.

5295H
LD HL,0FFFAH 21 FA FF
Load Register Pair HL with FFFAH (65530).
5298H
Compare it against last in Register Pair DE (RST 18H is the ROM DCOMPR compare).
5299H
A last of 65530 or more is a Bad parameters error.
529CH
LD HL,(569DH) 2A 9D 56
Load Register Pair HL with the newline starting number from 569DH.
529FH
LD (56A5H),HL 22 A5 56
Save it in 56A5H so the running counter can be reset before the rewrite pass.
52A2H
LD IX,(40A4H) DD 2A A4 40
Point Register IX at the first line record (from TXTTAB 40A4H).
52A6H
Test for end of program (helper at 559EH).
52A9H
At end of program, pass 0 is complete; go to the commit pass at 5479H.
52ACH
LD L,(IX+02H) DD 6E 02
Load the low byte of this line's old number into Register L.
52AFH
LD H,(IX+03H) DD 66 03
Load its high byte into Register H, so Register Pair HL holds the old line number.
52B2H
LD DE,(569BH) ED 5B 9B 56
Load Register Pair DE with the line lower bound from 569BH.
52B6H
Compare the old number against the lower bound.
52B7H
If the line is at or above the lower bound it is inside the range; handle it at 52CCH.
52B9H
LD (IX+01H),H DD 74 01
Otherwise the line is below the range: store its own high byte into the link word (IX+01H)...
52BCH
LD (IX+00H),L DD 75 00
...and its low byte into (IX+00H), so an unrenumbered line's link holds its unchanged number.
52BFH
LD DE,(569DH) ED 5B 9D 56
Load Register Pair DE with the running newline number.
52C3H
Compare the unchanged number against the new range's start.
52C4H
If an unrenumbered line's number reaches into the new range the result would collide; abort to Bad parameters.
52C7H
Advance Register IX to the next line record.
52CAH
Loop back to process it.
52CCH
LD DE,(569DH) ED 5B 9D 56
Load Register Pair DE with the running newline number for this in-range line.
52D0H
LD HL,(56A1H) 2A A1 56
Load Register Pair HL with last.
52D3H
Compare them.
52D4H
If the running number has passed last, the sequence has run out of room; Bad parameters.
52D7H
LD (IX+01H),D DD 72 01
Store the new number's high byte into the link word (IX+01H)...
52DAH
LD (IX+00H),E DD 73 00
...and its low byte into (IX+00H); this line now carries its assigned new number.
52DDH
LD HL,(569FH) 2A 9F 56
Load Register Pair HL with the increment from 569FH.
52E0H
ADD HL,DE 19
Add it to the current new number.
52E1H
A 16-bit overflow is a Bad parameters error.
52E4H
LD DE,0FFFAH 11 FA FF
Load Register Pair DE with FFFAH (65530).
52E7H
Compare the next new number against it.
52E8H
A next number of 65530 or more is out of range; Bad parameters.
52EBH
LD (569DH),HL 22 9D 56
Store the incremented value back as the running newline number.
52EEH
Advance Register IX to the next line record.
52F1H
If that was the last line, finish pass 0 at 5313H.
52F3H
LD H,(IX+03H) DD 66 03
Load the high byte of the next line's old number.
52F6H
LD L,(IX+02H) DD 6E 02
Load its low byte, so Register Pair HL holds the next old number.
52F9H
LD DE,(56A1H) ED 5B A1 56
Load Register Pair DE with last.
52FDH
Compare the next old number against last.
52FEH
If it equals last it is still in range; assign it at 52CCH.
5300H
If it is below last it is in range; assign it at 52CCH.
5302H
LD A,(IX+02H) DD 7E 02
Past the range: copy this line's old number low byte into its link word...
5305H
LD (IX+00H),A DD 77 00
...(IX+00H)...
5308H
LD A,(IX+03H) DD 7E 03
...and its high byte...
530BH
LD (IX+01H),A DD 77 01
...into (IX+01H), leaving lines after the range unchanged.
530EH
Advance to the next line record.
5311H
Loop until the end of program is reached.

5313H - Choose the Error-Check and Rewrite Passes

The running new-number counter is reset and the pass flag 56A7H selects the two reference passes: a validation pass (unless ! was given) followed by the rewrite pass.

5313H
LD HL,(56A5H) 2A A5 56
Reload the saved newline start from 56A5H...
5316H
LD (569DH),HL 22 9D 56
...back into the running counter 569DH, ready for the reference passes.
5319H
LD A,(56A7H) 3A A7 56
Read the pass flag 56A7H.
531CH
OR A B7
Test it.
531DH
When 0 (no !), run the error-checking reference pass at 5333H.
531FH
When set (! given), skip straight to displaying "No errors" at 532DH.
5321H
LD A,(56A7H) 3A A7 56
Read the pass flag again (reached at the end of a reference pass).
5324H
OR A B7
Test it.
5325H
If it is already set, the rewrite pass just finished; commit the numbers at 5479H.
5328H
LD A,01H 3E 01
Otherwise the validation pass just finished; load 01H...
532AH
LD (56A7H),A 32 A7 56
...and set the pass flag so the next pass rewrites.
532DH
LD HL,567EH 21 7E 56
Point Register Pair HL at the "No errors" message.
5330H
Display it through the helper at 553BH.

5333H - Reference Pass: Scan and Rebuild Each Line

Each program line is copied a byte at a time into the work buffer at 5700H. Text inside quoted strings is passed through untouched; outside strings, a reference-introducing token (THEN, GOTO, GOSUB, ELSE, RESUME, RUN, ERL) triggers the line-number-reference handler at 53FBH. On the rewrite pass the rebuilt line is spliced back into the program, growing or shrinking the text as the reference digits change length.

5333H
LD IX,(40A4H) DD 2A A4 40
Point Register IX at the first line record.
5337H
XOR A AF
Clear Register A.
5338H
LD (56A9H),A 32 A9 56
Clear the in-string flag 56A9H (0 = outside a quoted string).
533BH
Test for end of program.
533EH
At end of program, finish this pass at 5321H.
5340H
PUSH IX DD E5
Copy Register IX (the line record)...
5342H
POP IY FD E1
...into Register IY, which walks this line byte by byte.
5344H
LD HL,(56A3H) 2A A3 56
Load Register Pair HL with the work-buffer pointer 5700H from 56A3H.
5347H
LD A,00H 3E 00
Load 0 into Register A...
5349H
EX AF,AF' 08
...and swap it into the alternate accumulator as the rebuilt-line length counter.
534AH
XOR A AF
Clear Register A.
534BH
LD (56A5H),A 32 A5 56
Clear the per-line changed flag 56A5H.
534EH
LD A,(IY+04H) FD 7E 04
Load the current source byte from (IY+04H), the first token past the line header and then each following byte.
5351H
LD (HL),A 77
Store it into the work buffer at (HL).
5352H
EX AF,AF' 08
Bring the length counter into Register A.
5353H
INC A 3C
Increment it.
5354H
CP 0FFH FE FF
Compare with FFH.
5356H
A rebuilt line reaching 255 bytes is a Buffer overflow error.
5359H
EX AF,AF' 08
Return the counter to the alternate accumulator.
535AH
OR A B7
Test the source byte in Register A.
535BH
A zero byte is the end of the line; handle it at 5379H.
535DH
LD (HL),A 77
Store the byte into the work buffer.
535EH
CP 22H FE 22
Compare it with a double-quote (22H).
5360H
LD A,(56A9H) 3A A9 56
Load the in-string flag 56A9H.
5363H
If the byte was not a quote, leave the flag unchanged.
5365H
XOR 01H EE 01
On a quote, toggle the flag's low bit.
5367H
LD (56A9H),A 32 A9 56
Store the in-string flag back.
536AH
OR A B7
Test the flag.
536BH
Inside a quoted string, copy the byte through without token scanning.
536DH
LD A,(HL) 7E
Reload the source byte from the work buffer into Register A.
536EH
Test whether it is a reference-introducing token (helper at 55A8H).
5371H
If it is, decode the line-number reference that follows at 53FBH.
5374H
INC IY FD 23
Advance Register IY to the next source byte.
5376H
INC HL 23
Advance the work-buffer pointer.
5377H
Loop to copy the next byte.
5379H
LD A,(56A5H) 3A A5 56
Load the per-line changed flag 56A5H.
537CH
OR A B7
Test it.
537DH
If a reference was rewritten in this line, splice the rebuilt line back at 5384H.
537FH
Otherwise just advance Register IX to the next line record...
5382H
...and loop to the next line.
5384H
LD A,(56A7H) 3A A7 56
Read the pass flag 56A7H.
5387H
OR A B7
Test it.
5388H
On the validation pass (flag 0) no text is moved; just advance to the next line.
538AH
PUSH IX DD E5
Save the current line record.
538CH
Advance one line.
538FH
PUSH IX DD E5
Save that pointer.
5391H
If that was the end of program, stop scanning ahead at 5398H.
5393H
Otherwise keep advancing...
5396H
...to the end of program, to find where the text block ends.
5398H
PUSH IX DD E5
Save the end pointer.
539AH
POP HL E1
Recover it into Register Pair HL.
539BH
INC HL 23
Advance past the 0000H end marker.
539CH
POP DE D1
Recover the following-line pointer into Register Pair DE.
539DH
POP IX DD E1
Recover the current line record into Register IX.
539FH
PUSH IX DD E5
Save the current line record again.
53A1H
PUSH HL E5
Save the end-of-text pointer.
53A2H
PUSH DE D5
Save the following-line pointer.
53A3H
INC HL 23
Advance the end pointer.
53A4H
SBC HL,DE ED 52
Subtract the following-line pointer, giving the number of text bytes from the next line to the end.
53A6H
PUSH HL E5
Move that count...
53A7H
POP BC C1
...into Register Pair BC for the block move.
53A8H
POP DE D1
Recover the destination into Register Pair DE.
53A9H
POP HL E1
Recover the source into Register Pair HL.
53AAH
LD IY,(56A3H) FD 2A A3 56
Point Register IY at the rebuilt line in the work buffer 5700H.
53AEH
LD A,(IX+04H) DD 7E 04
Read a byte of the old (in-program) line at (IX+04H).
53B1H
OR A B7
Test it.
53B2H
At the old line's terminator its length is known; go to 53D1H.
53B4H
LD A,(IY+00H) FD 7E 00
Read the matching byte of the rebuilt line at (IY+00H).
53B7H
OR A B7
Test it.
53B8H
When the rebuilt line ends first it is shorter; close the gap at 53C0H.
53BAH
INC IX DD 23
Advance the old-line pointer.
53BCH
INC IY FD 23
Advance the rebuilt-line pointer.
53BEH
Loop to compare the two line lengths byte by byte.
53C0H
PUSH DE D5
The rebuilt line is shorter: copy the destination pointer...
53C1H
POP HL E1
...into Register Pair HL.
53C2H
LD A,(IX+04H) DD 7E 04
Read a byte of the old line at (IX+04H).
53C5H
OR A B7
Test it.
53C6H
At its terminator the shrink amount is measured; do the move at 53CDH.
53C8H
DEC DE 1B
Decrement the destination for each surplus byte.
53C9H
INC IX DD 23
Advance the old-line pointer.
53CBH
Loop.
53CDH
LDIR ED B0
Move the trailing text down over the gap (LDIR), closing the space the shorter line vacated.
53CFH
Continue with the splice at 53E6H.
53D1H
LD A,(IY+00H) FD 7E 00
The rebuilt line is the same length or longer: read a byte of the rebuilt line at (IY+00H).
53D4H
OR A B7
Test it.
53D5H
When equal length there is nothing to move; go to 53E6H.
53D7H
PUSH HL E5
Copy the source pointer...
53D8H
POP DE D1
...into Register Pair DE.
53D9H
LD A,(IY+00H) FD 7E 00
Read a byte of the rebuilt line at (IY+00H).
53DCH
OR A B7
Test it.
53DDH
At its terminator the growth amount is measured; do the move at 53E4H.
53DFH
INC DE 13
Advance the destination for each extra byte.
53E0H
INC IY FD 23
Advance the rebuilt-line pointer.
53E2H
Loop.
53E4H
LDDR ED B8
Move the trailing text up (LDDR), opening room for the longer line.
53E6H
POP IX DD E1
Recover the current line record into Register IX.
53E8H
LD DE,(56A3H) ED 5B A3 56
Point Register Pair DE at the rebuilt line in the work buffer.
53ECH
LD A,(DE) 1A
Read a rebuilt byte.
53EDH
LD (IX+04H),A DD 77 04
Store it into the program line at (IX+04H).
53F0H
OR A B7
Test it.
53F1H
At the terminator the line is fully written; resume at 53F8H.
53F3H
INC IX DD 23
Advance the program pointer.
53F5H
INC DE 13
Advance the work-buffer pointer.
53F6H
Loop.
53F8H
XOR A AF
Clear Register A.
53F9H
Rejoin the end-of-line handling at 537CH to move on to the next line.

53FBH - Handle a Line-Number Reference

The old target number that follows a reference token is accumulated, the line carrying that old number is found, its NEW number (held in its link word from pass 0) is converted to ASCII, and those digits are written into the rebuilt line in place of the old ones. A target that does not exist raises Can not find line.

53FBH
LD DE,0000H 11 00 00
Clear Register Pair DE, the accumulator for the old target line number.
53FEH
LD (HL),A 77
Store the reference token into the work buffer.
53FFH
EX AF,AF' 08
Bring the length counter into Register A.
5400H
INC A 3C
Increment it.
5401H
CP 0FFH FE FF
Compare with FFH.
5403H
Overflow is a Buffer overflow error.
5406H
EX AF,AF' 08
Return the counter to the alternate accumulator.
5407H
INC HL 23
Advance the work-buffer pointer.
5408H
INC IY FD 23
Advance the source pointer.
540AH
LD A,(IY+04H) FD 7E 04
Read the next source byte at (IY+04H).
540DH
OR A B7
Test it.
540EH
End of line ends this reference; resume the copy loop at 5351H.
5411H
CP 21H FE 21
Compare the byte with 21H.
5413H
Blanks and control bytes before the number are copied through (loop at 53FBH).
5415H
CP 2CH FE 2C
Compare it with a comma.
5417H
A comma (as in ON n GOTO a,b) continues the reference scan.
5419H
CP 0D5H FE D5
Compare it with token D5H.
541BH
That token is passed through and the scan continues.
541DH
CP 30H FE 30
Compare it with '0' (30H).
541FH
A leading '0' is copied through and the scan continues.
5421H
Test whether the byte is a digit (helper at 54FFH).
5424H
A non-digit means there is no line number here; resume the copy loop at 5351H.
5427H
Accumulate the digit into Register Pair DE (DE = DE*10 + digit).
542AH
On no overflow, continue collecting digits.
542CH
LD DE,0000H 11 00 00
On overflow, clear the accumulator...
542FH
...and report the reference as unfindable at 54A0H.
5431H
INC IY FD 23
Advance the source pointer.
5433H
LD A,(IY+04H) FD 7E 04
Read the next source byte.
5436H
Test whether it is a digit.
5439H
While digits remain, keep accumulating the old target number.
543BH
PUSH IX DD E5
Save the current line record.
543DH
LD IX,(40A4H) DD 2A A4 40
Point Register IX at the first line record to search for the target.
5441H
Test for end of program.
5444H
Skip the first advance on the opening iteration.
5446H
Advance to the next line record.
5449H
If the end is reached without a match, the target does not exist; Can not find line at 549EH.
544BH
LD A,(IX+02H) DD 7E 02
Compare the line's old-number low byte...
544EH
CP E BB
...against Register E.
544FH
On a mismatch, keep searching.
5451H
LD A,(IX+03H) DD 7E 03
Compare the high byte...
5454H
CP D BA
...against Register D.
5455H
On a mismatch, keep searching.
5457H
PUSH HL E5
Target found: save the work-buffer pointer.
5458H
LD L,(IX+00H) DD 6E 00
Load the target line's link-word low byte into Register L...
545BH
LD H,(IX+01H) DD 66 01
...and high byte into Register H, giving its NEW number (stored there in pass 0).
545EH
Convert that number to ASCII (helper at 557EH); Register Pair DE points at the digits.
5461H
POP HL E1
Recover the work-buffer pointer.
5462H
POP IX DD E1
Recover the current line record.
5464H
LD A,01H 3E 01
Load 01H...
5466H
LD (56A5H),A 32 A5 56
...and set the per-line changed flag 56A5H, marking this line for splicing.
5469H
LD A,(DE) 1A
Read a new-number ASCII digit.
546AH
OR A B7
Test for end of the digit string.
546BH
At its end, resume scanning the source line at 540AH.
546DH
LD (HL),A 77
Store the digit into the work buffer.
546EH
INC DE 13
Advance the digit pointer.
546FH
INC HL 23
Advance the work-buffer pointer.
5470H
EX AF,AF' 08
Bring the length counter into Register A.
5471H
INC A 3C
Increment it.
5472H
CP 0FFH FE FF
Compare with FFH.
5474H
Overflow is a Buffer overflow error.
5476H
EX AF,AF' 08
Return the counter to the alternate accumulator.
5477H
Loop for the next digit.

5479H - Commit the New Numbers into the Line-Number Fields

With every reference already rewritten, each line's new number - still sitting in its link word - is copied into the line-number field of the record.

5479H
LD IX,(40A4H) DD 2A A4 40
Point Register IX at the first line record.
547DH
Test for end of program.
5480H
At the end, rebuild the links at 54C7H.
5482H
LD A,(IX+00H) DD 7E 00
Load the line's link-word low byte (its new number)...
5485H
LD (IX+02H),A DD 77 02
...into the line-number field low byte (IX+02H).
5488H
LD A,(IX+01H) DD 7E 01
Load the link-word high byte...
548BH
LD (IX+03H),A DD 77 03
...into the line-number field high byte (IX+03H).
548EH
Advance to the next line record.
5491H
Loop.

5493H - Buffer Overflow Error

A rebuilt line longer than 254 bytes cannot fit the work buffer; the offending line is named and Buffer overflow is displayed before the links are rebuilt and control returns to BASIC.

5493H
Display "Error in line NNNN. " for the current line (helper at 5520H).
5496H
LD HL,565AH 21 5A 56
Point Register Pair HL at the "Buffer overflow" message.
5499H
Display it.
549CH
Rebuild the program links and exit at 54C7H.

549EH - Can Not Find Line Error

A GOTO/GOSUB/etc. that targets a non-existent line is reported with the offending line number and the missing target number.

549EH
POP IX DD E1
Discard the saved line record from the stack.
54A0H
PUSH DE D5
Save the missing target number.
54A1H
Display "Error in line NNNN. " for the current line.
54A4H
LD HL,566BH 21 6B 56
Point Register Pair HL at the "Can not find line " message.
54A7H
Display it.
54AAH
POP HL E1
Recover the missing target number into Register Pair HL.
54ABH
Print it through ROM LINPRT.
54AEH
LD HL,5697H 21 97 56
Point Register Pair HL at the trailing period-space text.
54B1H
Display it.
54B4H
Display a closing carriage return.
54B7H
Rebuild the program links and exit at 54C7H.

54B9H - Unreferenced Stub

This three-instruction fragment stores 01H into the first byte of the program text and joins the exit path. No instruction in the overlay transfers control to it.

54B9H
LD HL,(40A4H) 2A A4 40
Load Register Pair HL from TXTTAB 40A4H.
54BCH
LD A,01H 3E 01
Load 01H.
54BEH
LD (HL),A 77
Store it into the first byte of program text.
54BFH
Join the exit path at 54C7H.

54C1H - Bad Parameters Error

Displays Bad parameters and falls through to the link rebuild and exit.

54C1H
LD HL,564BH 21 4B 56
Point Register Pair HL at the "Bad parameters" message.
54C4H
Display it, then fall through to the link rebuild.

54C7H - Rebuild the Line Links, Fix the Pointers, Exit

Because reference rewriting may have moved text, every line's link word is rebuilt to point at the following line, and VARTAB/ARYTAB/STREND are set just past the new end of the program. Control then goes to the BASIC/CMD reload at 5551H.

54C7H
LD IX,(40A4H) DD 2A A4 40
Point Register IX at the first line record.
54CBH
Test for end of program.
54CEH
At the end, fix the program pointers at 54DEH.
54D0H
PUSH IX DD E5
Copy the current line record...
54D2H
POP HL E1
...into Register Pair HL.
54D3H
Advance Register IX to the next line record.
54D6H
PUSH IX DD E5
Copy that address...
54D8H
POP DE D1
...into Register Pair DE.
54D9H
LD (HL),E 73
Store the next-line address low byte into this line's link word...
54DAH
INC HL 23
...advance...
54DBH
LD (HL),D 72
...and store the high byte, relinking the line to its successor.
54DCH
Loop to relink every line.
54DEH
PUSH IX DD E5
Copy the end-of-program pointer...
54E0H
POP HL E1
...into Register Pair HL.
54E1H
INC HL 23
Advance past the two-byte end marker...
54E2H
INC HL 23
...(second byte).
54E3H
LD (40F9H),HL 22 F9 40
Set VARTAB 40F9H to the new end of program.
54E6H
LD (40FBH),HL 22 FB 40
Set ARYTAB 40FBH to the same address.
54E9H
LD (40FDH),HL 22 FD 40
Set STREND 40FDH to the same address, so variables rebuild above the renumbered program.
54ECH
Jump to the BASIC/CMD reload at 5551H.

54EFH - Parse a Decimal Number (helper)

Reads consecutive ASCII digits at (HL) into Register Pair DE, advancing HL past them; Carry is returned on 16-bit overflow.

54EFH
LD DE,0000H 11 00 00
Clear Register Pair DE, the running value.
54F2H
LD A,(HL) 7E
Read a character at (HL).
54F3H
Test whether it is a digit (Carry set = not a digit).
54F6H
CCF 3F
Complement the Carry so it is set for a digit.
54F7H
RET NC D0
On a non-digit, return with the value collected so far.
54F8H
Fold the digit into the running value (DE = DE*10 + digit).
54FBH
INC HL 23
Advance Register Pair HL.
54FCH
RET C D8
On overflow, return with Carry set.
54FDH
Loop for the next digit.

54FFH - Digit Test (helper)

Returns Carry clear when Register A holds an ASCII digit 0-9, Carry set otherwise.

54FFH
CP 30H FE 30
Compare Register A with '0' (30H).
5501H
RET C D8
Below '0' returns Carry set (not a digit).
5502H
CP 3AH FE 3A
Compare with ':' (3AH), one past '9'.
5504H
CCF 3F
Complement the Carry: it is now clear for 0-9 and set otherwise.
5505H
RET C9
Return.

5506H - Multiply by Ten and Add a Digit (helper)

Computes DE = DE*10 + (A-'0') by nine repeated additions; Carry is set on 16-bit overflow.

5506H
PUSH HL E5
Save Register Pair HL.
5507H
PUSH AF F5
Save Register A (the digit).
5508H
PUSH DE D5
Push the running value...
5509H
POP HL E1
...into Register Pair HL.
550AH
LD B,09H 06 09
Set Register B to 9 additions.
550CH
ADD HL,DE 19
Add the running value to itself repeatedly to build ten times the value.
550DH
On no carry, continue.
550FH
POP AF F1
On overflow, recover Register A...
5510H
POP HL E1
...and Register Pair HL...
5511H
SCF 37
...set Carry...
5512H
RET C9
...and return the overflow.
5513H
Repeat the addition nine times, giving HL = value*10.
5515H
POP AF F1
Recover the digit into Register A.
5516H
SUB 30H D6 30
Convert the ASCII digit to its value (subtract '0').
5518H
LD E,A 5F
Move it into Register E...
5519H
LD D,00H 16 00
...with a zero high byte in Register D.
551BH
ADC HL,DE ED 5A
Add the digit to value*10.
551DH
EX DE,HL EB
Return the result in Register Pair DE.
551EH
POP HL E1
Recover Register Pair HL.
551FH
RET C9
Return.

5520H - Display "Error in line NNNN. " (helper)

Prints the Error in line message, the current line's number, and a trailing period.

5520H
PUSH IX DD E5
Save the current line record.
5522H
LD HL,5688H 21 88 56
Point Register Pair HL at the "Error in line " message.
5525H
Display it.
5528H
POP IX DD E1
Recover the current line record.
552AH
LD L,(IX+02H) DD 6E 02
Load the line's number low byte into Register L...
552DH
LD H,(IX+03H) DD 66 03
...and high byte into Register H.
5530H
Print the line number through ROM LINPRT.
5533H
LD HL,5697H 21 97 56
Point Register Pair HL at the trailing period-space text.
5536H
Display it through 553BH.

5538H - Display-String Helper

A wrapper around @DSPLY that preserves Register Pair IY and DE across the call. Entry at 5538H displays a lone carriage return; entry at 553BH displays the string at (HL).

5538H
LD HL,5659H 21 59 56
Point Register Pair HL at a lone carriage return.
553BH
PUSH IY FD E5
Save Register Pair IY across the display call.
553DH
PUSH DE D5
Save Register Pair DE.
553EH
Display the string at (HL) through @DSPLY.
5541H
POP DE D1
Recover Register Pair DE.
5542H
POP IY FD E1
Recover Register Pair IY.
5544H
RET C9
Return.

5545H - Empty-Program Error, then Return to BASIC

Patches the Error in line message to read "line 0", displays it, and falls into the reload of BASIC/CMD.

5545H
LD HL,0D30H 21 30 0D
Load 0D30H (the characters '0' and carriage return).
5548H
LD (5696H),HL 22 96 56
Overwrite the terminator of the "Error in line " message so it reads "line 0".
554BH
LD HL,5688H 21 88 56
Point Register Pair HL at that message.
554EH
Display it.

5551H - Reload BASIC/CMD and Return to Ready

The overlay replaced the interpreter's image at 5200H, so the normal exit reloads BASIC/CMD through @RUN, passing the command * so the interpreter simply returns to its Ready prompt.

5551H
LD HL,55C8H 21 C8 55
Point Register Pair HL at the reload filespec at 55C8H ("BASIC/CMD").
5554H
LD DE,4480H 11 80 44
Point Register Pair DE at CFCB$ 4480H.
5557H
PUSH DE D5
Save the destination.
5558H
LD BC,000BH 01 0B 00
Set Register Pair BC to 11 bytes.
555BH
LDIR ED B0
Copy the filespec into CFCB$.
555DH
POP DE D1
Recover the destination into Register Pair DE.
555EH
LD HL,4318H 21 18 43
Point Register Pair HL at INBUF$ 4318H.
5561H
LD (HL),2AH 36 2A
Store a * (2AH) there, the do-nothing command line.
5563H
Jump to @RUN 4433H, which reloads BASIC/CMD and returns to the Ready prompt.

5566H - Uppercase a String (helper)

Folds lowercase letters a-z to uppercase in the string at (HL) up to the first control byte. No instruction in the overlay calls this routine.

5566H
PUSH AF F5
Save Register A.
5567H
PUSH HL E5
Save Register Pair HL.
5568H
LD A,(HL) 7E
Read a byte at (HL).
5569H
CP 20H FE 20
Compare it with a blank (20H).
556BH
A control byte below 20H ends the string.
556DH
CP 61H FE 61
Compare it with 'a' (61H).
556FH
Below 'a' it is already uppercase; skip the fold.
5571H
CP 7BH FE 7B
Compare it with '{' (7BH), one past 'z'.
5573H
Above 'z' skip the fold.
5575H
SUB 20H D6 20
Fold a lowercase letter to uppercase (subtract 20H).
5577H
LD (HL),A 77
Store it back.
5578H
INC HL 23
Advance Register Pair HL.
5579H
Loop.
557BH
POP HL E1
Recover Register Pair HL.
557CH
POP AF F1
Recover Register A.
557DH
RET C9
Return.

557EH - Convert a Line Number to ASCII (helper)

Uses the ROM number-formatter to turn the 16-bit line number in Register Pair HL into an ASCII digit string, returning Register Pair DE at the first digit.

557EH
PUSH HL E5
Save Register Pair HL (the line number).
557FH
Store the integer in Register Pair HL into the ROM accumulator (MAKINT).
5582H
XOR A AF
Clear Register A.
5583H
Initialize the ROM number-print buffer at 4130H (FOUINI).
5586H
OR (HL) B6
OR the first buffer byte to set the flags FOUT2 expects.
5587H
Convert the number to ASCII in the buffer (FOUT2); Register Pair HL points at it.
558AH
EX DE,HL EB
Move that pointer into Register Pair DE.
558BH
INC DE 13
Skip the leading sign/blank so Register Pair DE points at the first digit.
558CH
POP HL E1
Recover Register Pair HL.
558DH
RET C9
Return.

558EH - Advance to the Next Line Record (helper)

Steps Register IX past the four-byte link and line-number header and over the tokens to the following line's link word.

558EH
INC IX DD 23
Advance Register IX past the link word...
5590H
INC IX DD 23
...(second byte)...
5592H
INC IX DD 23
...over the line-number field...
5594H
INC IX DD 23
...(second byte); Register IX now points at the first token.
5596H
LD A,(IX+00H) DD 7E 00
Read a token byte at (IX+00H).
5599H
INC IX DD 23
Advance Register IX.
559BH
OR A B7
Test the byte.
559CH
Loop until the 00H line terminator, leaving Register IX at the next line's link word.

559EH - End-of-Program Test (helper)

Returns the Zero flag set when the link word at (IX+00H/+01H) is 0000H, the end-of-program marker.

559EH
LD A,(IX+00H) DD 7E 00
Read the link-word low byte at (IX+00H).
55A1H
OR A B7
Test it.
55A2H
RET NZ C0
A non-zero low byte means this is not the end; return with the Zero flag clear.
55A3H
LD A,(IX+01H) DD 7E 01
Read the link-word high byte at (IX+01H).
55A6H
OR A B7
Test it, setting the Zero flag for the 0000H end marker.
55A7H
RET C9
Return.

55A8H - Reference-Token Test (helper)

Returns the Zero flag set when Register A holds one of the seven keyword tokens that a line-number reference can follow.

55A8H
CP 0CAH FE CA
Compare Register A with CAH (THEN).
55AAH
RET Z C8
Return the Zero flag set on a match.
55ABH
CP 95H FE 95
Compare with 95H (ELSE).
55ADH
RET Z C8
Return on a match.
55AEH
CP 9FH FE 9F
Compare with 9FH (RESUME).
55B0H
RET Z C8
Return on a match.
55B1H
CP 8DH FE 8D
Compare with 8DH (GOTO).
55B3H
RET Z C8
Return on a match.
55B4H
CP 91H FE 91
Compare with 91H (GOSUB).
55B6H
RET Z C8
Return on a match.
55B7H
CP 8EH FE 8E
Compare with 8EH (RUN).
55B9H
RET Z C8
Return on a match.
55BAH
CP 0C2H FE C2
Compare with C2H (ERL).
55BCH
RET Z C8
Return on a match.
55BDH
RET C9
Return with the Zero flag clear when the byte is none of the reference tokens.

55BEH - Skip Blanks (helper)

Advances Register Pair HL one byte and then over any run of blanks, preserving Register A.

55BEH
PUSH AF F5
Save Register A.
55BFH
INC HL 23
Advance Register Pair HL.
55C0H
LD A,(HL) 7E
Read a byte at (HL).
55C1H
CP 20H FE 20
Compare it with a blank.
55C3H
Skip over any run of blanks.
55C5H
POP AF F1
Recover Register A.
55C6H
RET C9
Return.

55C7H - Filespec, Banner, Messages, and Parameter Table

The tail of the file holds the reload filespec, the sign-on banner, the status and error messages, and the parameter table whose default values are baked into the image.

55C7H
DEFM "LBASIC/CMD" 4C 42 41 53 49 43 2F 43 4D 44
Overlay-exit filespec. The reload routine at 5551H copies eleven bytes starting at 55C8H ("BASIC/CMD" plus 03H and 1CH) into CFCB$ 4480H to reload the interpreter; the leading 4CH ('L') at 55C7H is not copied.
55D1H
DEFB 03H 03
Filespec terminator for @RUN.
55D2H
DEFB 1CH, 1FH 1C 1F
Video control codes that open the banner: 1CH homes the cursor and 1FH clears to the end of the frame.
55D4H
DEFM "BASIC Line Renumbering Utility - Version 2.21" 42 41 53 49 43 20 4C 69 6E 65 20 52 65 6E 75 6D 62 65 72 69 6E 67 20 55 74 69 6C 69 74 79 20 20 2D 20 20 56 65 72 73 69 6F 6E 20 32 2E 32 31
Sign-on banner text, displayed at entry.
5603H
DEFB 0AH 0A
Line feed within the banner.
5604H
DEFM "Copyright 1987 MISOSYS, Inc., All rights reserved" 43 6F 70 79 72 69 67 68 74 20 31 39 38 37 20 4D 49 53 4F 53 59 53 2C 20 49 6E 63 2E 2C 20 41 6C 6C 20 72 69 67 68 74 73 20 72 65 73 65 72 76 65 64
Banner copyright line.
5635H
DEFB 0AH, 0DH 0A 0D
Line feed and carriage return ending the banner.
5637H
DEFM "Checking for errors" 43 68 65 63 6B 69 6E 67 20 66 6F 72 20 65 72 72 6F 72 73
Progress message shown before the validation pass.
564AH
DEFB 0DH 0D
Carriage return ending the message.
564BH
DEFM "Bad parameters" 42 61 64 20 70 61 72 61 6D 65 74 65 72 73
Error message for a malformed parameter list or an impossible renumber (out-of-sequence or overflowing numbers).
5659H
DEFB 0DH 0D
Carriage return; also displayed on its own through the 5538H helper entry.
565AH
DEFM "Buffer overflow" 42 75 66 66 65 72 20 6F 76 65 72 66 6C 6F 77
Error message when a rebuilt line will not fit the 254-byte work buffer.
5669H
DEFB 0AH, 0DH 0A 0D
Line feed and carriage return ending the message.
566BH
DEFM "Can not find line " 43 61 6E 20 6E 6F 74 20 66 69 6E 64 20 6C 69 6E 65 20
Error message prefix; the missing target line number is printed after it.
567DH
DEFB 03H 03
ETX terminator (no carriage return) so the number prints on the same line.
567EH
DEFM "No errors" 4E 6F 20 65 72 72 6F 72 73
Message shown after a clean validation pass, or at once when the ! option skips it.
5687H
DEFB 0DH 0D
Carriage return ending the message.
5688H
DEFM "Error in line " 45 72 72 6F 72 20 69 6E 20 6C 69 6E 65 20
Error message prefix; the offending line number is printed after it. The empty-program path at 5545H overwrites the terminator at 5696H so this reads "Error in line 0".
5696H
DEFB 03H 03
ETX terminator so the number prints on the same line.
5697H
DEFM ". " 2E 20 20
Period and blanks printed after a line number in the error messages.
569AH
DEFB 03H 03
ETX terminator.
569BH
DEFW 0001H 01 00
Parameter line, the first old line number to renumber. Default 1.
569DH
DEFW 0014H 14 00
Parameter newline, the new starting number and the running counter during pass 0. Default 20.
569FH
DEFW 0014H 14 00
Parameter inc, the increment between renumbered lines. Default 20.
56A1H
DEFW 0FFF9H F9 FF
Parameter last, the last old line number to renumber. Default 65529.
56A3H
DEFW 5700H 00 57
Pointer to the line work buffer, set just past the loaded image at 5700H.