Как узнать, какой оператор в какой строке меняет значение переменной в TCL - PullRequest
2 голосов
/ 24 апреля 2011

Иногда вы не можете понять, когда меняется значение переменной.И нужно найти строку, поместив точку наблюдения на переменную.Как это можно сделать?Может ли команда трассировки TCL быть полезной для получения строки, где была изменена переменная?

1 Ответ

4 голосов
/ 24 апреля 2011

Чтобы поместить точку наблюдения в переменную, вы используете команду trace. Вы можете получить расширенную информацию о контексте, в котором переменная была назначена с помощью команды info, особенно подкоманд level и frame. (Последний доступен только с Tcl 8.5 и далее.)

Подобные вещи должны давать нужную информацию:

trace add variable x write peekLocation
proc peekLocation args {
    puts "WRITTEN FROM >[info level -1]< CALL"
    puts "DETAILS: [info frame -1]"
}
# Demonstration...
proc foobar {} {
    global x  
    set x "jibber jabber"
}
foobar

Это не вполне работает, хотя; Вы можете легко найти, какая процедура работала во время обновления переменной, но где в этой процедуре произошло обновление, остается вне досягаемости. (Вместо этого вы видите вызов самого обратного вызова трассировки или, на одном уровне дальше по стеку, вызов процедуры, выполняющей манипуляции, ни один из которых не является таким полезным ...)


[РЕДАКТИРОВАТЬ]: Другой подход состоит в том, чтобы предположить, какая команда выполняет обновление (например, set), и выполнить несколько jiggery-pokery так, чтобы info level (единственная команда, которая может предоставить номер строки ) может делать правильные вещи:

rename set __orig_set;proc set args {doTrace;uplevel 1 [list __orig_set {*}$args]}
# Separate the probe from the instrumentation
proc doTrace {} {
    puts [info frame -2]
}

Это работает. Также довольно легко распространить его на другие команды, которые выполняют установку переменных (например, [incr], [lappend], [lset]). Причудливый зонд это:

proc doTrace {} {
    __orig_set f [info frame -2]
    dict with f {
        switch $type {
            source {
                puts "Write happened on line $line of file $file"
            }
            proc {
                puts "Write happened on line $line of procedure $proc"
            }
            default {
                puts "Write happened on line $line (command was >$cmd<)"
            }
        }
    }
}

Не стесняйтесь экспериментировать!

...