( xp -- execution pointer - pointer to word definition ip -- instruction pointer - pointer to pointer to word def fp -- C function pointer used to drive the VM ) var brk-xp var dbg-ip var dbg-task var dbg-emit defer dbg-cmd : dbg-first-ip ( xp -- [ip|0] ) dup cell + swap @ ( worddata fp ) dup $DOCOLON = if drop else dup $DOCREATE = if drop @ else $DODEFERRED = if @ dbg-first-ip else drop 0 then then then ; userword : tail :| rdrop dbg-first-ip >r |; , [ ' [ , ] ; immediate : get-dbg-xp ( ip -- xp ) brk-xp @ not if @ else drop brk-xp @ then ; : consume-dbg-xp ( ip -- xp ) get-dbg-xp 0 brk-xp ! ; : DBG-WAIT ( ip -- ip ) running dbg-task ! ' DBG-WAIT ' dbg-cmd redefine dup dbg-ip ! suspend ' dbg-cmd tail : .dbg ( ip -- ip ) task-emit @ >r dbg-emit @ dup if task-emit ! else drop then cr dup .wordin s" ip: " type dup . dup get-dbg-xp ` type cr >r .s r execute r >r ; : DBG-CONT ( ip -- ) >r ; : s ' DBG-STEP-IN ' dbg-cmd redefine ; userword : n ' DBG-STEP-OVER ' dbg-cmd redefine ; userword : c ' DBG-CONT ' dbg-cmd redefine ; userword : u ' DBG-RUN-TO-END ' dbg-cmd redefine ; userword : bt dbg-task @ task.bt ; userword : l dbg-ip @ decompile-from ; userword : bp.do 2 cells - ; : bp.ip ; immediate : bp.xp cell + ; ( byte golfing is annoyingly satisfying - we don't need or want $DOCOLON at the start nor ret at the end, so instead of using an inline function or a :noname, we just turn on the compiler with "]" and go. ) here ] bp.xp @ brk-xp ! r r@ breakpoint# reset-breakpoint