| Routines

2AFF: THE 'LET' COMMAND ROUTINE

Used by the routines at VAL_FET_1, FOR and INPUT. This is the actual assignment routine for the LET, READ and INPUT commands. When the destination variable is a 'newly declared variable' then DEST will point to the first letter of the variable's name as it occurs in the BASIC line. Bit 1 of FLAGX will be set. However if the destination variable 'exists already' then bit 1 of FLAGX will be reset and DEST will point for a numeric variable to the location before the five bytes of the 'old number', and for a string variable to the first location of the 'old string'. The use of DEST in this manner applies to simple variables and to elements of arrays. Bit 0 of FLAGX is set if the destination variable is a 'complete' simple string variable. (Signalling - delete the old copy.) Initially the current value of DEST is collected and bit 1 of FLAGS tested.
LET | 2AFF | LD HL,($5C4D) | Fetch the present address in DEST.
| 2B02 | BIT 1,(IY+$37) | Jump if handling a variable that 'exists already' (bit 1 of FLAGX reset).
| 2B06 | JR Z,L_EXISTS
A 'newly declared variable' is being used. So first the length of its name is found.
| 2B08 | LD BC,$0005 | Presume dealing with a numeric variable - 5 bytes.
Enter a loop to deal with the characters of a long name. Any spaces or colour codes in the name are ignored.
L_EACH_CH | 2B0B | INC BC | Add '1' to the counter for each character of a name.
L_NO_SP | 2B0C | INC HL | Move along the variable's name.
| 2B0D | LD A,(HL) | Fetch the 'present code'.
| 2B0E | CP " " | Jump back if it is a 'space', thereby ignoring spaces.
| 2B10 | JR Z,L_NO_SP
| 2B12 | JR NC,L_TEST_CH | Jump forward if the code is +21 to +FF.
| 2B14 | CP $10 | Accept, as a final code, those in the range +00 to +0F.
| 2B16 | JR C,L_SPACES
| 2B18 | CP $16 | Also accept the range +16 to +1F.
| 2B1A | JR NC,L_SPACES
| 2B1C | INC HL | Step past the control code after any of INK to OVER.
| 2B1D | JR L_NO_SP | Jump back as these control codes are treated as spaces.
Separate 'numeric' and 'string' names.
L_TEST_CH | 2B1F | CALL ALPHANUM | Is the code alphanumeric?
| 2B22 | JR C,L_EACH_CH | If It is so then accept it as a character of a 'long' name.
| 2B24 | CP "$" | Is the present code a '$'?
| 2B26 | JP Z,L_NEW | Jump forward as handling a 'newly declared' simple string.
The 'newly declared numeric variable' presently being handled will require BC spaces in the variables area for its name and its value. The room is made available and the name of the variable is copied over with the characters being 'marked' as required.
L_SPACES | 2B29 | LD A,C | Copy the 'length' to A.
| 2B2A | LD HL,($5C59) | Make HL point to the '+80-byte' at the end of the variables area (E-LINE-1).
| 2B2D | DEC HL
| 2B2E | CALL MAKE_ROOM | Now open up the variables area. Note: in effect BC spaces are made before the displaced '+80-byte'.
| 2B31 | INC HL | Point to the first 'new' byte.
| 2B32 | INC HL | Make DE point to the second 'new' byte.
| 2B33 | EX DE,HL
| 2B34 | PUSH DE | Save this pointer.
| 2B35 | LD HL,($5C4D) | Fetch the pointer to the start of the name (DEST).
| 2B38 | DEC DE | Make DE point to the first 'new' byte.
| 2B39 | SUB $06 | Make B hold the 'number of extra letters' that are found in a 'long name'.
| 2B3B | LD B,A
| 2B3C | JR Z,L_SINGLE | Jump forward if dealing with a variable with a 'short name'.
The 'extra' codes of a long name are passed to the variables area.
L_CHAR | 2B3E | INC HL | Point to each 'extra' code.
| 2B3F | LD A,(HL) | Fetch the code.
| 2B40 | CP $21 | Accept codes from +21 to +FF; ignore codes +00 to +20.
| 2B42 | JR C,L_CHAR
| 2B44 | OR $20 | Set bit 5, as for lower case letters.
| 2B46 | INC DE | Transfer the codes in turn to the 2nd 'new' byte onwards.
| 2B47 | LD (DE),A
| 2B48 | DJNZ L_CHAR | Go round the loop for all the 'extra' codes.
The last code of a 'long' name has to be ORed with +80.
| 2B4A | OR $80 | Mark the code as required and overwrite the last code.
| 2B4C | LD (DE),A
The first letter of the name of the variable being handled is now considered.
| 2B4D | LD A,$C0 | Prepare to mark the letter of a 'long' name.
L_SINGLE | 2B4F | LD HL,($5C4D) | Fetch the pointer to the letter (DEST).
| 2B52 | XOR (HL) | A holds +00 for a 'short' name and +C0 for a 'long' name.
| 2B53 | OR $20 | Set bit 5, as for lower case letters.
| 2B55 | POP HL | Drop the pointer now.
The subroutine L_FIRST is now called to enter the 'letter' into its appropriate location.
| 2B56 | CALL L_FIRST | Enter the letter and return with HL pointing to 'new +80-byte'.
The 'last value' can now be transferred to the variables area. Note that at this point HL always points to the location after the five locations allotted to the number. A 'RST $28' instruction is used to call the calculator and the 'last value' is deleted. However this value is not overwritten.
L_NUMERIC | 2B59 | PUSH HL | Save the 'destination' pointer.
| 2B5A | RST $28 | Use the calculator to move STKEND back five bytes.
| 2B5B | DEFB $02 | delete
| 2B5C | DEFB $38 | end_calc
| 2B5D | POP HL | Restore the pointer.
| 2B5E | LD BC,$0005 | Give the number a 'length' of five bytes.
| 2B61 | AND A | Make HL point to the first of the five locations and jump forward to make the actual transfer.
| 2B62 | SBC HL,BC
| 2B64 | JR L_ENTER
Come here if considering a variable that 'exists already'. First bit 6 of FLAGS is tested so as to separate numeric variables from string or array of string variables.
L_EXISTS | 2B66 | BIT 6,(IY+$01) | Jump forward if handling any kind of string variable (bit 6 of FLAGS reset).
| 2B6A | JR Z,L_DELETE
For numeric variables the 'new' number overwrites the 'old' number. So first HL has to be made to point to the location after the five bytes of the existing entry. At present HL points to the location before the five bytes.
| 2B6C | LD DE,$0006 | The five bytes of a number + 1.
| 2B6F | ADD HL,DE | HL now points 'after'.
| 2B70 | JR L_NUMERIC | Jump back to make the actual transfer.
The parameters of the string variable are fetched and complete simple strings separated from 'sliced' strings and array strings.
L_DELETE | 2B72 | LD HL,($5C4D) | Fetch the 'start' (DEST). Note: this line is redundant.
| 2B75 | LD BC,($5C72) | Fetch the 'length' (STRLEN).
| 2B79 | BIT 0,(IY+$37) | Jump if dealing with a complete simple string (bit 0 of FLAGX set); the old string will need to be 'deleted' in this case only.
| 2B7D | JR NZ,L_ADD
When dealing with a 'slice' of an existing simple string, a 'slice' of a string from an array of strings or a complete string from an array of strings there are two distinct stages involved. The first is to build up the 'new' string in the work space, lengthening or shortening it as required. The second stage is then to copy the 'new' string to its allotted room in the variables area. However do nothing if the string has no 'length'.
| 2B7F | LD A,B | Return if the string is a null string.
| 2B80 | OR C
| 2B81 | RET Z
Then make the required number of spaces available in the work space.
| 2B82 | PUSH HL | Save the 'start' (DEST).
| 2B83 | RST $30 | Make the necessary amount of room in the work space.
| 2B84 | PUSH DE | Save the pointer to the first location.
| 2B85 | PUSH BC | Save the 'length' for use later on.
| 2B86 | LD D,H | Make DE point to the last location.
| 2B87 | LD E,L
| 2B88 | INC HL | Make HL point 'one past' the new locations.
| 2B89 | LD (HL)," " | Enter a 'space' character.
| 2B8B | LDDR | Copy this character into all the new locations. Finish with HL pointing to the first new location.
The parameters of the string being handled are now fetched from the calculator stack.
| 2B8D | PUSH HL | Save the pointer briefly.
| 2B8E | CALL STK_FETCH | Fetch the 'new' parameters.
| 2B91 | POP HL | Restore the pointer.
Note: at this point the required amount of room has been made available in the work space for the 'variable in assignment'; e.g. for the statement 'LET A$(4 TO 8)="abcdefg"' five locations have been made. The parameters fetched above as a 'last value' represent the string that is to be copied into the new locations with Procrustean lengthening or shortening as required. The length of the 'new' string is compared to the length of the room made available for it.
| 2B92 | EX (SP),HL | 'Length' of new area to HL. 'Pointer' to new area to stack.
| 2B93 | AND A | Compare the two 'lengths' and jump forward if the 'new' string will fit into the room, i.e. no shortening required.
| 2B94 | SBC HL,BC
| 2B96 | ADD HL,BC
| 2B97 | JR NC,L_LENGTH
| 2B99 | LD B,H | However modify the 'new' length if it is too long.
| 2B9A | LD C,L
L_LENGTH | 2B9B | EX (SP),HL | 'Length' of new area to stack. 'Pointer' to new area to HL.
As long as the new string is not a 'null string' it is copied into the work space. Procrustean lengthening is achieved automatically if the 'new' string is shorter than the room available for it.
| 2B9C | EX DE,HL | 'Start' of new string to HL. 'Pointer' to new area to DE.
| 2B9D | LD A,B | Jump forward if the 'new' string is a 'null' string.
| 2B9E | OR C
| 2B9F | JR Z,L_IN_W_S
| 2BA1 | LDIR | Otherwise move the 'new' string to the work space.
The values that have been saved on the machine stack are restored.
L_IN_W_S | 2BA3 | POP BC | 'Length' of new area.
| 2BA4 | POP DE | 'Pointer' to new area.
| 2BA5 | POP HL | The start - the pointer to the 'variable in assignment' which was originally in DEST. L_ENTER is now used to pass the 'new' string to the variables area.
The following short subroutine is used to pass either a numeric value from the calculator stack, or a string from the work space, to its appropriate position in the variables area. The subroutine is therefore used for all except 'newly declared' simple strings and 'complete and existing' simple strings.
L_ENTER | 2BA6 | EX DE,HL | Change the pointers over.
| 2BA7 | LD A,B | Check once again that the length is not zero.
| 2BA8 | OR C
| 2BA9 | RET Z
| 2BAA | PUSH DE | Save the destination pointer.
| 2BAB | LDIR | Move the numeric value or the string.
| 2BAD | POP HL | Return with the HL register pair pointing to the first byte of the numeric value or the string.
| 2BAE | RET
When handling a 'complete and existing' simple string the new string is entered as if it were a 'newly declared' simple string before the existing version is 'reclaimed'.
L_ADD | 2BAF | DEC HL | Make HL point to the letter of the variable's name, i.e. DEST-3.
| 2BB0 | DEC HL
| 2BB1 | DEC HL
| 2BB2 | LD A,(HL) | Pick up the letter.
| 2BB3 | PUSH HL | Save the pointer to the 'existing version'.
| 2BB4 | PUSH BC | Save the 'length' of the 'existing string'.
| 2BB5 | CALL L_STRING | Use L_STRING to add the new string to the variables area.
| 2BB8 | POP BC | Restore the 'length'.
| 2BB9 | POP HL | Restore the pointer.
| 2BBA | INC BC | Allow one byte for the letter and two bytes for the length.
| 2BBB | INC BC
| 2BBC | INC BC
| 2BBD | JP RECLAIM_2 | Exit by jumping to RECLAIM_2 which will reclaim the whole of the existing version.
'Newly declared' simple strings are handled as follows:
L_NEW | 2BC0 | LD A,$DF | Prepare for the marking of the variable's letter.
| 2BC2 | LD HL,($5C4D) | Fetch the pointer to the letter (DEST).
| 2BC5 | AND (HL) | Mark the letter as required. L_STRING is now used to add the new string to the variables area.
The parameters of the 'new' string are fetched, sufficient room is made available for it and the string is then transferred.
L_STRING | 2BC6 | PUSH AF | Save the variable's letter.
| 2BC7 | CALL STK_FETCH | Fetch the 'start' and the 'length' of the 'new' string.
| 2BCA | EX DE,HL | Move the 'start' to HL.
| 2BCB | ADD HL,BC | Make HL point one past the string.
| 2BCC | PUSH BC | Save the 'length'.
| 2BCD | DEC HL | Make HL point to the end of the string.
| 2BCE | LD ($5C4D),HL | Save the pointer briefly in DEST.
| 2BD1 | INC BC | Allow one byte for the letter and two bytes for the length.
| 2BD2 | INC BC
| 2BD3 | INC BC
| 2BD4 | LD HL,($5C59) | Make HL point to the '+80-byte' at the end of the variables area (E-LINE-1).
| 2BD7 | DEC HL
| 2BD8 | CALL MAKE_ROOM | Now open up the variables area. Note: in effect BC spaces are made before the displaced '+80-byte'.
| 2BDB | LD HL,($5C4D) | Restore the pointer to the end of the 'new' string from DEST.
| 2BDE | POP BC | Make a copy of the length of the 'new' string.
| 2BDF | PUSH BC
| 2BE0 | INC BC | Add one to the length in case the 'new' string is a 'null' string.
| 2BE1 | LDDR | Now copy the 'new' string + one byte.
| 2BE3 | EX DE,HL | Make HL point to the byte that is to hold the high-length.
| 2BE4 | INC HL
| 2BE5 | POP BC | Fetch the 'length'.
| 2BE6 | LD (HL),B | Enter the high-length.
| 2BE7 | DEC HL | Back one.
| 2BE8 | LD (HL),C | Enter the low-length.
| 2BE9 | POP AF | Fetch the variable's letter.
The following subroutine is entered with the letter of the variable, suitably marked, in the A register. The letter overwrites the 'old +80-byte' in the variables area. The subroutine returns with the HL register pair pointing to the 'new +80-byte'.
L_FIRST | 2BEA | DEC HL | Make HL point to the 'old +80-byte'.
| 2BEB | LD (HL),A | It is overwritten with the letter of the variable.
| 2BEC | LD HL,($5C59) | Make HL point to the 'new +80-byte' (E-LINE-1).
| 2BEF | DEC HL
| 2BF0 | RET | Finished with all the 'newly declared variables'.