如何修复 tcl 中的“无法读取 "node_(0)":没有这样的变量”错误?

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

我正在设置一个网络环境,其中有 n 个节点被一个圆圈包围,使用 DSR 协议。然而,当我修复大部分错误时,我无法解决的最困惑的错误如标题。如何修复“无法读取 "node_(0)":没有这样的变量”错误?我不是已经在86行的for循环里定义了吗?

我找不到解决这个问题的方法,当我改变的时候

set node_($i) [$ns node]

set node_($i) [$ns_ node]

这是完整的代码。

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

当我键入 ns circle.tcl -nn 12 时,我希望输出:

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!

请帮帮我,我卡了好久

加四行,模拟即可运行.

set val(ifqlen)          50    ;# added (Line 7)
set val(nn)     10             ;# added (Line 10)
.
       -movementtrace  OFF \
       -ifqLen $val(ifqlen)    ;# added (Line 85)
.
for {set i 0} {$i < [expr $val(nn)]} {incr i} {
    set node_($i) [$ns node]   ;# added (Line 89)

set val(nn) 10 的原因:我没有让 [$argv] 工作。 ( $ ns file.tcl -nn 10$ ns file.tcl nn 10 )

Link 到编辑后的文件:https://www.dropbox.com/s/m7zsnga6wf29r95/2Ezio-Auditore-DSR.tcl?dl=0

所有 ~3500 ns2 模拟前 https://drive.google.com/drive/folders/0B7S255p3kFXNSmRYb2lGcDRUdWs?usp=sharing


编辑:添加了@Donal Fellows 的 'argument parser',现在可以 运行 和 $ ns file.tcl -nn 12。新例子 https://www.dropbox.com/s/br6qaeg5kj73k14/4-circle-Ezio-Auditore.tar.gz?dl=0

ns2 分析脚本https://drive.google.com/drive/folders/1rU_MFAEl1GCLMTJPLR3zbxPxkQQHkQ7T?usp=sharing

只要 val(nn) 不大于零,就会产生该错误,然后创建节点的循环:

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]
}

将简单地决定它无事可做,甚至不执行循环体一次。是什么原因造成的?好吧,如果我们看一下参数解析过程:

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]]
    }
}

我们可以看到很多问题,其中最大的就是这个(在set val($name):

这一行
lindex $argv[expr $i+1]

这里的问题是$argv和表达式求值之间缺少space;在将结果作为单个参数输入 lindex 之前连接两个字符串! (lindex 只有一个参数 returns 那个参数,使用“优雅地什么都不做”的原则。)这在所有情况下甚至在语法上都不正确,但可能在您尝试并结果的情况下在 val(nn) 中被设置为类似于字符串 -nn 101 的内容。现在,< 运算符(在节点生成循环中) 将在 任一 侧看起来不正确时使用 ASCII 排序-numeric 并且该字符串中有额外的垃圾,因此它绝对是非数字的。哦亲爱的。 (- 是 ASCII 字符代码 45,0 是 ASCII 字符代码 48,所以 - 出现在 0 之前。)这不是你想要的!

这是参数解析器的固定版本:

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]]
        }
    }
}

记住,在 Tcl 中 space 很重要!