Digest #276 2024-08-12

Contributions

[357] 2024-08-10 21:49:59 mykesx wrote:

comment - Resolve the forward reference orig1 using the location following the appended run-time semantics.

Seems to me that ELSE wastes a BRANCH and its target/offset. ELSE compiles this branch so THEN can have a branch target to patch at compile time.

This branch and offset might be 16 bytes wasted for a 64 bit Forth. Wasted for each ELSE,

If you keep an 8 byte stack of if/else/then state the extra branch can be eliminated.

IF pushes a token representing IF on this stack. ELSE will patch the branch added to the dictionary by IF. ELSE pops the IF token and pushes an ELSE token. THEN pops the token and if it’s an ELSE token, it doesn’t need to patch anything at run time.


[358] 2024-08-11 10:13:40 ruv wrote:

referenceImplementation - Example implementation for `ELSE`

: ELSE ( C: orig1 -- orig2 )
  POSTPONE AHEAD  1 CS-ROLL  POSTPONE THEN
; IMMEDIATE

Replies

[r1282] 2024-08-09 06:36:08 AntonErtl replies:

requestClarification - Temporary removing system-compilation items

Given that a part or all of the control-flow stack items may be elsewhere, a standard program cannot consume them with n>r.

If the committee wants to allow using depth-based techniques for accessing data stack items below control-flow stack items, AFAICS the way to go would be to delete the second sentence that you cited above.

The existence of non-standard code that uses such techniques can be seen as existing practice.


[r1283] 2024-08-09 06:42:38 AntonErtl replies:

requestClarification - State of other stacks after ABORT

Yes, I think that abort should empty the control-flow stack and the floating-point stack, and the document should be amended to specify that. The former is easy to specify, the latter has the complication that the core system has no floating-point stack. I still would specify it with the core abort rather than having an additional FP version of abort; such redefinitions have produced confusion among readers of the standard document in the past.


[r1284] 2024-08-09 09:46:50 ruv replies:

referenceImplementation - The reference implementation is incorrect

[r327] still misses the clearing of the data stack as discussed in [r1154].

In the [r327] variant some items can be cleared from the data stack, since when an error occurs, CATCH restores depth of all stacks, including the data stack. But it's not quite correct since user's items can be there before CATCH.

The following addition:

  SP0 @ SP! ( perform the "clear the data stack" action of ABORT )

is not correct since it empties the data stack unconditionally, even when no error occurs.

One more implementation variant, I hope more correct:

 \ A system should have ordinary words for these actions:
: ENTER-COMPILATION ( -- ) ] ;
: LEAVE-COMPILATION ( -- ) POSTPONE [ ;
: COMPILATION ( -- flag ) STATE @ 0<> ;

: QUIT ( i*x -- ⊥ ) ( C: j*x -- ⊥ ) ( F: k*r -- ⊥ )
  RP0 @  SET-RP \ empty the return stack
  ... \ set the input source to the user input device
  BEGIN
    LEAVE-COMPILATION \ (if any) - enter interpretation state
    [: BEGIN REFILL WHILE INTERPRET COMPILATION 0= IF ." OK " THEN CR REPEAT ;] CATCH
  DUP WHILE ( ior ) CR
    \ NB: in this point the input source specifications are restored (formally, by `THROW`)
    CASE
      -1 OF ENDOF \ abort, no any message
      -2 OF ( display message from ABORT" ) ENDOF
      ( default ) DUP ." Exception # " . CR
    ENDCASE
    DEPTH NDROP \ empty the data stack and the control-flow stack
    FDEPTH FNDROP \ empty the floating point stack
    ... \ ensure that all processing has been completed, and no ambiguous condition exists
  REPEAT BYE \ no error, the end of the input stream has been reached
;

The symbol "" in a stack diagram (the bottom type) means that the caller never gets the control back.


[r1285] 2024-08-09 11:52:54 ruv replies:

requestClarification - Temporary removing system-compilation items

Given that a part or all of the control-flow stack items may be elsewhere, a standard program cannot consume them with n>r.

Yes, another part may be elsewhere, and n>r consumes only the part that is on the data stack. But, the stack parameters that were on the data stack are unavailable only due to this part on the data stack.

Another question is, why might this code work incorrectly on a standard Forth system? I can only guess that : stores the depth, and ; checks that the depth is not changed. But it would be very strange behavior, since ; is not allowed to fail due to changes in the stack depth, but only due to colon-sys.

AFAICS the way to go would be to delete the second sentence that you cited above.

I would interpret that sentence as an explanation to the reader.

What about the following wording:

The possible presence of such items on the data stack means that any items already there shall be is unavailable to a program (except pick and roll words) until the control-flow-stack items are removed from the data stack.


[r1286] 2024-08-09 16:06:47 ruv replies:

requestClarification - Temporary removing system-compilation items

I have realized that if a program is allowed to change the stack depth due to consuming or producing stack parameter under system-compilation items, then a system cannot implement leave as I described in the contribution 185.

Conversely, if a system is allowed to implement leave in that way, then a program is not allowed to change the number of stack parameters under system-compilation items.

At the moment, in this dilemma, I would prefer to give programs more options and tighten systems.


[r1287] 2024-08-09 18:44:12 ruv replies:

comment - Better API for multitasking

Exception handling

The standard specifies a behavior for the case when an exception is not caught by a program (functions of abort and quit). This behavior is not suitable for other threads/tasks.

So, another behavior should be specified: the thread is terminated, and the throw code is saved. This throw code should be obtainable via a valid task-id.

Shared resources

The user input devise is a shared resource too. What behavior is expected when two tasks call quit in parallel?


[r1288] 2024-08-11 10:47:14 ruv replies:

comment - Resolve the forward reference orig1 using the location following the appended run-time semantics.

Seems to me that ELSE wastes a BRANCH and its target/offset.

The specification does not dictate any particular implementation, only the behavior that a standard program can observe (or depends on).

You can even resolve references in run-time (and/or use something like a computed goto under the hood), as long as it does not affect the behavior of a standard program.


[r1289] 2024-08-11 11:40:02 ruv replies:

requestClarification - Why do we use +n and not u in the stack diagram for n>r and nr>

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.


[r1290] 2024-08-11 14:13:03 AntonErtl replies:

comment - Resolve the forward reference orig1 using the location following the appended run-time semantics.

The specification of else is in terms of two origs. These can be cs-rolled during compilation (and sometimes the cs-roll is implicit). An example is

begin ... while ... while ... repeat ... else ... then

Maybe it's possible to still implement something along the lines of mykesx' idea by having one stack item on the additional stack per control-flow stack item and then perform a roll of that stack for every cs-roll during compilation. One would also have to care for cleaning up this run-time stack on exit and throw, and doing the manipulations of the additional stack even when jumping across some control-flow word. Overall this looks complicated and fraught with pitfalls. If you want to save program memory on a 64-bit machine (why?), use native-code compilation; native-code jumps typically cost 2-5 bytes on AMD64.


[r1291] 2024-08-11 14:15:21 mykesx replies:

comment - Resolve the forward reference orig1 using the location following the appended run-time semantics.

Am I not reading the paragraph for compilation correctly?

It talks about then patching the branch added by else…