Saint:: Stand Alone Instrumenter
This is the design documentation for the saint or Stand Alone Instrumenter
package for Tuba and other Tcl tools.
Background
In Tuba, the instrumenter is tightly integrated in the debugger code. This
makes a tool like testinstrumenter very difficult. And any other non-Tuba
use of the instrumenter (such as Tea) is next to impossible.
Goals
I want to decouple the instrumenter from the debugger so that it can be
used as a general code instrumenter. Tools that can use this could be a
proc lister, line-of-code counter, a profiler, code documentors, etc.
Another advantage to this decoupling is to be able to swap in different
parsers for Tuba.
Interfaces
In order for the instrumenter to have some smarts, there needs to be a
two-way communication between the instrumenter and the client. This interface
will be in terms of procs (a Tea class version will be available later).
Instrumenter Interface
All procs of the instrumenter should be defined in a namespace called instrumenter.
This namespace should be relative so that the client can stick it anywhere
it wants.
Namespace
All instrumenting implementations must adhere to the following interface.
This allows the client to talk to the instrumenter in an abstract fashion.
The namespace definition should look something like this:
namespace eval instrumenter {
...
}
The procs
The following procs must be defined by the instrumenter. Clients should
not assume that these will be exported.
instrumenter::init {libdir clientns options}
This initializes the instrumenter.
Inputs
libdir
The full path pointing to the lib directory where the instrumenter
source came from. Useful for loading auxliary files.
clientns
The namespace where the client callback procs are defined. The callback
procs are discussed in the Client Interface.
options
Options for the instrumenter in array get format. These can
be dependent on the instrumenter. The following are standard across all
instrumenters:
instrumenter::instrument {file}
This instruments a file. Can be called many times.
Inputs
Outputs
Return the instrumented code contained in file.
instrumenter::purgeCache {}
Purges the cache directory of all files.
Inputs
Outputs
instrumenter::getLevel {}
This is for retrieving the current block level. The instrumenter needs
to keep track of what level it is parsing. The value is maintained only
at load time, not run time.
Inputs
Outputs
An integer value of the current block level. 0 signifies the top level.
Client Interface
The client must also provide an interface for the instrumenter. There are
two types of callbacks the instrumenter will make back to the client: those
at instrument time, and those at runtime.
Namespace
The client tells the instrumented the namespace to use for the callbacks
when he calls the instrumenter::init proc; therefore, there is
no special namespace requirements for the client.
Instrument-time procs
Instrument time callbacks are mostly for statistics to inform the client
when various Tcl entities crop up, like procs or statements.
foundCommand{file line commandvar}
Called for every command found during instrumentation. This callback
is only called if the commandaction initialization variable is set
to ? (ask).
Inputs
file
Name of the source file the command was found in.
line
Beginning line number of the command.
commandvar
The name of the variable containing the command. To read and possibly
modify the command, you must use upvar.
Outputs
The command value in commandvar can be modified. This allows the client
to do some extra processing on the command.
The following return codes have meaning to the instrumenter:
0 - ignore the command
1 - put the command into the instrumented buffer, but don't instrument
it
2 - put the command into the instrumented buffer, and instrument it
foundComment {file begline commentvar}
foundProc {file line commandvar procnamevar dynamicflag}
Called for every proc found. This callback is only called if the initialization
variable procaction is set to ? (ask).
Inputs
file
Name of the source file the proc was defined in.
line
Line number proc begins on.
commandvar
The name of the variable containing the proc command. This is so the
client can change the proc command to something else. Client needs to use
upvar to access variable.
procnamevar
Name of the variable holding the name of the proc. The client can modify
the procname. Client needs to use upvar to access variable.
dynamicflag
This flag is true (1) if the proc has been deemed a dynamic proc; false
(0) otherwise.
Outputs
The command value in commandvar can be modified. This allows the client
to do some extra processing on the command. The proc name can be modified
in the same manner.
The following return codes have meaning to the instrumenter:
0 - ignore the proc definition
1 - put the proc into the instrumented buffer, but don't instrument
it
2 - put the proc into the instrumented buffer, and instrument it
Run-time procs
Runtime callbacks are invoked if the instrumented code is ever run.
statement {file line stmt}
This is the main callback the instrumentation inserts. Each statement
in the file is wrapped with this callback.
Inputs
file
The name of the source file this statement lives in.
line
Line number of the statement.
stmt
The original statement. Statement may contain nested instrumentation
if it is a composite statement like if or while.
Outputs
This should return whatever the statement returns, both error codes
and return text.
procEntry {procname}
Called at the beginning of each proc. This callback is only called
when the initialization variable procentryaction is set to 1.
Inputs
procname
The name of the procedure just entered. Should this be fully qualified
with namespace?
Outputs
procExit {procname}
Called when a proc exits. This callback is only called when the initialization
variable procexitaction is set to 1.
Inputs
procname
The name of the procedure just exited. Should this be fully qualified
with namespace?
Outputs