Prev: 2C8D Up: Map Next: 2D1B
2C9B: THE 'DECIMAL TO FLOATING POINT' SUBROUTINE
Used by the routine at S_DECIMAL.
As part of syntax checking decimal numbers that occur in a BASIC line are converted to their floating-point forms. This subroutine reads the decimal number digit by digit and gives its result as a 'last value' on the calculator stack. But first it deals with the alternative notation BIN, which introduces a sequence of 0's and 1's giving the binary representation of the required number.
Input
A Code of the first character in the number
Output
DEC_TO_FP 2C9B CP $C4 Is the character a 'BIN'?
2C9D JR NZ,NOT_BIN Jump if it is not 'BIN'.
2C9F LD DE,$0000 Initialise result to zero in DE.
BIN_DIGIT 2CA2 RST $20 Get the next character.
2CA3 SUB "1" Subtract the character code for '1'.
2CA5 ADC A,$00 0 now gives 0 with carry set; 1 gives 0 with carry reset.
2CA7 JR NZ,BIN_END Any other character causes a jump to BIN_END and will be checked for syntax during or after scanning.
2CA9 EX DE,HL Result so far to HL now.
2CAA CCF Complement the carry flag.
2CAB ADC HL,HL Shift the result left, with the carry going to bit 0.
2CAD JP C,REPORT_6 Report overflow if more than 65535.
2CB0 EX DE,HL Return the result so far to DE.
2CB1 JR BIN_DIGIT Jump back for next 0 or 1.
BIN_END 2CB3 LD B,D Copy result to BC for stacking.
2CB4 LD C,E
2CB5 JP STACK_BC Jump forward to stack the result.
For other numbers, first any integer part is converted; if the next character is a decimal, then the decimal fraction is considered.
NOT_BIN 2CB8 CP "." Is the first character a '.'?
2CBA JR Z,DECIMAL If so, jump forward.
2CBC CALL INT_TO_FP Otherwise, form a 'last value' of the integer.
2CBF CP "." Is the next character a '.'?
2CC1 JR NZ,E_FORMAT Jump forward to see if it is an 'E'.
2CC3 RST $20 Get the next character.
2CC4 CALL NUMERIC Is it a digit?
2CC7 JR C,E_FORMAT Jump if not (e.g. 1.E4 is allowed).
2CC9 JR DEC_STO_1 Jump forward to deal with the digits after the decimal point.
DECIMAL 2CCB RST $20 If the number started with a decimal, see if the next character is a digit.
2CCC CALL NUMERIC
DEC_RPT_C 2CCF JP C,REPORT_C Report the error if it is not.
2CD2 RST $28 Use the calculator to stack zero as the integer part of such numbers.
2CD3 DEFB $A0 stk_zero
2CD4 DEFB $38 end_calc
DEC_STO_1 2CD5 RST $28 Use the calculator to copy the number 1 to mem-0.
2CD6 DEFB $A1 stk_one
2CD7 DEFB $C0 st_mem_0
2CD8 DEFB $02 delete
2CD9 DEFB $38 end_calc
For each passage of the following loop, the number (N) saved in the memory area mem-0 is fetched, divided by 10 and restored, i.e. N goes from 1 to .1 to .01 to .001 etc. The present digit (D) is multiplied by N/10 and added to the 'last value' (V), giving V+D*N/10.
NXT_DGT_1 2CDA RST $18 Get the present character.
2CDB CALL STK_DIGIT If it is a digit (D) then stack it.
2CDE JR C,E_FORMAT If not jump forward.
2CE0 RST $28 Now use the calculator.
2CE1 DEFB $E0 get_mem_0: V, D, N
2CE2 DEFB $A4 stk_ten: V, D, N, 10
2CE3 DEFB $05 division: V, D, N/10
2CE4 DEFB $C0 st_mem_0: V, D, N/10 (N/10 is copied to mem-0)
2CE5 DEFB $04 multiply: V, D*N/10
2CE6 DEFB $0F addition: V+D*N/10
2CE7 DEFB $38 end_calc
2CE8 RST $20 Get the next character.
2CE9 JR NXT_DGT_1 Jump back (one more byte than needed) to consider it.
Next consider any 'E notation', i.e. the form xEm or xem where m is a positive or negative integer.
E_FORMAT 2CEB CP "E" Is the present character an 'E'?
2CED JR Z,SIGN_FLAG Jump forward if it is.
2CEF CP "e" Is it an 'e'?
2CF1 RET NZ Finished unless it is so.
SIGN_FLAG 2CF2 LD B,$FF Use B as a sign flag, +FF for '+'.
2CF4 RST $20 Get the next character.
2CF5 CP "+" Is it a '+'?
2CF7 JR Z,SIGN_DONE Jump forward.
2CF9 CP "-" Is it a '-'?
2CFB JR NZ,ST_E_PART Jump if neither '+' nor '-'.
2CFD INC B Change the sign of the flag.
SIGN_DONE 2CFE RST $20 Point to the first digit.
ST_E_PART 2CFF CALL NUMERIC Is it indeed a digit?
2D02 JR C,DEC_RPT_C Report the error if not.
2D04 PUSH BC Save the flag in B briefly.
2D05 CALL INT_TO_FP Stack ABS m, where m is the exponent.
2D08 CALL FP_TO_A Transfer ABS m to A.
2D0B POP BC Restore the sign flag to B.
2D0C JP C,REPORT_6 Report the overflow now if ABS m is greater than 255 or indeed greater than 127 (other values greater than about 39 will be detected later).
2D0F AND A
2D10 JP M,REPORT_6
2D13 INC B Test the sign flag in B; '+' (i.e. +FF) will now set the zero flag.
2D14 JR Z,E_FP_JUMP Jump if sign of m is '+'.
2D16 NEG Negate m if sign is '-'.
E_FP_JUMP 2D18 JP e_to_fp Jump to assign to the 'last value' the result of x*10↑m.
Prev: 2C8D Up: Map Next: 2D1B