我需要将perl脚本转换为Tcl脚本。我之前曾在Python工作,但这是一个新挑战,因为我是perl和tcl的新手。
任何人都可以给我一些关于如何在Tcl中表示以下行的指示:
my @GPO_regs = qw(0x70034 0x70038 0x7003C 0x70040 0x70044);
sub write_phy {
my($phy, $register, $value) = @_;
$value = oct($val) if $value =~ /^0/;
if ($DEBUG) { printf("Write PHY ${phy} register ${register} =
0x%0.8X\n", $value); };
`./write_phy.pl ${phy} ${register} ${value}`;
}
在另一个Perl文件中:
my ($phyAddr, $regAddr) = @ARGV;
if($phyAddr =~ /0x/) {
$phyAddr = oct($phyAddr);
}
if($regAddr =~ /0x/) {
$regAddr = oct($regAddr);
}
my $registerValue = 1 << 31 | $phyAddr << 25 | $regAddr << 20 | 2 << 1;
my $registerHex = sprintf("0x%X", $registerValue);
`./read_write_spi_reg -a 0x070064 -w ${registerHex}`;
my $value = `./read_write_spi_reg -a 0x070068 -r`;
if( $value >> 16 != 0 ) {
die "Error reading PHY register";
}
chomp($value);
printf("${value}\n");
感谢您的支持。
答案 0 :(得分:2)
好吧,让我们在您的第一个文件中考虑您的代码:
my @GPO_regs = qw(0x70034 0x70038 0x7003C 0x70040 0x70044);
这(创建一个从未使用过的有效全局变量?)将被翻译成:
set GPO_regs {0x70034 0x70038 0x7003C 0x70040 0x70044}
鉴于此:
sub write_phy {
my($phy, $register, $value) = @_;
# Stuff...
}
变为:
proc write_phy {phy register value} {
# Translation of Stuff...
}
继续查看子程序的内容(应用明显的修正后):
$value = oct($value) if $value =~ /^0/;
如果该字符串以前导零开头,则该行解码字符串的八进制值。默认情况下,Tcl会在某些情况下执行此操作,但请注意。我将使用正则表达式来执行“如果该字符串以前导零开头”,即使我通常不这样做,因为这将帮助您翻译其他文件:
if { [regexp {^0} $value] } {
# The [scan] command is a lot like the C sscanf() function, if you know that
scan $value "%o" value
}
翻译这个唯一棘手的事情:
if ($DEBUG) { printf("Write PHY ${phy} register ${register} = 0x%0.8X\n", $value); };
是Tcl对Perl有不同的变量范围规则,因此DEBUG
变量将不存在。在这种情况下,最简单的方法是使用变量的完全限定名称。
if {$::DEBUG} {
puts [format "Write PHY ${phy} register ${register} = 0x%0.8X" $value]
### However, I recommend this instead:
# puts [format "Write PHY %s register %s = 0x%0.8X" $phy $register $value]
### As unexpected % symbols in phy or register won't make it choke. The equivalent
### advice would apply if you were sticking with Perl.
}
最后,Perl中的反引号直接转换为Tcl&#39; exec
,所以这个:
`./write_phy.pl ${phy} ${register} ${value}`;
成为这个:
exec ./write_phy.pl $phy $register $value
您通常可以从Tcl变量名称周围省略{
大括号}
;你只需要它们就会导致一个不必要的解析。
把这些放在一起,我得到:
set GPO_regs {0x70034 0x70038 0x7003C 0x70040 0x70044}
proc write_phy {phy register value} {
if { [regexp {^0} $value] } {
scan $value "%o" value
}
if {$::DEBUG} {
puts [format "Write PHY %s register %s = 0x%0.8X" $phy $register $value]
}
exec ./write_phy.pl $phy $register $value
}
请注意,另一个文件中的代码有一些潜伏的错误!我不会深入了解它,但您需要知道的关键事项是,未用作if
条件的表达式应包含在expr
中,如下所示:
set registerValue [expr {1 << 31 | $phyAddr << 25 | $regAddr << 20 | 2 << 1}]
以及将脚本的参数拆分为变量的推荐方法如下:
lassign $argv phyAddr regAddr
(Tcl&#39; s $
并不意味着“这是一个变量”,它意味着“从这个变量中读取”。变量名称传递给操纵的东西变量本身 - 例如set
和lassign
- 通常不应该在前面有$
。)
此外,Perl的die
与Tcl的error
非常相似,而Tcl的exec
会自动执行chomp
- 喜欢操作它的结果。