20th Anniversary: Forth data structures
We could then address the forces in easy-to-read syntax--LEFT FORCE @ or DOWN FORCE !--to make the code simpler and its intention clearer. After sampling these forces at various points in a cycle, we had to decide whether to declare multiple arrays or factor the data with a two-dimensional array. As Listing 1 shows, adding a word that creates two-dimensional arrays isn't very difficult.
With the addition of these arrays, we can get and store data using such phrases as START DOWN FORCE @ and MIDDLE RIGHT FORCE !. Note that declaring arrays in this fashion takes one-based arguments, but the indices to the arrays are zero-based.
(For connoisseurs of exotica or for those concerned with massive interrelations of data samples, Listing 2 contains one of my favorite words, DIMARRAY. This compact CREATE...DOES> word is used to declare arrays of any number of dimensions with any number of elements in each dimension. For dealing with such multidimensional beasts, an optional run-time index limit checker is provided in the word DIMLIMS.)
Trimming the overhead
Astute Forth programmers will realize that the indexing process just described consumes run-time cycles. In cases where the desired indices are known at compile time, this runtime overhead may be abolished without seriously impacting the readability of the code. If at some point in the code we'll store the top stack item to the END UP FORCE, we write the phrase:
... [ END UP FORCE ] LITERAL ! ...
inside a colon definition to cause the array-address calculation to take place at compile time and be stored in the routine as a numeric literal.
Handling I/O data
I/O handlers can benefit from the use of symbolic constants as much as arrays. The statement 13 ECCO PC!, for example, is hardly as readable as CNT-INIT COUNTER-0 PC!. Symbolic constants are often only the beginning, however. Depending on hardware constraints, your input and output routines may require special data structures.