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...