IBM Variable Lister
Peter F. Nicholson
This handy utility lists all the variables in your IBM BASIC programs. It runs on any PC with at least 64K RAM or PCjr with at least 128K RAM.
The ability to list variables is a valuable aid in debugging and documenting BASIC programs. The three programs accompanying this article show how IBM BASIC variables are stored and let you list the variables in any IBM BASIC program.
"Variable Lister" (Program 3) is the actual utility. Programs 1 and 2 demonstrate how IBM BASIC stores variables for those who are interested in the details (see below). But you don't have to be familiar with the theory to use Variable Lister.
The first step is to type in and save Program 3. (Note: All three programs assume that your screen is in the 80-column mode. Enter WIDTH 80 from BASIC or MODE 80 from DOS before running the programs.)
Once Variable Lister is saved on disk, there are two ways to run it. The easiest way is to run your own program first, break out, then activate Variable Lister with the CHAIN command. For example, if you have saved Variable Lister under the filename "VARLIST," enter CHAIN "VARLIST",70,ALL and press ENTER. This preserves your program's variables while Variable Lister loads and runs.
After doing this, Variable Lister replaces your program in memory. If you want to get a variable list while your program remains in memory, you need to renumber Variable Lister with line numbers not used in your program, and then merge it with your program using CHAIN MERGE. See the IBM BASIC Manual for details.
Of course, Variable Lister uses variables of its own. To avoid confusion, these variables (BAS, XLEN, CTA, CTV, III, JJ1, ADO, VARNAME$, ARRNAME$, ITV!, and TESTARRAY) are suppressed from the variable list, and should not be used by your program.
The subroutine beginning at line 820 sorts variables and arrays alphabetically. There may be times when you'd rather display them chronologically (the order in which they're defined as the program runs). This is easily done by deleting the statement GOSUB 820 from lines 500 and 520.
How It Works
IBM BASIC uses four types of variables—integer, string, single-precision, or double-precision. The term scalar describes all variables that are not arrays. Appendix I of the IBM BASIC Manual explains how and where scalars are stored. Page I-2 of this appendix shows where the scalar storage area starts, and pages 1-3 and 1-4 explain the meaning of the data stored there.
If you want to see a graphic illustration of scalar variable storage, type in and save Program 1, then enter RUN. The program defines four variables—each a different type—and displays the descriptor bytes that describe each. You'll see two columns of numbers for each variable. The left column provides a reference number for each byte of the descriptor, and the right column shows the value that each byte contains.
The first byte of the descriptor indicates the variable type. This byte contains a 2 for an integer variable, 3 for a string, and 4 or 8 for a single- or double-precision variable, respectively. The next two bytes hold the first two characters of the variable name. For the variable A, we see the value of 65, the ASCII code for the letter A. The letter B is shown with an ASCII code of 66, and so on.
When a variable name has more than two characters, the fourth byte of the descriptor shows the number of remaining characters. The additional characters are stored immediately after this byte, with 128 added to their ASCII codes. Thus, where the variable is named ABC, you will see the values 65 and 66 (ASCII codes for AB), 1 (the number of remaining characters), and 195 (128 + ASCII code for C). The final bytes in each descriptor, high-lighted in reverse video, show the value given to each variable.
The IBM BASIC Manual gives few details about how and where array variables are stored. However, its memory map does show that scalars, arrays, and strings occupy three contiguous areas in memory. You can use these formulas to find the boundaries of each zone:
PEEK(&H358)+256*PEEK(&H359) Scalar variable space starts PEEK(&H35A)+256*PEEK(&H35B)-1 Scalar variable space ends PEEK(&H35A) + 256*PEEK(&H35B) Array space starts PEEK(&H35C)+256*PEEK(&H35D)-1 Array space ends PEEK(&H35C)+256*PEEK(&H35D) String space starts
(Of course, the PEEKs won't return meaningful results until your variables have actually been declared. Prior to that time, the storage zones are empty, and the pointers all point to the same place.)
Like scalars, array variables can be any of four types: integer, string, single-precision, or double-precision. Thus, the first part of an array descriptor is the same as a scalar descriptor—first comes a type byte, followed by the characters of the array name—but additional bytes are needed to describe the more complex structure of an array. The two bytes after the name show the number of bytes needed to complete the array; this includes a description of the array's elements and dimensions, and the array data itself.
The next byte in the array descriptor (highlighted in reverse video) shows the number of dimensions in the array. For example, the statement DIM A(2,200) creates a two-dimensional array; the statement DIM B(l,2,3,4,5,6) creates an array with six dimensions. Although it's rarely necessary to use more than a few dimensions, IBM BASIC lets you define an array with as many as 255 of them.
The DIM statement that defines an array also specifies the maximum number of elements in each dimension. The array descriptor contains two more bytes for each dimension in the array, indicating the number of elements in that dimension. An array dimension may contain a maximum of 32,767 elements. If the number of elements is not specified, the default value of 10 elements is assigned.
Program 2 graphically illustrates array storage. Its display is similar to that of Program 1, using reverse video to highlight the area allocated for the array dimension and element numbers.
Strings stored in program lines may not be stored in string space. For example, say that your program has this line:
5 A$ = "A": B$ = STRING$(2,CHR$(65"
Variable Lister reports both A$ and B$ as variables, but the string space is only two bytes long, since the character A for A$ is stored in line 5 of the program where it is defined.
Functions defined in a program are indicated by the FN prefix and are listed last for the variable type. A function is shown by adding 128 to the code of the first character. If your program contains DEF FNAA%, Variable Lister displays 2, 193 (65 + 128), 65, 0. Where your program consists of the line 5 A% = 1:DEF FNA%(X,Y) = X^2+Y^2, Variable Lister reports A, FNA, X, and Y as variables.
The program lists array dimensions exactly as defined in your DIM statement, independent of the OPTION BASE you have selected. If your program consists of the line 5 DIM A(2,2), the report should list A(2,2) and show 47 bytes occupied. If the program consists of 5 OPTION BASE 1: DIM A(2,2), the report should list A(2,2) and show 27 bytes occupied.
Keep in mind that string space is filled from the top of memory downward. To find the starting address of your stack area, use PEEK(&H30A) + 256 * PEEK (&H30B). Use PEEK(&H32F) + 256 * PEEK(&H330) to find the current string space. To get an accurate report, you may first need to issue a FRE("") command as described in the manual.
Finally, Variable Lister cannot report any variable that your program does not actually use. Consider this example:
5 D$="12-31-84":IF RIGHT$(D$,2) = "85" THEN A = l
Since the IF condition can never be satisfied, the computer never executes A = l. Variable Lister reports only one variable—D$.