Post Reply 
Accessing data in linked array on HP-50g
06-25-2021, 05:03 PM
Post: #1
Accessing data in linked array on HP-50g
Hi all,
What is the best way to access data in a linked array on the HP-50g? According to the description I have, a linked array consists of pointers pointing to the actual objects in RAM (or ROM). What matters here is the object being referenced, not the pointer itself. The object only needs to be read, not evaluated. How can I best do this? Solutions preferably in sys RPL. Sincerely, Karel.

I use HP-16C, WP-34S emulator, HP-35s, HP-48GX, HP-50g, and HP Prime G2.
Find all posts by this user
Quote this message in a reply
06-26-2021, 01:53 AM (This post was last modified: 06-26-2021 12:02 PM by Giuseppe Donnini.)
Post: #2
RE: Accessing data in linked array on HP-50g
(06-25-2021 05:03 PM)cahlucas Wrote:  What is the best way to access data in a linked array?

At least on the HP-48GX, the following System RPL words work interchangeably with ordinary arrays and linked arrays.

GETATELN ( #0371Dh )

# arry --> ob TRUE

# lnkarry --> ob TRUE
# lnkarry --> FALSE

where # specifies a lexicographic element number for arry or a lexicographic pointer table entry number for lnkarry. For lnkarry, GETATELN returns FALSE if the specified element does not exist. Otherwise, it returns the specified element of arry or lnkarry and TRUE.

Note that FALSE is only returned for a null pointer within the limits of a linked array, so you have to make sure that # is within the range of arry or lnkarry. This can be checked with the following words:


DIMLIMITS ( #035A9h )

arry --> {}
lnkarry --> {}

Returns a list of binary integer objects representing the dimensionality of arry or lnkarry. The length of the list represents the dimension count and the internals are the dimension limits.


ARSIZE ( #03562h )

arry --> #
lnkarry --> #

For arry, ARSIZE returns the number of elements of the array in #. For lnkarry, it returns the number of pointer table entries of the linked array in #.


(06-25-2021 05:03 PM)cahlucas Wrote:  a linked array consists of pointers pointing to the actual objects in RAM (or ROM).

No, the pointers do not point to objects, but to object bodies. Moreover, the referenced object bodies are not at liberty to live just anywhere in RAM or ROM, but must live inside the body of the containing linked array object itself, because linked arrays, like ordinary arrays, are atomic, not composite.
Find all posts by this user
Quote this message in a reply
06-26-2021, 02:45 PM
Post: #3
RE: Accessing data in linked array on HP-50g
(06-25-2021 05:03 PM)cahlucas Wrote:  Hi all,
What is the best way to access data in a linked array on the HP-50g? According to the description I have, a linked array consists of pointers pointing to the actual objects in RAM (or ROM). What matters here is the object being referenced, not the pointer itself. The object only needs to be read, not evaluated. How can I best do this? Solutions preferably in sys RPL. Sincerely, Karel.

There's very little in the way of documentation for RPL linked arrays. This thread may have some information of interest to you.

As stated by Cyrille in that thread, linked arrays are primarily useful for building large lists of strings. This can come up if you need a library of strings that goes beyond the limits of message tables.

I would add that a large list of constants with high numbers of duplicates can also benefit from the use of linked arrrays, and there's an example given in that thread of how to build one (though that example could be improved by using MASD syntax instead).

Just curious -- what is your goal for using a linked array here? It may be that a standard array works just as well, and may even be smaller.
Find all posts by this user
Quote this message in a reply
06-26-2021, 05:36 PM
Post: #4
RE: Accessing data in linked array on HP-50g
(06-26-2021 01:53 AM)Giuseppe Donnini Wrote:  At least on the HP-48GX, the following System RPL words work interchangeably with ordinary arrays and linked arrays.

GETATELN ( #0371Dh )
# arry --> ob TRUE
# lnkarry --> ob TRUE
# lnkarry --> FALSE
where # specifies a lexicographic element number for arry or a lexicographic pointer table entry number for lnkarry. For lnkarry, GETATELN returns FALSE if the specified element does not exist. Otherwise, it returns the specified element of arry or lnkarry and TRUE.
Note that FALSE is only returned for a null pointer within the limits of a linked array, so you have to make sure that # is within the range of arry or lnkarry. This can be checked with the following words:

DIMLIMITS ( #035A9h )
arry --> {}
lnkarry --> {}
Returns a list of binary integer objects representing the dimensionality of arry or lnkarry. The length of the list represents the dimension count and the internals are the dimension limits.

ARSIZE ( #03562h )
arry --> #
lnkarry --> #
For arry, ARSIZE returns the number of elements of the array in #. For lnkarry, it returns the number of pointer table entries of the linked array in #.
Dear Mr. Donnini,
Thank you very much for your response. My question with your answer is: How should I translate this into a working program? I am currently making a "pretty print" program for the HP-82240B Infrared printer. All data objects can be printed with this, including symbolics, as well as user and system RPL programs (the latter only in string form), in a clear layout that is very well-arranged, only linked arrays need to be added. So it's about extracting the various objects in the linked array one by one, and then printing them. Or unpack the linked array completely, as possible with a standard array, or list, after which all the objects are on the stack (hopefully). I hope to hear from you soon. Sincerely, Karel.

I use HP-16C, WP-34S emulator, HP-35s, HP-48GX, HP-50g, and HP Prime G2.
Find all posts by this user
Quote this message in a reply
06-27-2021, 05:19 PM (This post was last modified: 06-27-2021 09:24 PM by Giuseppe Donnini.)
Post: #5
RE: Accessing data in linked array on HP-50g
[ WARNING: The following information relates to the HP-48; it may also apply to the HP-50G, but no warranty is given. ]

Here are a few things you should keep in mind:
  • At the User RPL level, linked arrays are treated as system objects, which are not meant to be handled directly by the user. They are therefore simply decompiled as Linked Array – regardless of their actual contents.
     
  • The same holds true for ordinary arrays that do not conform to the specific requirements of a User RPL array, which must either be a vector (or one-dimensional array) of real or complex numbers, or a matrix (or two-dimensional array) of real or complex numbers. Anything else is simply decompiled – at least on the HP-48 – as Array of <object type>. How does your program handle such non-standard arrays? Did you make provisions for arrays of any type and dimensionality?
     
  • It is not possible to convert a linked array to an unlinked one without addressing the null-pointer problem. How should inexistent elements be represented in an ordinary array? You could use default values, but they are not guaranteed to be indistinguishable from actual values, since both must be of the same type.
     
  • It is a bit easier to convert a linked array to a list because the latter is a composite object and can therefore hold a pointer to a unique placeholder value, like NOVAL, in order to represent a void element. (Note, however, that NOVAL is not available on the HP-48S/SX.).

The following program, which I tentatively call LA\->, takes a linked array as argument and returns its elements in row order to the stack, followed by a list specifying its dimensions. Non-existent elements are represented by the special placeholder NOVAL. For this reason, the program will not run on an HP-48S/SX.


*******************************************************************************
* LA\->                                                           G/G+/GX only
*******************************************************************************
* ABSTRACT : Dissects a linked array by returning its elements in row order,
*            followed by a list of its dimensions.
*
* STACK    : ( lnkarry --> el1...eln { %dim1...%dimx } )
*
*            * Non-existent elements are represented by xNOVAL.
*
*            * The dimension(s) are always returned in a list, even when the
*              initial argument is a vector, that is, a one-dimensional linked
*              array.
*******************************************************************************
ASSEMBLE

* Binary transfer header.

        NIBASC /HPHP48-K/

* Unsupported, but stable entry points:

=lnkarry      EQU #1CCD8
=ARRYLP_DO    EQU #37BCB

* Rompointer entry points:

=~xNOVAL      EQU #05B0AB

RPL

EXTERNAL xNOVAL

::
  CK1NoBlame         ( *Require 1 argument without recording the command* )
  CK&DISPATCH1       ( *Dispatch table including second, tag-stripping, pass* )
  lnkarry            ( *Require linked array, or tagged linked array* )
  ::                 ( lnkarry --> )
    ARRYLP_DO (DO)   ( *Take apart linked array* )
      INDEX@ OVER    ( el1...eli-1 lnkarry #i lnkarry )
      GETATELN       ( el1...eli-1 lnkarry <eli TRUE>|<FALSE> )
      ?SKIP          ( *If element does not exist,... )
      xNOVAL         (  ...return xNOVAL instead* )
      SWAP           ( el1...eli-1 eli lnkarry )
    LOOP             ( el1...eln lnkarry )
    DIMLIMITS        ( el1...eln { #dim1...#dimx } )
    INNERCOMP        ( *Convert bints to reals within dimension list* )
    NULL{} SWAP
    ZERO_DO (DO)
      SWAP
      UNCOERCE
      >HCOMP
    LOOP             ( --> el1...eln { %dim1...%dimx } )
  ;
;

N.B. The second loop could be optimized by return stack manipulations, but since the chances of encountering a zillionth-dimensional array are reasonably low, I opted for the most legible form.

A compiled version of the program, called LAto, is attached to the posting, together with three already compiled linked arrays for testing purposes:
  • LA1 is a copy of the only linked array present in the ROM of the HP-48G/G+/GX. It is a vector of 119 character strings and constitutes the message table for the Plot Input Form.
     
  • LA2 is a four-element vector of real numbers of which only the second (% 2) is present.
     
  • LA3 is a three-dimensional 2 x 3 x 4 array of 24 system binary integers, half of which (the odd numbers) are present.


Attached File(s)
.zip  lnkarry.zip (Size: 2.28 KB / Downloads: 7)
Find all posts by this user
Quote this message in a reply
06-27-2021, 07:15 PM
Post: #6
RE: Accessing data in linked array on HP-50g
(06-27-2021 05:19 PM)Giuseppe Donnini Wrote:  How does your program handle such non-standard arrays? Did you make provisions for arrays of any type and dimensionality?

Dear Mr. Donnini,
My program handles as far as I can judge only 'regular' arrays and matrices, both 1 and 2 dimensional (see code). I'll get to work with your code, as far as I can translate the pointers to the HP-50g. This may take some time, so it may take a few days before I will respond. Sincerely, Karel.

Code:

::
DUPTYPEMATRIX?_      // Idenify Array or Matrix
ZEROZERO
{
 NULLLAM
 NULLLAM
 NULLLAM
}
BIND                         // Make local vars
3GETLAM
ITE                            // Specify: Array or Matrix
"Matrix of:"
"Array of:"
PTR 2F127                 // Print string
DROP
FPTR 6 17C               // Explode Array or matrix
::
  INNERCOMP
  #2=                       // Check dimension
  case
  ::                           // If 2 dimensional
    COERCE2
    2DUP
    1PUTLAM
    2PUTLAM
    #*
    reversym
    DROP
    2GETLAM
    #1+_ONE_DO
    3GETLAM
    ITE                       // Start of sub-matrix
    "Submatrix "
    "Subarray "
    INDEX@               // Insert counter
    #>$
    &$
    CHR_:
    >T$
    PTR 2F127           // Print message
    DROP
    1GETLAM
    ZERO_DO
    DO>STR
    PTR 2F127           // Print Array part
    DROP
    LOOP
    LOOP
  ;
  COERCE                // If 1 dimensional
  #1+_ONE_DO
  ISTOP@
  INDEX@#-
  ROLL
  DO>STR
  PTR 2F127             // Print array part
  DROP
  LOOP
 ;
 "End of  "               // Indicate: end of array or matrix
 3GETLAM
 ITE
 "Matrix."
 "Array."
 &$
 PTR 2F127             // Print message
 DROP
ABND
;                            // End code
@
[/code]

I use HP-16C, WP-34S emulator, HP-35s, HP-48GX, HP-50g, and HP Prime G2.
Find all posts by this user
Quote this message in a reply
06-27-2021, 09:43 PM
Post: #7
RE: Accessing data in linked array on HP-50g
I am quite unfamiliar with the HP-50G, but after a quick check, I found the following:
  • ARRYLP_DO is at #19147h.
     
  • xNOVAL is at #3F0FCh (which is a normal pointer, not a rompointer).
     
  • Instead of lnkarry, just use BINT95 at #334BDh.
Find all posts by this user
Quote this message in a reply
07-19-2021, 12:44 AM
Post: #8
RE: Accessing data in linked array on HP-50g
I thought I might give this a try, as it seemed like a nice exercise.

Playing around with this, I ran into a couple of wrinkles pertaining to which built-in commands support the various array object types. As an example: you pretty much have to use GETATELN to obtain a specific linked array element. However, GETATELN doesn't work with type 29 matrices. So there's no one-size-fits-all command that performs that function for all array types. Likewise, ^XEQARRY> works well for type 3|4|29 arrays, but not for linked arrays.

This is one approach among many -- probably not the best or worst, but it should at least give some ideas for bits and pieces that might be useful for your implementation. It does use two undocumented built-ins that are accurate for a v2.15 firmware (I haven't checked other firmware versions for validity):

- SysPR1 (PTR 2F127) is the internal version of the UserRPL PR1 command
- DupArryType (PTR 2F2C4) is the code run by the UserRPL TYPE command to determine the type of a regular array object (3|4|29)

This implementation uses a "decode the sequential index" approach for determining the labels for each element's indices. It essentially takes the index number of the current element and iteratively divides by the dimensions identified for the object to determine the current element's position label (the indices are converted to 1-based in the process). This is similar to how you might convert a number to a different base, but it uses a list of the dimensions instead of a constant base as the divisor.

There's a couple of non-standard techniques used in this implementation which might benefit from further explanation:

1) Placing the main code object onto the return stack allows it to run for both of the overloaded dispatch types identified as part of the CK&DISPATCH1 structure. If the code had been part of library, this would not have been the best approach. In this case, I wanted the program to be fully encapsulated into one code object, and this approach is an efficient way to implement a single code base for multiple object types.

2) The dimensions list is processed using the return stack processing technique. This is an efficient (and fast) way to process each element of a list in sequence. Might be a bit heavy-handed for this situation, but it does show an example of how to do that if you are interested in using that approach with SysRPL programs.

Here's the commented code:
Code:
!NO CODE
!ASM
   DC SysPR1         2F127
   DC DupArryType    2F2C4
!RPL
::
   ( needs 1 argument )
   CK1NoBlame
   
   ( this routine is placed on the return stack for execution after object validation )
   ' ::
      COERCE                              ( convert array type to BINT )
            
      ( print the object type description )
      "Type " OVER #>$ &$ APPEND_SPACE    ( "Type <n> " )
      BINT23 3PICK #= IT :: "Linked " &$ ; ( insert "Linked " if appropriate )
      OVER BINT29 EQITE "Matrix" "Array" &$ ( "Matrix" or "Array" as appropriate )
      SysPR1 DROP                         ( print and DROP the object type )
   
      BINT23 EQ                           ( linked array = TRUE, otherwise FALSE )

      ( setup lams )
      SWAPDUP FPTR2 ^DIMLIMITS            ( obtain a list of dimensions )
      INNERCOMP reversym {}N              ( reverse the dimensions list )
      OVERARSIZE                          ( obtain the count of array elements )
      {{ count dims array }}              ( bind locals )

      ( explode all array elements onto the stack )
      ITE ::                              ( TRUE - array is a Linked Array )
         count #1+_ONE_DO                 ( loop for each element position )
            INDEX@ array GETATELN         ( get current element )
            NOT_IT "<undefined>"          ( string if position has no defined element )
         LOOP
      ;
      ::                                  ( FALSE - array is type 3, 4, or 29 )
         array FPTR2 ^XEQARRY>            ( explode array elements onto stack )
         DROP                             ( drop the unneeded dimensions list )
      ;
      
      ( print each element with a positional label )
      count reversym                      ( reverse the elements )
         ZERO_DO                          ( loop for each element )
         NULL$                            ( initial element label )
         INDEX@                           ( current element number [0-based] )
         
         ( determine the position label indices )
         ::
            dims >R                       ( place dimensions list on return stack )
            BEGIN
               RSWAP                      ( move list data into topmost return stack position )
               ticR NOTcase :: RDROP ;    ( get next divisor or exit )
               RSWAP                      ( restore return stack order )
               #/ SWAP                    ( determine quotient & remainder )
               #1+ #>$ tok- SWAP&$        ( determine current index [1-based] )
               ROT &$SWAP                 ( add current index to index string )
            AGAIN
         ;
         DROP                             ( drop the final quotient )

         BINT2 LAST$                      ( drop leading dash )
         "  #" SWAP&$                     ( prepend "  #" to label )
         ": " &$                          ( append ": " to label )
         
         SWAP DO>STR &$                   ( append current element as string )         
         SysPR1 DROP                      ( print and DROP the object )       
      LOOP

      ABND                                ( abandon locals )
   ;
   >R                                     ( place the above routine on the return
                                            stack for later execution )
   
   ( must be either array type or linked array )
   ( any other object type raises "Bad Argument Type" error )
   CK&DISPATCH1
   arry DupArryType     ( type %3 [real], %4 [complex], %29 [matrix] )
   BINT95 %23           ( type %23 [linked array] )
;
@
Find all posts by this user
Quote this message in a reply
Post Reply 




User(s) browsing this thread: 1 Guest(s)