!pr0
!lm12
!rm75
All About PTRGET & GETARYPT................Bob Sander-Cederlof

Both Leo Reich and E. Melioli have asked for some clarification on how to pass array variables between Applesoft programs and assembly language programs.  I hope this little article will be of some help to them.

The Variable Tables:

We need to start with a look at the structure of the Applesoft variable tables.  There are two variable tables:  one for simple variables, and the other for arrays.  (You might turn to page 137 of the Applesoft Reference Manual now.)  Entries in these tables include the variable names; some codes to distinguish real, integer, and string variables; and the value if numeric.  String variables include the length of the string and the address of the string, but not the string itself.

The address of the start of the simple variable table is kept in $69,$6A.  The next pair, $6B and $6C, hold the address of the end of the simple variable table plus one.  This happens to also be the address of the beginning of the array variable table.  The address of the end of the arrays plus one is kept in $6D,$6E.  The actual string values may be inside the program itself, in the case of "string" values; or in the space between the top of the array variable table and HIMEM.

Here is a picture, with a few more pointers thrown in for good measure:

!lm+5
(73.74) -->    HIMEM

               <string values>

(6F.70) -->    String Bottom

               <free space>

(6D.6E) -->    Free Memory Bottom

               <arrays>

(6B.6C) -->    Array Variable Bottom

               <variables>

(69.6A) -->    Simple Variable Bottom

               <program>

(67.68) -->    Program Bottom
!lm-5

Inside an Array:

Let's look a little closer at the array variable space.  Each array in there consists of a header part and a data part.  The header part contains the name, flags to indicate real-integer- string, the offset to the next array, the number of dimensions, and each dimension.  The data part contains all the numeric values for real or integer arrays, and all the string length-address pairs for string arrays.

Here is a picture of the header part:

!lm+5
Bytes  Contents
-----------------------
0,1    Name of Array
2,3    Offset
4      # of dimensions
5,6    last dimension
...
x,y    first dimension
!lm-5

The sign bits in each byte of the name combine to tell what type of array variable this is.  If both bytes are positive, it is a real array; if both are negative, it is integer.  Contrary to what it says on page 137 of the Applesoft manual, if the 1st byte is positive and the 2nd byte negative it is a string array.  The manual has it backwards.

The value in the offset can be added to the address of the first byte of the header to give the address of the first byte of the header of the next array (or the end of arrays if there are no more).

The number of dimensions is one byte, which obviously means no more than 255 dimensions per array.  Oh well!  In my sample below I assume that no more than 120 dimensions have been declared.  If you try to declare more than that, you will see how hard it is.

The dimensions are stored in backward order, last dimension first.  Why?  Why not?  It has to do with the order they are used in calculating position for an individual element.  Each dimension is also one larger than you declare in the DIM statement, because subscripts start at 0.

The data part of an array consists of the elements ordered so that the first subscript changes fastest.  That is, element X(2,10) directly follows element X(1,10) in memory.  Integer array elements are two bytes each, with the high byte first.  Note:  this is just about the only place in all the 6502 kingdom where you will find highbytes first on 16-bit values!

Real array elements take five bytes each:  one byte for exponent, and four for mantissa.  String array elements take three bytes each:  one for length of the string, and two for the address of the string.  Note:  the string array elements DO NOT hold the string data, but only the address and length of that data! 

Getting to the Point:

There is a powerful and much-used subroutine in the Applesoft ROMs which will find a particular variable in the tables.  It is called PTRGET, and starts at $DFE3.  It is too complicated to fully explain here, but here is what it does:

!lm+9
!pp-4
1.  Reads the variable name from the program text.
2.  Determines whether the variable is a simple one or an array.
3.  Searches the appropriate table for the name.
4.  If the name is not found, create a variable of the approriate type (simple or array; integer, real, or string).
5.  Return with the address of the variable in Y,A (high-byte in the Y-register, low-byte in the A-register) and also in $83,84.
!pp0
!lm-9

That is usually what happens.  Actually there are several different entry points and two control bytes which modify PTRGET's behavior depending on the caller's whims.  DIMFLG ($XX) is set non-zero when called by the DIM-statement processor, and is otherwise cleared to zero.  SUBFLG ($YY) has four different states:

!lm+5
$00 -- normal value
$40 -- when called by GTARYPT
$80 -- when called to process "DEF FN"
$C1-$DA -- when called to process "FN"
!lm-5

We are concerned with the two cases SUBFLG = 0 and SUBFLG = $40, with DIMFLG = 0.  Since the point of this whole article is to clarify access to array variables, I will concentrate on the main entry at $DFE3 and the GETARYPT subroutine at $F7D9.  $DFE3 sets SUBFLG = 0, while GETARYPT sets SUBFLG = $40.

When we want to find an individual element inside an array, we call PTRGET at $DFE3.  When we want to find the whole array, we call GETARYPT at $F7D9.  GETARYPT is used by the STORE and RECALL Applesoft statements (which you might not realize even exist, since their function is only of interest to cassette tape users!)

The "& X" calls in the following program use PTRGET to find an array element.

On the other hand, if we want to sort the array, or if we want to save it all on disk, or some other feat which requires seeing the whole thing at once, we need to call GETARYPT.  Then we can even find out how many subscripts were used in the DIM statement, and what the value of each dimension is.  GETARYPT returns with the starting address of the whole array in $9B and $9C (called LOWTR).

The "& Y" call in the program prints out the starting address and length of each string of a string array.

I hope that as you work through the descriptions and examples above they are of some help.
