Обрабатывать аргумент как строку в выражении Tcl 'expr'
Я использую короткий синтаксис оператора if, например:
proc WriteParameter {Parameter Value} {
# Ugly option - WORKS
if {$Parameter eq "Unique"} {
set Register ControlStatus
set Data ${Value}0
set Mask EF
} else {
set Register $Parameter
set Data $Value
set Mask {}
}
# Elegant option - DOESN'T WORK
set Register [expr {$Parameter eq "Unique" ? "ControlStatus" : $Parameter}]
set Data [expr {$Parameter eq "Unique" ? ${Value}0 : $Value}]
set Mask [expr {$Parameter eq "Unique" ? EF : {}}]
puts $Register-$Data-$Mask
return 0
}
set Value 4E20 ;# Merely hexadecimal number
set Parameter Regular
WriteParameter $Parameter $Value
Проблема заключается в том, что в элегантном варианте, поскольку оператор 'expr' всегда обрабатывает свои аргументы как целые числа, 'Data' получает значение 4e+20, которое является просто научной нотацией 'Value'.
Однако мне нужно, чтобы "Данные" были "Значение" (например, для записи во внешний регистр).
Есть идеи?
1 ответ
expr
язык довольно отличается от остальной части Tcl. Вы должны больше заботиться о синтаксисе там. Положить вещи в "
двойные кавычки"
может помочь.
set Register [expr {$Parameter eq "Unique" ? "ControlStatus" : $Parameter}]
set Data [expr {$Parameter eq "Unique" ? "${Value}0" : $Value}]
set Mask [expr {$Parameter eq "Unique" ? "EF" : {}}]
Тем не менее, вы могли бы лучше использовать if
поскольку это не пытается преобразовать результаты его рук в число (используя приблизительно правила для констант C) в отличие от expr
,
set Register [if {$Parameter eq "Unique"} {string cat ControlStatus} {string cat $Parameter}]
set Data [if {$Parameter eq "Unique"} {string cat $Value 0} {string cat $Value}]
set Mask [if {$Parameter eq "Unique"} {string cat EF}]
# We can omit the else clause; the default is an empty string anyway
Это зависит от string cat
, который был представлен в Tcl 8.6.3 (ну, 8.6.2, но в подсистеме ввода / вывода были некоторые ошибки, которых вы действительно хотите избежать). Если вы используете что-то от 8.5 до 8.6.1, используйте это вместо:
set Register [if {$Parameter eq "Unique"} {return -level 0 ControlStatus} {return -level 0 $Parameter}]
set Data [if {$Parameter eq "Unique"} {return -level 0 ${Value}0} {return -level 0 $Value}]
set Mask [if {$Parameter eq "Unique"} {return -level 0 EF}]
Да, return -level 0
просто дает значение в качестве результата. "Очевидное и обнаруживаемое"…
Если вы используете 8.4 или более раннюю версию (Обновите, мужик! У вас нет поддержки безопасности!), Вам нужна небольшая вспомогательная процедура:
proc value {value} {return $value}
set Register [if {$Parameter eq "Unique"} {value ControlStatus} {value $Parameter}]
set Data [if {$Parameter eq "Unique"} {value $Value 0} {value $Value}]
set Mask [if {$Parameter eq "Unique"} {value EF}]
value
описанная выше процедура будет работать и с более поздними версиями Tcl, но она дает менее эффективный байт-код.
Тем не менее, для всего вышеперечисленного я бы сделал что-то другое:
set Register $Parameter
set Data $Value
set Mask ""
if {$Parameter eq "Unique"} {
set Register ControlStatus
append Data 0
set Mask EF
}
Я мог бы также использовать scan
проанализировать значение и format
составить результаты обратно в гекс (при необходимости). Таким образом, было бы намного проще думать о ценности, а не только о представлении.