Function that reads a floating-point number from ASCII text.
Reads a string and converts it to a floating point number in FACCUM. The first thing we do is some initialisation.
Decrement string ptr so it points to just before the number, also set FACCUM to 0. | ||||
0AB3 | 2B | FIn | DCX H | |
0AB4 | CDBE09 | CALL FZero | ||
Set B,D,E to 0 and C to 255. | ||||
0AB7 | 47 | MOV B,A | B=count of fractional digits | |
0AB8 | 57 | MOV D,A | D=exponent sign | |
0AB9 | 5F | MOV E,A | E=exponent | |
0ABA | 2F | CMA | C=decimal_point_done (0xFF for no, 0x00 for yes) | |
0ABB | 4F | MOV C,A |
This is the head of the loop that processes one character of ASCII text at a time.
Get next ASCII character and if it's a digit (as determined by carry flag) then jump down to ProcessDigit. | ||||
0ABC | D7 | FInLoop | RST NextChar | |
0ABD | DA040B | JC ProcessDigit | ||
If we have a decimal point then jump down to increment C and loop back up here (unless we've already encountered a decimal point). | ||||
0AC0 | FE2E | CPI '.' | ||
0AC2 | CAE40A | JZ 0AE4 | ||
If it's not an 'E' indicating exponent then assume we've reached the end of the number and jump to ScaleResult. | ||||
0AC5 | FE45 | CPI 'E' | ||
0AC7 | C2E80A | JNZ ScaleResult |
A decimal exponent has been given (eg 'E+23'). Here we read that (signed) exponent value into E. In this block we use D to hold the exponent sign (0xFF for minus and 0x01 for positive) while we loop reading the digits
Get first character of exponent (following the E). | ||||
0ACA | D7 | GetExponent | RST NextChar | |
0ACB | 15 | DCR D | ||
0ACC | FE99 | CPI KWID_- | ||
0ACE | CAD80A | JZ NextExponentDigit | ||
0AD1 | 14 | INR D | ||
0AD2 | FE98 | CPI KWID_+ | ||
0AD4 | CAD80A | JZ NextExponentDigit | ||
Exponent sign was not given, so it's implicitly +ve (D is 0 after above). We decrement HL so we can get the same character again without jumping. | ||||
0AD7 | 2B | DCX H | ||
If the next char is a digit (of the exponent) then jump down to deal with it. | ||||
0AD8 | D7 | NextExponentDigit | RST NextChar | |
0AD9 | DA230B | JC DoExponentDigit | ||
0ADC | 14 | INR D | ||
0ADD | C2E80A | JNZ ScaleResult | ||
D was 0xFF (ie negative exponent) therefore E = 0 - E | ||||
0AE0 | AF | XRA A | ||
0AE1 | 93 | SUB E | ||
0AE2 | 5F | MOV E,A | ||
0AE3 | 0C | INR C | C was 0xFF, so here it | |
0AE4 | 0C | INR C | becomes 0x01. | |
0AE5 | CABC0A | JZ FInLoop | If C is now zero |
We believe we've read all the characters that make up the number. The last thing that needs to be done is decimally scale our number in FACCUM with respect to the position of the decimal point and the decimal exponent value in E.
0AE8 | E5 | ScaleResult | PUSH H | |
The number of decimal positions to shift by is given by E-B, that is the (E)xponent minus the number of fractional digits given. The direction to shift in is also given by this subtraction, in the sign flag. This is preserved in the following loop. | ||||
0AE9 | 7B | MOV A,E | ||
0AEA | 90 | SUB B | ||
If we're shifting up (ie *ing by 10) then call the function to do that and jump to the end of the loop. | ||||
0AEB | F4FC0A | DecimalLoop | CP DecimalShiftUp | |
0AEE | F2F70A | JP DecimalLoopEnd | ||
We're shifting down (ie sign flag is set) so call the function to do that and increment A, | ||||
0AF1 | F5 | PUSH PSW | ||
0AF2 | CD2309 | CALL FDivByTen | ||
0AF5 | F1 | POP PSW | ||
0AF6 | 3C | INR A | ||
If A is not yet 0 then we have more shifting to do and so loop back. Otherwise we restore the prog ptr and return. | ||||
0AF7 | C2EB0A | DecimalLoopEnd | JNZ DecimalLoop | |
0AFA | E1 | POP H | ||
0AFB | C9 | RET |
Helper function for shifting the result decimally up one place. We only do this if A !=0, and at the end we decrement A before returning.
0AFC | C8 | DecimalShiftUp | RZ | |
0AFD | F5 | PUSH PSW | ||
0AFE | CDC309 | CALL FMulByTen | ||
0B01 | F1 | POP PSW | ||
0B02 | 3D | DCR A | ||
0B03 | C9 | RET |
Process an ASCII digit. We multiply the current total by ten, then add this digit value to it.
Preserve the current exponent (DE) and copy the ASCII digit value to D. | ||||
0B04 | D5 | ProcessDigit | PUSH D | |
0B05 | 57 | MOV D,A | ||
Increment the count of fractional digits in B. C is 0xFF if no decimal point has been encountered, and 0 if it has. Adding with carry (which is set before this block is jumped to) makes this work. | ||||
0B06 | 78 | MOV A,B | ||
0B07 | 89 | ADC C | ||
0B08 | 47 | MOV B,A | ||
0B09 | C5 | PUSH B | ||
0B0A | E5 | PUSH H | ||
Multiply the current total in FACCUM by ten and get the digit value in A. | ||||
0B0B | D5 | PUSH D | ||
0B0C | CDC309 | CALL FMulByTen | ||
0B0F | F1 | POP PSW | ||
0B10 | D630 | SUI '0' | ||
Add this digit's value to FACCUM. To do this we first preserve FACCUM on the stack, then load FACCUM with the digit value (in A) via a call to FCharToFloat. Then we get the old FACCUM off the stack into BCDE and call FAdd. | ||||
0B12 | CD020A | CALL FPush | ||
0B15 | CDE509 | CALL FCharToFloat | ||
0B18 | C1 | POP B | ||
0B19 | D1 | POP D | ||
0B1A | CD1208 | CALL FAdd+2 | ||
Restore regpairs and jump back to FInLoop | ||||
0B1D | E1 | POP H | ||
0B1E | C1 | POP B | ||
0B1F | D1 | POP D | ||
0B20 | C3BC0A | JMP FInLoop |
Deal with a digit of the exponent. This is simple - just multiply the current exponent value (in E) by ten, then add the digit value to it, and finally jump back.
E=E*10 + (HL) | ||||
0B23 | 7B | DoExponentDigit | MOV A,E | |
0B24 | 07 | RLC | ||
0B25 | 07 | RLC | ||
0B26 | 83 | ADD E | ||
0B27 | 07 | RLC | ||
0B28 | 86 | ADD M | ||
0B29 | D630 | SUI '0' | ||
0B2B | 5F | MOV E,A | ||
0B2C | C3D80A | JMP NextExponentDigit |