On Wed, Aug 13, 2025 at 07:56:17AM -0500, Eric Blake wrote:
> So, observe what happens when I do this in gforth:
> 
> : nop ;
> defer cleanup
> ' nop ' cleanup defer!
> : unknown-word -13 throw ;
> : ?:
>   >in @ >r ['] parse-name perform find-name 0=
>   if r> >in ! : exit then
>   noname marker latestxt ['] cleanup defer!  \ install marker
>   r@ >in ! : postpone unknown-word postpone ; immediate \ hide existing word
>   r> >in ! : \ proceed to parse as normal, ; will clean up
>   ;
> : ;
>   postpone ;
>   cleanup \ undo ?: if needed, otherwise a nop
>   ['] nop ['] cleanup defer!  \ restore nop cleanup
>   ; immediate
> 
> Now I can do:
> 
> ?: a ." in a, v1" ;
> ?: a ." in a, v2" ;
> a
> => in a, v1
> 
> and more usefully, if I typo:
> 
> ?: -rot -rot -rot ;
> *the terminal*:17:9: error: Undefined word
> ?: -rot >>>-rot<<< -rot ?;
> 
> the Forth compiler tells me about my problem!

One slight improvement.  If there is an error before ;, then the
temporary disabled version of the macro will remain in force (use "see
-rot" to see what I mean).  Better might be to have ?: use catch and
kick off a nested interpreter loop that is guaranteed to end via a
throw (whether a premature throw because the colon definition is
buggy, or an intended throw during the cleanup used by ;), so that the
marker is always invoked whether or not ; was reached.

: nop ;
defer cleanup
' nop ' cleanup defer!
: unknown-word -13 throw ;
: ?:
  >in @ >r ['] parse-name perform find-name 0=
  if r> >in ! : exit then
  noname marker latestxt \ create marker
  \ set cleanup to throw a witness value if reached by ;
  [: ['] cleanup throw ;] ['] cleanup defer!
  r@ >in ! : postpone unknown-word postpone ; immediate \ hide existing word
  r> >in ! >r ( r: markerxt ) \ prepare for throwaway parse
  \ NOTE: the quotation below should probably refill as needed...
  [: : interpret ;] catch \ run nested interpreter on throwaway word
  r> execute \ invoke the marker
  ['] nop ['] cleanup defer! \ reset cleanup
  dup ['] cleanup <> and throw \ rethrow anything except success
;
: ; postpone ; cleanup ; immediate

Fixing this to auto-refill (so that ?: to ; can extend across lines,
even when entered interactively) is an exercise for the reader; my
point here was adding in the nested interpreter to guarantee cleanup
whether or not the ; is reached.

With that amended definition:

?: -rot -rot -rot ;
*terminal*:1:4: warning: redefined -rot
prim:1670:1: warning: original location
*the terminal*:1:9: error: Undefined word
?: -rot >>>-rot<<< -rot ;
: a ." in a v1" ;  ok
?: a ." in a v2" ;
*terminal*:3:4: warning: redefined a
*terminal*:2:3: warning: original location
*terminal*:3:18: warning: redefined a
*terminal*:3:4: warning: original location ok
a in a v1 ok

and "see -rot" is still fine.

HOWEVER, I think I hit a gforth bug:

?: a if ;
*terminal*:6:4: warning: redefined a
*terminal*:2:3: warning: original location
*the terminal*:6:9: error: Control structure mismatch
?: a if >>>;<<<
: c ; 
*the terminal*:7:1: error: Cannot allocate memory
>>>:<<< c ;
Backtrace:
kernel/stringk.fs:75:24:                 0 $7F703F61B248 throw 
kernel/stringk.fs:90:28:                 1 $7F703F61B488 $!len 
                                         2 $7F703F5FE068 
kernel/stringk.fs:136:14:                3 $7F703F61B9D8 $+!len 
kernel/stringk.fs:146:28:                4 $7F703F61BB08 $room 
kernel/stringk.fs:148:25:                5 $7F703F6123A0 $bit 
kernel/comp.fs:840:9:                    6 $7F703F615F88 flush-code 
kernel/comp.fs:843:5:                    7 $7F703F616018 :start 

"Control structure mismatch" occurring while a colon definition is
incomplete, followed by calling a word defined by marker, appears to
hose state so that it is no longer possible to define any new words.
I can't figure out why that fails, while "Undefined word" passed,
other than to guess that the control stack is not being entirely
cleaned up as part of the throw/catch handshake.

So in addition to my earlier worry about how to silence redefinition
warnings, I'm now wondering why gforth can't safely use a marker after
certain parse errors.


Reply via email to