\ Original Date: September 12, 1988 \ Last Modified: September 28, 1988 \ Author: Jack W. Brown \ Function: Boiler plate, Bullet proof integer numeric input. \ Usage: #IN ( -- number ) \ Overview: \ The idea is to allow only valid single signed integer input \ with editing by checking each key press as it arrives. All \ invalid key presses including function keys will be rejected. \ The value of the number is formed as valid digits are entered \ so that it is impossible to enter a number outside the range \ of -32767 through 32767. If the cursor is first positioned \ screen entry will be limited to 6 character positions from this \ initial cursor postion. \ Notes: \ 1) All word defintions have been author and date coded to \ reflect the date and author of the most recent change. \ 2) Revision history added to beginning of file. \ This is absolute requirement when a team of programmers \ is working on a very large application. Any change made \ is reflected in the revision history and with the actual \ word definition. \ 3) Only non-FORTH83 word used in #OUT \ Possible Improvements: \ 1) Modify code to allow single signed number input in any BASE. \ 2) Modify code or make a new version called D#IN for bullet proof \ input of signed double integers. \ Revision History: \ JWB 12 09 88 Converted from F83 Blocks to *.SEQ file for F-PC \ JWB 28 09 88 Commented out test for invalid interval in (IN) \ JWB 28 09 88 Inserted comment about non standard word #OUT. \ JWB 28 09 88 Added CONSTANTs to make code more readable and \ to avoid non standard ASCII and CONTROL. \ JWB 28 09 88 Clarified operation of RUBOUT. \ JWB 28 09 88 Clarified operation of +DIGIT. \ JWB 28 09 88 Renamed RESET? to CLEAR_SIGN? for readability. \ JWB 28 09 88 Changed . to _ in CORRECT.IT and PROCESS.IT \ JWB 28 09 88 Modified NEGATIVE? to include DUP \ JWB 28 09 88 Reformated #IN and removed DUP to accomodate above. \ Constants added for readablilty. 07 CONSTANT CONTROL_G \ Bell character 08 CONSTANT CONTROL_H \ Back space character. 48 CONSTANT ASCII_0 \ The digit " 0 " 57 CONSTANT ASCII_9 \ The digit " 9 " 45 CONSTANT ASCII_- \ The minus sign character. 13 CONSTANT CONTROL_M \ The carriage return character \ Interval testing words. Naming convention motivated by the \ mathematical intervals (a,b) [a,b] (a,b] and [a,b). \ Would better names be (A,B) [A,B] ... ? \ Application Note: In VP-Planner these four words were \ implemented in machine code and saved approximately 500 bytes, \ resulted in increased execution speed and better readability \ than when actual tests were coded inline in highlevel Forth. \ (IN) leaves a true flag if a < x < b : (IN) ( x a b -- flag ) ( JWB 28 09 88 ) \ 2DUP < NOT ABORT" Invalid interval." -ROT OVER < -ROT > AND ; \ [IN] leaves a true flag if a <= x <= b , otherwise false. : [IN] ( x a b -- flag ) ( JWB 02 10 85 ) 1+ SWAP 1- SWAP (IN) ; \ (IN] leaves a true flag if a < x <= b , otherwise false. : (IN] ( x a b -- flag ) ( JWB 02 10 85 ) 1+ (IN) ; \ [IN) leaves a true flag if a <= x < b , otherwise false. : [IN) ( x a b -- flag ) ( JWB 02 10 85 ) SWAP 1- SWAP (IN) ; \ Note #OUT is not in the FORTH83 standard. ( JWB 28 09 88 ) \ #OUT is a variable that contains the number of charaters output since \ the last carriage return. Its value must be corrected so that words \ EMITing characters leave its value the same as the actual horizontal \ cursor position. If this is not done systems like L&P F83 may produce \ auto word wrap when #OUT exceeds 80. \ Sound alarm bell. : BELL ( -- ) ( JWB 07 10 85 ) CONTROL_G EMIT -1 #OUT +! ; \ Leave true flag if valid digit. : DIGIT? ( n -- flag ) ( JWB 07 10 85 ) ASCII_0 ASCII_9 [IN] ; \ Rub out most recent digit. Note that correction to #OUT is -4 \ because three characters have been EMITed and the cursor ends \ up one character position to the left! : RUBOUT ( -- ) ( JWB 28 09 88 ) CONTROL_H EMIT SPACE CONTROL_H EMIT -4 #OUT +! ; \ Erase digit from screen, adjust number being formed and \ decrement the digit count. Note: \ count = number of digits that have currently been entered. \ n = the value of the number currently on the screen. : -DIGIT ( count n -- count-1 n/10 ) ( JWB 28 09 88 ) RUBOUT \ Remove character from screen. SWAP 1- SWAP \ Adjust digit count. 10 / ; \ Adjust value of number. \ Increment digit count and add in digit. This word is complicated \ by the fact that we must check to make sure that the digit entered \ must not allow the number formed to be outside the valid single \ signed integer range. Note: n'= 10n+key-48 : +DIGIT ( count n key -- count+1 n' If valid key) ( JWB 28 09 88 ) ( -- count n If invalid key ) SWAP 10 UM* \ Scale number by 10 and leave as double#. 2 PICK ASCII_0 - \ Convert key to digit value. 0 D+ \ Extend to double, add to leave new value. 32767. 2OVER DU< \ Check for out of range single number. IF 10 UM/MOD \ Too big, restore original value. NIP NIP BELL \ remove remainder, and key. ELSE DROP \ convert double number to single number. SWAP EMIT \ Echo digit key to the screen. SWAP 1+ SWAP \ Increment the current digit count. THEN ; \ Reset sign flag to indicate non negative number if digit count \ is zero. : CLEAR_SIGN? ( flag count n -- ff count n ) ( JWB 28 09 88 ) OVER 0= IF ROT DROP FALSE -ROT THEN ; \ Correct an error input. : CORRECT_IT ( flag count num key -- flag count num ) ( JWB 28 09 88 ) DROP OVER 0<> \ Is digit count non zero? IF -DIGIT \ Remove most recent digit. ELSE BELL \ Sound warning. THEN CLEAR_SIGN? ; \ Clear numbers sign if count is 0. \ Process all other keystrokes. : PROCESS_IT ( flag count num key -- flag count num ) ( JWB 28 09 88 ) DUP DIGIT? \ Check for digit. IF +DIGIT \ Echo & convert digit, inc count ELSE DROP BELL \ Invalid key or overflow. THEN ; \ Apply sign to number. : APPLY-SIGN ( flg count num key -- num ) ( JWB 28 09 88 ) DROP NIP SWAP \ Drop key, nip count, get sign flag. IF NEGATE THEN ; \ Apply sign to number. \ Negative number? : NEGATIVE? ( count num key -- count num key flag ) ( JWB 28 09 88 ) DUP ASCII_- = 3 PICK 0= AND ; \ Set sign flag to true indicating a negative number \ is being input. : SET-FLAG ( flg cnt num key -- flg cnt num ) ( JWB 07 10 85 ) EMIT ROT DROP TRUE -ROT \ Set sign flag true. SWAP 1+ SWAP ; \ Increment digit count. \ This is the boiler plate, bullet proof interger number \ input routine. It supposedly only allows input of positive \ or negative 16 bit integers. Only valid digit keys are \ allowed. \ flag = sign flag, true means negative number being entered. \ false means positive number. \ count = current count of digits entered. \ number= current value of number on users screen. \ key = key press code from users input. : #IN ( -- number ) ( JWB 28 09 88 ) FALSE 0 0 ( flag count number ) BEGIN KEY ( flag count number key ) \ Fetch key press. NEGATIVE? \ Negative number? IF SET-FLAG \ Set sign flag true. ELSE DUP CONTROL_M = \ Return entered? IF APPLY-SIGN EXIT \ Apply sign to number and exit THEN DUP CONTROL_H = \ Correct error input? IF CORRECT_IT \ This does it. ELSE PROCESS_IT \ Process all other keys. THEN THEN AGAIN ; \ Word to test #IN : TEST ( -- ) BEGIN CR #IN 3 SPACES DUP . 0= UNTIL ;