如何从 -command 选项中的代码获取结果

How to get result from code in a -command option

参考:https://en.wikibooks.org/wiki/Tcl_Programming/Tk_examples#A_little_calculator

我是Tcl语言的初学者。 我会试着用这个计算器代码来制作阶乘过程,

使用按钮“!”

发生这样的错误:

invalid command name "if{x<2}"
invalid command name "if{x<2}"
    while executing
"if{x<2} {
 return 1
} else "
    (procedure "fac" line 2)
    invoked from within
"fac {$row}"
    invoked from within
".20 invoke"
    ("uplevel" body line 1)
    invoked from within
"uplevel #0 [list $w invoke]"
    (procedure "tk::ButtonUp" line 24)
    invoked from within
"tk::ButtonUp .20"
    (command bound to event)

并使用“!”在像这样的键盘错误代码

    wrong # args: should be "fac x"
    wrong # args: should be "fac x"
        while executing
    "fac"
        (command bound to event)

在此代码中

package require Tk
    wm title . Calculator
    grid [entry .e -textvar e -just right] -columnspan 5
    bind .e <Return> =
    bind .e <!> fac

    set n 0

    foreach row {
       {7 8 9 + -}
       {4 5 6 * /}
       {1 2 3 ( )}
       {C 0 . = !}
    } {
       foreach key $row { 
           switch -- $key {
               =       {set cmd =}
               C       {set cmd {set clear 1; set e ""}}
               !       {set cmd {[fac {$row}]}} 
               default {set cmd "hit $key"}
           }
           lappend keys [button .[incr n] -text $key -command $cmd]
       }
       eval grid $keys -sticky we ;#-padx 1 -pady 1
       set keys [list]
    }
    grid .$n -columnspan 2 ;# make last key (=) double wide
    proc = {} {
       regsub { =.+!} $::e "" ::e ;# maybe clear previous result
       if [catch {set ::res [expr [string map {/ *1.0/} $::e]]}] {
           .e config -fg red 
       }
       append ::e = $::res 
       .e xview end
       set ::clear 1
    }
    proc fac {x} {
    if{$x<2} {
     return 1
    } else 
    {
    return $x[fac[incr x-1]]
    }
    }

    # expr {$x<2? x 1: $x*[fac [incr x -1]]}}

    proc hit {key} {
       if $::clear {
           set ::e ""
           if ![regexp {[0-9().]} $key] {set ::e $::res}
           .e config -fg black
           .e icursor end
           set ::clear 0
       }
       .e insert end $key
    }
    set clear 0
    focus .e           ;# allow keyboard input
    wm resizable . 0 0

所以,我无法在 -command 或 cmd 中获取结果过程。

如何在 Tcl 中使用 cmd、-command 选项获得 return 过程结果?

对不起,英语很难读,谢谢。

P.S。我想 "cmd",可能是 "Macro" 中的其他语言(如 C 风格)?

你的问题是:

proc fac {x} {
if{$x<2} {
 return 1
} else 
{
return $x[fac[incr x-1]]
}
}

不计算阶乘。是的,它正在声明一个过程,fac,但是该过程的实现脚本在多个方面都是错误的,这等同于语法错误。让我们首先修复明显缺少 spaces 或额外换行符的地方:

proc fac {x} {
if {$x<2} {
 return 1
} else {
return $x[fac [incr x -1]]
}
}

现在将计算 something(我们通过在 if 和它的第一个参数之间添加 space 来摆脱语法问题x-1incr 的参数中,在递归调用中在 fac[incr …] 之间,并在 [=21= 之后去掉额外的换行符]) 但它仍然不是您想要的,因为它没有将 $x 乘以 [fac [incr x -1]];添加那个([expr {… * …}])给我们这个:

proc fac {x} {
if {$x<2} {
 return 1
} else {
return [expr {$x * [fac [incr x -1]]}]
}
}

现在我们得到了一个实际起作用的阶乘!为了清楚起见,让我们快速整理一下缩进:

proc fac {x} {
    if {$x<2} {
        return 1
    } else {
        return [expr {$x * [fac [incr x -1]]}]
    }
}

有更有效的方法来实现阶乘,但至少现在这是一个干净的工作示例。


一般来说,在修复你的脚本时,你应该首先修复语法错误(Tcl 关心 spaces 和换行符以及它们之间的区别),然后是你的语义错误(例如,一个缺失的乘法),然后是你的缩进。但有时修复缩进会使语法错误更加明显,因此该顺序不是严格的规则!

您可能想要查找并安装 nagelfar tool 的副本。那会进行语法分析,并会为您找出代码中的各种错误。