\ ###################################################################### ANEW --NUMBER-- DECIMAL \ Wil Baden 1999-02-20 \ ******************************************************************* \ * * \ * Wil Baden 1999-02-20 * \ * * \ * Input Number Conversion * \ * * \ * DPL NH NUMBER NUMBER? * \ * * \ ******************************************************************* \ Elizabeth D Rather wrote in comp.lang.forth: \ Many implementations provide "hooks" for the application, \ ... e.g., retaining the "discarded" high-order part of the \ last number converted in a place the appl can find it, and \ providing a way to know how many "decimal places" in a \ just-converted number. \ Unfortunately, ANS Forth doesn't go very far in this \ direction, because when we studied this situation we found \ the specific approaches differed so much we were unable to \ derive a good synthesis. \ However, handling user input is normally in a part of the \ application that is highly platform-dependent (e.g., using a \ Winxx dialog box, keypad on an embedded system, etc.) so \ you're already outside the normal scope of the Standard and \ you may as well make use of whatever your implementation \ provides in this line. \ In SwiftForth, for example, there are two application-layer \ words for input number conversions: \ NUMBER ( c-addr u -- n | d ) \ Convert the string to a single-cell integer if no \ punctuation is found, double-cell integer if punctuated. \ [Error when not a number.] \ NUMBER? ( c-addr u -- 0 | n 1 | d 2 ) \ Attempt to convert the string to a number. 0 indicates \ failure. If the number is punctuated, return 2 with the \ double result beneath; otherwise, return 1 with the \ single result beneath. \ Both words use `DPL` to indicate the number of digits to the \ right of the rightmost punctuation (if any) . It's negative \ if there was no punctuation. So you can check it to find \ out whether you got a single or a double, and in the \ latter case use it for scaling if desired. If it was a \ single and you are concerned about possible overflow, the \ discarded high-order part may be found in `NH`. \ ******************************************************************* \ * NUMBER NUMBER? * \ ******************************************************************* \ Coded by Wil Baden from Elizabeth D. Rather's description. \ `NUMBER?` is used to check if a string is numeric, so "bad" \ punctuation is rejected. \ DPL ( -- addr ) \ User variable containing the number of places \ after the decimal point for numeric input conversion. \ NH ( -- addr ) \ Variable for the high-order part of a single number. \ Is-Numeric-Punctuation ( c -- flag ) \ Test a character for numeric punctuation: : + , - . / \ NUMBER? ( str len -- 0 | num 1 | num . 2 ) \ Convert a string to a number. This version rejects \ bad punctuation. \ NUMBER ( str len -- n | n . ) \ Convert a string to a number in the current base \ using `NUMBER?`. Error when string is not a number. \ ************************ NUMBER NUMBER? ************************ VARIABLE DPL VARIABLE NH : Is-Numeric-Punctuation ( c -- flag ) dup [char] : = SWAP [char] + - 5 U< OR ; : Not-a-Number S" 2DROP 0 EXIT " EVALUATE ; IMMEDIATE \ Check that string is a number. : NUMBER? ( str len -- 0 | num 1 | num . 2 ) -1 DPL ! \ Reject empty string. dup 0= ?? Not-a-Number over C@ [char] - = dup NH ! 1 AND /STRING \ Reject lone minus sign. dup 0= ?? Not-a-Number \ Reject double minus sign. over C@ [char] - = ?? Not-a-Number \ Reject lone punctuation. dup 1 = IF over C@ Is-Numeric-Punctuation ?? Not-a-Number THEN 0. 2SWAP ( num . str len) BEGIN >NUMBER dup WHILE over C@ Is-Numeric-Punctuation \ Reject successive punctuations. over DPL @ <> AND WHILE 1 /STRING dup DPL ! REPEAT THEN ( num . str len) ?dup AND IF ( num . str) C@ BL - ?? Not-a-Number THEN ( num .) NH @ ?? DNEGATE DPL @ 0< IF NH ! 1 ELSE 2 THEN ; : NUMBER NUMBER? 0= ABORT" Not a Humber. " ; \\ ************************ End of NUMBER ************************* GLOSSARY DPL ( -- addr ) 05-NUMBER User variable containing the number of places after the decimal point for numeric input conversion. Is-Numeric-Punctuation ( c -- flag ) 05-NUMBER Test a character for numeric punctuation: : + , - . / NH ( -- addr ) 05-NUMBER Variable for the high-order part of a single number. NUMBER ( str len -- n | n . ) 05-NUMBER Convert a string to a number in the current base using `NUMBER?`. Error when string is not a number. NUMBER? ( str len -- 0 | num 1 | num . 2 ) 05-NUMBER Convert a string to a number. This version rejects bad punctuation. [END]