Prev: 27B0 Up: Map Next: 28AB
27BD: 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 27BD CALL SYNTAX_Z Unless syntax is being checked, a jump is made to SF_RUN.
27C0 JR NZ,SF_RUN
27C2 RST $20 Get the first character of the name.
27C3 CALL ALPHA If it is not alphabetic, then report the error.
27C6 JP NC,REPORT_C
27C9 RST $20 Get the next character.
27CA CP "$" Is it a '$'?
27CC PUSH AF Save the zero flag on the stack.
27CD JR NZ,SF_BRKT_1 Jump if it was not a '$'.
27CF RST $20 But get the next character if it was.
SF_BRKT_1 27D0 CP "(" If the character is not a '(', then report the error.
27D2 JR NZ,SF_RPRT_C
27D4 RST $20 Get the next character.
27D5 CP ")" Is it a ')'?
27D7 JR Z,SF_FLAG_6 Jump if it is; there are no arguments.
SF_ARGMTS 27D9 CALL SCANNING Within the loop, call SCANNING to check the syntax of each argument and to insert floating-point numbers.
27DC RST $18 Get the character which follows the argument; if it is not a ',' then jump - no more arguments.
27DD CP ","
27DF JR NZ,SF_BRKT_2
27E1 RST $20 Get the first character in the next argument.
27E2 JR SF_ARGMTS Loop back to consider this argument.
SF_BRKT_2 27E4 CP ")" Is the current character a ')'?
SF_RPRT_C 27E6 JP NZ,REPORT_C Report the error if it is not.
SF_FLAG_6 27E9 RST $20 Point to the next character in the BASIC line.
27EA LD HL,$5C3B Assume a string-valued function and reset bit 6 of FLAGS.
27ED RES 6,(HL)
27EF POP AF Restore the zero flag, jump if the FN is indeed string-valued.
27F0 JR Z,SF_SYN_EN
27F2 SET 6,(HL) Otherwise, set bit 6 of FLAGS.
SF_SYN_EN 27F4 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 27F7 RST $20 Get the first character of the name.
27F8 AND $DF Reset bit 5 for upper case.
27FA LD B,A Copy the name to B.
27FB RST $20 Get the next character.
27FC SUB "$" Subtract +24, the code for '$'.
27FE LD C,A Copy the result to C (zero for a string, non-zero for a numerical function).
27FF JR NZ,SF_ARGMT1 Jump if non-zero: numerical function.
2801 RST $20 Get the next character, the '('.
SF_ARGMT1 2802 RST $20 Get 1st character of 1st argument.
2803 PUSH HL Save the pointer to it on the stack.
2804 LD HL,($5C53) Point to the start of the program (PROG).
2807 DEC HL Go back one location.
SF_FND_DF 2808 LD DE,$00CE The search will be for 'DEF FN'.
280B PUSH BC Save the name and 'string status'.
280C CALL LOOK_PROG Search the program now.
280F POP BC Restore the name and status.
2810 JR NC,SF_CP_DEF Jump if a DEF FN statement found.
Report P - FN without DEF.
2812 RST $08 Call the error handling routine.
2813 DEFB $18
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 2814 PUSH HL Save the pointer to the DEF FN character in case the search has to be resumed.
2815 CALL FN_SKPOVR Get the name of the DEF FN function.
2818 AND $DF Reset bit 5 for upper case.
281A CP B Does it match the FN name?
281B JR NZ,SF_NOT_FD Jump if it does not match.
281D CALL FN_SKPOVR Get the next character in the DEF FN.
2820 SUB "$" Subtract +24, the code for '$'.
2822 CP C Compare the status with that of FN.
2823 JR Z,SF_VALUES Jump if complete match now found.
SF_NOT_FD 2825 POP HL Restore the pointer to the 'DEF FN'.
2826 DEC HL Step back one location.
2827 LD DE,$0200 Use the search routine to find the end of the DEF FN statement, preparing for the next search; save the name and status meanwhile.
282A PUSH BC
282B CALL EACH_STMT
282E POP BC
282F 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 2831 AND A If HL is now pointing to a '$', move on to the '('.
2832 CALL Z,FN_SKPOVR
2835 POP DE Discard the pointer to 'DEF FN'.
2836 POP DE Get the pointer to the first argument of FN, and copy it to CH-ADD.
2837 LD ($5C5D),DE
283B CALL FN_SKPOVR Move past the '(' now.
283E PUSH HL Save this pointer on the stack.
283F CP ")" Is it pointing to a ')'?
2841 JR Z,SF_R_BR_2 If so, jump: FN has no arguments.
SF_ARG_LP 2843 INC HL Point to the next code.
2844 LD A,(HL) Put the code into A.
2845 CP $0E Is it the 'number marker' code, +0E?
2847 LD D,$40 Set bit 6 of D for a numerical argument.
2849 JR Z,SF_ARG_VL Jump on zero: numerical argument.
284B DEC HL Now ensure that HL is pointing to the '$' character (not e.g. to a control code).
284C CALL FN_SKPOVR
284F INC HL HL now points to the 'number marker'.
2850 LD D,$00 Bit 6 of D is reset: string argument.
SF_ARG_VL 2852 INC HL Point to the 1st of the 5 bytes in DEF FN.
2853 PUSH HL Save this pointer on the stack.
2854 PUSH DE Save the 'string status' of the argument.
2855 CALL SCANNING Now evaluate the argument.
2858 POP AF Get the no./string flag into A.
2859 XOR (IY+$01) Test bit 6 of it against the result of SCANNING (bit 6 of FLAGS).
285C AND $40
285E JR NZ,REPORT_Q Give report Q if they did not match.
2860 POP HL Get the pointer to the first of the 5 spaces in DEF FN into DE.
2861 EX DE,HL
2862 LD HL,($5C65) Point HL at STKEND.
2865 LD BC,$0005 BC will count 5 bytes to be moved.
2868 SBC HL,BC First, decrease STKEND by 5, so deleting the 'last value' from the stack.
286A LD ($5C65),HL
286D LDIR Copy the 5 bytes into the spaces in DEF FN.
286F EX DE,HL Point HL at the next code.
2870 DEC HL Ensure that HL points to the character after the 5 bytes.
2871 CALL FN_SKPOVR
2874 CP ")" Is it a ')'?
2876 JR Z,SF_R_BR_2 Jump if it is: no more arguments in the DEF FN statement.
2878 PUSH HL It is a ',': save the pointer to it.
2879 RST $18 Get the character after the last argument that was evaluated from FN.
287A CP "," If it is not a ',' jump: mismatched arguments of FN and DEF FN.
287C JR NZ,REPORT_Q
287E RST $20 Point CH-ADD to the next argument of FN.
287F POP HL Point HL to the ',' in DEF FN again.
2880 CALL FN_SKPOVR Move HL on to the next argument in DEF FN.
2883 JR SF_ARG_LP Jump back to consider this argument.
SF_R_BR_2 2885 PUSH HL Save the pointer to the ')' in DEF FN.
2886 RST $18 Get the character after the last argument in FN.
2887 CP ")" Is it a ')'?
2889 JR Z,SF_VALUE If so, jump to evaluate the function; but if not, give report Q.
Report Q - Parameter error.
REPORT_Q 288B RST $08 Call the error handling routine.
288C DEFB $19
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 288D POP DE Restore pointer to ')' in DEF FN.
288E EX DE,HL Get this pointer into HL.
288F LD ($5C5D),HL Insert it into CH-ADD.
2892 LD HL,($5C0B) Get the old value of DEFADD.
2895 EX (SP),HL Stack it, and get the start address of the arguments area of DEF FN into DEFADD.
2896 LD ($5C0B),HL
2899 PUSH DE Save address of ')' in FN.
289A RST $20 Move CH-ADD on past ')' and '=' to the start of the expression for the function in DEF FN.
289B RST $20
289C CALL SCANNING Now evaluate the function.
289F POP HL Restore the address of ')' in FN.
28A0 LD ($5C5D),HL Store it in CH-ADD.
28A3 POP HL Restore original value of DEFADD.
28A4 LD ($5C0B),HL Put it back into DEFADD.
28A7 RST $20 Get the next character in the BASIC line.
28A8 JP S_CONT_2 Jump back to continue scanning.
Prev: 27B0 Up: Map Next: 28AB