15.6.2.1908 N>R n-to-r TOOLS EXT

Interpretation:

Interpretation semantics for this word are undefined.

Execution:

( i * n +n -- ) ( R: -- j * x +n )

Remove n+1 items from the data stack and store them for later retrieval by NR>. The return stack may be used to store the data. Until this data has been retrieved by NR>:

  • this data will not be overwritten by a subsequent invocation of N>R and
  • a program may not access data placed on the return stack before the invocation of N>R.

See:

Rationale:

An implementation may store the stack items in any manner. It may store them on the return stack, in any order. A stack-constrained system may prefer to use a buffer to store the items and place a reference to the buffer on the return stack.

Implementation:

This implementation depends on the return address being on the return stack.

: N>R \ xn .. x1 N -- ; R: -- x1 .. xn n
\ Transfer N items and count to the return stack.
   DUP                        \ xn .. x1 N N --
   BEGIN
      DUP
   WHILE
      ROT R> SWAP >R >R      \ xn .. N N -- ; R: .. x1 --
      1-                      \ xn .. N 'N -- ; R: .. x1 --
   REPEAT
   DROP                       \ N -- ; R: x1 .. xn --
   R> SWAP >R >R
;

Testing:

: TNR1 N>R SWAP NR> ;
T{ 1 2 10 20 30 3 TNR1 -> 2 1 10 20 30 3 }T

: TNR2 N>R N>R SWAP NR> NR> ;
T{ 1 2 10 20 30 3 40 50 2 TNR2 -> 2 1 10 20 30 3 40 50 2 }T

ContributeContributions

JimPetersonavatar of JimPeterson [281] Bad Stack Notation?Comment2023-02-13 15:22:04

Given that "A stack-constrained system may prefer to use a buffer to store the items and place a reference to the buffer on the return stack.", I think a better stack notation for execution semantics would be "( i * x +n -- ) ( R: -- strg-sys )" (or some other "*-sys"), to indicate pretty clearly that: 1) the user can not rely on what data format gets pushed onto the return stack, and 2) something gets pushed on to the return stack and should not be meddled with.

ruvavatar of ruv

  1. the user can not rely on what data format gets pushed onto the return stack, and 2) something gets pushed on to the return stack and should not be meddled with.

When i is unknown, the data type symbol i*x already meets these both goals.

What is wrong in the diagram is that it assumes to take i*n from the data stack.

A correct variant: ( i*x +n -- ) ( R: -- j*x +n )

AntonErtlavatar of AntonErtl

The ( in +n -- ) part is wrong. It's either ( nx +n -- ) or, if we say that i*x just means an arbitrary number of (i.e., not necessarily i) stack items, then it should be ( x1 ... xn +n -- ).

ruvavatar of ruv

I suppose that i=n follows from the statement "Remove n+1 items from the data stack".

The diagram ( x1 ... xn +n -- ) seems incorrect for the case n=0, since it starts from 1, and implies at least one x. Although, the diagrams for GET-ORDER and SET-ORDER have the same problem.

Concerning order of numbering, in other similar cases it's ascending towards the bottom of the stack (see ROLL or GET-ORDER).

So, taking into account that in all other cases, if the number of items is known beforehand in run-time then the notation ( x_[n] x_[n-1] ... is used (i.e., not i*x), a better variant could be:

  • N>R ( x_n ... x_1 n | 0 -- )
  • NR> ( -- x_n ... x_1 n | 0 )

It's obvious that n>1, so it's not necessary to indicate that n>0 via +n data type. Maybe it's even better to use the data type u instead of n for these words.

And then a correction for GET-ORDER and SET-ORDER:

  • GET-ORDER ( -- wid_n ... wid_1 n | 0 )
  • SET-ORDER ( wid_n ... wid_1 n | 0 | -1 -- )

ruvavatar of ruv

that n>0 via +n data type.

Correction:

that n 0 via +n data type.

ruvavatar of ruv

And n ≥ 1, correspondingly.

ruvavatar of ruv

Including a diagram for the return stack, and using u instead of n, we get:

  • N>R ( x_n ... x_1 u | 0 -- ) ( R: -- j*x u | 0 )
  • NR> ( -- x_n ... x_1 u | 0 ) ( R: j*x u | 0 -- )

I still think that a variant based on i*x is correct too, and far better readable:

  • N>R ( i*x u -- ) ( R: -- j*x u )
  • NR> ( -- i*x u ) ( R: j*x u -- )

And from the specification should be clear that i=u, but j is unknown.

JimPetersonavatar of JimPeterson

I think what I mean to say is if, as a stack-constrained system, I choose to use a buffer to store the items and place a reference to the buffer on the return stack, my stack notation would be:

N>R ( i*n +n -- ) ( R: -- pBuf )

Given that the rationale says that I can do that, I don't think the documentation should imply anything about the format of the data on the return stack after the call except that some opaque data exists there, much like what the stack notation for DO and LOOP say.

ruvavatar of ruv

Even when a buffer is used, the spec requires to put the number of items on the top of the return stack. I.e., only the part j*x may vary. So a possible variant for actual implementation is: N>R ( i*x +n -- ) ( R: -- addr.buf +n ) NB: add.buf is a subtype of j*x, given that j is undetermined.


Of course, a new implementation-dependent data type nr-sys can be introduced into the specification, so the stack diagrams will be:

  • N>R ( u*x u -- ) ( R: -- nr-sys u )
  • NR> ( -- u*x u ) ( R: nr-sys u -- )

But you have to provide another rationale for that — since the data type j*r already meets the goals you mentioned before.

With enough reason, the spec can be even changed in a backward-incompatible way as:

  • N>R ( u*x u -- ) ( R: -- nr-sys )
  • NR> ( -- u*x u ) ( R: nr-sys -- )

JimPetersonavatar of JimPeterson

Ah! Now I understand what you were saying. It was not immediately clear to me that j*x could mean nr-sys, or that the rationale was saying that just pushing nr-sys was not an option. I read the statement to mean that it was an option. I definitely think that:

( x<sup>n ... x<sup>1 +n -- ) ( R: -- nr-sys +n )

would be a much clearer stack notation, for what it's worth. It also feels like there should be some mention of an ambiguous condition if n<0.

AidanPitt-Brookeavatar of AidanPitt-Brooke

It also feels like there should be some mention of an ambiguous condition if n<0.

This part is already made clear in the stack effect: the symbol +n means "non-negative number". Giving any word a value of an inappropriate type always results in an ambiguous condition, so I don't think it needs to be re-stated in the prose. (It would probably be wise for standard systems to declare how they handle this particular case, but standard programs will respect the type constraints of the standard.)

Reply New Version

ruvavatar of ruv [310] Why do we use +n and not u in the stack diagram for n>r and nr>Request for clarification2023-09-23 01:06:43

A citation from the Discussion section (in r1079):

On the data stack x_n ... x_1 +n because that is the way we usually specify a numbered number of cells (even for +n=0). See, e.g., get-order.

Well, in get-order n (the signed number data type) is probably incorrectly used after set-order, where n can be -1.

But in other words: pick, roll, cs-pick, cs-roll, — the unsigned number data type (identified by u) is used to indicate the number of items.

So the question is: why is +n used in the stack diagrams for n>r and nr> instead of u?

ruvavatar of ruv

In all cases where a stack parameter means the number of items on the stack, or a non-negative index of an item on the stack, this parameter shall have the data type "non-negative number" and the symbol +n should be used for this parameter in a stack diagram.

Rationale

  1. We should use the smallest appropriate data type to describe a stack parameter. Thus, if it's known that a stack parameter always belongs to +n, we should not use the larger data type u to describe this parameter.

  2. We shall be consistent. The word depth ( -- +n ) specifies that the returned parameter belongs to +n, that is, the stack depth cannot be more than max-n (the largest usable signed integer, see 3.2.6). It means, for other words, a count of some items on the stack or a non-negative index of a stack item shall be described with +n (or with a subtype of +n).

  3. In practice, it is almost impossible that the stack depth increases max-n. Because max-n means that the stack takes amount of memory that is equal to at least a half of theoretically available data space in a Forth system.

ruvavatar of ruv

A fact of historical curiosity.

Elizabeth D Rather <erather@forth.com> wrote on 2010-03-14 12:11:15 -10:00, in comp.lang.forth, with subject Re: RfD: N>R and NR>, message-id <iaidnUCzzNCZwgDWnZ2dnUVZ_h6dnZ2d@supernews.com>

Peter Knaggs wrote:
...

I also agree with Anton in that "n" should be either "u" or "+n" as "n" allows for a negative value.

Yes, this is important. And I certainly favor +n over u. God forbid there should be thousands of cells of this stuff!

I.e, there were arguments to use +n in 2010.

ruvavatar of ruv

This request for clarification is closed by another comment on 2025-09-29.

I wrote on 2024-06-30

We should use the smallest appropriate data type to describe a stack parameter.

Because arrow type are contravariant in their input and covariant in their output, the most specific arrow type has the most general input type and the most specific output type.

Closed
Reply New Version

EricBlakeavatar of EricBlake [394] Enhance n>r test to validate that n>r r@ r>n sees nSuggested Testcase2025-08-04 14:23:53

The standard is clear that although the implementation can store j*x words for the rest of the saved portion of the data stack with no 1:1 correspondence to the original i*x words, the return stack MUST have n as its top entry.

There is debate on whether this should be relaxed; ruv mentioned at https://forth-standard.org/standard/tools/NtoR#reply-964 changing things in a backward-incompatible way as:

    N>R ( u*x u -- ) ( R: -- nr-sys )
    NR> ( -- u*x u ) ( R: nr-sys -- )

But unless that change is made, we should probably test that an implementation complies with the current wording, which is observable to a standard program via R@. I (temporarily) made the mistake of not complying in one of my attempted reference implementations at https://forth-standard.org/standard/tools/NRfrom#contribution-393, when I had swapped the order of n and a buffer address on the return stack. Thus, I suggest adding:

: TNR3 N>R SWAP R@ NR> ;
T{ 1 2 10 20 30 3 TNR3 -> 2 1 3 10 20 30 3 }T
Reply New Version