iu2 2007-01-24
Seeking for a simple debug scheme, I've managed to do it using tclsh (must have stdin..). Actually now it doesn't seem to me so simple... ;-)
# break point - pause execution
proc bp {} {
interp alias {} tracecmd {} tracecmd1
}
# continue execution
proc cont {} {
interp alias {} tracecmd {} tracecmd2
}
# used after a bp command
proc tracecmd1 {cmd op} {
puts $cmd
puts -nonewline "[lindex [info level -1] 0]> "
gets stdin a
while {$a ne ""} {if {[catch {uplevel 1 puts \[$a\]} err]} {puts $err}
gets stdin a
}
}
# used before a bp command or after a cont command
proc tracecmd2 {cmd op} {
if {$cmd eq "bp"} {
interp alias {} tracecmd {} tracecmd1
}
}
interp alias {} tracecmd {} tracecmd2
I tried it on this
proc func1 {v} {
func2 10
foreach x {1 2 3 4 5} {
}
bp
for {set i 0} {$i < $v} {incr i} {
puts i=$i
}
}
proc func2 {a} {
puts {This is func2}
puts var=$a
}
Of cource
trace add execution func1 enterstep tracecmd
must be added before the
func1 or whatever debugged function.
To debug this I invoked
tclsh, then
sourced the code with func1, func2 and the debug procs. Then I called func1 via tclsh. func1 runs until the bp. Pressing Enter continues to the next command/line.
cont and then Enter continues execution until end of proc or until next bp. Any other input is evaluated so variables can be inspected, changed, other procs can be called, etc..
trace add execution func1 enterstep tracecmd must be added before the debugged function. This line can be converted to a simple proc, of course.
A different approach to replace the
trace add... line: Here is the
traceMe proc which when put on the first line of any proc, makes it tracable. This seems dangerous but worked with my simple example
# if this is the first line in a function, make it tracable
proc traceMe {} {
set funcname [lindex [info level -1] 0]
# redefine the function, to not include the traceMe command
proc $funcname [info args $funcname] [join [lrange [split [info body $funcname] \n] 1 end] \n]
# put a trace, will take effect only on next invocation
uplevel #0 [list trace add execution $funcname enterstep tracecmd]
# re-invoke
uplevel 2 [info level -1]
# cancel original incovation
return -code return {}
}
Now func1 can be rewritten
proc func1 {v} {
traceMe
func2 10
foreach x {1 2 3 4 5} {
}
bp
for {set i 0} {$i < $v} {incr i} {
puts i=$i
}
}
I wonder if I could call it
debug with grace...