APP / FREE / MIT EXAMPLE SOURCE
A thoughtful little calculator
Decimal arithmetic, keyboard entry, and clear recovery from divide-by-zero errors.

Take it for a spin.
Type digits and operators. Enter calculates; Backspace deletes. Click the buttons for clear and sign change.
Extract the Windows download to a writable folder and open calculator.exe. Escape closes it. Database examples keep their local data in the working folder.
See how it works.
State machines, decimal place value, events, and explicit error recovery.
A basic sequential calculator, without expression precedence or arbitrary precision.
READ / CHANGE / UNDERSTAND
The whole example is yours.
These are the exact files in the source download. Start with the model, then follow the window’s event loop. Comments explain the decisions.
// A calculator is a state machine: entry, pending operator, and accumulator.
// Decimal parsing is explicit so the example teaches place value as well as UI.
ParseDecimal(text value) returns float
{
float parsed=0
float place=1
bool fraction=false
bool negative=false
for i from 0 < Text.Length(value)
{
int c=Text.CodeUnitAt(value,i)
if c==45
{
negative=true
}
else if c==46
{
fraction=true
}
else if c>=48 and c<=57
{
if fraction
{
place=place*0.1
parsed=parsed+Math.IntToFloat(c-48)*place
}
else
{
parsed=parsed*10+Math.IntToFloat(c-48)
}
}
}
if negative
{
return -parsed
}
return parsed
}
class Calculator
{
text entry="0"
text operation=""
float accumulator=0
bool fresh=true
bool fault=false
Press(text key)
{
if key=="C"
{
this.entry="0"
this.operation=""
this.accumulator=0
this.fresh=true
this.fault=false
return
}
if this.fault
{
return
}
// Percent is a unary operation on the current entry, not a second equals key.
if key=="%"
{
this.entry=Text.From(ParseDecimal(this.entry)/100.0)
this.fresh=false
return
}
if key=="DEL"
{
if !this.fresh and Text.Length(this.entry)>1
{
this.entry=Text.Slice(this.entry,0,Text.Length(this.entry)-1)
}
else
{
this.entry="0"
}
return
}
if key=="+/-"
{
if this.entry!="0"
{
if Text.CodeUnitAt(this.entry,0)==45
{
this.entry=Text.Slice(this.entry,1,Text.Length(this.entry))
}
else
{
this.entry="-"+this.entry
}
}
return
}
if key=="+" or key=="-" or key=="*" or key=="/" or key=="="
{
float value=ParseDecimal(this.entry)
// Changing an operator before entering a new number does not calculate twice.
if this.operation!="" and !this.fresh
{
if this.operation=="+"
{
this.accumulator=this.accumulator+value
}
if this.operation=="-"
{
this.accumulator=this.accumulator-value
}
if this.operation=="*"
{
this.accumulator=this.accumulator*value
}
if this.operation=="/"
{
if value==0
{
this.entry="Cannot divide by zero"
this.fault=true
return
}
this.accumulator=this.accumulator/value
}
}
else if this.operation==""
{
this.accumulator=value
}
this.entry=Text.From(this.accumulator)
this.operation=key
if key=="="
{
this.operation=""
}
this.fresh=true
return
}
if this.fresh
{
this.entry="0"
this.fresh=false
}
if key=="."
{
if !Text.Contains(this.entry,".")
{
this.entry=this.entry+"."
}
return
}
if Text.Length(key)==1 and Text.CodeUnitAt(key,0)>=48 and Text.CodeUnitAt(key,0)<=57 and Text.Length(this.entry)<12
{
if this.entry=="0"
{
this.entry=key
}
else
{
this.entry=this.entry+key
}
}
}
}
