Elements of a FORTH Data Base Design
Glen B. Haydon
Route 2, Box 429
La Honda, CA 94020
Copyright 1982 by Haydon Enterprises
All Rights Reserved
In the spirit of the FORTH Interest Group, this discussion and the FORTH screens are placed in the public domain. However, further distribution must include this notice and an appropriate acknowledgment.
In this day and age, data base design and manipulation is one of the major activities best accomplished with computers. In practice, FORTH proves to be an ideal language for developing and using custom data bases. By comparison with other languages, high or low-level, FORTH is a winner. It meets the requirements of being interactive and providing documentation as identified by Fred Brooks in his The Mythical Man-Month as ideal for the development of new systems. The amazing speed and ease with which custom data bases can be developed more than justifies the effort required to learn FORTH.
I have developed a number of small data bases of up to 800 records containing 128 bytes each to serve my specific needs. I have also initialized, with simple formatted input and output routines, a custom data base for inventory control in a few hours one evening. Having used languages other than FORTH for similar work, it is highly unlikely I will ever go back to them.
This discussion presents a group of utility FORTH word definitions which facilitate the development of custom data bases and a sample application using utilities to define a small file. A number of techniques available in FORTH are illustrated.
Some months ago, at a regular monthly meeting of the FORTH Interest Group in Hayward, California, the prime mover of the group distributed and discussed several FORTH screens which provided the foundation for beginning the definition of a data base file. I have modified his screens slightly and expanded them to provide a general framework with which to define custom accounting data bases. I will assume that the reader has some knowledge of the fig-FORTH Model and proceed with the examination of screens developed from it. In this discussion, FORTH words are in ail capital letters to set them apart from the English words in the text.
The first two screens provide eight utility FORTH words for developing a data base file. The comments included within parentheses in the screens should, combined with the mnemonic nature of the words, give you a clue to what is hap-penning. The first two words are variables used in manipulating the file, REC# and OPEN. 2@ is a FORTH word, and alias for D@, which fetches the next two values beginning with the address on the top of the stack and places them on the stack. The word, LAYOUT, places two parameters of the new definition of a file on the stack for subsequent use. READ is the first word one will have occasion to use in routine manipulating records in the data base. It takes the number of the desired record from the top of the stack and, after checking to see that it is a valid record, places its value in the variable REC# which is used to identify the record then under consideration. The -word RECORD takes the value for a record number from the stack and returns its address to the stack. Finally, ADDRESS takes the record number at the variable REC# and using RECORD leaves the address of that record on the top of the stack. With only these eight FORTH words: two variables, one utility word, and four basic words for file reference, we can proceed to the definition of three defining words in the next screen.
The three words on the next screen are called defiing words because they are used to define new FORTH words as the names of fields in our record and to define the name for the file we are defiing, each with specific properties. These words utilize the combination of the FORTH primitives < BUILDS and DOES which are present in the model. It may take some time to fully appreciate what these primitive words accomplish and the way they work. Perhaps an examination of what they are doing in this Screen will help you understand their function.
Two types of record fields are distinguished and defined with separate words, a numerical or data field and a text field. The first word, DFIELD, is used to add to a record being defined, a field containing the number of bytes given on the top of the stack and gives that field a name. In subsequent use, that newly defined word (data field name) will cause the address of that field in the record whose value is currently in the variable REC# to be left on the stack. This word is used to identify the location in a record where a numerical value is to be stored in a binary form. I call it a "data field," in contrast with a "text field" in which the length of the field should also be immediately available. Thus TFIELD is used to define a "text field" which will identify a field in the new record with a length equal to the number of bytes given on the top of the stack, and gives that field a name. In subsequent use, that newly de-freed word (text field name) will cause not only the address of that text field in the record whose value is currently in the variable REC# to be left on the stack, but also the length of that field. The length is convenient when the primitive word TYPE is used to print the character string in that field. Obviously, the length is not needed in a data field. Thus provisions are made for defining two types of fields in a record. As new fields are added to a record in the course of its definition, the current length of the record is maintained on the top of the stack.
Once the definition of the fields in a record is completed, the value of the record length remains on the stack. To this we need to add values for the number of records we wish to include and finally the block number in which the records are to start, before we can use the defining word FILE to give the file a name. Later when the new file name is used, the address of the necessary file parameters is placed in the recently defined variables OPEN as required for access to any given record with the words defined in the first Screen.
With these two Screens we have the file utilities necessary to define a new file. However, several characteristics of the particular implementation of FORTH which is being used are important. Most systems created under the model have 128 bytes per block although any multiple of 128 can be used. In these systems then, the largest record length can be no longer than 128 bytes, but with a larger block size, larger records can be used. In order to take maximum advantage of the block size, it should be very nearly equal to a multiple of the record length. For example, a record length of 70 bytes would not leave enough room in a 128 byte block for a second record and in this case
58 bytes of space would be wasted. If need be, such a designed file would work, but at the expense of memory space. Also, the initial block to be used in the definition created by the word FILE must be chosen according to the block size for the particular implementation. For example, block 400 in an implementation with 128 bytes per block would be block 50 in an implementation with 1024 bytes per block. Although I find a block size of 1024 to be more efficient and use it routinely, the Screens presented here have been written for and tested on an implementation with 128 bytes per block.
Before starting with a discussion of an example of the application of these file development utilities, several Screens of utilities for use in the input and output of numerical data will prove to be most helpful. These include a group of double precision utilities, date compression and expansion routines, and numerical routines for handling dollar amounts and storing them as double precision integers.
The double precision integer utilities are used in date compression and expansion as well as in the double precision integer operations for dollar amounts. These are simple extensions from the limited double precision words found in the model and should require no further explanation. The input on the stack before executing the word and the output left on the stack afterwards are indicated in the format used in the fig-FORTH Glossary. You will note that several of these are mixed double and single precision operations which are sufficient for the requirements of this program.
The date compression routine is really simple. When I find the time I will develop an algorithm to convert the date to a true Julian day and store the least significant value. This would make calculation of the time between two given dates easy. In the meantime, the present routine allows one to enter the date as numerical values separated by slashes, a commonly used format, and reduce the value to a single 16-bit integer requiring only two bytes for storage. The routine provides an example of using a delimiter other than a space to parse WORD and the use of NUMBER to interpret a numerical value without searching the dictionary. After the parsing of the input, three double precision numbers are left on the stack. The word DATEBIT defines a simple algorithm which is applied to reduce these three double precision values to 16 bits. The execution of ?DATE first prompts with the format to be used, then waits for the value to be entered. The value is then converted to the 16 bits and left on the stack for storage. Since . is used to connote "print" in FORTH, .DATE is defined to print a properly formatted date from a 16-bit integer on the stack. This routine is useful as an example of conversion of a binary value to a text string for printing.
Finally, we have a Screen to define some FORTH words used to input and output dollar amounts and convert them to and from double precision, 32-bit integers with the necessary scaling for the location of the decimal point. In FORTH, the use of a decimal point forces an input number to a double precision integer which takes four bytes. A convenient FORTH primitive word, DPL for decimal point locator, keeps a count on the number of digits entered following the decimal point. Utilizing this value as an input for a case type word, the numerical value entered can be scaled properly, regardless of how many digits are entered to the right of the decimal, if any. This method of executing a case-like routine is straightforward. First, the action to be taken in each case is defined. 0SCALE means that there were no digits to the right of the decimal, which requires that the entered double precision integer must be multiplied by 100. In a similar manner ISCALE is used meaning that there was only one digit entered following the decimal point and the entered double precision integer must be multiplied by 10. 2SCALE doe nothing, since no scaling is needed. Finally, if more than 2 digits are entered, an error must have been made and an appropriate error message is given. Once each of these cases is defined, their code filed addresses, CFA, can be stored beginning with the address of a defined variable NSCALE and extending into the allotted space. The word SCALE then finds the value of the variable DPL and counts over to the proper code field address which is then placed on the stack and the selected word is executed.
After this scaling operation, the word to input a dollar amount ?$AMOUNT is defined, which leaves the scaled double precision integer on the stack ready to be stored. Finally, a routine defined by the word .$AMOUNT connoting "print dollar amount," will print the double precision integer on the top of the stack as a dollar value right justified in eight spaces.
There are certainly other and probably better ways to accomplish the work done by these three Screens of utilities, but they work. The way they work provides some examples of the beauty of FORTH as it exists in the model.
With these five Screens, we can very quickly define a record for a data base with custom selected fields and then the associated file characteristics. In the past, I have several times included in a data base values calculated from other values in the base. On occasion, it has been necessary to change one of the original values. This has always required that the calculated fields be re-done too. I now find that it is more convenient to enter only the basic data. Ail calculations can be made while the output is being formatted and printed with no significant loss of time. The slowest part of printing the formatted remit is the delay in the output device.
As an example of the definition of a new data base, I have chosen one in which each record would be allotted 4 fields for a two byte tag, a 30 byte stock name, a two byte date, and a 4 byte stock price. Though little could be done with this as a data base, it does provide an example of each type of input. Finally, a simple set of routines is given to clear the records, input new records, and print out a list of the records in the file.
As a matter of convention, I give each field a name with no prefix. Thus a data field name will leave an address on the stack and a text field name will leave an address and count on the stack. By using the FORTH connotations of ! for store and . for print, I define some utilities for inputting data and text, and for printing out the respective fields. From these utilities I can assemble an input format and an output format as desired. I have not included routines for error checking, which would be most desirable especially in a hostile environment.
Now to examine the actual example of the definition of a File which we will call DEMO. Each record will begin with zero offset from the record address and a 0 is entered followed by 2 for a two-byte length of a data field to be named TAG. Many occasions in later manipulation of records make it desirable to have such a field for adding flags, etc. Following this definition the length value of 2 is left on the stack so that for the next field only its length need be entered. In this case a text field of 30 bytes which is given the name NAME which then leaves the value of 32 (the length of the TAG field plus the NAME field) on the stack. Then a two-byte data field, DAY, is reserved for a 16-bit compressed date and then a four-byte data field DOLLAR, for a double precision integer value of a dollar amount. With this, the 4 fields within the record of a new file are de/med. Next we will define the file name. According to the utility for generating a new file, we must first add to the value of the record length remaining on the stack, a value for the number of records we plan to include in the file and then the first block number to be used as determined by the FORTH implementation in use. Then, we use the word FILE to create a file with these parameters and give it the name DEMO. The data base file is now defined. For the record number whose value is in the variable REC#, we can place the value of the address of the data fields, the address and count of the text fields on the stack by simply entering the field name. Next a few simple utilities will make accessing these new fields easier.
Remembering the connotations associated with the FORTH words ! and. we will define words to input data or text to the appropriate fields of that record whose value is currently in the variable REC#. These are simple File primitives which will then be available for routines to format input and output as desired. The field TAG is not used at this time and specific routines are not defined. To store a name in the name field we define the word !NAME. This routine first fills the existing field with blanks, ASCII 32 (decimal) and then pauses for input from the keyboard. The input text is truncated to the maximum length of the text field if necessary and then moved to that field. In order to output the name in the field we define the word .NAME. In a similar manner we define !DAY to store a 16-bit integer value of a date which has been compressed into that field. In the earlier utilities we have already defined ?DATE which waits for a date to be input and leaves the compressed value on the stack. All that is necessary is to put the address of the field on the stack with DAY and then store the encoded date there. We then define .DAY to output the date stored in the DAY field. We get the 16-bit value stored there to the top of the stack and use the previously defined word .DATE to output it in the proper format. Finally we define !DOLLAR to parse a dollar value input with a decimal point in any location and scaled to a double precision number which is then stored in the proper field. In a similar manner, .DOLLAR is defined to format the stored double precision integer to a right justified eight-digit number preceded by a dollar sign. With these definitions, we have completed a set of FORTH words to input and output data from records in our data base.
Immediately after putting data into a record, it is often desirable to see what is actually present in that record. The values in each byte of a record can be displayed using a dump routine. Simply place the desired record address on the top of the stack by entering the record number followed by our file utility word READ and ADDRESS followed by the length of the record and the word for your dump routine. But the byte values printed out in hex or decimal are not really all that helpful It is hard to interpret the numerical value in their byte pattern. A convenient word .REC is defined to print out the current record number followed by the formatted output of the value in each field using the above utilities and an appropriate number of spaces and carriage returns. This is the most rudimentary form of a formatted output. If desired, the output could be presented in reverse video by a slight modification of this routine. It could also be placed anywhere on the Screen.
Finally, a few examples of formatting input and output routines are shown on the last Screen. First, it is desirable to clear all data in a file with a word CLEAR. DATA before entering new data. This particular definition clears only the first block, all that is necessary in this application. You should be able to modify the definition of this word to meet the requirements of your application and particular implementation of FORTH.
I use the 0 record in a file for a variety of information about the file, which I can address directly from the address of its first byte without using the field definitions, or I can use specific bytes or fields in ways other than I have defined them. In this example I use the value in the integer at the field TAG in the 0 record to keep track of the last record currently in the File. When this record is cleared with CLEAR-DATA a value of 0 is present in the location of TAG which means that there are no records present. 0 READ places the value of 0 in the variable REC# and then TAG places the address on the top of the stack and @ gets that value, the last record number used in the file. To add a new record, this value is, incremented and then duplicated on the stack. The top copy is stored back in the field of TAG in the 0 record which is updated. Then the second copy is placed in the variable REC# and we are ready to fill in the information for the next record.
A series of prompts can be formatted on the Screen in any convenient arrangement as in this example. Following the desired prompt for each field, the previously defined word is used to get the information for the field and store it there. After entering a record, it is always nice to see the data you actually put in. This is done with the word .REC followed by the FORTH primitive UPDATE to flag the buffer as altered and FLUSH to save the new record on the disk in the file. This assures that the image of the record which is displayed is the version saved on the disk.
An output format can be developed in a similar manner. In this example I have included a check to see if there are any records in a file because the DO... LOOP will always print one loop and peculiar output is generated if the bytes in the fields are all set to zero. This output routine presents a simple list of the record numbers and the formatted content of the fields.
In conclusion, I find this approach to file definition is time saving and hope that you will find it useful The discussion of the FORTH utilities used to define a new data base field and the example of handling data, provides some elaboration of the information included on the Screens. This will be a review for one who already has learned the primitives in the FORTH model and who understands how the language works, but perhaps the discussion of these Screens will help those less experienced. There is nothing sacred about the techniques used here. Modify the various words to suit your particular needs. It is easy enough to develop new formats interactively. However, I would encourage you to utilize and build on the standards of the fig-FORTH model. When the 79 Standards become generally available, it should be relatively easy to update your Screens without changing the format of the record file. The importance of utilizing an accepted standard in developing programs for ultimate use in a wide variety of implementations of FORTH cannot be over-emphasized.
I wish to thank Bill Ragsdale for his encouragement to write this discussion based on his presentation to the FORTH Interest Group at one of their monthly meetings last year.
Application Note: These FORTH routines have been developed on a FORTH Operating System for the Heathkit H89. This system is available from the Mountain View Press, Box 4656, Mountain View, CA 94040 [Route2 Box 429, La Honda, CA 94020]. The compiled FORTH program image can be saved on disk and will be up and running in less than four seconds from a cold boot. The system has 1024 byte blocks hich also increases the speed of operation.
However, after development, the Screens were loaded on a FORTH implementation derived from the fig-FORTH for 8080 Assembly Source Listing which is available from the FORTH Interest Group, Box 1105, San Carlos, CA 9.4070 in printed form and already on disk also from the Mountain View Press. This version has 128 byte blocks and operates in conjunction with CP/M. To this has been added the fig-EDITOR from the fig-FORTH Installation Manual and a single extension, DUMP, used to illustrate the appearance of the records as stored in a block.
The printed session illustrated was made using the CP/M control P to echo the output on the printer. The session starts with CP/M loaded and its usual prompt: The CP/M file, FORTH60.COM, is the object module of the fig-FORTH model The warning messages are not on Screens 4 and S and the warning flag is turned off. Then the Screens for the fig-EDITOR and a good dump routine are loaded. Finally, the Screens discussed are loaded. The file DEMO is called and the application of some of the file utilities is illustrated. This presentation will hopefully assure that there are no errors in the printed screens.
Brooks, F. P., Jr., The Mythical Man-Month, Addison-Wesley Publishing Company, 1975.
.... , fig-FORTH Installation Manual, Glossary, Model, Forth Interest Group, Box 1105, San Calos, CA 94070.
.... , fig-FORTH for 8080 Assembly Source Listing, Forth Interest Group, Box 1105, San Carlos, CA 94070 B
SCR # 21 0 ( SCREEN 21: COMMENTS AND LOAD FOR DEMO DATA FILE ) 1 27 EMIT 69 EMIT CR CR CR CR CR 2 ." This demonstraticn data system provides a pattern for the" 3 CR ." further development of any type of data base. The basic" 4 CR ." file formating definitions are on Screens 22 and 23. Some" 5 CR ." utilities are on 24, 25, and 26. The demo file" 6 CR ." definitions are on 27. Elementary file manipulation" 7 CR ." utilities are on 28. This model should get you started." 8 : PROCEDE CR CR ." ENTER 'Y' TO LOAD SCREENS " KEY 89 = IF 9 29 22 DO I LOAD LOOP ENDIF ; 10 PROCEDE 11 ;S 12 13 14 15 SCR # 22 0 CR ." SCREEN 22: FILE DEVELOPMENT" 1 0 VARIABLE REC# ( holds the current record number ) 2 0 VARIABLE OPEN ( points to current file descriptor ) 3 4 : 2@ DUP 2+ @ SWAP @ ; ( double fetch ) 5 6 : LAYOUT ( leave bytes/record-2, and bytes/block-1 ) 7 OPEN @ 4 + 2@ ; 8 : READ ( n-th record, on stack, is made current ) 9 0 MAX DUP OPEN @ 2+ @ < 0= 10 IF ." FILE ERROR" QUIT THEN REC# '. ; 11 : RECORD ( leave address of n-th record ) 12 LAYOUT */MOD OPEN @ @ + BLOCK + ; 13 : ADERESS ( leave address of the current record ) 14 REC# @ RECORD ; 15 ;S SCR # 23 0 CR ." SCREEN 23: FILE DEVELOPMENT - 2" 1 : TFIELD <BUILDS ( create a text field ) 2 OVER , DUP , + ( leaves file count for this definition ) 3 DOES> ( leaves: addr, count ) 4 2@ ADDRESS + SWAP ; 5 : DFIELD <BUILES ( create a data field ) 6 OVER , + ( leaves file count for this definition ) 7 DOES> ( leaves address ) 8 @ ADDRESS + ; 9 : FILE ( create a naned storage allocation ) 10 <BUILDS , ( origin block ) 11 1+ , ( number of records in file ) 12 DUP B/BUF OVER / * , ( # bytes per block ) 13 , ( # bytes per record ) 14 DOES> OPEN ! ; ( when file name used, point to ) 15 ;S ( its descriptor parameters. ) SCR # 24 0 CR ." SCREEN 24: DOUBLE PRECISION ARITHMETIC" 1 : D/ ( d, u--- d ) 2 SWAP OVER /MOD >R SWAP U/ SWAP DROP R> ; 3 : D* ( d, u--- d ) 4 DUP ROT * ROT ROT U* ROT + ; 5 : D/MOD ( d, u--- r, q ) U/ ; 6 : D@ ( addr --- d ) DUP 2 + @ SWAP @ ; 7 : D! ( d, addr --- ) DUP ROT SWAP ! 2 +., ; 8 : DDUP( d --- d, d ) 2DUP ; 9 : DSWAP ( dl, d2, --- d2, dl ) ROT >R ROT R> ; 10 : DDROP ( dl, d2 --- ) DROP DROP ; 11 ;S 12 13 14 15 SCR # 25 0 CR ." SCREEN 25: DATE COMPRESSION AND EXPANSION" 1 : DATEBIT ( converts date input to 2 bytes ) 2 32 D* D+ 13 D* D+ DROP ; 3 : ?DATE ." ( MM/DD/YY )" 4 QUERY 47 WORD HERE NUMBER 47 WORD HERE NUMBER BL WORD 5 HERE NUMBER DATEBIT ; 6 : .DATE ( formats 2 byte date code and prints ) 7 0 13 U/ 32 /MOD ROT 100 * ROT + 0 100 D* ROT 0 D+ 8 <# # # 47 HOLD # # 47 HOLD # # #> TYPE ; 9 ;S 10 11 12 13 14 15 SCR # 26 0 CR ." SCREEN 26: ?$AMOUNT AND .$AMOUNT " 1 ( define action for each scale case ) 2 : 0SCALE 100 D* ; : 1SCALE 10 D* ; : 2SCALE ; 3 : 3SCALE ." INPUT ERROR" CR ; 4 ( define scale case and extend for each with 'CFA' ) 5 ' 0SCALE CFA VARIABLE NSCALE ' 1SCALE CFA , ' 2SCALE CFA , 6 ' 3SCALE CFA , 7 ( scale double precision value according to 'DPL' ) 8 : SCALE DPL @ 3 MIN 2 * NSCALE + @ EXECUTE ; 9 ( walt for decimal value and scale it- leave value on stack ) 10 : ?$AMOUNT QUERY BL WORD HERE NUMBER SCALE ; 11 ( print d from stack as $ and right justify in 8 spaces ) 12 : .$AMOUNT 13 DUP ROT ROT DABS <# # # 46 HOLD #S SIGN #> 14 36 EMIT DUP 8 SWAP - SPACES TYPE ; 15 ;S SCR # 27 0 CR ." SCREEN 27: DEMO FILE - RECORD GENERATION" 1 0 2 DFIELD TAG ( a tag ) 2 30 TFIELD NAME ( item name ) 3 2 DFIELD DAY ( the date ) 4 4 DFIELD DOLLAR ( a dollar amount ) 5 200 ( number of records ) 400 ( starting block ) 6 FILE DEMO 7 : !NAME ( wait for name then store it in record ) 8 NAME DROP 30 32 FILL QUERY 1 TEXT PAD COUNT 9 NAME ROT MIN CMOVE UPDATE ; 10 : .NAME ( print name field ) NAME TYPE ; 11 ( the rest follow in the same way ) 12 : !DAY ?DATE DAY ! UPDATE ; : .DAY DAY @ .DATE ; 13 : !DOLLAR ?$AMOUNT DOLLAR D! UPDATE ; 14 : .DOLLAR DOLLAR D@ .$AMOUNT ; 15 : .REC CR REC# @ 3 .R 2 SPACES .NAME .DAY 2 SPACES .DOLLAR ; SCR # 28 0 CR ." SCREEN 28: DEMO FILE - CLEAR.DATA, INPUT, OUTPUT" 1 ( clear especially tag in the 0 record in file ) 2 : CLEAR. DATA 0 READ TAG 128 0 FILL UPDATE ; 3 ( example of formatting for input ) 4 : INPUT 0 READ TAG @ 1+ UPDATE DUP TAG ! READ 5 CR CR ." ENTER NAME -->" !NAME 6 CR ." ENTER DATE -->" !DAY ( has a format prompt ) 7 CR ." ENTER AMOUNT -->" !DOLLAR 8 .REC FLUSH ; ( save this record on disk ) 9 ( list files 1 through the number in TAG of 0 record ) 10 : OUTPUT 0 READ TAG @ DUP 0= IF CR CR ." EMPTY FILE" 11 DROP ELSE 1+ 1 DO FORTH I READ .REC LOOP ENDIF CR CR ; 12 ;S 13 14 15
[Log of a Demo]
A> A>FORTH60 ( fig-FCRTH Model ) 8080 fig-FORTH 1.1 OK OK 0 WARNING ! ( Warning messages not on Screens 4 & 5 ) OK OK OK 47 LOAD ( fig-EDITOR ) R MSG # 4 I MSG # 4 FLUSH MSG # 4 OK OK OK 49 LOAD ( My version of a good dump ) SCREEN 49: GOOD DUMP OK OK OK 21 LOAD ( Loads Screens discussed ) This demonstration data system provides a pattern for the further developnent of any type of data base. The basic file formating definitions are on Screens 22 and 23. Some utilities are on 24, 25, and 26. The demo file definitions are on 27. Elementary file manipulation utilities are on 28. This model should get you started. ENTER 'Y' TO LOAD SCREENS SCREEN 22: FILE DEVELOR4ENT 2@ MSG # 4 SCREEN 23: FILE DEVELOPMENT - 2 SCREEN 24: DOUBLE PRECISION ARITHMETIC SCREEN 25: DATE COMPRESSION AND EXPANSION SCREEN 26: ?$AMOUNT AND . $AMOUNT SCREEN 27: DEMO FILE - RECORD GENERATION SCREEN 28: DEMO FILE - CLEAR.DATA, INPUT, OUTPUT OK OK OK OK DEMO OK CLEAR. DATA OK OUTPUT EMPTY FILE OK INPUT ENTER NAME--> ZENITH ENTER DATE --> ( MM/DD/YY ) 4/21/81 ENTER AMOUNT --> 18.50 1 ZENITH 04/21/81 $ 18.50OK OK INPUT ENTER NAME--> IBM ENTER DATE--> ( MM/DD/YY ) 4/21/81 ENTER AMOUNT--> 60. 2 IBM 04/21/81 $ 60.00OK OK INPUT ENTER NAME--> DEC ENTER DATE--> ( MM/DD/YY ) 4/21/81 ENTER AMOUNT--> 103.5 3 DEC 04/21/81 $ 103.50OK OK OK 0 READ ADDRESS HEX 80 DUMP DECIMAL 58CA 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 O ................. 58DA 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 O ................. 58EA 0 0 0 0 0 0 0 0 5A 45 4E 49 54 48 20 20 .........ZENITH 58FA 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ....:...IB 590A 20 20 20 20 20 20 B5 84 0 0 3A 7 0 0 49 42 M 592A 20 20 20 20 20 20 20 20 20 20 20 20 B5 84 0 0 .... 593A 70 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 P................ OK OK OK OUTPUT 1 ZENITH 04/21/81 $ 18.50 2 IBM 04/21/81 $ 60.00 3 DEC 04/21/81 $103.50 OK OK OK OK : STATEMENT CR CR 20 SPACES ." STATEMENT " CR CR OUTPUT CR CR ." TOTAL VALUE " 33 SPACES 0 0 0 READ TAG @ 1+ 1 DO I READ DOLLAR D@ D+ LOOP .$AMOUNT CR CR CR ; OK OK OK STATEMENT STATEMENT 1 ZENITH 04/21/81 $ 18.50 2 IBM 04/21/81 $ 60.00 3 DEC 04/21/81 $ 103.50 TOTAL VALUE $ 182.00 OK