| Routines

10173: THE 'SCANNING FUNCTION' SUBROUTINE

Used by the routine at S_FN. This subroutine evaluates a user defined function which occurs in a BASIC line. The subroutine can be considered in four stages: i. The syntax of the FN statement is checked during syntax checking. ii. During line execution, a search is made of the program area for a DEF FN statement, and the names of the functions are compared, until a match is found - or an error is reported. iii. The arguments of the FN are evaluated by calls to SCANNING. iv. The function itself is evaluated by calling SCANNING, which in turn calls LOOK_VARS and so STK_F_ARG.
S_FN_SBRN | 10173 | CALL SYNTAX_Z | Unless syntax is being checked, a jump is made to SF_RUN.
| 10176 | JR NZ,SF_RUN
| 10178 | RST 32 | Get the first character of the name.
| 10179 | CALL ALPHA | If it is not alphabetic, then report the error.
| 10182 | JP NC,REPORT_C
| 10185 | RST 32 | Get the next character.
| 10186 | CP "$" | Is it a '$'?
| 10188 | PUSH AF | Save the zero flag on the stack.
| 10189 | JR NZ,SF_BRKT_1 | Jump if it was not a '$'.
| 10191 | RST 32 | But get the next character if it was.
SF_BRKT_1 | 10192 | CP "(" | If the character is not a '(', then report the error.
| 10194 | JR NZ,SF_RPRT_C
| 10196 | RST 32 | Get the next character.
| 10197 | CP ")" | Is it a ')'?
| 10199 | JR Z,SF_FLAG_6 | Jump if it is; there are no arguments.
SF_ARGMTS | 10201 | CALL SCANNING | Within the loop, call SCANNING to check the syntax of each argument and to insert floating-point numbers.
| 10204 | RST 24 | Get the character which follows the argument; if it is not a ',' then jump - no more arguments.
| 10205 | CP ","
| 10207 | JR NZ,SF_BRKT_2
| 10209 | RST 32 | Get the first character in the next argument.
| 10210 | JR SF_ARGMTS | Loop back to consider this argument.
SF_BRKT_2 | 10212 | CP ")" | Is the current character a ')'?
SF_RPRT_C | 10214 | JP NZ,REPORT_C | Report the error if it is not.
SF_FLAG_6 | 10217 | RST 32 | Point to the next character in the BASIC line.
| 10218 | LD HL,23611 | Assume a string-valued function and reset bit 6 of FLAGS.
| 10221 | RES 6,(HL)
| 10223 | POP AF | Restore the zero flag, jump if the FN is indeed string-valued.
| 10224 | JR Z,SF_SYN_EN
| 10226 | SET 6,(HL) | Otherwise, set bit 6 of FLAGS.
SF_SYN_EN | 10228 | JP S_CONT_2 | Jump back to continue scanning the line.
ii. During line execution, a search must first be made for a DEF FN statement.
SF_RUN | 10231 | RST 32 | Get the first character of the name.
| 10232 | AND 223 | Reset bit 5 for upper case.
| 10234 | LD B,A | Copy the name to B.
| 10235 | RST 32 | Get the next character.
| 10236 | SUB "$" | Subtract 36, the code for '$'.
| 10238 | LD C,A | Copy the result to C (zero for a string, non-zero for a numerical function).
| 10239 | JR NZ,SF_ARGMT1 | Jump if non-zero: numerical function.
| 10241 | RST 32 | Get the next character, the '('.
SF_ARGMT1 | 10242 | RST 32 | Get 1st character of 1st argument.
| 10243 | PUSH HL | Save the pointer to it on the stack.
| 10244 | LD HL,(23635) | Point to the start of the program (PROG).
| 10247 | DEC HL | Go back one location.
SF_FND_DF | 10248 | LD DE,206 | The search will be for 'DEF FN'.
| 10251 | PUSH BC | Save the name and 'string status'.
| 10252 | CALL LOOK_PROG | Search the program now.
| 10255 | POP BC | Restore the name and status.
| 10256 | JR NC,SF_CP_DEF | Jump if a DEF FN statement found.
Report P - FN without DEF.
| 10258 | RST 8 | Call the error handling routine.
| 10259 | DEFB 24
When a DEF FN statement is found, the name and status of the two functions are compared; if they do not match, the search is resumed.
SF_CP_DEF | 10260 | PUSH HL | Save the pointer to the DEF FN character in case the search has to be resumed.
| 10261 | CALL FN_SKPOVR | Get the name of the DEF FN function.
| 10264 | AND 223 | Reset bit 5 for upper case.
| 10266 | CP B | Does it match the FN name?
| 10267 | JR NZ,SF_NOT_FD | Jump if it does not match.
| 10269 | CALL FN_SKPOVR | Get the next character in the DEF FN.
| 10272 | SUB "$" | Subtract 36, the code for '$'.
| 10274 | CP C | Compare the status with that of FN.
| 10275 | JR Z,SF_VALUES | Jump if complete match now found.
SF_NOT_FD | 10277 | POP HL | Restore the pointer to the 'DEF FN'.
| 10278 | DEC HL | Step back one location.
| 10279 | LD DE,512 | Use the search routine to find the end of the DEF FN statement, preparing for the next search; save the name and status meanwhile.
| 10282 | PUSH BC
| 10283 | CALL EACH_STMT
| 10286 | POP BC
| 10287 | JR SF_FND_DF | Jump back for a further search.
iii. The correct DEF FN statement has now been found. The arguments of the FN statement will be evaluated by repeated calls of SCANNING, and their 5 byte values (or parameters, for strings) will be inserted into the DEF FN statement in the spaces made there at syntax checking. HL will be used to point along the DEF FN statement (calling FN_SKPOVR as needed) while CH-ADD points along the FN statement (calling NEXT_CHAR as needed).
SF_VALUES | 10289 | AND A | If HL is now pointing to a '$', move on to the '('.
| 10290 | CALL Z,FN_SKPOVR
| 10293 | POP DE | Discard the pointer to 'DEF FN'.
| 10294 | POP DE | Get the pointer to the first argument of FN, and copy it to CH-ADD.
| 10295 | LD (23645),DE
| 10299 | CALL FN_SKPOVR | Move past the '(' now.
| 10302 | PUSH HL | Save this pointer on the stack.
| 10303 | CP ")" | Is it pointing to a ')'?
| 10305 | JR Z,SF_R_BR_2 | If so, jump: FN has no arguments.
SF_ARG_LP | 10307 | INC HL | Point to the next code.
| 10308 | LD A,(HL) | Put the code into A.
| 10309 | CP 14 | Is it the 'number marker' code, 14?
| 10311 | LD D,64 | Set bit 6 of D for a numerical argument.
| 10313 | JR Z,SF_ARG_VL | Jump on zero: numerical argument.
| 10315 | DEC HL | Now ensure that HL is pointing to the '$' character (not e.g. to a control code).
| 10316 | CALL FN_SKPOVR
| 10319 | INC HL | HL now points to the 'number marker'.
| 10320 | LD D,0 | Bit 6 of D is reset: string argument.
SF_ARG_VL | 10322 | INC HL | Point to the 1st of the 5 bytes in DEF FN.
| 10323 | PUSH HL | Save this pointer on the stack.
| 10324 | PUSH DE | Save the 'string status' of the argument.
| 10325 | CALL SCANNING | Now evaluate the argument.
| 10328 | POP AF | Get the no./string flag into A.
| 10329 | XOR (IY+1) | Test bit 6 of it against the result of SCANNING (bit 6 of FLAGS).
| 10332 | AND 64
| 10334 | JR NZ,REPORT_Q | Give report Q if they did not match.
| 10336 | POP HL | Get the pointer to the first of the 5 spaces in DEF FN into DE.
| 10337 | EX DE,HL
| 10338 | LD HL,(23653) | Point HL at STKEND.
| 10341 | LD BC,5 | BC will count 5 bytes to be moved.
| 10344 | SBC HL,BC | First, decrease STKEND by 5, so deleting the 'last value' from the stack.
| 10346 | LD (23653),HL
| 10349 | LDIR | Copy the 5 bytes into the spaces in DEF FN.
| 10351 | EX DE,HL | Point HL at the next code.
| 10352 | DEC HL | Ensure that HL points to the character after the 5 bytes.
| 10353 | CALL FN_SKPOVR
| 10356 | CP ")" | Is it a ')'?
| 10358 | JR Z,SF_R_BR_2 | Jump if it is: no more arguments in the DEF FN statement.
| 10360 | PUSH HL | It is a ',': save the pointer to it.
| 10361 | RST 24 | Get the character after the last argument that was evaluated from FN.
| 10362 | CP "," | If it is not a ',' jump: mismatched arguments of FN and DEF FN.
| 10364 | JR NZ,REPORT_Q
| 10366 | RST 32 | Point CH-ADD to the next argument of FN.
| 10367 | POP HL | Point HL to the ',' in DEF FN again.
| 10368 | CALL FN_SKPOVR | Move HL on to the next argument in DEF FN.
| 10371 | JR SF_ARG_LP | Jump back to consider this argument.
SF_R_BR_2 | 10373 | PUSH HL | Save the pointer to the ')' in DEF FN.
| 10374 | RST 24 | Get the character after the last argument in FN.
| 10375 | CP ")" | Is it a ')'?
| 10377 | JR Z,SF_VALUE | If so, jump to evaluate the function; but if not, give report Q.
Report Q - Parameter error.
REPORT_Q | 10379 | RST 8 | Call the error handling routine.
| 10380 | DEFB 25
iv. Finally, the function itself is evaluated by calling SCANNING, after first setting DEFADD to hold the address of the arguments as they occur in the DEF FN statement. This ensures that LOOK_VARS, when called by SCANNING, will first search these arguments for the required values, before making a search of the variables area.
SF_VALUE | 10381 | POP DE | Restore pointer to ')' in DEF FN.
| 10382 | EX DE,HL | Get this pointer into HL.
| 10383 | LD (23645),HL | Insert it into CH-ADD.
| 10386 | LD HL,(23563) | Get the old value of DEFADD.
| 10389 | EX (SP),HL | Stack it, and get the start address of the arguments area of DEF FN into DEFADD.
| 10390 | LD (23563),HL
| 10393 | PUSH DE | Save address of ')' in FN.
| 10394 | RST 32 | Move CH-ADD on past ')' and '=' to the start of the expression for the function in DEF FN.
| 10395 | RST 32
| 10396 | CALL SCANNING | Now evaluate the function.
| 10399 | POP HL | Restore the address of ')' in FN.
| 10400 | LD (23645),HL | Store it in CH-ADD.
| 10403 | POP HL | Restore original value of DEFADD.
| 10404 | LD (23563),HL | Put it back into DEFADD.
| 10407 | RST 32 | Get the next character in the BASIC line.
| 10408 | JP S_CONT_2 | Jump back to continue scanning.