The Museum of HP Calculators

HP Articles Forum

[Return to the Index ]
[ Previous | Next ]


UserRPL stack commands

Posted by James M. Prange (Michigan) on 8 July 2007, 3:51 a.m.

It has been asserted that the RPL stack manipulation commands are "numerous and unintuitive".

Numerous? Well, perhaps, but most of the UserRPL stack commands can be grouped into just three "families", plus three more commands that don't really fit into those families. Unintuitive? I think not, at least for most of them.

With the fixed-depth 4-register stack of "Classic RPN", the stack commands are few and simple. With the added flexibility of RPL's variable-depth stack, having more (and more flexible) stack commands seems desirable. If you really wanted to, you could get by with just the stack commands DEPTH, either ROLL or ROLLD, PICK, and DROPN (along with some extra keystrokes or programming).

With Classic RPN models, the T register is replicated downward as arguments are taken from the bottom of the stack, so an endless supply of whatever is in the T register is available as an argument for additional operations. With RPL's variable-depth stack, this feature isn't available. Perhaps the simplest work-around for the loss of this feature is to store an object in a named variable (local or global), and then calling the variable by name can provide an endless supply of the object to level 1, for as long as the variable exists unchanged. If you need the object to be on a different level, then call it by name and use stack manipulation to move it to wherever you need it. Alternatively, DEPTH PICK will copy the topmost level down to level 1, which has the potential to provide an endless supply of the object in the topmost level to level 1 (as long as the topmost level isn't changed). Of course, if you need the object to be on a different level, then follow DEPTH PICK with a stack manipulation to move it to wherever you need it, or perhaps store it in a variable for later use.

Regarding the RPL model "series", I treat the 28C and 28S as the "28 series", the 48SX, 48S, 48GX, 48G, and 48G+ as the "48 series", and the 49G, 49g+, 48gII, and 50g as the "49 series".

Regarding character translations in this article, "\<<" and "\>>" represent the UserRPL program delimiter characters, and "\->" represents the right-arrow character.

For the "stack diagrams", of course there can be an indefinite number of levels above those that I show, in which case, except for being moved up or down, those higher levels are unaffected.

Regarding LAST, or alternatively LASTARG on the 48 and 49 series, the assumption is that this is enabled, that is, on the 28 series, flag 31 is set, and on the 48 and 49 series, flag -55 is clear.

Where I show sequences or programs that have the same effect as a command, that refers only to the stack itself, not to what LAST or LASTARG will return.

I really don't think that the UserRPL stack commands are difficult to learn, although keeping track of exactly which objects are on which levels can be difficult when you use more than a few levels. Well, you can always use named global or local variables when it seems too difficult to keep track of the stack.

Of course, being careful of the order in which objects are put on the stack in the first place helps to reduce the need for stack manipulation; it may not be needed at all.

If you're going to need an object again, then use a stack manipulation that copies it, and for its final use, use a stack manipulation that moves it instead.

In general, it helps to have a "clean" stack when you start something new. Unneeded objects on the stack use up memory and may slow down execution, and of course add "clutter". Discard (or store in a global variable for future use) anything that you don't need on the stack anymore, either just before starting something new, or else when you finish what you're doing.

Of course, to manipulate a stack level, that level has to actually exist, or else you'll get an error. But some of these commands take a number for an argument, and if the argument is 0, then these (except for UNPICK and NDUPN, each of which requires two arguments) don't error out even with an empty stack.

For stack commands that take a numeric argument, non-integer values are rounded to integer values, and a negative number is treated the same as 0. With the 49 series, either a zint (an "exact integer") or a "real number" can be used. The commands that return a count to the stack always return it as a real number.

Also note that the commands that take a numeric argument first remove the numeric argument from the stack, and then act on the remainder of the stack, so when you use n as the numeric argument, it refers to the stack levels as they will be after n is removed from the stack.

Note that the stack doesn't really have any objects in it. That you seem to see objects in the stack is due to a bit of indirection. The stack is really a stack of 5-nibble pointers (that you don't see) with the objects pointed to elsewhere in memory. When the "stack display" needs to be updated, the objects pointed to are decompiled to string forms suitable for display with the current stack display modes and font size, and those are what you see. The stack manipulation commands can be fast because objects of various types and sizes aren't being manipulated; only the fixed-size stack pointers are being manipulated. For example, when you use DUP to make a "copy of the object on level 1", you aren't really making a copy of the object, you're just making a copy of the pointer, and when you use SWAP to "exchange the objects on levels 1 and 2", you aren't really exchanging the objects, you're just exchanging the pointers.

I've listed the stack commands in the following order:

DEPTH
ROLL
ROLLD
ROT
UNROT (added with the 49 series)
SWAP
PICK
PICK3 (added with the 49 series)
OVER
DUP
DUPDUP (added with the 49 series)
DUPN
DUP2
NDUPN (added with the 49 series)
DROPN
DROP2
DROP
; (added with the 49 series)
CLEAR
NIP (added with the 49 series)
UNPICK (added with the 49 series)
Two more that I wouldn't really consider to be "stack commands", but which are often used with the stack.
\->LIST
LIST\->
The 48 and 49 series also provide various operations in an "interactive stack". When the "standard stack display" is active (no "special environment" active) this can be invoked by pressing the CursorUp key, and in the 49 series, even when in a special environment, by pressing the HIST key. Some stack operations, such as ECHO, may be available with a menu key in various special environments. I don't cover these operations in this article, but I do recommend that you experiment with them.

A command for obtaining information about the stack:

Commands intended for moving stack levels:

Commands intended for copying stack levels:

A command intended to push an object to the stack a number of times, and return the count:

Commands intended for removing stack levels:

A command intended for replacing an existing level:

List commands often used with the stack:

I believe that that pretty well covers all of the UserRPL stack commands.

Of course, SysRPL has a lot more stack commands available, so sometimes with SysRPL you can achieve your goal with fewer stack manipulations, saving time and memory usage. As with most things when using RPL, a problem may be that there are so many different ways to accomplish the same thing.

This isn't really what I'd call "stack manipulation", but it seems related and can be useful. DEPTH \->LIST puts the contents of the entire stack into a list that can be stored in a variable for safe-keeping, so you can start working on something else with a "clean slate" without losing what you were working on. This can also be useful in a program when you don't have an easy way of knowing how many objects will be put on the stack; of course the DEPTH command can tell you where the top of the stack is, and thus how many objects you've put on the stack. When you want to restore the saved stack (inserted below anything on the current stack), recall the list to the stack and do LIST\-> DROP. With SysRPL, you can do similar things (with the 49 series) with the "virtual stack" commands.

For "interactive use" (not within a program), assuming that "last stack" saves are enabled, an alternative way to save a copy of the current stack is to do a HALT to save it as the "last stack" within a "suspended environment", then CLEAR to get your "clean slate" for working on something else, and then when you want to restore your saved stack, do CONT immediately followed by the UNDO operation (on a 48SX/S, LeftShift STACK, above the 2 key) to replace the current stack with the saved stack. But note that if you press ENTER (or any key that invokes an implicit ENTER) between CONT and UNDO, then the saved stack will be lost.

Regards,
James

Edited: 26 Sept 2007, 12:23 a.m.

Password:

[ Return to the Message Index ]

Go back to the main exhibit hall