Perl 到 Tcl 代码转换

Perl to Tcl code conversion

我需要将 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");

感谢您的支持。

好吧,让我们考虑一下第一个文件中的代码:

my @GPO_regs = qw(0x70034 0x70038 0x7003C 0x70040 0x70044);

这(它正在创建一个从未使用过的 effectively-global 变量?)将被翻译成:

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变量会不存在。在这种情况下,最简单的技术是使用变量的 fully-qualified 名称。

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 的 exec,因此:

`./write_phy.pl ${phy} ${register} ${value}`;

变成这样:

exec ./write_phy.pl $phy $register $value

您通常可以省略 Tcl 变量名周围的 { 大括号 };您只需要在会导致 otherwise-unwanted 解析的地方使用它们。

将这些放在一起,我得到:

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 的 $ 并不意味着“这是一个变量”,它的意思是“从这个变量中读取”。变量 names 传递给操作变量本身——例如 setlassign——前面通常不应有 $。)

此外,Perl 的 die 很像 Tcl 的 error,而 Tcl 的 exec 会自动对其结果执行类似 chomp 的操作。