
 package require Tk
 wm title . Calculator
 grid [entry .e -textvar e -just right] -columnspan 5
 bind .e <Return> =
 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 ""}}
            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 {lappend ::e = [set ::res [expr 1.0*$::e]]}] {
        .e config -fg red
    }
    .e xview end
    set ::clear 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[Rob Hegt] - By adding the below 'fix' proc and changing the line doing the expr to the one given below, it is no longer necessary to add a . in case of a division. proc fix {str} {
  if {[string first "." "$str"] < 0} {
    if {[string first "/" "$str"] > -1} {
      set str "$str."
    }
  }
  return "$str"
 }
…
    if [catch {lappend ::e = [set ::res [expr [fix $::e]]]}] {RS: Yes, but this fix raises an error with well-formed expressions like 1/(2+3). It is simpler, and more bullet-proof, to just prefix 1.0* to the expression when giving it to expr.2-4-2004 MDD: How does one get around the internal int conversion in, for example, 1 / (2 * 4 / 5), which produces an answer of 1.0, rather than the correct answer of 0.625 ? One way to do it might be to go through the entire formula string and replace all ints with doubles, prior to passing it to expr, but that seems a little clunky. Anybody have a cleaner way to do it?RS: Thank you for finding this subtle bug! Isn't Wiki code review great?- I admit that prefixing 1.0* is not bulletproof enough: evaluation goes not always from left to right, parenthesized sub-expressions come first. The precision loss occurs only with division, so it is sufficient to force at least one operand of "/" to double. The following modification passes your test, and I can't presently think of situations where it would produce bad syntax:
 set ::res [expr [string map {/ *1.0/} $::e]]At least it's short, compared to the alternative of tokenizing and parsing the expression, and applying a double() to one of "/"'s operands...MDD:  That seems to do it.  Thanks.Programmable scientific calculator in two lines: (why, it can do asin and log ;-)
 pack [entry .e -textvar e -width 50]
 bind .e <Return> {catch {expr [string map {/ *1./} $e]} res; set e $res} ;# RS & FRFR suggests changing the binding to: bind .e <Return> {catch {expr [string map {/ *1./} $e]} res; set e $res;.e selection range 0 end}to allow easy typing in of a new calculation without having to delete everything first. RS: In principle yes, but the standard selection on Windows (-fg white -bg darkblue} makes the result much less conspicuous... Also, the ::clear variable makes sure that the entry is cleared when you start a new calculation; but you many also edit the original, or re-use its result by typing an operator.And, as CL noted, this thingy is programmable: enter for example [proc fac x {expr {$x<2? 1: $x*[fac [incr x -1]]}}]into the entry, disregard warnings; now you can do[fac 10]and receive [fac 10] = 3628800.0 as result...
See also: Programmable RPN calculator - t-Calc
AM I used to use a UNIX program, called bc, that allows you to type in expressions like "1+2.3" and then you get the result, 3.3. But that is not available on PC ... so, I wrote me a little Tcl script a few years ago to compensate for that. I have revised it, as one of its features was not very satisfactory. Here it is: A bc-like calculator
Derek Peschel 2005-04-27 See A fancier little calculator. The code has big bugs, so I hope a separate page will make reviewing/debugging easier. I wanted to leave a nice finished present but I'm too new to Tcl so I need help. But there are still some potentially good ideas.
[Lectus] - 2011-04-30 09:26:47Here is another simple programmable calculator written using Itcl:
package req math
package req Itcl
namespace import itcl::*
proc func {name arguments body} {
        proc tcl::mathfunc::$name $arguments [list expr $body]
}
class calculator {
# if we pass init arg we're using it as a standalone program.
        constructor {{init '}} {
                if {$init eq "init"} {
                        calculator::REPL
                }
        }
        method eval {line} {
                if {$line eq "exit"} {exit} 
        
                set funcname {}
                set funcargs {}
                set funcbody {}
                if { [regexp {(.+)\((.+)\)=(.+)} $line -> funcname funcargs funcbody] } {
                        func $funcname $funcargs $funcbody
                        return $funcname
                } else {
                        if {[catch {expr $line} res]} {
                                puts stderr "Error in expression!"
                                return 0
                        } else { return $res }
                }
        }
                
        method read {} {
                gets stdin line
                calculator::eval $line
        }
                
        method REPL {} {
                while 1 {
                        puts -nonewline "\n>> "
                        puts [calculator::read]
                }
        }
}
calculator calc initUsage:$ tclsh calc.tcl >> f(x y)= $x > $y ? $x : $y f >> f(2,3) 3 >> f(5,1) 5 >> g(x)=$x*2 g >> 1 + g(5) 11Explanation: I used an Itcl class to create a reusable calculator. The eval method evaluates expressions, and if the expression is a function it will define it in tcl::mathfunc namespace, so that it's available in expr. The REPL method defines the prompt that keeps reading and evaluating expressions. Type 'exit' to exit the calculator.

