Revision 0.5 2017-01-25
Background
>FLOAT is the Forth-94
string-to-float conversion primitive. While most implementations
seek to follow the specification
given by the Forth-94,
few are strictly compliant. A common deficit is the inability to
exclude all illegal input.
The implementation presented here aims to achieve full
compliance with Forth-94 in a minimum of code. A test is included
to check against common errors.
Implementation
\ FINPUT.F version 0.5 2017-01-25 \ \ A minimum yet compliant implementation of Forth-94 >FLOAT. \ Works with separate or common stack float model. No \ particular effort has been made to optimize for speed or \ conversion accuracy. \ \ The requirements for Forth-94 floating-point text input \ are met through the function (fnumber). \ \ Implementation dependencies: \ 2's complement arithmetic \ 1 char = 1 address unit \ \ This code is PUBLIC DOMAIN. Use at your own risk. \ \ History: \ \ 0.1 Replaced .1E F* with 10E F/ for better accuracy. \ Added conditional to allow leading decimal point \ on forth text input. \ \ 0.2 Simplified case-insensitive character tests. \ \ 0.3 Factored fnumber to provide (fnumber). \ \ 0.4 Add option to disable a string of blanks from \ returning true. \ 0.5 Replace EXIT THEN with END FORTH DEFINITIONS DECIMAL CR .( Loading FINPUT 0.5 2017-01-25 ... ) 1 \ Change to 0 to compile shorter less strict code DUP [IF] .( strict ) [ELSE] .( short ) [THEN] .( version ) CR VARIABLE exp \ exponent VARIABLE dpf \ decimal point FVARIABLE tmp 10 0 D>F FCONSTANT ften \ 10.E0 : getc ( a u -- a' u' c ) 1 /STRING OVER 1- C@ ; \ get sign : gets ( a u -- a' u' n|0 ) DUP IF getc DUP [CHAR] - = IF END [CHAR] + <> /STRING THEN 0 ; : getdigs ( a u -- a' u' ) BEGIN DUP WHILE getc [CHAR] 0 - DUP 9 U> IF DROP -1 /STRING END 0 D>F tmp F@ ften F* F+ tmp F! dpf @ exp +! REPEAT ; DUP [IF] ( strict ) : getmant ( a u -- a' u' flag ) TUCK getdigs DUP IF OVER C@ [CHAR] . = IF -1 dpf ! 1 /STRING getdigs THEN THEN ROT OVER - dpf @ + ; [ELSE] : getmant ( a u -- a' u' flag ) getdigs DUP IF OVER C@ [CHAR] . = IF -1 dpf ! 1 /STRING getdigs THEN THEN ; [THEN] : getexp ( a u -- a' u' ) DUP IF OVER C@ 33 OR [CHAR] e = ( 'D' 'E' 'd' 'e') 1 AND /STRING THEN gets >R 0 0 2SWAP >NUMBER 2SWAP D>S R> IF NEGATE THEN exp @ + BEGIN ?DUP WHILE DUP 0< IF 1+ tmp F@ ften F/ ELSE 1- tmp F@ ften F* THEN tmp F! REPEAT ; \ NOTE: If a string of blanks is not required to \ return 0.0E and true, remove the lines marked ( **) [IF] ( strict ) \ Forth-94 function (strict) : >FLOAT ( c-addr u -- r true | false ) [ 0 0 D>F ] FLITERAL tmp F! 0 exp ! 0 dpf ! 2DUP -TRAILING NIP 0<> AND DUP IF ( **) gets >R getmant IF getexp DUP WHILE THEN 2DROP R> DROP 0 END ELSE 0 >R THEN ( **) 2DROP tmp F@ R> IF FNEGATE THEN TRUE ; [ELSE] \ Forth-94 function (non-strict) : >FLOAT ( a u -- r true | false ) [ 0 0 D>F ] FLITERAL tmp F! 0 exp ! 0 dpf ! -TRAILING ( **) gets >R getmant getexp IF R> 2DROP 0 END DROP tmp F@ R> IF FNEGATE THEN TRUE ; [THEN] \ Forth text float input. Floating-point numbers may be \ entered using F#. 1 [IF] ( Scan for 'E' or 'e') : escan ( c-addr u1 -- u2 ) BEGIN DUP WHILE OVER C@ 32 OR [CHAR] e - WHILE 1 /STRING REPEAT THEN NIP ; [ELSE] ( Forth-94 specifies 'E') : escan ( c-addr u -- fl ) S" E" SEARCH >R 2DROP R> ; [THEN] 1 [IF] ( Forth-94 behaviour ) : (fnumber) ( c-addr u -- [r] flag ) DUP 1 > IF ( at least 2 chars ) OVER DUP C@ [CHAR] . < - ( skip sign) C@ [CHAR] . > >R ( 1st char must be a digit) 2DUP escan R> AND BASE @ 10 = AND 0= WHILE THEN 2DROP 0 ELSE >FLOAT THEN ; [ELSE] ( allow leading decimal point ) : (fnumber) ( c-addr u -- [r] flag ) 2DUP escan BASE @ 10 = AND IF >FLOAT ELSE 2DROP 0 THEN ; [THEN] : fnumber ( c-addr u -- [r] flag ) (fnumber) DUP >R STATE @ AND IF POSTPONE FLITERAL THEN R> ; : F# ( "number" ) BL WORD COUNT fnumber 0= ABORT" bad float" ; IMMEDIATE [DEFINED] DXFORTH [IF] BEHEAD exp getexp BEHEAD escan escan [THEN] 0 [IF] ( Test ) : CHECK ( addr len flag ) >R CR [CHAR] " EMIT 2DUP TYPE [CHAR] " EMIT 8 OVER - SPACES >FLOAT DUP >R IF FDROP THEN R> ." --> " DUP IF ." TRUE " ELSE ." FALSE" THEN R> - IF ." *fail* " ELSE ." pass " THEN ; : TEST ( -- ) CR ." Checking >FLOAT Forth-94 compliance ..." CR S" ." FALSE CHECK S" E" FALSE CHECK S" .E" FALSE CHECK S" .E-" FALSE CHECK S" +" FALSE CHECK S" -" FALSE CHECK S" 9" FALSE CHECK S" 9 " FALSE CHECK S" " TRUE CHECK S" " TRUE CHECK S" 1+1" TRUE CHECK S" 1-1" TRUE CHECK S" 9" TRUE CHECK S" 9." TRUE CHECK S" .9" TRUE CHECK S" 9E" TRUE CHECK S" 9e+" TRUE CHECK S" 9d-" TRUE CHECK ; TEST [THEN] \ end
Top Home Forth
Page updated: 25 Jan 2017