Post Reply 
User-defined functions in Free42
01-13-2021, 05:19 PM
Post: #21
RE: User-defined functions in Free42
I have some stack save/restore routines on my 42S that might offer some inspiration on how to design this.

There's just one save routine:

SS - Save stack (saves the entire stack, including L)

Then there are a few different restore routines that restore the stack in various ways, called just before the program returns. The names start with R, followed by a list of what to restore to each stack register - X, Y, Z, T, L, in that order. An underscore signifies "leave it alone", i.e. that register contains an output of the program that's calling the save/restore routines.

R_YZTX - Leave X alone, restore Y, Z, T to their original positions, restore previous X into L. Similar to one-input, one-output functions like LN, or some two-input, one-output functions like %.

R_ZTTX - Leave X alone, restore Z to Y, T to Z and T, and X to L. Similar to two-input, one-output functions like +.

R_TTTX - Leave X alone, restore T into Y, Z, and T, and restore X to L. Three-input, one-output function, or a four-input, one-output function. (Are there any examples of these?)

A few other examples that I could potentially implement if I needed them:

RYZTTX - A one-input, no-output function that drops the stack, and saves the previous X in L.

R_XYZL - A no-input, one-output function, like RCL, DATE, etc.

R__ZTL - A no-input, two-output function that overwrites X and Y, such as MEAN.
Visit this user's website Find all posts by this user
Quote this message in a reply
01-13-2021, 05:56 PM
Post: #22
RE: User-defined functions in Free42
(01-13-2021 05:19 PM)Dave Britten Wrote:  I have some stack save/restore routines on my 42S that might offer some inspiration on how to design this.

There's just one save routine:

SS - Save stack (saves the entire stack, including L)

Then there are a few different restore routines that restore the stack in various ways, called just before the program returns. The names start with R, followed by a list of what to restore to each stack register - X, Y, Z, T, L, in that order. An underscore signifies "leave it alone", i.e. that register contains an output of the program that's calling the save/restore routines.

R_YZTX - Leave X alone, restore Y, Z, T to their original positions, restore previous X into L. Similar to one-input, one-output functions like LN, or some two-input, one-output functions like %.

That corresponds to the behavior of FUNC 11.

(01-13-2021 05:19 PM)Dave Britten Wrote:  R_ZTTX - Leave X alone, restore Z to Y, T to Z and T, and X to L. Similar to two-input, one-output functions like +.

That corresponds to the behavior of FUNC 21.

(01-13-2021 05:19 PM)Dave Britten Wrote:  R_TTTX - Leave X alone, restore T into Y, Z, and T, and restore X to L. Three-input, one-output function, or a four-input, one-output function. (Are there any examples of these?)

That corresponds to the behavior of FUNC 31.

The HP-42S doesn't have any built-in functions like this, but in Free42, FMA fits that pattern.

(01-13-2021 05:19 PM)Dave Britten Wrote:  A few other examples that I could potentially implement if I needed them:

RYZTTX - A one-input, no-output function that drops the stack, and saves the previous X in L.

That corresponds to the behavior of FUNC 10.

(01-13-2021 05:19 PM)Dave Britten Wrote:  R_XYZL - A no-input, one-output function, like RCL, DATE, etc.

That corresponds to the behavior of FUNC 01.

(01-13-2021 05:19 PM)Dave Britten Wrote:  R__ZTL - A no-input, two-output function that overwrites X and Y, such as MEAN.

That almost corresponds to the behavior of FUNC 22, except for what ends up in LASTx... but note that MEAN puts the old X in LASTx, so the pattern is R__ZTX, and that does match the behavior of FUNC 22.
Visit this user's website Find all posts by this user
Quote this message in a reply
01-13-2021, 10:48 PM
Post: #23
RE: User-defined functions in Free42
(01-13-2021 05:19 PM)Dave Britten Wrote:  There's just one save routine:

SS - Save stack (saves the entire stack, including L)

Then there are a few different restore routines that restore the stack in various ways, called just before the program returns

What about Dave's idea of placing the specs at the end, RPN style ?

We could even combine LBL + SS as say, LBLS, saving 1 step.
This make the code steps same as before stack saving feature was added.

LBLS "TEST"
...
RTN 12 ; 1 input, 2 output

This seems to give more flexibility to the code too.
Example, for bad input, error out, and restore the whole stack ... RTN 00
Find all posts by this user
Quote this message in a reply
01-13-2021, 10:53 PM
Post: #24
RE: User-defined functions in Free42
(01-13-2021 10:48 PM)Albert Chan Wrote:  Example, for bad input, error out, and restore the whole stack ... RTN 00

I like that, and this could be the default behavior if an error occurs (and isn't caught with flag 25) inside the user-defined function. Bubble up the error, restore the whole stack, and return.
Visit this user's website Find all posts by this user
Quote this message in a reply
01-13-2021, 11:21 PM
Post: #25
RE: User-defined functions in Free42
RTNERR already has the effect of restoring the stack completely, i.e. as if FUNC 00 had been called. Otherwise, the FUNC io mechanism seems flexible enough, since most functions always consume the same number of arguments and return the same number of results.

I toyed with the idea of adding special versions of XEQ and LBL as well, but ended up with FUNC and a small number of special RTN instructions because that seems to provide a good combination of flexibility and simplicity. Note that RTNYES, RTNNO, and RTNERR can also be used in subroutines that don't use FUNC, so any desired weird stack behavior can be coded manually even in combination with these new RTN variations.
Visit this user's website Find all posts by this user
Quote this message in a reply
01-14-2021, 01:34 AM
Post: #26
RE: User-defined functions in Free42
Putting the stack semantics on the RTN means they are repeated throughout the function if there are multiple returns. This feels bad.

Forth function definitions include the stack diagram at the beginning of the function.

Pauli
Find all posts by this user
Quote this message in a reply
01-14-2021, 01:37 AM
Post: #27
RE: User-defined functions in Free42
(01-14-2021 01:34 AM)Paul Dale Wrote:  Putting the stack semantics on the RTN means they are repeated throughout the function if there are multiple returns. This feels bad.

Forth function definitions include the stack diagram at the beginning of the function.

Pauli

What about functions that should have different behaviors depending on the types/values of the inputs? Maybe a function takes two real arguments from the stack, but if X is complex, it only takes one. The COMPLEX function itself is one such example.
Visit this user's website Find all posts by this user
Quote this message in a reply
01-14-2021, 02:08 AM
Post: #28
RE: User-defined functions in Free42
(01-14-2021 01:37 AM)Dave Britten Wrote:  What about functions that should have different behaviors depending on the types/values of the inputs? Maybe a function takes two real arguments from the stack, but if X is complex, it only takes one. The COMPLEX function itself is one such example.

For any semantics that FUNC doesn't cover, you can still write your own code. FUNC is supposed to make it easier to write the common types of user-defined functions, not be the ultimate solution for absolutely every imaginable type of function.

Note that variable-number-of-arguments semantics are not common at all. As far as HP-42S built-in functions are concerned, the complete list is COMPLEX, R->P, and P->R.
Visit this user's website Find all posts by this user
Quote this message in a reply
01-14-2021, 03:21 AM
Post: #29
RE: User-defined functions in Free42
Deciding the number of inputs and outputs dynamically could be handled by having another function that overrides the number saved by FUNC. That would be pretty easy to implement, since the two-digit number passed to FUNC is just saved to a hidden variable and not used until RTN and friends perform the stack restoration. Maybe in some later release... I just released 2.5.24 with FUNC nn and RTNYES/RTNNO/RTNERR, let's see how that goes first...
Visit this user's website Find all posts by this user
Quote this message in a reply
01-14-2021, 03:48 AM
Post: #30
RE: User-defined functions in Free42
(01-14-2021 02:08 AM)Thomas Okken Wrote:  Note that variable-number-of-arguments semantics are not common at all. As far as HP-42S built-in functions are concerned, the complete list is COMPLEX, R->P, and P->R.

These three could be solved with a complex? conditional test:

Code:
LBL"MYFUNC"
  complex?
    GTO 00
  FUNC 21
  ...
  RTN
LBL 00
  FUNC 11
  ...
  RTN

I suspect that a little more would be needed.


Pauli
Find all posts by this user
Quote this message in a reply
01-14-2021, 04:06 AM
Post: #31
RE: User-defined functions in Free42
That would work.

Things don't get ugly until you need to disturb the stack in order to find out how many parameters or returns there are...
Visit this user's website Find all posts by this user
Quote this message in a reply
01-14-2021, 07:23 AM
Post: #32
RE: User-defined functions in Free42
(01-14-2021 02:08 AM)Thomas Okken Wrote:  Note that variable-number-of-arguments semantics are not common at all. As far as HP-42S built-in functions are concerned, the complete list is COMPLEX, R->P, and P->R.

And AGRAPH and PIXEL.

Cheers, Werner
Find all posts by this user
Quote this message in a reply
01-14-2021, 09:07 AM
Post: #33
RE: User-defined functions in Free42
(01-14-2021 04:06 AM)Thomas Okken Wrote:  Things don't get ugly until you need to disturb the stack in order to find out how many parameters or returns there are...

Agreed, a pair of commands to save and restore the stack + last X would address this without needing a replace the FUNC argument command. They'd also be useful elsewhere.


Pauli
Find all posts by this user
Quote this message in a reply
01-14-2021, 12:44 PM
Post: #34
RE: User-defined functions in Free42
Or FUNC could be modified to cover all use cases: Allow calling it more than once, with subsequent calls only updating the input and output parameter counts, not re-saving the stack.
Visit this user's website Find all posts by this user
Quote this message in a reply
01-14-2021, 12:56 PM
Post: #35
RE: User-defined functions in Free42
(01-14-2021 03:21 AM)Thomas Okken Wrote:  Deciding the number of inputs and outputs dynamically could be handled by having another function that overrides the number saved by FUNC. That would be pretty easy to implement, since the two-digit number passed to FUNC is just saved to a hidden variable and not used until RTN and friends perform the stack restoration. Maybe in some later release... I just released 2.5.24 with FUNC nn and RTNYES/RTNNO/RTNERR, let's see how that goes first...

This is all starting to sound like structured programming, which RPN definitely is not. Smile I would vote against having to declare the number of inputs and outputs at the beginning of the function. It starts making this look like RPL or other high-level languages, and adds complexity to allowing for functions like COMPLEX that can have different behavior depending on the inputs.

If I were implementing it, I'd have one instruction such as FUNC (or possibly even just a different LBL, maybe FLBL for example) to push the entire stack, and leave the details of the stack restoration to just before the RTN. Either have multiple different RTN instructions that specify what to restore, or a separate instruction placed just before RTN that restores the stack using the registers that were saved in the current stack frame. Pop and discard the stack frame on RTN/END.
Visit this user's website Find all posts by this user
Quote this message in a reply
01-14-2021, 02:55 PM
Post: #36
RE: User-defined functions in Free42
I'm having trouble imagining functions where the number of inputs and outputs isn't known very early on in the function. Specifying it late seems like more of a hassle to me, not less.

Except for functions like OBJ-> perhaps, but that kind of thing doesn't really make sense unless you have an unlimited stack, and if you have an unlimited stack, the whole FUNC mechanism is kind of redundant.
Visit this user's website Find all posts by this user
Quote this message in a reply
01-14-2021, 04:32 PM
Post: #37
RE: User-defined functions in Free42
(01-14-2021 07:23 AM)Werner Wrote:  
(01-14-2021 02:08 AM)Thomas Okken Wrote:  Note that variable-number-of-arguments semantics are not common at all. As far as HP-42S built-in functions are concerned, the complete list is COMPLEX, R->P, and P->R.

And AGRAPH and PIXEL.

Touché!

The good news is that for all the examples of variable-argument functions given so far, the number of arguments can be determined without disturbing the stack, using the CPX? and MAT? functions, so for that style of function at least, no further instruction set surgery is necessary.
Visit this user's website Find all posts by this user
Quote this message in a reply
01-14-2021, 05:02 PM
Post: #38
RE: User-defined functions in Free42
(01-14-2021 02:55 PM)Thomas Okken Wrote:  I'm having trouble imagining functions where the number of inputs and outputs isn't known very early on in the function. Specifying it late seems like more of a hassle to me, not less.

Both ways are equivalent.
It is just a matter of style, prefix vs postfix.

However, I think postfix may be easier to read, and document.
Values to return are almost always right above RTN statement (unless it crashes).

With well documented code, we just read the line above RTN, and know what it is.

...
X<>Y    ; q r q q
RTN 02  ; q r b a
Find all posts by this user
Quote this message in a reply
01-14-2021, 11:52 PM
Post: #39
RE: User-defined functions in Free42
I much prefer prefix for the argument counts. When you want to know what a LBL does, it is easier to go there and look for the early FUNC statement than it is to have to find the end and step back to the FUNC statements.


Pauli
Find all posts by this user
Quote this message in a reply
01-25-2021, 01:08 PM
Post: #40
RE: User-defined functions in Free42
After having executed FUNC, would it be possible to have the stack defined as local variables X, Y, Z and T that you can use afterwards? or at the very least the ones used as input.
eg FUNC1x would have local variable "X" created etc.
Werner
Find all posts by this user
Quote this message in a reply
Post Reply 




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