[Index] [Previous] [Next]

2.9 Reading Numbers

Function that reads a floating-point number from ASCII text.

FIn

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

 


[Index] [Previous] [Next]