tclns2

How to fix ‘can't read "node_(0)": no such variable’ error in tcl?


I'm setting up a net environment that there are n nodes surrounded by a circle with DSR protocol. However, when I fixed most of the errors, the most confused error that I couldn't solve like the title. How to fix 'can't read "node_(0)": no such variable' error? Didn't I already define it in the for loop at line 86?

I can't find a solution to this problem and when I changed

set node_($i) [$ns node]

to

set node_($i) [$ns_ node]

Here's the full code.

set val(chan)   Channel/WirelessChannel
set val(prop)   Propagation/TwoRayGround
set val(netif)  Phy/WirelessPhy
set val(mac)    Mac/802_11
set val(ifq)    CMUPriQueue
set val(ll)     LL
set val(ant)    Antenna/OmniAntenna
set val(ifqlan) 50
set val(nn)     0
set val(rp)     DSR
set val(x)      1000
set val(y)      1000
set val(r)      400

proc usage {} \
{
    global argv0
    puts "\nusage: $argv0 \[-nn node\] \[-r r\] \[-x x\] \[-y y\]\n"
    puts "note: \[-nn nodes\] is essential, and the others are optional.\n"
}

proc getval {argc argv} \
{
    global val
    lappend vallist nn r x y z
    for {set i 0} {$i < $argc} {incr i} {
        set arg [lindex $argv $i]
        if {[string range $arg 0 0] != "-"} continue
        set name [string range $arg 1 end]
        set val($name) [lindex $argv[expr $i+1]]
    }
}


getval $argc $argv
if {$val(nn) == 0} {
    usage
    exit
}


set ns [new Simulator]  

set tracefd [open circle.tr w]
$ns trace-all $tracefd

set namtracefd [open circle.nam w]  
$ns namtrace-all-wireless $namtracefd $val(x) $val(y)


proc finish {} \
{
    global ns tracefd namtracefd
    $ns flush-trace 
    #close the trace file
    close $tracefd
    close $namtracefd
    #execute nam on the trace file
    exec nam circle.nam &
    exit 0
}


set topo [new Topography]   

$topo load_flatgrid $val(x) $val(y)

create-god $val(nn)
$ns node-config     -addressType    def\
        -adhocRouting   $val(rp)\
        -llType         $val(ll)\
        -macType        $val(mac)\
        -ifqType        $val(ifq)\
        -ifqLan         $val(ifqlan)\
        -antType        $val(ant)\
        -propType       $val(prop)\
        -phyType        $val(netif)\
        -channelType    $val(chan)\
        -topoInstance   $topo\
        -agenttrace     ON\
        -routertrace    ON\
        -mactrace       OFF\
        -movementtrace  OFF

##################################
for {set i 0} {$i < $val(nn)} {incr i} {
    set node_($i) [$ns node]
    $node_($i) random-motion 0
    $node_($i) set X_ [expr $val(r) * cos($i * 2 * 3.14159 / $val(nn))]
    $node_($i) set Y_ [expr $val(r) * sin($i * 2 * 3.14159 / $val(nn))]
    $node_($i) set Z_ 0
    $ns initial_node_pos $node_($i) [expr $val(x) / 10]
}
##################################

set tcp [new Agent/UDP]
$ns attach-agent $node_(0) $tcp
set null [new Agent/Null]
$ns attach-agent $node_([expr $val(nn) / 2]) $null

set cbr [new Application/Traffic/CBR]
$cbr set packetSize_ 5000
$cbr set interval_ 0.05
$cbr attach-agent $tcp
$ns connect $tcp $null

$ns at 0.1 "$cbr start"
$ns at 3.0 "$cbr stop"
$ns at 5.0 "finish"
$ns run

When i type ns circle.tcl -nn 12, I expect the output:

num_node is set 12
warning: Please use -channel as shown in tcl/ex/wireless-mitf.tcl
INITIALIZE THE LIST xListHead
channel.cc:sendUp - Calc highestAntennaZ_and distCST_
SORTING LISTS ...DONE!

Please help me, I've been stuck for a long time.


Solution

  • That error will be produced whenever val(nn) is not greater than zero, as then the loop that creates the nodes:

    for {set i 0} {$i < $val(nn)} {incr i} {
        set node_($i) [$ns node]
        $node_($i) random-motion 0
        $node_($i) set X_ [expr $val(r) * cos($i * 2 * 3.14159 / $val(nn))]
        $node_($i) set Y_ [expr $val(r) * sin($i * 2 * 3.14159 / $val(nn))]
        $node_($i) set Z_ 0
        $ns initial_node_pos $node_($i) [expr $val(x) / 10]
    }
    

    will simply decide that it has nothing to do and not execute the body of the loop even once. What might cause that? Well, if we look at the argument parsing procedure:

    proc getval {argc argv} \
    {
        global val
        lappend vallist nn r x y z
        for {set i 0} {$i < $argc} {incr i} {
            set arg [lindex $argv $i]
            if {[string range $arg 0 0] != "-"} continue
            set name [string range $arg 1 end]
            set val($name) [lindex $argv[expr $i+1]]
        }
    }
    

    we can see a number of problems, of which the biggest is this (on the line with set val($name):

    lindex $argv[expr $i+1]
    

    The problem here is the lack of a space between $argv and the expression evaluation; that concatenates the two strings before feeding the result into lindex as a single argument! (lindex with a single argument just returns that argument, using the principle of “do nothing, gracefully”.) That's not even syntactically correct in all cases, but probably was in the cases you tried and resulted in val(nn) being set to something like the string -nn 101. Now, the < operator (in the node generation loop) will use ASCII ordering whenever either side looks non-numeric and that string has extra garbage in it so it is definitely non-numeric. Oh dear. (- is ASCII character code 45 and 0 is ASCII character code 48, so - comes before 0.) This isn't what you wanted!

    Here's a fixed version of the argument parser:

    proc getval {argc argv} {
        global val
        for {set i 0} {$i < $argc} {incr i} {
            set arg [lindex $argv $i]
            if {[string index $arg 0] eq "-"} {
                set val([string range $arg 1 end]) [lindex $argv [incr i]]
            }
        }
    }
    

    Remember, in Tcl the spaces are important!