Parent TCL procedure - tcl

let's say you have a TCL procedure ProcA and a TCL script ScrpB.
ProcA sources ScrpB.
How can I know, from within ScrpB, that ProcA sourced it?
Thank you
I tried the folowing.
From within ScrpB called to "info frame" and did get any usefule info.

info level 0 is specifically what you are looking for. You can browse the entire calling stack by adding something like this in the called proc:
for {set i [info level]} {$i > 0} {set i [expr {$i - 1}]} {
lappend stack [info level $i]
}
return $stack

Related

How to pass integers to tcl procedure in vmd

I am new in tcl programming and I need to write a script for vmd that calculates two distances between two couples of atoms and print them in an output file. I do not understand why measure can not take atom_1, etc. This is my script and thank you for your help
proc distance {distance_1 atom_1 atom_2 distance_2 atom_3 atom_4 output} {
set outfile [open $output w]
puts $outfile "frame, $distance_1, $distance_2"
set nf [molinfo top get numframes]
for {set i 0} {$i < $nf} {incr i} {
set d1 [measure bond {$atom_1 $atom_2} frame $i]
set d2 [measure bond {$atom_3 $atom_4} frame $i]
puts $outfile "$i , $d1 , $d2"
}
close $outfile
}
The problem here is:
measure bond {$atom_1 $atom_2} frame $i
The issue is that {…} in Tcl actually means “quote this exactly, with no substitutions at all”. Instead of sending a list of two numbers in, it passes a list of two non-numbers (the literal strings $atom_1 and $atom_2).
The fix is to replace {$atom_1 $atom_2} with [list $atom_1 $atom_2].
Yes, proc and for and if make use of this behaviour. It's just that they pass things back to the Tcl interpreter engine as part of their execution.

invalid command name "Agent/LeachAgent"

I try to implement a simple scenario for LEACH protocol but I get this error:
Creating Sensors ...
invalid command name "Agent/LeachAgent"
while executing
"Agent/LeachAgent create _o2340 "
invoked from within
"catch "$className create $o $args" msg"
invoked from within
"if [catch "$className create $o $args" msg] {
if [string match "__FAILED_SHADOW_OBJECT_" $msg] {
delete $o
return ""
}
global errorInfo
error "class $..."
(procedure "new" line 3)
invoked from within
"new Agent/LeachAgent"
("for" body line 3)
invoked from within
"for {set i 1} {$i <= $val(nsn)} {incr i} {
set agent($i) [new Agent/LeachAgent]
$ns attach-agent $node_($i) $agent($i)
$agent($i) set packetSize_..."
(file "newleach3.tcl" line 187)
I use ubuntu 16.04 and ns-allinone-2.35 . when I ran my tcl file for the first time, i did not get this error.
Change your script to use Agent/RCAgent/LeachAgent as class name:
set agent($i) [new Agent/RCAgent/LeachAgent]
From what I can see, there is no Agent/LeachAgent in ns-allinone-2.35.
I was not successful in writing a correct code for attaching Leach protocol in my scenario, but I found that mannasim has a Mannasim Script Generator (MSG). It is a front-end for TCL simulation scripts easy creation.

Tcl: [info level] vs. [info frame]

What is the difference between frames and levels of execution?
I wrote a small example to find out. I realized that the level number was incremented every time a proc was called.
On the other hand, the frame number was incremented on every
proc call
source command
eval command
etc.
For this reason, I started to think of levels as of a subset of frames. Now I'm debugging some real-life code and I realized that the level number can increase without the frame number being increased too. How to make sense of this stuff?
Stack levels, which is what info level talks about, are the important ones, because they're the ones that you can use upvar and uplevel to access into. This means that the Tcl “stack“ is really a tree, since you can use uplevel to go up to a higher level and start a new branch, with each step deeper being taken by a call to a procedure (or procedure-like thing) or a call to namespace eval; the info level command really talks about the current branch traced all the way back to the root.
The info frame command walks the tree of frames rather differently — I think it uses the actual way in which they are stacked, with frames being able to appear twice — and reports very different information about each of those frames. Personally, I only really find that it is useful for debugging.
Let's try a simple example. This is an interactive session.
% proc foo {y} {set x 1;bar $y $x $y}
% proc bar {a b args} {
puts [info level 0]
puts [info level -1]
puts [info frame 0]
puts [info frame -1]
}
% foo 3
bar 3 1 3
foo 3
type proc line 4 cmd {info frame 0} proc ::bar level 0
type proc line 1 cmd {bar $y $x $y} proc ::foo level 1
OK, as you can see, info level is reporting the actual values that were used and does not report itself, whereas info frame is reporting what that level is currently doing.
Here's a more complex example:
% proc foo {y} {set x 1;grill $y $x $y}
% proc grill {a b c} {uplevel 1 [list bar $a $b $c]}
% proc bar {args} {
for {set i 1} {$i<=[info level]} {incr i} {puts $i-->[info level $i]}
for {set i 1} {$i<=[info frame]} {incr i} {puts $i==>[info frame $i]}
}
% foo 3
1-->foo 3
2-->bar 3 1 3
1==>type eval line 1 cmd {foo 3} level 2
2==>type proc line 1 cmd {grill $y $x $y} proc ::foo level 1
3==>type proc line 1 cmd {uplevel 1 [list bar $a $b $c]} proc ::grill
4==>type eval line 1 cmd {bar 3 1 3} proc ::grill
5==>type proc line 3 cmd {info frame $i} proc ::bar level 0
As you can see, info level does not see that the uplevel happened, but info frame does. But only info level can really tell you what the arguments are. (Note that if you put the code in a file that you source, info frame reports even more information.)

How we create sink(5) variable in tcl script

i am using 20 node in ns2 , i am trying to access the a(0) a(1) a(2) a(3) a(4) variables with for loop how can i do that
here is my code
for {set i 0} {$i < $val(nn)} {incr i} {
set sink($i) [new Agent/LossMonitor]
$ns attach-agent $n($i) $sink($i)
}
but its gives an error
bad variable name "sink(0)": upvar won't create a scalar variable that looks like an array element
i declare the variable in following manner
proc record {} {
global sink(0) sink(1) sink(2) sink(3) sink(4) sink(5)
}
Just use
global sink
(global is just a special upvar case)
variables that end with (...) are (associative) arrays, using numbers as key is not recommended, it is better to use a list instead, e.g.
set mylist {}
# append some elements
lappend mylist "foo" "bar" "baz"
# get the 2nd element
puts [lindex $mylist 1]
# set the 3rd element to "Hello World"
lset mylist 2 "Hello World"

Expanded TCL interpreter in TCL

I have implemented many TCL extensions for a specific tool in the domain of formal methods (extensions are implemented in C but I do not want solution to rely on this fact). Thus, the users of my tool can use TCL for prototyping algorithms. Many of them are just linear list of commands (they are powerfull), e.g.:
my_read_file f
my_do_something a b c
my_do_something_else a b c
Now, I am interested in timing. It is possible to change the script to get:
puts [time [my_read_file f] 1]
puts [time [my_do_something a b c] 1]
puts [time [my_do_something_else a b c] 1]
Instead of this I want to define procedure xsource that executes a TCL script and get/write timing for all my commands. Some kind of a profiler. I wrote a naive implementation where the main idea is as follows:
set f [open [lindex $argv 0] r]
set inputLine ""
while {[gets $f line] >= 0} {
set d [expr [string length $line] - 1]
if { $d >= 0 } {
if { [string index $line 0] != "#" } {
if {[string index $line $d] == "\\"} {
set inputLine "$inputLine [string trimright [string range $line 0 [expr $d - 1]]]"
} else {
set inputLine "$inputLine $line"
set inputLine [string trimleft $inputLine]
puts $inputLine
puts [time {eval $inputLine} 1]
}
set inputLine ""
}
}
}
It works for linear list of commands and even allows comments and commands over multiple lines. But it fails if the user uses if statements, loops, and definition of procedures. Can you propose a better approach? It must be pure TCL script with as few extensions as possible.
One way of doing what you're asking for is to use execution traces. Here's a script that can do just that:
package require Tcl 8.5
# The machinery for tracking command execution times; prints the time taken
# upon termination of the command. More info is available too (e.g., did the
# command have an exception) but isn't printed here.
variable timerStack {}
proc timerEnter {cmd op} {
variable timerStack
lappend timerStack [clock microseconds]
}
proc timerLeave {cmd code result op} {
variable timerStack
set now [clock microseconds]
set then [lindex $timerStack end]
set timerStack [lrange $timerStack 0 end-1]
# Remove this length check to print everything out; could be a lot!
# Alternatively, modify the comparison to print more stack frames.
if {[llength $timerStack] < 1} {
puts "[expr {$now-$then}]: $cmd"
}
}
# Add the magic!
trace add execution source enterstep timerEnter
trace add execution source leavestep timerLeave
# And invoke the magic, magically
source [set argv [lassign $argv argv0];set argv0]
# Alternatively, if you don't want argument rewriting, just do:
# source yourScript.tcl
Then you'd call it like this (assuming you've put it in a file called timer.tcl):
tclsh8.5 timer.tcl yourScript.tcl
Be aware that this script has a considerable amount of overhead, as it inhibits many optimization strategies that are normally used. That won't matter too much for uses where you're doing the real meat in your own C code, but when it's lots of loops in Tcl then you'll notice a lot.
You can wrap your commands which you want to measure. And name wrappers exactly as the original ones (renaming original procs before). After that, when instrumented command is executed it actually executes the wrapper, which executes the original procedure and measure the time of execution. The example below (Tcl 8.5).
proc instrument {procs} {
set skip_procs {proc rename instrument puts time subst uplevel return}
foreach p $procs {
if {$p ni $skip_procs} {
uplevel [subst -nocommands {
rename $p __$p
proc $p {args} {
puts "$p: [time {set r [__$p {*}\$args]}]"
return \$r
}
}]
}
}
}
proc my_proc {a} {
set r 1
for {set i 1} {$i <= $a} {incr i} {
set r [expr {$r * $i}]
}
return $r
}
proc my_another_proc {a b} {
set r 0
for {set i $a} {$i <= $b} {incr i} {
incr r $i
}
return $r
}
instrument [info commands my_*]
puts "100 = [my_proc 100]"
puts "200 = [my_proc 100]"
puts "100 - 200 = [my_another_proc 100 200]"
You might want to look at the command "info complete". It can tell you if what you have accumulated so far looks complete from the point of view of most common Tcl syntax markers. It will deal with command input that might be spread across multiple physical lines.