| Routines

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
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.