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.