The design for BASIC's debugger I've got now resembles this:
.sub _main
.local foo
.local bar
[...rest of declarations...]
[....PIR for statement 1...]
bsr DEBUGGER
[....PIR for statement 2...]
bsr DEBUGGER
[....PIR for statement 3...]
bsr DEBUGGER
end
# This block appears at the end of every BASIC lexical scope.
DEBUGGER:
if one-stepping, DEBUG
# Loop over break list
if current statement is on global break list, DEBUG
# End loop
ret
DEBUG:
# Push lexically scoped things into a Px register
# so I can see them (by name) outside of this scope
$P0=new PerlHash
$P0["foo"]=foo
$P0["bar"]=bar
# etc...
.arg $P0
call _DEBUG_CMDS
.result $P0
# Put variable values back into lexicals
foo=$P0["foo"]
bar=$P0["bar"]
ret
.end
.sub _DEBUG_CMDS
.param PerlHash values
# Debugger command-line interface...etc...
.return values
.end
And this seems to work. Everywhere that I've got a lexical scope (most
BASIC programs only have one, newer ones a couple) I repeat the DEBUGGER
and DEBUG labels at the end of the block, of course using whatever
variables are declared inside of that block.
This functions fine. However...
Apparently, skipping forward (bsr) and back (ret) inside of this block is
causing IMCC fits -- it'll compile a program like this, but it will take a
very long time. I'm looking for suggestions on how I could improve
this. Right now it's simple, and it works. When the blocks get too large
though it's horribly inefficient at compile-time.
No comment on your *particular* problem, but might I suggest that you
keep your break "list" in a hash, instead?
Then you'd have:
DEBUGGER:
if $one_stepping, DEBUG
set $at_breakpoint_p, $breakpoints[$current_statement]
unless $at_breakpoint_p, END_OF_DEBUG
DEBUG:
... stuff from DEBUG ...
END_OF_DEBUG
ret
--
$a=24;split//,240513;s/\B/ => /for@@=qw(ac ab bc ba cb ca
);{push(@b,$a),($a-=6)^=1 for 2..$a/6x--$|;print "$@[$a%6
]\n";((6<=($a-=6))?$a+=$_[$a%6]-$a%6:($a=pop @b))&&redo;}