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

Page Customization

Summary:

LDOS 5.3.1 BASIC/OV4 Disassembly - The LBASIC Active Variable Dump (Model I)

BASIC/OV4 is the last of the four LBASIC overlays shipped with LDOS 5.3.1. It backs the DOS version 5 statement CMD"V [*DO | *PR] [-S] [-A] [=x]", which dumps a list of the variables that are currently active in the BASIC workspace, together with their values, and lists any user defined functions. It can be issued while a program is running, after it has been interrupted with BREAK, or after it has ended, because the overlay reads the interpreter's own variable tables rather than the program text.

The parameters are those documented in the MISOSYS BASIC Reference Manual (M-40-061). *DO sends the dump to the video display and is the default; *PR sends it to the line printer. -S restricts the dump to scalars, -A restricts it to array variables, and =x restricts it to variables whose first letter is x. Both BASIC/CMD and BASIC/OV4 must be present on the disk.

The mechanism is the interesting part. BASIC/OV4 contains no floating point formatter and no string handling of its own. For every variable it finds it BUILDS A FRAGMENT OF BASIC SOURCE TEXT in a work buffer at 557FH - a quoted literal holding the variable's name, followed by the same name again as a live variable reference - and then hands that text to the Level II ROM's PRINT loop, entering it at 2069H so that the device code in Register A is planted in PRTFLG 409CH on the way in. The interpreter evaluates the reference and prints the value. A one dimensional array A$ therefore produces the successive lines A$(0) = "A$(0), A$(1) = "A$(1) and so on, each of which the ROM prints as the subscript expression followed by the element's contents. A user defined function is handled the other way round: its definition text is untokenized back into readable form through the ROM's BUFLIN expander, entered at 2B85H so that the destination buffer is taken from Register Pair BC instead of from BUFPNT 40A7H, and the result is displayed directly with @DSPLY.

The overlay is a standard LDOS load module of 960 bytes: one type 1FH copyright record ("Copyright 1991 MISOSYS, Inc., All rights reserved"), five type 01H load records and a type 02H transfer record. It is the only one of the four BASIC overlays whose image is not contiguous. The image occupies 5200H-5569H and 5574H-557EH, 885 bytes in all, with a ten byte hole at 556AH-5573H that the overlay zeroes itself at run time and uses as five 16-bit subscript counters. The transfer address is 5200H. The disassembly listing was rebuilt from the binary and compared byte for byte: 885 of 885 bytes covered, zero mismatches, no byte loaded twice. The listing carries one byte that is not in the file, at 557FH; the image ends at 557EH and that byte is not shown on this page.

BASIC/OV4 is loaded over LBASIC's own image at 5200H by @RUN at 4433H, exactly as BASIC/OV1 and BASIC/OV2 are. BASIC/CMD's CMD dispatcher at 5454H matches the letter V at 5475H, sets Register B to 34H so that 54A5H builds the filespec "BASIC/OV4" into CFCB$ 4480H, and then does LD HL,4319H / LD DE,4480H / JP 4433H. The overlay is therefore entered at 5200H with Register Pair HL pointing one byte into INBUF$ 4318H, at the character following the V, so that it can read its own parameters. It does not switch stacks; it runs on LBASIC's stack throughout. Because its image stops at 557EH, everything of BASIC/CMD above that address - including the RST 10H replacement at 6579H, the PRINT hooks and the whole 49-slot Disk BASIC vector table's targets - is still in place while the overlay runs, which is what makes the borrowed ROM PRINT path work.

The overlay exits the same way BASIC/OV1 and BASIC/OV2 do. 5217H block moves eleven bytes from 522DH into CFCB$ 4480H, writes an asterisk into INBUF$ 4318H and jumps to @RUN at 4433H, so BASIC/CMD is reloaded and re-entered through its own re-entry path with the program and the variables intact. The byte at 522CH is an ASCII L that is not part of the copy, the same shared source fragment artefact that appears at 55C7H in BASIC/OV1 and at 56A5H in BASIC/OV2.

The sign-on banner "BASIC Active Variable Dump - Version 4.1" is present in the image at 54C0H-54EAH, complete with its home-cursor and clear-to-end-of-frame control bytes, but no instruction in the overlay displays it. The only reference to the string is the LD HL,54C0H at 5201H, and the POP HL at 5204H overwrites Register Pair HL before it can be used. That is stated here as a fact of the image, not as a fault.

BASIC/OV4 issues no RST 28H supervisor request of its own, so the request code table on the main LDOS disassembly page is unchanged by it.

Memory Map

Address RangeContents
5200H-522BH
44 bytes
Entry point, dump selection and the exit stub that reloads BASIC/CMD
522CH-5236H
11 bytes
The unused ASCII L artefact plus the reload filespec "BASIC/CMD" and its 03H terminator
5237H-52A9H
115 bytes
The simple (scalar) variable walk, from VARTAB 40F9H to ARYTAB 40FBH
52AAH-53A8H
255 bytes
The array variable walk, from ARYTAB 40FBH to STREND 40FDH, including the subscript odometer
53A9H-53D5H
45 bytes
Build the variable's name and type declaration character into the output buffer
53D6H-53EEH
25 bytes
The two entry string copier, with the quote aware delimiter test
53EFH-5404H
22 bytes
Convert a 16-bit subscript to five ASCII decimal digits
5405H-5418H
20 bytes
Terminate the built line and print it through the Level II ROM PRINT loop
5419H-541FH
7 bytes
Compare Register Pair IX against Register Pair DE
5420H-5438H
25 bytes
Keyboard poll for the pause key and for BREAK
5439H-5449H
17 bytes
Display a string on the selected output device
544AH-54B0H
103 bytes
The command line parameter parser and the two error exits
54B1H-54BFH
15 bytes
Skip blanks, and fetch the next character folded to upper case
54C0H-54EAH
43 bytes
The sign-on banner. Present in the image but never displayed
54EBH-5569H
127 bytes
The two section headings, the five message strings and three work bytes
556AH-5573H
10 bytes
Not loaded. Five 16-bit subscript counters, zeroed by the overlay at 52E5H
5574H-557EH
11 bytes
The restriction letter, the decimal conversion buffer and the output line prefix
557FH upward
uninitialised
Not part of the image. The line the overlay builds for each variable
567FH upward
uninitialised
Not part of the image. Staging buffer for a user defined function's definition text

Variable and Work Cell List

AddressPurpose
520CH
1 byte
Self-Modifying Code
The operand of LD A,01H at 520BH, which gates the CALL NZ,5237H at 520EH. It ships as 01H so the scalar dump runs by default, and the -A switch writes 00H there at 5491H to suppress it.
5212H
1 byte
Self-Modifying Code
The operand of LD A,01H at 5211H, which gates the CALL NZ,52AAH at 5214H. It ships as 01H so the array dump runs by default, and the -S switch writes 00H there at 5487H to suppress it.
5567H
1 byte
The position of the subscript the odometer is currently advancing, counted from 1 at the leftmost subscript. Zero means every subscript has rolled over and the array is finished. Ships as 00H, which is also the 00H that follows the "Invalid output device!" message.
5568H
1 byte
The number of dimensions of the array being dumped, taken from array header offset 05H at 52CCH.
5569H
1 byte
The output device code. 00H selects the video display and 01H selects the line printer. It is used twice: 5439H tests it to choose between @DSPLY 4467H and @PRINT 446AH, and 5405H passes it to the ROM in Register A so that it becomes PRTFLG 409CH, whose convention is the same 00H video / 01H printer.
556AH-5573H
10 bytes
Not loaded from the file. Five 16-bit subscript counters, one per dimension, addressed through Register Pair IY. The overlay zeroes all ten bytes at 52E5H before it starts an array.
5574H
1 byte
The =x restriction letter, stored at 5499H after case folding. 00H means no restriction. Tested at 5249H for scalars and at 52BCH for arrays.
5575H-5579H
5 bytes
The five digit decimal conversion buffer, filled from the low digit upward by 53EFH. It ships as five blanks.
557AH
1 byte
The 00H that terminates the decimal conversion buffer for the string copier at 53D6H.
557BH
1 byte
The 22H quotation mark that opens the BASIC string literal the overlay builds. 5405H hands this address to the ROM PRINT loop.
557CH-557EH
3 bytes
Three blanks that indent every dumped line. The user defined function path displays from 557CH, so it starts here and skips the quotation mark.
557FH upward
uninitialised
Not part of the image. The variable's name and type character are built here by 53A9H and everything else is appended after them.
567FH upward
uninitialised
Not part of the image. The tokenized definition text of a user defined function is copied here at 526CH before the ROM expander at 2B85H reads it back.

Major Routine List

AddressName and Purpose
5200HEntry Point
Entry from @RUN with Register Pair HL at 4319H. Parses the parameters, emits a carriage return, then calls the scalar dump and the array dump according to the two self-modified gate bytes.
5217HExit Stub
Copies "BASIC/CMD" and its 03H terminator into CFCB$ 4480H, writes an asterisk into INBUF$ 4318H and jumps to @RUN 4433H so BASIC/CMD is reloaded and re-entered.
5237HSimple Variable Dump
Prints the "Simple Variables:" heading, then walks the scalar table from VARTAB 40F9H to ARYTAB 40FBH, three header bytes plus a value whose length is the type byte itself.
52AAHArray Variable Dump
Prints the "Array Variables:" heading, then walks the array table from ARYTAB 40FBH to STREND 40FDH, generating a line for every element of every array through an odometer over the subscript counters.
53A9HBuild The Variable Name
Writes the variable's two name characters, in the stored order second then first, followed by the type declaration character derived from the type byte: 08H gives #, 04H gives !, 03H gives $ and 02H gives %.
53D6HString Copier
Copies from (DE) to (HL) until a 00H byte. The 53D8H entry takes a second stop character in Register B, honoured only outside a quoted string; Register C toggles on every 22H so a delimiter inside a literal is ignored.
53EFHSubscript To Decimal
Converts Register Pair HL to five ASCII digits at 5575H-5579H using @DIV 44C4H, and returns Register Pair DE pointing at the first digit.
5405HPrint The Built Line
Terminates the built line with 00H, then enters the Level II ROM PRINT loop at 2069H with Register Pair HL at the leading quotation mark 557BH and Register A holding the device code, so that the ROM evaluates the fragment as a PRINT argument list.
5419HTable End Test
Subtracts Register Pair DE from Register Pair IX and returns with the Z FLAG set when they are equal, which is how both walks detect the end of their table.
5420HKeyboard Poll
Scans the keyboard through ROM @KBD 002BH. Code 60H holds the listing until another key is pressed; the routine returns with the Z FLAG set when the key was 01H, BREAK.
5439HDisplay A String
Sends the 0DH terminated string at (HL) to @DSPLY 4467H or to @PRINT 446AH according to the device byte 5569H, preserving Register Pair IX.
544AHParameter Parser
Reads *DO, *PR, -S, -A and =x from the command tail, writing the device byte, the two gate bytes and the restriction letter. Every failure goes to one of the two error exits.
54A4HParameter Error Exit
Displays "Parameter error!" through @LOGOT 447BH and leaves through the exit stub. The 54A8H entry inside its LD IX instruction displays "Invalid output device!" instead.
54B1HSkip Blanks
54B2H returns the character at (HL) with the Z FLAG set at a 0DH; 54B1H advances first. 54BBH advances and returns the next character with bit 5 reset, folding lower case to upper case.

Cross-Reference Notes

BASIC/OV4 is reached only from BASIC/CMD. The CMD statement handler at 57C6H passes a quoted string of two characters or more to the dispatcher at 5454H, which requires a space as the second character and then matches the first: N selects BASIC/OV1, X selects BASIC/OV2 and V sets Register B to 34H and selects BASIC/OV4. 54A5H builds the eight character stem "BASIC/OV" plus that digit into CFCB$ 4480H, 54E1H has already copied the quoted string into INBUF$ 4318H with a carriage return terminator, and 5484H hands both to @RUN.

Resident LDOS vectors used: @RUN 4433H, @DSPLY 4467H, @PRINT 446AH, @LOGOT 447BH and @DIV 44C4H. Level II ROM entry points used: @KBD 002BH, $KEY 0049H, the LD (409CH),A inside LPRINT at 2069H, and the expander inside BUFLIN at 2B85H. BASIC workspace read: VARTAB 40F9H, ARYTAB 40FBH and STREND 40FDH. LDOS buffers used: INBUF$ 4318H and CFCB$ 4480H. No RST 28H supervisor request is issued.

The variable entry layout this overlay depends on is the same one BASIC/OV3 selector 04H walks: a scalar entry is a type byte whose value is also the length of the value that follows, then the second name character, then the first name character, then the value; and bit 7 of the first name character marks a user defined function, which is the bit BASIC/CMD's function reference parser at 55EBH sets. An array header is that same three byte prefix followed by a 16-bit block length, a dimension count and one 16-bit dimension size per dimension, stored last dimension first.

Disassembly:

5200H - Entry Point, Dump Selection and the Exit Stub

The transfer address of the module. @RUN has just written the overlay over LBASIC's own image at 5200H and entered it here with Register Pair HL pointing at 4319H, one byte into INBUF$ 4318H, which holds the text of the CMD string with a 0DH terminator. The three bytes 4318H, 4319H and onwards therefore read V, then the space the dispatcher insisted on, then the parameters. This block parses those parameters, runs whichever of the two dumps the parameters left enabled, and falls into the stub that reloads BASIC/CMD.

5200
PUSH HL E5
Save Register Pair HL, which holds 4319H, the address of the first parameter character inside INBUF$ 4318H, onto the stack.
5201
LD HL,54C0H 21 C0 54
Load Register Pair HL with 54C0H, the address of the sign-on banner (the two control bytes 1CH and 1FH followed by the text "BASIC Active Variable Dump - Version 4.1" and a 0DH terminator). This value is discarded three bytes later and the banner is never displayed; 54C0H is not referenced anywhere else in the image.
5204
POP HL E1
Restore Register Pair HL from the stack, so it holds 4319H again, the address of the first parameter character inside INBUF$ 4318H. This overwrites the banner address loaded at 5201H before anything can use it.
5205
GOSUB to 544AH to parse the command line parameters. Register Pair HL points at 4319H, the first parameter character. The parser sets the output device byte 5569H, the restriction letter 5574H and the two gate bytes 520CH and 5212H, and returns with Register Pair HL pointing at the 0DH that terminates the command string. Any parameter failure never returns here; it goes to one of the two error exits and then to the exit stub at 5217H.
5208
GOSUB to 5439H to display the string at (HL) on the selected device. Register Pair HL points at the 0DH terminator the parser stopped on, so the string is empty and the only character emitted is that carriage return, which moves the output to a fresh line before the first heading is printed.
520B
LD A,01H 3E 01
Self-Modifying Code
Load Register A with the scalar dump gate byte held at 520CH, the operand of this instruction. It is assembled as 01H so that scalars are dumped by default, and the -A switch writes 00H there at 5491H when the user asks for array variables only.
520D
OR A B7
OR Register A, which holds the scalar dump gate byte fetched from 520CH, with itself. This changes nothing but sets the flags: the Z FLAG is set when the gate byte is 00H and the NZ FLAG is set when it is 01H.
520E
If the NZ FLAG has been set, meaning the gate byte at 520CH is still 01H and scalars have not been suppressed by -A, GOSUB to 5237H to print the "Simple Variables:" heading and dump every scalar variable between VARTAB 40F9H and ARYTAB 40FBH.
5211
LD A,01H 3E 01
Self-Modifying Code
Load Register A with the array dump gate byte held at 5212H, the operand of this instruction. It is assembled as 01H so that arrays are dumped by default, and the -S switch writes 00H there at 5487H when the user asks for scalars only.
5213
OR A B7
OR Register A, which holds the array dump gate byte fetched from 5212H, with itself, to set the flags from it. The Z FLAG is set when the gate byte is 00H and the NZ FLAG is set when it is 01H.
5214
If the NZ FLAG has been set, meaning the gate byte at 5212H is still 01H and arrays have not been suppressed by -S, GOSUB to 52AAH to print the "Array Variables:" heading and dump every element of every array between ARYTAB 40FBH and STREND 40FDH.

Exit Stub
Every path out of the overlay arrives here: normal completion falls through from 5214H, a BREAK detected by the keyboard poll jumps here from 52A4H, 534EH or 53A3H, and both parameter error messages jump here from 54AEH. The stub reloads BASIC/CMD from disk with a command tail of a single asterisk, which is BASIC/CMD's documented re-entry request, so the interpreter comes back with the program and the variables untouched.

5217
Point Register Pair HL at 522DH, the first character of the reload filespec "BASIC/CMD" held in the overlay's own image, as the source of the block move.
521A
LD DE,4480H 11 80 44
Point Register Pair DE at CFCB$ 4480H, the resident command file control block buffer that @RUN reads the filespec from, as the destination of the block move.
521D
PUSH DE D5
Save Register Pair DE, which holds 4480H, the address of CFCB$, onto the stack. The block move is about to advance it, and @RUN needs the original value.
521E
LD BC,000BH 01 0B 00
Load Register Pair BC with 000BH, eleven, the number of bytes to move. That is the nine characters of "BASIC/CMD", the 03H terminator at 5236H, and one further byte at 5237H which is copied but never examined by @RUN.
5221
LDIR ED B0
Block move eleven bytes. Source is Register Pair HL at 522DH in the overlay image, destination is Register Pair DE at CFCB$ 4480H, count is Register Pair BC at 000BH, and both pointers increment. This plants the filespec of the file to be loaded next.
5223
POP DE D1
Restore Register Pair DE from the stack, so it holds 4480H again, the address of CFCB$, which is the file control block argument @RUN expects.
5224
LD HL,4318H 21 18 43
Point Register Pair HL at INBUF$ 4318H, the resident input buffer that @RUN passes to the loaded program as its command tail.
5227
LD (HL),2AH 36 2A
Store 2AH, ASCII *, at the address in Register Pair HL, which is INBUF$ 4318H. BASIC/CMD saves the first character of its command tail at 5354H and tests it at 5355H and 53F4H; an asterisk there means re-enter BASIC with the existing program and variables rather than cold start.
5229
JUMP to the resident @RUN vector at 4433H to load and execute the file named in CFCB$ 4480H, which is BASIC/CMD, passing the command tail at Register Pair HL, which is INBUF$ 4318H holding the single asterisk. Control never comes back to the overlay; the loaded copy of BASIC/CMD takes over the memory this code occupies.

522CH - Reload Filespec For BASIC/CMD

The eleven bytes the exit stub moves into CFCB$ 4480H, preceded by one byte that is not part of them. The same "L" plus "BASIC/CMD" plus 03H layout appears at 55C7H in BASIC/OV1 and at 56A5H in BASIC/OV2, always with the copy starting one byte in, so the file that gets loaded is BASIC/CMD and not LBASIC/CMD.

522C
DEFB 4CH 4C
ASCII L. The block move at 5221H starts at 522DH, so this byte is never copied and never read by anything in the overlay.
522D-5235
DEFM "BASIC/CMD" 42 41 53 49 43 2F 43 4D 44
The filespec of the file the exit stub loads, moved into CFCB$ 4480H by the block move at 5221H. No drive is specified, so LDOS searches every enabled drive.
5236
DEFB 03H 03
The 03H end of text delimiter that closes the filespec for @FSPEC, which @RUN uses to parse CFCB$ 4480H into a file control block.

5237H - The Simple Variable Dump

Called from 520EH when the gate byte at 520CH is non-zero. The scalar variable table runs from VARTAB 40F9H up to ARYTAB 40FBH, and each entry is a type byte whose value is also the length of the value that follows it, then the second name character, then the first name character, then the value itself. This routine walks that table and, for each entry that passes the =x restriction, either displays a user defined function's definition or builds a BASIC PRINT argument list that makes the interpreter print the variable's value.

5237
Point Register Pair HL at 54EBH, the heading string. It begins with the 0AH line feed at 54EBH, carries the text "Simple Variables:" at 54ECH-54FCH and is terminated by the 0DH at 54FDH.
523A
GOSUB to 5439H to send the string at Register Pair HL, which is the "Simple Variables:" heading at 54EBH, to the video display or the printer according to the device byte at 5569H.
523D
LD IX,(40F9H) DD 2A F9 40
Load Register Pair IX with the 16-bit value at VARTAB 40F9H, the address at which Level II BASIC keeps the start of the simple variable table. Register Pair IX is the walking pointer for the whole routine and always addresses the type byte of the entry being examined.

Loop Start
Each pass handles one scalar entry. Register Pair DE is reloaded from ARYTAB on every pass because the interpreter is not running while the dump proceeds and the table cannot move, but the reload also costs nothing and keeps the test self-contained.

5241
LD DE,(40FBH) ED 5B FB 40
Load Register Pair DE with the 16-bit value at ARYTAB 40FBH, the address at which Level II BASIC keeps the start of the array table. That address is one past the end of the scalar table, so it is the terminating value for this walk.
5245
GOSUB to 5419H to subtract Register Pair DE, the end of the scalar table taken from ARYTAB 40FBH, from Register Pair IX, the current entry pointer. The routine returns with the Z FLAG set when the two are equal.
5248
RET Z C8
If the Z FLAG has been set, meaning Register Pair IX has reached the value from ARYTAB 40FBH and there are no more scalar entries, RETurn to the caller at 5211H so that the array dump can follow.
5249
LD A,(5574H) 3A 74 55
Fetch the =x restriction letter from 5574H into Register A. The parser stored it there at 5499H after folding it to upper case; it is 00H when no =x parameter was given.
524C
OR A B7
OR Register A, which holds the restriction letter from 5574H, with itself to set the flags. The Z FLAG is set when the byte is 00H, meaning no restriction was requested.
524D
If the Z FLAG has been set, meaning the restriction byte at 5574H is 00H and every variable is wanted, JUMP to 5256H to dump this entry without testing its name.
524F
XOR (IX+02H) DD AE 02
Exclusive-OR Register A, which holds the restriction letter from 5574H, with the byte at offset 02H from Register Pair IX, which is the FIRST character of this variable's name. Every bit that differs between the two is left set.
5252
AND 7FH E6 7F
AND Register A, which holds the difference bits from the name comparison, with 7FH to discard bit 7. Bit 7 of the first name character is the user defined function marker and is not part of the name, so it must not be allowed to make a match fail.
5254
If the NZ FLAG has been set, meaning at least one of the low seven bits differed and this variable's first letter is not the letter given with =x, JUMP to 5297H to step over this entry without printing anything.
5256
GOSUB to 53A9H to write this variable's name and its type declaration character into the output buffer starting at 557FH, reading the two name characters from offsets 02H and 01H of Register Pair IX and the type from offset 00H. The routine returns with Register Pair HL pointing at the first free byte after the name.
5259
BIT 7,(IX+02H) DD CB 02 7E
Test bit 7 of the byte at offset 02H from Register Pair IX, the first character of this variable's name. BASIC/CMD's function reference parser at 55EBH sets that bit on the first letter so that function names occupy their own namespace, so a set bit here means this entry is a DEF FN definition rather than an ordinary variable.
525D
If the Z FLAG has been set, meaning bit 7 of the first name character at offset 02H of Register Pair IX is clear and this is an ordinary scalar variable, JUMP to 5286H to build the PRINT argument list for its value.

User Defined Function Path
The value field of a DEF FN entry is not a number but a pointer into the program text at which the function's tokenized definition begins, planted there by BASIC/CMD's DEF handler at 56E3H and read by its evaluator at 5603H. The overlay copies that text into a staging buffer, expands the tokens back into readable keywords with the ROM's own untokenizer, and displays the result.

525F
PUSH HL E5
Save Register Pair HL, which points at the first free byte of the output buffer just past the function's name at 557FH, onto the stack. It becomes the destination the ROM untokenizer writes to.
5260
LD E,(IX+03H) DD 5E 03
Load Register E with the byte at offset 03H from Register Pair IX, the low half of the pointer to this function's definition text inside the BASIC program.
5263
LD D,(IX+04H) DD 56 04
Load Register D with the byte at offset 04H from Register Pair IX, the high half of the pointer to this function's definition text, so that Register Pair DE now addresses the tokenized definition in the program.
5266
LD HL,567FH 21 7F 56
Point Register Pair HL at 567FH, uninitialised RAM well above the overlay's image, which is used as the staging buffer for the copied definition text.
5269
PUSH HL E5
Save Register Pair HL, which holds 567FH, the address of the staging buffer, onto the stack. The copy about to run advances it and the untokenizer needs the original.
526A
LD B,3AH 06 3A
Load Register B with 3AH, ASCII :, as the stop character for the copier at 53D8H. A colon ends the DEF FN statement, so the copy takes the definition and nothing that follows it on the same program line.
526C
GOSUB to 53D8H to copy the tokenized definition from (DE), the program text address taken from offsets 03H and 04H of Register Pair IX, to (HL), the staging buffer at 567FH, stopping at a 00H end of line byte or at the colon in Register B when that colon is not inside a quoted string. Register Pair HL is returned pointing at the byte that stopped the copy.
526F
LD (HL),00H 36 00
Store 00H at the address in Register Pair HL, the byte in the staging buffer at which the copy stopped, so that the staged text ends with the end of line marker the ROM untokenizer expects.
5271
POP HL E1
Restore Register Pair HL from the stack, so it holds 567FH again, the start of the staged definition text, which is the source the ROM untokenizer reads.
5272
POP BC C1
Restore Register Pair BC from the stack with the value pushed at 525FH, the position in the output buffer just past the function's name, which is the destination the ROM untokenizer writes to.
5273
GOSUB to the Level II ROM at 2B85H, seven bytes into the untokenizer BUFLIN at 2B7EH. The front door of BUFLIN takes its destination from BUFPNT 40A7H, which under LBASIC points into BASIC/CMD's initialization code at 5309H and is therefore inside this overlay's own image; entering at 2B85H skips that fetch and uses the destination already supplied in Register Pair BC. The routine expands the text at Register Pair HL, the staged definition at 567FH, into readable characters at Register Pair BC, looking every byte of 80H or more up in the reserved word list at 1650H, and returns Register Pair BC advanced past what it wrote.
5276
PUSH BC C5
Save Register Pair BC, which the untokenizer left pointing at the first free byte of the output buffer after the expanded definition text, onto the stack so that it can be transferred to Register Pair HL.
5277
POP HL E1
Restore into Register Pair HL the value just pushed from Register Pair BC, the first free byte of the output buffer after the expanded definition, which is where the trailing legend is appended.
5278
Point Register Pair DE at 552EH, the sixteen character legend " <User Def Func>" which is closed by the 0DH at 553EH.
527B
GOSUB to 53D6H to append the legend at Register Pair DE, 552EH, to the output buffer at Register Pair HL. This entry stops only on a 00H byte, and the legend ends with a 0DH rather than a 00H, so the copy runs on through "Parameter error!" and "Invalid output device!" and only stops at the 00H at 5567H. The extra bytes land in uninitialised RAM above the buffer and are never seen, because the display routine stops at the first 0DH, which is the one that closes the legend.
527E
Point Register Pair HL at 557CH, the first of the three blanks that indent every dumped line. This is three bytes before the output buffer at 557FH and one byte past the quotation mark at 557BH, so the quotation mark is deliberately skipped: this path displays plain text rather than handing a BASIC string literal to the interpreter.
5281
GOSUB to 5439H to send the string at Register Pair HL, the built line starting at 557CH, to the video display or the printer according to the device byte at 5569H. The 0DH copied from 553EH terminates it.
5284
JUMP to 5297H to advance Register Pair IX to the next scalar entry, rejoining the path the ordinary variables take.

Ordinary Scalar Path
Nothing here formats a value. The routine finishes the BASIC source fragment that was started by the name builder at 53A9H, so that the buffer holds a quoted literal giving the variable's name followed by the same name again as a live variable reference, and lets the interpreter's own PRINT loop evaluate it.

5286
Point Register Pair DE at 5529H, the four characters space, equals sign, space and quotation mark, terminated by the 00H at 552DH. The quotation mark closes the string literal that the one at 557BH opened.
5289
GOSUB to 53D6H to append the four characters at Register Pair DE, 5529H, to the output buffer at Register Pair HL, which the name builder left pointing just past the variable's name. The copy stops on the 00H at 552DH and Register Pair HL is returned pointing at the byte that follows what was written.
528C
LD B,3DH 06 3D
Load Register B with 3DH, ASCII =, as the stop character for the copier at 53D8H. That is the character the copy about to run must not pass, and it selects exactly the variable name plus the single blank that follows it.
528E
LD DE,557FH 11 7F 55
Point Register Pair DE at 557FH, the START of the output buffer, which holds the variable's name and type character followed by the four characters just appended. The buffer is about to be read back into itself so that the name appears a second time, this time outside the closing quotation mark, where the interpreter will read it as a variable reference.
5291
GOSUB to 53D8H to copy from (DE), the start of the buffer at 557FH, to (HL), the current end of the buffer, stopping at the equals sign held in Register B. The characters copied are therefore the variable's name and the blank that follows it. The routine stores the stopping character before it tests it but does not advance Register Pair HL past it, so that byte is left to be overwritten.
5294
GOSUB to 5405H to write the 00H terminator at the address in Register Pair HL, overwriting the copied equals sign, and to hand the finished fragment at 557BH to the Level II ROM PRINT loop, which evaluates the variable reference and prints its value.

Advance To The Next Scalar Entry
Reached from 5254H when the =x restriction rejected the variable, from 5284H after a user defined function, and by falling through after an ordinary variable has been printed.

5297
LD A,(IX+00H) DD 7E 00
Load Register A with the byte at offset 00H from Register Pair IX, this entry's type byte. In Level II BASIC that byte is also the length in bytes of the value stored in the entry: 02H integer, 03H string descriptor, 04H single precision and 08H double precision.
529A
ADD A,03H C6 03
ADD 03H to Register A, which holds the entry's value length taken from offset 00H of Register Pair IX, to account for the three header bytes - the type byte and the two name characters - so that Register A now holds the total size of the entry.
529C
LD C,A 4F
Copy Register A, the total size of this scalar entry, into Register C as the low half of the sixteen bit offset that will be added to the walking pointer.
529D
LD B,00H 06 00
Load Register B with 00H so that Register Pair BC holds the entry size in the range 5 to 11 with a zero high byte, ready for the sixteen bit addition.
529F
ADD IX,BC DD 09
ADD Register Pair BC, the total size of this entry, to Register Pair IX, the walking pointer, so that Register Pair IX now addresses the type byte of the next scalar entry.
52A1
GOSUB to 5420H to scan the keyboard. The routine holds the listing while the pause key, code 60H, is being pressed and returns with the Z FLAG set when the key read was 01H, the BREAK key.
52A4
If the Z FLAG has been set, meaning the keyboard poll at 5420H saw the BREAK key, JUMP to the exit stub at 5217H to abandon the dump and reload BASIC/CMD.

Loop End

52A7
LOOP BACK to 5241H to reload the end of table address from ARYTAB 40FBH and test the advanced Register Pair IX against it, so that the next scalar entry can be handled.

52AAH - The Array Variable Dump

Called from 5214H when the gate byte at 5212H is non-zero. The array table runs from ARYTAB 40FBH up to STREND 40FDH. An array header is a type byte, the second name character, the first name character, a 16-bit block length, a dimension count, and then one 16-bit dimension size per dimension stored last dimension first. This routine walks that table and, for each array, drives an odometer over the subscript counters at 556AH so that one line is produced for every element in the array, each line being a BASIC PRINT argument list containing the subscripted reference twice - once inside a quoted literal and once as live source text.

52AA
Point Register Pair HL at 54FEH, the heading string. It begins with the 0AH line feed at 54FEH, carries the text "Array Variables:" at 54FFH-550EH and is terminated by the 0DH at 550FH.
52AD
GOSUB to 5439H to send the string at Register Pair HL, which is the "Array Variables:" heading at 54FEH, to the video display or the printer according to the device byte at 5569H.
52B0
LD IX,(40FBH) DD 2A FB 40
Load Register Pair IX with the 16-bit value at ARYTAB 40FBH, the address at which Level II BASIC keeps the start of the array table. Register Pair IX becomes the walking pointer and addresses the type byte of the array header being examined.

Loop Start
Each pass handles one complete array.

52B4
LD DE,(40FDH) ED 5B FD 40
Load Register Pair DE with the 16-bit value at STREND 40FDH, the first free byte above all of the variable storage, which is one past the end of the array table and therefore the terminating value for this walk.
52B8
GOSUB to 5419H to subtract Register Pair DE, the end of the array table taken from STREND 40FDH, from Register Pair IX, the current array header pointer. The routine returns with the Z FLAG set when the two are equal.
52BB
RET Z C8
If the Z FLAG has been set, meaning Register Pair IX has reached the value from STREND 40FDH and there are no more arrays, RETurn to the caller at 5217H, which is the exit stub.
52BC
LD A,(5574H) 3A 74 55
Fetch the =x restriction letter from 5574H into Register A. The parser stored it there at 5499H after folding it to upper case; it is 00H when no =x parameter was given.
52BF
OR A B7
OR Register A, which holds the restriction letter from 5574H, with itself to set the flags. The Z FLAG is set when the byte is 00H, meaning every array is wanted.
52C0
If the Z FLAG has been set, meaning the restriction byte at 5574H is 00H, JUMP to 52C9H to dump this array without testing its name.
52C3
CP (IX+02H) DD BE 02
Compare Register A, the restriction letter from 5574H, against the byte at offset 02H from Register Pair IX, the FIRST character of this array's name. An array name never carries the bit 7 function marker, so no masking is needed here and a plain compare is enough. If they are equal the Z FLAG is set; otherwise the NZ FLAG is set.
52C6
If the NZ FLAG has been set, meaning the first letter of this array's name at offset 02H of Register Pair IX is not the letter given with =x, JUMP to 5393H to step over the whole array without printing anything.
52C9
GOSUB to 53A9H to write this array's name and its type declaration character into the output buffer starting at 557FH, reading the two name characters from offsets 02H and 01H of Register Pair IX and the type from offset 00H. The routine returns with Register Pair HL pointing at the first free byte after the name, which is where the opening parenthesis goes.
52CC
LD A,(IX+05H) DD 7E 05
Load Register A with the byte at offset 05H from Register Pair IX, the number of dimensions this array was declared with. The dimension sizes themselves start at offset 06H, two bytes each, stored last dimension first.
52CF
LD (5568H),A 32 68 55
Store Register A, the dimension count just read from offset 05H of Register Pair IX, at 5568H. The odometer reads it back at 5332H to decide whether the subscript it has just printed is the last one and the closing parenthesis is due.
52D2
CP 06H FE 06
Compare Register A, the dimension count from offset 05H of Register Pair IX, against 06H. The counter block at 556AH is ten bytes long and holds five 16-bit counters, so six or more dimensions cannot be tracked. If the count is below 6 the CARRY FLAG is set; if it is 6 or more the NO CARRY FLAG is set.
52D4
PUSH IX DD E5
Save Register Pair IX, which holds the address of this array's header, onto the stack. The pointer is about to be walked forwards and backwards across the dimension size table and the header address is needed again at 5391H to find the next array.
52D6
If the NO CARRY FLAG has been set, meaning the dimension count taken from offset 05H of Register Pair IX is 6 or more and the five counters at 556AH cannot represent it, JUMP to 5388H to append the "* Too many subscripts *" message instead of enumerating the elements.
52D9
ADD A,A 87
ADD Register A, the dimension count, to itself, doubling it. Each dimension size occupies two bytes, so Register A now holds the length in bytes of the dimension size table that follows offset 05H.
52DA
LD B,A 47
Copy Register A, twice the dimension count, into Register B as the count for the pointer advance loop that follows.

Loop Start
Advance Register Pair IX by two bytes per dimension so that offsets 04H and 05H, which addressed the block length and the dimension count on entry, come to address the LAST word of the dimension size table. Because those sizes are stored last dimension first, that last word is the size of the FIRST subscript, which is the one printed first.

52DB
INC IX DD 23
INCrement Register Pair IX, the array pointer, by 1.
52DD
DECrement Register B, which holds twice the dimension count, and LOOP BACK to 52DBH while it is not zero, so that Register Pair IX finishes at the array header address plus twice the dimension count.

Loop End

52DF
Point Register Pair IY at 556AH, the first of the five 16-bit subscript counters. Those ten bytes are not loaded from the file, so they hold whatever was in memory and must be cleared before use.
52E3
LD B,0AH 06 0A
Load Register B with 0AH, ten, the number of bytes in the counter block at 556AH-5573H, as the count for the clearing loop.

Loop Start
Zero the ten byte subscript counter block. This is what gives the unloaded gap in the module image its meaning: the overlay initialises it itself rather than carrying ten zero bytes on disk.

52E5
LD (IY+00H),00H FD 36 00 00
Store 00H at the address in Register Pair IY, which walks 556AH through 5573H, clearing one byte of the subscript counter block.
52E9
INC IY FD 23
INCrement Register Pair IY, the counter block pointer, by 1 to address the next byte of 556AH-5573H.
52EB
DECrement Register B, the remaining byte count, and LOOP BACK to 52E5H while it is not zero, so that all ten bytes of the counter block at 556AH-5573H are cleared.

Loop End

52ED
LD (HL),28H 36 28
Store 28H, ASCII (, at the address in Register Pair HL, the first free byte of the output buffer after the array's name and type character, opening the subscript list.
52EF
INC HL 23
INCrement Register Pair HL, the output buffer pointer, by 1 so that it addresses the byte after the opening parenthesis.
52F0
Point Register Pair IY back at 556AH, the counter for the FIRST subscript, now that the clearing loop has left it at 5574H.
52F4
LD A,01H 3E 01
Load Register A with 01H, the position number of the leftmost subscript, which is where the odometer starts.
52F6
LD (5567H),A 32 67 55
Store Register A, the value 01H, at 5567H, the cell that records which subscript position the odometer is currently working on. A value of zero there means every subscript has rolled over and the array is finished.

Loop Start
The odometer. Each pass through 52F9H deals with one subscript position. The stack carries the array header address pushed at 52D4H and, above it, one saved output buffer position for every subscript position currently open, pushed here.

52F9
PUSH HL E5
Save Register Pair HL, the position in the output buffer at which this subscript's digits begin, onto the stack. Every element printed for this subscript rewinds to that position, and when the subscript rolls over the saved position of the subscript to its left is uncovered.
52FA
LD A,(5567H) 3A 67 55
Fetch the current subscript position from 5567H into Register A. It counts from 1 at the leftmost subscript and is decremented back to zero at 537FH as each subscript rolls over.
52FD
OR A B7
OR Register A, the current subscript position from 5567H, with itself to set the flags. The Z FLAG is set when the position has fallen to zero, which happens only after the leftmost subscript has rolled over and the whole array has been enumerated.
52FE
If the Z FLAG has been set, meaning the subscript position at 5567H is zero and every element of this array has been printed, JUMP to 5391H to recover the array header address and move on to the next array.
5301
LD L,(IX+04H) DD 6E 04
Load Register L with the byte at offset 04H from Register Pair IX, the low half of the declared size of the dimension the odometer is currently on. Register Pair IX was advanced by twice the dimension count at 52DBH and is stepped back two bytes at 533CH for each subscript to the right, so offsets 04H and 05H always address the size word of the current subscript.
5304
LD H,(IX+05H) DD 66 05
Load Register H with the byte at offset 05H from Register Pair IX, the high half of the declared size of the current dimension, so that Register Pair HL now holds that size. Level II stores the number of elements, which is the declared subscript bound plus one.
5307
LD E,(IY+00H) FD 5E 00
Load Register E with the byte at offset 00H from Register Pair IY, the low half of the counter for the current subscript, held in the block at 556AH-5573H.
530A
LD D,(IY+01H) FD 56 01
Load Register D with the byte at offset 01H from Register Pair IY, the high half of the counter for the current subscript, so that Register Pair DE now holds the subscript value about to be printed.
530D
OR A B7
OR Register A, which holds the subscript position fetched from 5567H, with itself. The value is not used, but the instruction clears the CARRY FLAG so that the sixteen bit subtract with carry that follows performs a plain subtraction.
530E
SBC HL,DE ED 52
SUBtract Register Pair DE, the current counter value from the block at Register Pair IY, from Register Pair HL, the dimension size taken from offsets 04H and 05H of Register Pair IX. The Z FLAG is set when the counter has reached the element count and this subscript has run out of values.
5310
If the Z FLAG has been set, meaning the counter at Register Pair IY equals the dimension size at offsets 04H and 05H of Register Pair IX, JUMP to 536CH to reset this counter and carry into the subscript on its left.
5313
PUSH DE D5
Save Register Pair DE, the current subscript value taken from the counter block at Register Pair IY, onto the stack so that it can be transferred to Register Pair HL, which is what the decimal converter takes its argument in.
5314
POP HL E1
Restore into Register Pair HL the value just pushed from Register Pair DE, the subscript value to be printed. Register Pair DE still holds the same value.
5315
INC DE 13
INCrement Register Pair DE, the copy of the subscript value, by 1, forming the value the counter will hold on the next visit to this subscript.
5316
LD (IY+00H),E FD 73 00
Store Register E, the low half of the incremented subscript value, at offset 00H from Register Pair IY, the low byte of the counter for the current subscript.
5319
LD (IY+01H),D FD 72 01
Store Register D, the high half of the incremented subscript value, at offset 01H from Register Pair IY, the high byte of the counter for the current subscript, so the counter is left ready for the next element.
531C
GOSUB to 53EFH to convert Register Pair HL, the subscript value being printed, into five ASCII decimal digits with leading zeros in the buffer at 5575H-5579H. The routine returns with Register Pair DE pointing at 5575H, the most significant digit.
531F
LD B,04H 06 04
Load Register B with 04H, the greatest number of leading zeros that may be discarded from the five digit field, so that at least one digit always survives and a subscript of zero prints as a single 0.

Loop Start
Skip leading zeros in the five digit field at 5575H-5579H by advancing Register Pair DE past them.

5321
LD A,(DE) 1A
Fetch the digit at the address in Register Pair DE, which walks the five digit field at 5575H-5579H from its most significant end, into Register A.
5322
CP 30H FE 30
Compare Register A, the digit just fetched from the field at Register Pair DE, against 30H, ASCII 0. If they are equal the Z FLAG is set and the digit is a leading zero; otherwise the NZ FLAG is set.
5324
If the NZ FLAG has been set, meaning the character at Register Pair DE is a significant digit, JUMP to 5329H with Register Pair DE pointing at the first digit that will actually be printed.
5326
INC DE 13
INCrement Register Pair DE, the pointer into the five digit field at 5575H-5579H, by 1 to step past the leading zero just examined.
5327
DECrement Register B, the count of leading zeros still allowed to be discarded, and LOOP BACK to 5321H while it is not zero, so that at most four of the five digits can be skipped.

Loop End

5329
POP HL E1
Restore Register Pair HL from the stack with the value pushed at 52F9H, the position in the output buffer at which this subscript's digits begin, so that each element rewrites the field from the same place.
532A
PUSH HL E5
Save Register Pair HL, that same output buffer position, back onto the stack so that the entry remains available for the next element. Together with the previous instruction this is a peek at the top of the stack rather than a removal.
532B
GOSUB to 53D6H to copy the digits at Register Pair DE, the first significant digit of the field at 5575H-5579H, into the output buffer at Register Pair HL. The copy stops on the 00H at 557AH that closes the field.
532E
LD A,(5567H) 3A 67 55
Fetch the current subscript position from 5567H into Register A, counting from 1 at the leftmost subscript.
5331
LD C,A 4F
Copy Register A, the current subscript position from 5567H, into Register C so that Register A is free to receive the dimension count.
5332
LD A,(5568H) 3A 68 55
Fetch the array's dimension count from 5568H into Register A, where 52CFH stored it from offset 05H of the array header.
5335
SUB C 91
SUBtract Register C, the current subscript position, from Register A, the dimension count from 5568H. The Z FLAG is set when the subscript just written was the rightmost one and the subscript list is complete.
5336
If the Z FLAG has been set, meaning the subscript position from 5567H equals the dimension count from 5568H and every subscript has been written, JUMP to 5354H to close the parenthesis and print the element.
5339
LD (HL),2CH 36 2C
Store 2CH, ASCII ,, at the address in Register Pair HL, the byte in the output buffer just past the digits written for this subscript, separating it from the subscript to its right.
533B
INC HL 23
INCrement Register Pair HL, the output buffer pointer, by 1 so that it addresses the byte at which the next subscript's digits will begin.
533C
DEC IX DD 2B
DECrement Register Pair IX, the array pointer, by 1.
533E
DEC IX DD 2B
DECrement Register Pair IX by 1 again, so that offsets 04H and 05H now address the previous entry in the dimension size table. Because those sizes are stored last dimension first, stepping DOWN through the table moves RIGHT through the subscript list.
5340
INC IY FD 23
INCrement Register Pair IY, the counter block pointer, by 1.
5342
INC IY FD 23
INCrement Register Pair IY by 1 again, so that offsets 00H and 01H now address the next 16-bit counter in the block at 556AH-5573H, the one belonging to the subscript to the right.
5344
LD A,(5567H) 3A 67 55
Fetch the current subscript position from 5567H into Register A so that it can be advanced.
5347
INC A 3C
INCrement Register A, the subscript position, by 1 to name the subscript to the right of the one just written.
5348
LD (5567H),A 32 67 55
Store Register A, the advanced subscript position, back at 5567H so that the next pass through the odometer works on the next subscript.
534B
GOSUB to 5420H to scan the keyboard. The routine holds the listing while the pause key, code 60H, is pressed and returns with the Z FLAG set when the key read was 01H, the BREAK key.
534E
If the Z FLAG has been set, meaning the keyboard poll at 5420H saw the BREAK key, JUMP to the exit stub at 5217H to abandon the dump and reload BASIC/CMD.
5351
LOOP BACK to 52F9H to save the new output buffer position and start work on the subscript to the right.

Complete Subscript List
Reached from 5336H when the rightmost subscript has just been written. The reference is closed and handed to the interpreter, then the odometer resumes at the same subscript position with the counter one higher.

5354
LD (HL),29H 36 29
Store 29H, ASCII ), at the address in Register Pair HL, the byte in the output buffer just past the last subscript's digits, closing the subscript list.
5356
INC HL 23
INCrement Register Pair HL, the output buffer pointer, by 1 so that it addresses the byte after the closing parenthesis.
5357
Point Register Pair DE at 5529H, the four characters space, equals sign, space and quotation mark, terminated by the 00H at 552DH. The quotation mark closes the string literal that the one at 557BH opened.
535A
GOSUB to 53D6H to append the four characters at Register Pair DE, 5529H, to the output buffer at Register Pair HL, stopping on the 00H at 552DH.
535D
LD B,3DH 06 3D
Load Register B with 3DH, ASCII =, as the stop character for the copier at 53D8H, so that the copy about to run takes the array reference but not the equals sign that follows it in the buffer.
535F
LD DE,557FH 11 7F 55
Point Register Pair DE at 557FH, the START of the output buffer, which holds the array's name, its type character and the complete parenthesised subscript list. The buffer is read back into itself so that the whole reference appears a second time outside the closing quotation mark, where the interpreter will evaluate it.
5362
GOSUB to 53D8H to copy from (DE), the start of the buffer at 557FH, to (HL), its current end, stopping at the equals sign held in Register B. The characters copied are the array name, the type character, the subscript list and the blank that follows it.
5365
GOSUB to 5405H to write the 00H terminator at the address in Register Pair HL, overwriting the copied equals sign, and to hand the finished fragment at 557BH to the Level II ROM PRINT loop, which evaluates the subscripted reference and prints the element's value.
5368
POP HL E1
Restore Register Pair HL from the stack with the value pushed at 52F9H, the position in the output buffer at which this subscript's digits begin, so that the next element of this subscript is written over the same field.
5369
LOOP BACK to 52F9H to save that position again and print the next element of the current subscript.

Subscript Rollover
Reached from 5310H when the counter for the current subscript has reached the dimension's element count. The counter is reset, the pointers step back to the subscript on the left, and the buffer position saved for the exhausted subscript is discarded so that the enclosing one is uncovered.

536C
LD (IY+00H),00H FD 36 00 00
Store 00H at offset 00H from Register Pair IY, the low byte of the counter for the subscript that has just run out, resetting it for the next time the subscript to its left advances.
5370
LD (IY+01H),00H FD 36 01 00
Store 00H at offset 01H from Register Pair IY, the high byte of that same counter, completing the reset to zero.
5374
DEC IY FD 2B
DECrement Register Pair IY, the counter block pointer, by 1.
5376
DEC IY FD 2B
DECrement Register Pair IY by 1 again, so that offsets 00H and 01H address the counter of the subscript to the LEFT of the one that has just rolled over.
5378
INC IX DD 23
INCrement Register Pair IX, the array pointer, by 1.
537A
INC IX DD 23
INCrement Register Pair IX by 1 again, so that offsets 04H and 05H address the dimension size belonging to the subscript on the left, undoing one of the pairs of decrements made at 533CH.
537C
LD A,(5567H) 3A 67 55
Fetch the current subscript position from 5567H into Register A so that it can be stepped back to the left.
537F
DEC A 3D
DECrement Register A, the subscript position, by 1. When the leftmost subscript rolls over this produces zero, which is the value 52FDH tests to end the array.
5380
LD (5567H),A 32 67 55
Store Register A, the subscript position stepped one to the left, back at 5567H.
5383
POP HL E1
Restore Register Pair HL from the stack, discarding the output buffer position that was saved for the subscript which has just rolled over; that field is being abandoned.
5384
POP HL E1
Restore Register Pair HL from the stack again, recovering the output buffer position of the subscript to the left, which is where the rebuilt subscript list resumes. When the leftmost subscript rolls over there is no such entry left and this instruction takes back the array header address pushed at 52D4H, which the PUSH HL at 52F9H immediately puts back for the POP IX at 5391H to collect.
5385
LOOP BACK to 52F9H to save the recovered position and continue with the subscript on the left, or, when the position at 5567H has reached zero, to fall through to the end of array path.

Too Many Subscripts
Reached from 52D6H when the array was declared with six or more dimensions, which the five counters at 556AH cannot enumerate. The array's name is already in the buffer and the message is simply appended to it.

5388
Point Register Pair DE at 5510H, the text "* Too many subscripts *)" which is terminated by the 00H at 5528H. The closing parenthesis at 5527H stands in for the subscript list that is not being generated.
538B
GOSUB to 53D6H to append the message at Register Pair DE, 5510H, to the output buffer at Register Pair HL, which the name builder left pointing just past the array's name. The copy stops on the 00H at 5528H.
538E
GOSUB to 5405H to terminate the line and hand it to the Level II ROM PRINT loop. The text after the closing quotation mark is not a variable reference in this case, so the ROM prints the literal and finds nothing further to evaluate.

Advance To The Next Array
5391H is reached from 52FEH when the array has been fully enumerated and from 538EH after the too many subscripts message; 5393H is reached from 52C6H when the =x restriction rejected the array, in which case the header address is still in Register Pair IX and no stacked copy has to be recovered.

5391
POP IX DD E1
Restore Register Pair IX from the stack with the array header address that was pushed at 52D4H and passed back down through the rollover path, so that the header's own offsets can be read again.
5393
LD E,(IX+03H) DD 5E 03
Load Register E with the byte at offset 03H from Register Pair IX, the low half of the array's block length, which counts the dimension size table and all of the element data but not the five byte prefix.
5396
LD D,(IX+04H) DD 56 04
Load Register D with the byte at offset 04H from Register Pair IX, the high half of the array's block length, so that Register Pair DE holds the whole 16-bit length.
5399
LD BC,0005H 01 05 00
Load Register Pair BC with 0005H, the size of the array header prefix - the type byte, the two name characters and the two byte block length - which the block length in Register Pair DE does not include.
539C
ADD IX,BC DD 09
ADD Register Pair BC, the five byte prefix size, to Register Pair IX, the array header address, so that Register Pair IX addresses the dimension count byte plus one.
539E
ADD IX,DE DD 19
ADD Register Pair DE, the block length taken from offsets 03H and 04H of the header, to Register Pair IX, so that Register Pair IX now addresses the type byte of the next array header, or STREND 40FDH if this was the last array.
53A0
GOSUB to 5420H to scan the keyboard. The routine holds the listing while the pause key, code 60H, is pressed and returns with the Z FLAG set when the key read was 01H, the BREAK key.
53A3
If the Z FLAG has been set, meaning the keyboard poll at 5420H saw the BREAK key, JUMP to the exit stub at 5217H to abandon the dump and reload BASIC/CMD.

Loop End

53A6
LOOP BACK to 52B4H to reload the end of table address from STREND 40FDH and test the advanced Register Pair IX against it, so that the next array can be handled.

53A9H - Build The Variable Name And Type Character

Called from 5256H for a scalar and from 52C9H for an array. Register Pair IX addresses the entry's type byte. In a Level II BASIC variable entry the two name characters are stored in the order second character then first character, at offsets 01H and 02H, so this routine writes offset 02H first. The type declaration character is derived arithmetically from the type byte rather than from a table. Exit is with Register Pair HL pointing at the first free byte after what was written.

53A9
LD HL,557FH 21 7F 55
Point Register Pair HL at 557FH, the start of the output buffer. That address is one past the end of the module image, so the buffer is uninitialised RAM which the overlay simply claims; the three blanks and the quotation mark that precede it at 557BH-557EH are part of the image.
53AC
LD A,(IX+02H) DD 7E 02
Load Register A with the byte at offset 02H from Register Pair IX, the FIRST character of the variable's name, which is stored after the second character in a Level II variable entry.
53AF
AND 7FH E6 7F
AND Register A, the first name character, with 7FH to clear bit 7. That bit is the user defined function marker set by BASIC/CMD's function reference parser at 55EBH and is not part of the printable name.
53B1
LD (HL),A 77
Store Register A, the first name character with its marker bit removed, at the address in Register Pair HL, which is 557FH, the first byte of the output buffer.
53B2
INC HL 23
INCrement Register Pair HL, the output buffer pointer, by 1 to address the byte after the first name character.
53B3
LD A,(IX+01H) DD 7E 01
Load Register A with the byte at offset 01H from Register Pair IX, the SECOND character of the variable's name. Level II identifies a variable by its first two characters only, and a one character name carries 00H here.
53B6
OR A B7
OR Register A, the second name character, with itself to set the flags. The Z FLAG is set when the byte is 00H and the name is a single character.
53B7
If the Z FLAG has been set, meaning the second name character at offset 01H of Register Pair IX is 00H, JUMP to 53BCH so that nothing is written for it and the name stays one character long.
53BA
LD (HL),A 77
Store Register A, the second name character, at the address in Register Pair HL, the second byte of the output buffer.
53BB
INC HL 23
INCrement Register Pair HL, the output buffer pointer, by 1 to address the byte at which the type declaration character goes.
53BC
LD A,(IX+00H) DD 7E 00
Load Register A with the byte at offset 00H from Register Pair IX, the variable's type byte: 02H integer, 03H string, 04H single precision or 08H double precision.
53BF
CP 08H FE 08
Compare Register A, the type byte from offset 00H of Register Pair IX, against 08H, the double precision code. If they are equal the Z FLAG is set; otherwise the NZ FLAG is set.
53C1
If the NZ FLAG has been set, meaning the type byte is not 08H, JUMP to 53C8H to test the remaining types.
53C4
RRCA 0F
Rotate Register A right. Register A holds 08H, so the result is 04H. Bit 0 was clear, so the CARRY FLAG is cleared and nothing rotates round into bit 7.
53C5
JUMP to 53CFH with Register A holding 04H, the value that the subtraction there turns into 23H, ASCII #, the double precision declaration character.
53C8
CP 04H FE 04
Compare Register A, the type byte from offset 00H of Register Pair IX, against 04H, the single precision code. If they are equal the Z FLAG is set; otherwise the NZ FLAG is set.
53CA
If the NZ FLAG has been set, meaning the type byte is 02H or 03H, JUMP to 53CFH with that value unchanged: 03H becomes 24H, ASCII $, and 02H becomes 25H, ASCII %.
53CD
INC A 3C
INCrement Register A, which holds 04H, by 1.
53CE
INC A 3C
INCrement Register A by 1 again, giving 06H, the value that the subtraction at 53D2H turns into 21H, ASCII !, the single precision declaration character.
53CF
LD B,A 47
Copy Register A, which now holds 02H for an integer, 03H for a string, 06H for single precision or 04H for double precision, into Register B so that it can be subtracted from the constant.
53D0
LD A,27H 3E 27
Load Register A with 27H, ASCII ', the constant the four declaration characters are counted back from. Subtracting 2, 3, 4 and 6 gives 25H, 24H, 23H and 21H, which are %, $, # and ! respectively.
53D2
SUB B 90
SUBtract Register B, the adjusted type value, from Register A, which holds 27H, producing the type declaration character for this variable.
53D3
LD (HL),A 77
Store Register A, the type declaration character, at the address in Register Pair HL, the byte in the output buffer just after the name.
53D4
INC HL 23
INCrement Register Pair HL, the output buffer pointer, by 1 so that it addresses the first free byte after the complete name.
53D5
RET C9
RETurn to the caller, at 5256H for a scalar or 52C9H for an array, with Register Pair HL pointing at the first free byte of the output buffer.

53D6H - The String Copier

Two entries into one loop. Both copy from (DE) to (HL) and stop on a 00H byte. The 53D8H entry additionally takes a stop character in Register B, which is honoured only when the copy is not inside a quoted string; Register C carries the in-string state and toggles between 00H and 22H on every quotation mark encountered. The stopping character is written to the destination before it is tested, but Register Pair HL is not advanced past it, so the caller may overwrite it. Exit is with Register Pair HL pointing at the first free byte.

53D6
LD B,00H 06 00
Load Register B with 00H, so that this entry has no additional stop character. A stored byte is never zero, because a zero byte ends the copy before the comparison is reached, so the test against Register B can never succeed on this path.
53D8
LD C,00H 0E 00
Load Register C with 00H, clearing the in-string flag so that the copy begins outside a quoted literal. Callers enter here with the stop character already in Register B: 3AH at 526CH, and 3DH at 5291H and 5362H.

Loop Start

53DA
LD A,(DE) 1A
Fetch the next source byte from the address in Register Pair DE into Register A.
53DB
OR A B7
OR Register A, the source byte just fetched, with itself to set the flags. The Z FLAG is set when the byte is 00H, which every string this routine reads uses as its terminator.
53DC
RET Z C8
If the Z FLAG has been set, meaning the source byte at Register Pair DE is 00H, RETurn to the caller with Register Pair HL pointing at the first byte not written.
53DD
LD (HL),A 77
Store Register A, the source byte, at the address in Register Pair HL, the current destination. This happens before the stop character is tested, so a stopping character is written even though the pointer is not advanced past it.
53DE
INC C 0C
INCrement Register C, the in-string flag, by 1.
53DF
DEC C 0D
DECrement Register C by 1 again, restoring its value. The pair exists solely to set the flags from Register C without disturbing Register A: the Z FLAG is set when Register C is 00H and the copy is outside a quoted literal.
53E0
If the NZ FLAG has been set, meaning Register C is not zero and the copy is inside a quoted literal, JUMP to 53E4H to skip the stop character test, so that a colon or an equals sign inside a string is copied like any other character.
53E2
CP B B8
Compare Register A, the source byte just stored, against Register B, the caller's stop character. If they are equal the Z FLAG is set; otherwise the NZ FLAG is set.
53E3
RET Z C8
If the Z FLAG has been set, meaning the byte just stored is the caller's stop character and it was outside a quoted literal, RETurn with Register Pair HL still pointing at that byte so the caller can overwrite it.
53E4
CP 22H FE 22
Compare Register A, the source byte just stored, against 22H, the quotation mark. If they are equal the Z FLAG is set; otherwise the NZ FLAG is set.
53E6
If the NZ FLAG has been set, meaning the byte is not a quotation mark, JUMP to 53EAH to advance the pointers and leave the in-string flag alone.
53E8
XOR C A9
Exclusive-OR Register A, which holds 22H, with Register C, the in-string flag, which is either 00H or 22H. The result is 22H when the flag was clear and 00H when it was set, which is the toggle.
53E9
LD C,A 4F
Copy Register A, the toggled value, back into Register C, so the in-string flag now records that the copy has entered or left a quoted literal.
53EA
INC DE 13
INCrement Register Pair DE, the source pointer, by 1 to address the next byte to be copied.
53EB
INC HL 23
INCrement Register Pair HL, the destination pointer, by 1 to address the next byte to be written.

Loop End

53EC
LOOP BACK to 53DAH to fetch and copy the next source byte.

53EFH - Convert A Subscript To Five Decimal Digits

Called from 531CH with the subscript value in Register Pair HL. The digits are produced least significant first by repeated division by ten through the resident @DIV vector, and are written backwards into the five byte field at 5575H-5579H, which the image ships as five blanks. The 00H at 557AH terminates the field for the string copier. Leading zeros are not suppressed here; the caller skips them at 5321H.

53EF
Point Register Pair DE at 5579H, the LAST byte of the five digit field, because the digits come out of the division least significant first and the field is filled backwards.
53F2
LD C,05H 0E 05
Load Register C with 05H, the number of digit positions in the field at 5575H-5579H, as the loop count.

Loop Start

53F4
LD A,0AH 3E 0A
Load Register A with 0AH, ten, the divisor that @DIV takes in Register A.
53F6
GOSUB to the resident @DIV vector at 44C4H, which divides Register Pair HL, the remaining part of the subscript value, by Register A, which holds ten. It returns the quotient in Register Pair HL and the remainder, the next digit, in Register A.
53F9
ADD A,30H C6 30
ADD 30H to Register A, the remainder returned by @DIV, converting the binary digit 0 to 9 into the ASCII character 0 to 9.
53FB
LD (DE),A 12
Store Register A, the ASCII digit, at the address in Register Pair DE, which walks the five digit field at 5575H-5579H from its last byte downwards.
53FC
DEC DE 1B
DECrement Register Pair DE, the digit field pointer, by 1 to address the next more significant position.
53FD
DEC C 0D
DECrement Register C, the count of digit positions still to fill, by 1 and set the flags from the result.

Loop End

53FE
If the NZ FLAG has been set, meaning Register C has not yet reached zero and digit positions remain, LOOP BACK to 53F4H to divide the quotient in Register Pair HL by ten again.
5401
Point Register Pair DE at 5575H, the first and most significant digit of the completed field, which is the value the caller at 531CH expects to receive.
5404
RET C9
RETurn to the caller at 531CH with the five digit field filled and Register Pair DE addressing its most significant digit.

5405H - Print The Built Line Through The ROM

Called from 5294H for a scalar, from 5365H for an array element and from 538EH for the too many subscripts message. By this point the buffer from 557BH holds a fragment of BASIC source: a quotation mark, three blanks, the variable's name, the characters space equals space, a closing quotation mark, and then the same reference again as live text. Handing that to the interpreter's PRINT loop is what makes the value appear, and is why the overlay needs no formatter of its own.

5405
LD (HL),00H 36 00
Store 00H at the address in Register Pair HL, the byte at which the last copy stopped, terminating the built line. On the two paths that arrive from the copier at 53D8H this overwrites the equals sign that the copier stored but did not step past; PRINT treats a 00H as the end of the statement.
5407
PUSH IY FD E5
Save Register Pair IY, which the array dump uses to address the subscript counter block at 556AH-5573H, onto the stack. The ROM makes no promise about it.
5409
PUSH IX DD E5
Save Register Pair IX, the walking pointer into the scalar or array table, onto the stack for the same reason.
540B
Point Register Pair HL at 557BH, the quotation mark that opens the built fragment, which is the text pointer the ROM PRINT loop reads its argument list from. The three blanks at 557CH-557EH follow it and become the indent inside the printed literal.
540E
LD A,(5569H) 3A 69 55
Fetch the output device code from 5569H into Register A. The parser leaves 00H there for *DO and 01H for *PR, which are exactly the values Level II BASIC uses in PRTFLG 409CH for the video display and the line printer.
5411
GOSUB to the Level II ROM at 2069H, two bytes into LPRINT at 2067H. LPRINT itself loads Register A with 01H and then falls into this instruction, which stores Register A at PRTFLG 409CH and drops into the common PRINT processing path at 206CH. Entering at 2069H therefore selects the device from the value already in Register A, and the ROM then evaluates the argument list at Register Pair HL, printing the quoted literal and the value of the variable reference that follows it.
5414
POP IX DD E1
Restore Register Pair IX from the stack, so that the walking pointer into the scalar or array table is intact after the ROM PRINT loop has run.
5416
POP IY FD E1
Restore Register Pair IY from the stack, so that the pointer into the subscript counter block at 556AH-5573H is intact.
5418
RET C9
RETurn to the caller at 5294H, 5365H or 538EH with the line printed.

5419H - Compare The Walking Pointer Against The Table End

Called from 5245H with the value from ARYTAB 40FBH in Register Pair DE and from 52B8H with the value from STREND 40FDH. Register Pair IX cannot be compared directly, so it is moved through the stack into Register Pair HL first. Only the flags matter to the callers.

5419
PUSH IX DD E5
Save Register Pair IX, the walking pointer into the scalar or array table, onto the stack so that its value can be recovered into a register pair the sixteen bit subtract can use.
541B
POP HL E1
Restore into Register Pair HL the value just pushed from Register Pair IX, the current table position.
541C
OR A B7
OR Register A with itself. Register A holds whatever the caller left in it and the value is not used; the instruction is here to clear the CARRY FLAG so that the subtract with carry that follows performs a plain subtraction.
541D
SBC HL,DE ED 52
SUBtract Register Pair DE, the end of table address supplied by the caller from ARYTAB 40FBH or STREND 40FDH, from Register Pair HL, the current table position. The Z FLAG is set when the two are equal and the walk is finished.
541F
RET C9
RETurn to the caller at 5245H or 52B8H with the flags set from the comparison. Register Pair IX is unchanged; Register Pair HL is destroyed, which is harmless because both callers reload it before it is next used.

5420H - Keyboard Poll For Pause And BREAK

Called after every printed line, from 52A1H in the scalar walk and from 534BH and 53A0H in the array walk. It gives the user the two controls a long listing needs: shift and at-sign holds the display, and BREAK abandons the dump. Both index registers are preserved because the ROM keyboard routines make no promises about them.

5420
PUSH IX DD E5
Save Register Pair IX, the walking pointer into the scalar or array table, onto the stack before the ROM is entered.
5422
PUSH IY FD E5
Save Register Pair IY, the pointer into the subscript counter block at 556AH-5573H, onto the stack for the same reason.
5424
GOSUB to the ROM keyboard routine @KBD at 002BH, which scans the keyboard matrix once through the keyboard device control block at 4015H and returns the character in Register A, or 00H when no key is down. It does not wait.
5427
CP 60H FE 60
Compare Register A, the character returned by @KBD, against 60H, the code produced by shift and at-sign, which is the standard TRS-80 pause key. If they are equal the Z FLAG is set; otherwise the NZ FLAG is set.
5429
If the NZ FLAG has been set, meaning the key read was not the pause key, JUMP to 5432H to test it against BREAK instead.

Loop Start
The pause key was seen. The routine now waits for a key and keeps waiting as long as the pause key is what comes back, so the listing resumes on any other key.

542B
GOSUB to the ROM routine $KEY at 0049H, which calls @KBD 002BH in a loop until a key is actually pressed and returns that character in Register A. Unlike @KBD it does wait.
542E
CP 60H FE 60
Compare Register A, the character returned by $KEY, against 60H, the pause key. If they are equal the Z FLAG is set; otherwise the NZ FLAG is set.

Loop End

5430
If the Z FLAG has been set, meaning the key that was pressed is the pause key again, LOOP BACK to 542BH and keep waiting, so that holding the pause key down does not immediately release the pause.
5432
CP 01H FE 01
Compare Register A, the character last read from the keyboard, against 01H, the code the Model I keyboard driver returns for the BREAK key. If they are equal the Z FLAG is set, which is the condition all three callers test.
5434
POP IY FD E1
Restore Register Pair IY from the stack, so that the pointer into the subscript counter block is intact. POP does not disturb the flags set by the comparison.
5436
POP IX DD E1
Restore Register Pair IX from the stack, so that the walking pointer into the scalar or array table is intact, again without disturbing the flags.
5438
RET C9
RETurn to the caller at 52A1H, 534BH or 53A0H with the Z FLAG set when the BREAK key was pressed.

5439H - Display A String On The Selected Device

Called from 5208H with an empty string, from 523AH and 52ADH with the two section headings and from 5281H with a user defined function's line. Register Pair HL points at a string terminated by a 0DH, which both service calls display. The routine chooses between them from the device byte at 5569H, holding the flags from that test across the first call.

5439
LD A,(5569H) 3A 69 55
Fetch the output device code from 5569H into Register A. It is 00H for the video display, which is the default, and 01H when the *PR parameter selected the line printer at 546FH.
543C
OR A B7
OR Register A, the device code from 5569H, with itself to set the flags. The Z FLAG is set for the video display and the NZ FLAG for the printer.
543D
PUSH IX DD E5
Save Register Pair IX, the walking pointer into the scalar or array table, onto the stack. The resident display routines do not preserve it.
543F
PUSH AF F5
Save Register A and the flags onto the stack. The flags carry the device decision and the first conditional call would destroy them, so they are stored and recovered between the two calls.
5440
If the Z FLAG has been set, meaning the device byte at 5569H is 00H, GOSUB to the resident @DSPLY vector at 4467H to display the 0DH terminated string at Register Pair HL on the video display.
5443
POP AF F1
Restore Register A and the flags from the stack, recovering the device decision that the call to @DSPLY would otherwise have destroyed.
5444
If the NZ FLAG has been set, meaning the device byte at 5569H is 01H, GOSUB to the resident @PRINT vector at 446AH to send the same 0DH terminated string at Register Pair HL to the line printer instead.
5447
POP IX DD E1
Restore Register Pair IX from the stack, so that the walking pointer into the scalar or array table survives the display.
5449
RET C9
RETurn to the caller at 5208H, 523AH, 52ADH or 5281H.

544AH - The Command Line Parameter Parser

Called from 5205H with Register Pair HL at 4319H, one byte into INBUF$ 4318H, where BASIC/CMD's command string copier at 54E1H left the text of the CMD"V" argument with a 0DH terminator. The parser accepts the four documented forms in the order the manual gives them: an optional *DO or *PR device selection first, then any number of -S, -A and =x parameters. Every failure leaves through one of the two error exits and never returns to the caller.

544A
GOSUB to 54B2H to step Register Pair HL over any blanks and return the first non-blank character of the command tail in Register A, with the Z FLAG set if that character is the 0DH terminator.
544D
RET Z C8
If the Z FLAG has been set, meaning the command tail is empty, RETurn to 5208H with Register Pair HL pointing at the 0DH and every setting left at its default: video output, both dumps enabled and no name restriction.
544E
CP 2AH FE 2A
Compare Register A, the first non-blank character of the tail, against 2AH, ASCII *, which introduces a device specification. If they are equal the Z FLAG is set; otherwise the NZ FLAG is set.
5450
If the NZ FLAG has been set, meaning the character is not an asterisk and no device was named, JUMP to 5473H to look for the switch parameters instead. The video display therefore remains selected.
5452
GOSUB to 54BBH to advance Register Pair HL by one and return the next character in Register A with bit 5 cleared, so that a lower case device name is folded to upper case.
5455
CP 44H FE 44
Compare Register A, the character after the asterisk, against 44H, ASCII D, the first letter of the *DO video device. If they are equal the Z FLAG is set; otherwise the NZ FLAG is set.
5457
If the NZ FLAG has been set, meaning the character after the asterisk is not D, JUMP to 5462H to test it against the printer device name instead.
5459
GOSUB to 54BBH to advance Register Pair HL by one and return the next character in Register A folded to upper case, which should be the second letter of the device name.
545C
CP 4FH FE 4F
Compare Register A, the second letter of the device name, against 4FH, ASCII O, completing the name *DO. If they are equal the Z FLAG is set; otherwise the NZ FLAG is set.
545E
If the Z FLAG has been set, meaning the device named is *DO, JUMP to 5472H to step past the name and carry on. Nothing is stored, because 00H at 5569H already selects the video display.
5460
JUMP to 54A8H to display "Invalid output device!" and leave. The device name began *D but did not continue with an O.
5462
CP 50H FE 50
Compare Register A, the character after the asterisk, against 50H, ASCII P, the first letter of the *PR printer device. If they are equal the Z FLAG is set; otherwise the NZ FLAG is set.
5464
If the NZ FLAG has been set, meaning the character after the asterisk is neither D nor P, JUMP to 54A8H to display "Invalid output device!" and leave.
5466
GOSUB to 54BBH to advance Register Pair HL by one and return the next character in Register A folded to upper case, which should be the second letter of the printer device name.
5469
CP 52H FE 52
Compare Register A, the second letter of the device name, against 52H, ASCII R, completing the name *PR. If they are equal the Z FLAG is set; otherwise the NZ FLAG is set.
546B
If the NZ FLAG has been set, meaning the device name began *P but did not continue with an R, JUMP to 54A8H to display "Invalid output device!" and leave.
546D
LD A,01H 3E 01
Load Register A with 01H, the code for the line printer. It is the value LDOS uses to pick @PRINT 446AH at 5444H and the value Level II BASIC uses in PRTFLG 409CH for the printer.
546F
LD (5569H),A 32 69 55
Store Register A, the value 01H, at 5569H, the output device byte, so that every heading, every dumped line and every user defined function goes to the line printer instead of the video display.
5472
INC HL 23
INCrement Register Pair HL, the command tail pointer, by 1 to step past the last character of the parameter that has just been accepted.

Parameter Loop Start
Every accepted switch comes back here, so -S, -A and =x may be given in any order and any number of times, separated by blanks.

5473
GOSUB to 54B2H to step Register Pair HL over any blanks and return the next non-blank character of the tail in Register A, with the Z FLAG set if that character is the 0DH terminator.
5476
RET Z C8
If the Z FLAG has been set, meaning the end of the command tail has been reached, RETurn to 5208H with Register Pair HL pointing at the 0DH terminator, which is the empty string that 5208H then displays as a single carriage return.
5477
CP 3DH FE 3D
Compare Register A, the next non-blank character, against 3DH, ASCII =, which introduces the single letter name restriction. If they are equal the Z FLAG is set; otherwise the NZ FLAG is set.
5479
If the Z FLAG has been set, meaning an equals sign was found, JUMP to 5496H to read and validate the letter that follows it.
547B
CP 2DH FE 2D
Compare Register A, the next non-blank character, against 2DH, ASCII -, which introduces the two restriction switches. If they are equal the Z FLAG is set; otherwise the NZ FLAG is set.
547D
If the NZ FLAG has been set, meaning the character is neither an equals sign nor a hyphen and so cannot begin any documented parameter, JUMP to 54A4H to display "Parameter error!" and leave.
547F
GOSUB to 54BBH to advance Register Pair HL by one and return the switch letter in Register A folded to upper case.
5482
CP 53H FE 53
Compare Register A, the switch letter, against 53H, ASCII S, the switch that restricts the dump to scalars. If they are equal the Z FLAG is set; otherwise the NZ FLAG is set.
5484
If the NZ FLAG has been set, meaning the switch letter is not S, JUMP to 548CH to test it against the array switch instead.
5486
XOR A AF
Set Register A to ZERO and clear all flags, ready to disable one of the two dumps.
5487
LD (5212H),A 32 12 52
Self-Modifying Code
Store 00H at 5212H, which is the operand of the LD A,01H at 5211H. That instruction feeds the CALL NZ,52AAH at 5214H, so writing zero there suppresses the array dump entirely and leaves only the scalars, which is what -S asks for.
548A
LOOP BACK to 5472H to step past the switch letter and look for another parameter.
548C
CP 41H FE 41
Compare Register A, the switch letter, against 41H, ASCII A, the switch that restricts the dump to array variables. If they are equal the Z FLAG is set; otherwise the NZ FLAG is set.
548E
If the NZ FLAG has been set, meaning the letter after the hyphen is neither S nor A, JUMP to 54A4H to display "Parameter error!" and leave.
5490
XOR A AF
Set Register A to ZERO and clear all flags, ready to disable the other dump.
5491
LD (520CH),A 32 0C 52
Self-Modifying Code
Store 00H at 520CH, which is the operand of the LD A,01H at 520BH. That instruction feeds the CALL NZ,5237H at 520EH, so writing zero there suppresses the scalar dump entirely and leaves only the arrays, which is what -A asks for.
5494
LOOP BACK to 5472H to step past the switch letter and look for another parameter.
5496
GOSUB to 54BBH to advance Register Pair HL by one and return the character after the equals sign in Register A with bit 5 cleared, so a lower case letter is folded to upper case before it is stored.
5499
LD (5574H),A 32 74 55
Store Register A, the restriction letter, at 5574H. It is stored before it is validated, which does no harm because a failed validation never returns to the dumps. The two walks test it at 5249H and 52BCH against the first character of each variable's name.
549C
CP 41H FE 41
Compare Register A, the restriction letter just stored at 5574H, against 41H, ASCII A. If the letter is below A the CARRY FLAG is set; if it is A or above the NO CARRY FLAG is set.
549E
If the CARRY FLAG has been set, meaning the character after the equals sign sorts below A and is not a letter, JUMP to 54A4H to display "Parameter error!" and leave.
54A0
CP 5BH FE 5B
Compare Register A, the restriction letter, against 5BH, the character immediately above Z. If the letter is Z or below the CARRY FLAG is set; if it is above the NO CARRY FLAG is set.
54A2
If the CARRY FLAG has been set, meaning the restriction letter lies in the range A to Z, LOOP BACK to 5472H to step past it and look for another parameter.

Error Path
Two messages share one exit. The four bytes at 54A7H hold a single DD-prefixed LD IX,5550H when they are entered at 54A7H, and the same bytes from 54A8H onward hold LD HL,5550H. Entered at 54A4H the routine loads Register Pair HL with the address of "Parameter error!" and the LD IX that follows is inert; entered at 54A8H it loads Register Pair HL with the address of "Invalid output device!" instead. One four byte sequence, two messages, and the DD prefix is what makes the first entry step over the second.

54A4
Point Register Pair HL at 553FH, the message "Parameter error!" which is terminated by the 0DH at 554FH. This is the entry taken when a parameter was not one of the documented forms.
54A7
LD IX,5550H DD 21 50 55
Load Register Pair IX with 5550H when these four bytes are entered at 54A7H, having fallen through from the instruction above. Nothing in the overlay ever reads Register Pair IX after this point, so the load has no effect; its purpose is to swallow the three bytes that form the alternative entry.
54A8
Point Register Pair HL at 5550H, the message "Invalid output device!" which is terminated by the 0DH at 5566H. These are the same three bytes shown on the row above without the DD prefix, and this is the entry reached by the three jumps at 5460H, 5464H and 546BH.
54AB
GOSUB to the resident @LOGOT vector at 447BH to send the 0DH terminated message at Register Pair HL to the system log device, which is the video display.
54AE
JUMP to the exit stub at 5217H to reload BASIC/CMD, so a bad parameter abandons the dump and returns to the interpreter without printing anything.

54B1H - Character Fetch Helpers

Two small routines the parser leans on. 54B2H returns the character at (HL) and, when that character is a blank, advances through 54B1H until it is not; the Z FLAG marks the 0DH that ends the command tail. 54BBH advances one character unconditionally and clears bit 5 of the result, which folds the letters a to z onto A to Z so that every parameter may be typed in either case.

Loop Start

54B1
INC HL 23
INCrement Register Pair HL, the pointer into the command tail in INBUF$ 4318H, by 1 to step over the blank that was just examined.
54B2
LD A,(HL) 7E
Fetch the character at the address in Register Pair HL, the current position in the command tail, into Register A. This is the entry the parser calls at 544AH and 5473H.
54B3
CP 0DH FE 0D
Compare Register A, the character just fetched, against 0DH, the carriage return that BASIC/CMD's string copier at 54E1H put at the end of the tail. If they are equal the Z FLAG is set.
54B5
RET Z C8
If the Z FLAG has been set, meaning the end of the command tail has been reached, RETurn with Register Pair HL pointing at the 0DH and Register A holding it, which both callers treat as the end of the parameters.
54B6
CP 20H FE 20
Compare Register A, the character just fetched, against 20H, a blank. If they are equal the Z FLAG is set; otherwise the NZ FLAG is set.
54B8
RET NZ C0
If the NZ FLAG has been set, meaning the character is neither a carriage return nor a blank, RETurn with that character in Register A and Register Pair HL pointing at it.

Loop End

54B9
LOOP BACK to 54B1H to step past this blank and examine the character that follows it.
54BB
INC HL 23
INCrement Register Pair HL, the pointer into the command tail, by 1. This entry always advances, because every caller has just consumed a character and wants the next one.
54BC
LD A,(HL) 7E
Fetch the character at the new position in Register Pair HL into Register A.
54BD
RES 5,A CB AF
Clear bit 5 of Register A, the character just fetched. That is the bit that separates the lower case letters from the upper case ones, so d becomes D and p becomes P, and every parameter letter may be typed either way.
54BF
RET C9
RETurn to the caller at 5452H, 5459H, 5466H, 547FH or 5496H with the folded character in Register A.

54C0H - The Sign-On Banner

The banner is complete and correctly formed, with the two video control bytes that home the cursor and clear the frame ahead of it and a carriage return behind it, but it is never sent anywhere. The only instruction in the image that names 54C0H is the LD HL,54C0H at 5201H, and the POP HL at 5204H replaces Register Pair HL before any display call is made. BASIC/OV1 and BASIC/OV2 display their equivalents at 55D2H and 579EH.

54C0
DEFB 1CH 1C
The video control code that homes the cursor to the top left of the display.
54C1
DEFB 1FH 1F
The video control code that erases from the cursor to the end of the frame. Following the home code, the pair clears the screen.
54C2-54E9
DEFM "BASIC Active Variable Dump - Version 4.1" 42 41 53 49 43 20 41 63 74 69 76 65 20 56 61 72 69 61 62 6C 65 20 44 75 6D 70 20 2D 20 56 65 72 73 69 6F 6E 20 34 2E 31
The banner text, forty characters, naming the overlay and its version.
54EA
DEFB 0DH 0D
The carriage return that would terminate the banner for @DSPLY. It is also read as the first byte of nothing else; the heading string that follows starts one byte later, at 54EBH.

54EBH - Section Headings, Messages And Work Bytes

Two heading strings and five message strings, followed by three bytes that are work cells rather than text. The two headings are terminated by carriage returns and are sent through 5439H; the four strings that are appended to the output buffer are terminated by 00H for the string copier at 53D6H; and the two error messages are terminated by carriage returns because they go to @LOGOT. The user defined function legend at 552EH is the exception: it is appended by the copier yet ends with a carriage return, so that copy runs past it and only stops at the 00H at 5567H, which is harmless because the display stops at the carriage return.

54EB
DEFB 0AH 0A
The line feed that opens the scalar heading. 5237H points Register Pair HL here, so the heading begins by moving the display down one line.
54EC-54FC
DEFM "Simple Variables:" 53 69 6D 70 6C 65 20 56 61 72 69 61 62 6C 65 73 3A
The heading printed at 523AH before the scalar variables are listed.
54FD
DEFB 0DH 0D
The carriage return that terminates the scalar heading for @DSPLY or @PRINT.
54FE
DEFB 0AH 0A
The line feed that opens the array heading. 52AAH points Register Pair HL here, so the heading begins by moving the display down one line.
54FF-550E
DEFM "Array Variables:" 41 72 72 61 79 20 56 61 72 69 61 62 6C 65 73 3A
The heading printed at 52ADH before the array variables are listed.
550F
DEFB 0DH 0D
The carriage return that terminates the array heading for @DSPLY or @PRINT.
5510-5527
DEFM "* Too many subscripts *)" 2A 20 54 6F 6F 20 6D 61 6E 79 20 73 75 62 73 63 72 69 70 74 73 20 2A 29
Appended to an array's name at 538BH when the array has six or more dimensions, which the five counters at 556AH-5573H cannot enumerate. The closing parenthesis stands in for the subscript list that is not produced.
5528
DEFB 00H 00
The 00H that stops the string copier at the end of the too many subscripts message.
5529-552B
DEFM " = " 20 3D 20
Blank, equals sign, blank. Appended to the built line at 5289H for a scalar and at 535AH for an array element, separating the name inside the quoted literal from the value that the interpreter will print.
552C
DEFB 22H 22
The quotation mark that CLOSES the BASIC string literal opened by the one at 557BH, so that everything copied into the buffer after this point is read by the interpreter as live source text rather than as literal characters.
552D
DEFB 00H 00
The 00H that stops the string copier after those four characters.
552E-553D
DEFM " <User Def Func>" 20 3C 55 73 65 72 20 44 65 66 20 46 75 6E 63 3E
The legend appended at 527BH after a user defined function's expanded definition text, marking the line as a DEF FN rather than a variable.
553E
DEFB 0DH 0D
The carriage return that terminates the user defined function line for the display routine at 5439H. It does not stop the string copier at 53D6H, which is why that copy runs on into the messages below and only ends at the 00H at 5567H.
553F-554E
DEFM "Parameter error!" 50 61 72 61 6D 65 74 65 72 20 65 72 72 6F 72 21
Displayed through @LOGOT 447BH from the error exit at 54A4H, which is reached when a parameter is not one of the documented forms or when the letter after an equals sign is not in the range A to Z.
554F
DEFB 0DH 0D
The carriage return that terminates the parameter error message for @LOGOT.
5550-5565
DEFM "Invalid output device!" 49 6E 76 61 6C 69 64 20 6F 75 74 70 75 74 20 64 65 76 69 63 65 21
Displayed through @LOGOT 447BH from the alternative error entry at 54A8H, which is reached when the name after the asterisk is not *DO or *PR.
5566
DEFB 0DH 0D
The carriage return that terminates the invalid device message for @LOGOT.
5567
DEFB 00H 00
The current subscript position, counting from 1 at the leftmost subscript. It is set to 01H at 52F6H, advanced at 5348H, stepped back at 5380H and tested at 52FDH; a value of zero ends the array. It also serves as the byte that finally stops the over-running string copy started at 527BH.
5568
DEFB 00H 00
The number of dimensions of the array being dumped, written at 52CFH from offset 05H of the array header and read at 5332H to decide when the subscript list is complete.
5569
DEFB 00H 00
The output device code. It ships as 00H, the video display, and is set to 01H at 546FH when the *PR parameter is given. 5439H reads it to choose between @DSPLY 4467H and @PRINT 446AH, and 540EH reads it as the value that becomes PRTFLG 409CH for the ROM PRINT loop.

556AH - The Subscript Counter Block

These ten bytes are the gap in the module image. No load record covers them, so they hold whatever was in memory when the overlay arrived, and the array dump clears all ten at 52E5H before it starts on an array. They are five 16-bit counters, one per subscript position, addressed through Register Pair IY at offsets 00H and 01H, and it is their number that fixes the six dimension limit tested at 52D2H.

556A-5573
DEFS 10
Five 16-bit subscript counters. Each counts from zero up to the element count of its dimension, is incremented at 5316H, is compared against the dimension size at 530EH and is reset to zero at 536CH when it rolls over into the counter on its left.

5574H - Work Cells And The Output Line Prefix

The last load record of the module covers just these eleven bytes. They are the restriction letter, the five digit decimal conversion field with its terminator, and the four characters that stand immediately in front of the output buffer at 557FH. The image ends at 557EH; everything from 557FH up is uninitialised RAM that the overlay claims for the line it builds.

5574
DEFB 00H 00
The =x restriction letter, written at 5499H after case folding and tested at 5249H for scalars and at 52BCH for arrays. It ships as 00H, which means no restriction and therefore every variable.
5575-5579
DEFM " " 20 20 20 20 20
The five digit decimal conversion field, filled from 5579H downwards by the converter at 53EFH. It ships as blanks; every subscript overwrites all five positions, and the leading zeros are skipped by the caller at 5321H rather than being blanked here.
557A
DEFB 00H 00
The 00H that terminates the five digit field for the string copier at 53D6H when the digits are appended to the output buffer at 532BH.
557B
DEFB 22H 22
The quotation mark that opens the BASIC string literal. 5405H hands this address to the ROM PRINT loop, so this is the first character the interpreter parses in every line the overlay prints.
557C-557E
DEFM " " 20 20 20
Three blanks that indent every dumped line inside the quoted literal. The user defined function path at 527EH displays from 557CH rather than 557BH, so it prints the same indent as plain text and never involves the interpreter.