user_mpr
user_mpr

Reputation: 11

How to get list of triggered procs\commands by Tcl interpreter

I wonder if there are possible to check what interpreter ran (procs\commands) during execution? In order in which they were running?

Background: I need to see how the script works and put some (my)code in a particular place.

Upvotes: 1

Views: 574

Answers (1)

Donal Fellows
Donal Fellows

Reputation: 137767

You want an execution trace. In particular, the enterstep mode will give you a callback on each command being called (at some considerable performance hit) and the leavestep mode will allow you to also see the result of that command (many commands have an empty result).

A place to get started with them is by making a wrapper script that puts the trace on source and then sourceing your main script.

proc DebugStepTrace {command op args} {
    puts "ENTER: $command"
}

trace add execution source enterstep DebugStepTrace
source main.tcl

In almost all practical code, that will produce a vast amount of output. In particular, you'll probably be overwhelmed by all the proc calls. Let's do a more subtle tracer that hides some information so you can look at the bigger picture.

proc DebugStepTrace {command op args} {
    set trimmed [regsub {\n.*} $command "..."]
    puts "ENTER: $trimmed"
}

# Apply this procedure to [source] as above, of course

You can also use info script in a procedure (not usually recommended, but right in this case) and info frame to get more information:

proc DebugStepTrace {command op args} {
    # Trim off everything after the first newline for sanity
    set trimmed [regsub {\n.*} $command "..."]

    # Basic guess at extended info
    set filename [file tail [info script]]
    set line 0

    # May have better information in the frame
    set frame [info frame -2]
    if {[dict exists $frame file]} {
        set filename [file tail [dict get $frame file]]
        set line [dict get $frame line]
    }

    # Print what we've discovered
    puts "ENTER:${filename}:${line}:$trimmed"
}

info frame is a bit tricky to use, requiring both experimentation to get the right level selector and care because the interesting keys in the resulting dictionary (typically file and line for code location info) aren't guaranteed to be there if there's “clever” code generation games being played.


In a highly event-driven Tk application this probably won't be enough; you may well need to add traces to procedures so that you also follow callbacks. Or you can change the way you apply the trace so that you've got them enabled during Tk callback processing as well:

trace add execution source enterstep DebugStepTrace
trace add execution tkwait enterstep DebugStepTrace
source main.tcl
tkwait window .

That tkwait window call is basically what wish does for you after running the script you specify. We do it explicitly so that we can trace what happens while it is running.

Upvotes: 0

Related Questions