+my %alias = (
+ chr 4 => 'quit', # ^D
+ chr 9 => 'more', # tab
+ '_' => 'chs', # change sign; 48: y
+ 'e' => 'eex', # exponent; 48: z
+# "\033\133\062\176" => 'swap', # ins
+ "\033\133\063\176" => "clear", # del
+ chr 127 => 'drop', # backspace
+ chr 8 => 'drop', # backspace
+ chr 13 => 'enter', # enter
+ ' ' => 'enter', # space
+ "\014" => 'refresh', # ^L
+# "\033\133\110" => 'refresh', # home
+
+# "\033\133\101" => '', # up; 48: k (stack)
+# "\033\133\104" => '', # left; 48: p (picture)
+# "\033\133\102" => '', # down; 48: q (view)
+ "\033\133\103" => 'swap', # right; 48: r (swap)
+
+ '&' => 'and',
+ '|' => 'or',
+ '#' => 'xor',
+ '~' => 'not',
+
+ "s" => 'sin',
+ "\033s" => 'asin',
+ "c" => 'cos',
+ "\033c" => 'acos',
+ "t" => 'tan',
+ "\033t" => 'atan',
+ "l" => 'log',
+ "\033l" => 'alog',
+ "n" => 'ln',
+ "\033n" => 'exp',
+ "q" => 'sq',
+ "\033q" => 'sqrt',
+ "\033^" => 'xroot',
+); # %alias
+
+=cut
+HP48 keys:
+ S T U V W X
+ - sin cos tan sqrt ^ 1/x
+ < asin acos atan sq alog exp
+ > [a] ∫ ∑ xroot log ln
+=cut
+
+my %action = (
+ 'more' => [0, sub {
+ $menumin += $set{menushow};
+ $menumin = 0 if $menumin>=$#menu;
+ showmenu();
+ }], # tab
+ 'digit'=> [-2, sub { $val{i} = ($val{frac} *= 10) ? $val{i}+$_/$val{frac} : $val{i}*10+$_ }],
+ '.' => [-2, sub { $val{frac} = 1 }], # decimal point
+ 'eex' => [-2, sub {}], # exponent
+ 'chs' => [0, sub {
+ if (defined $val{i}) {
+ $val{i} = -$val{i};
+ } else {
+ $stack[0] = -$stack[0];
+ }
+ }], # negative
+
+ 'drop' => [0, sub {
+ if (defined $val{i}) {
+ $val{i} = ($val{frac} = int $val{frac}/10)
+ ? int($val{i}*$val{frac})/$val{frac} : int $val{i}/10
+ } else {
+ shift @stack;
+ }
+ }], # backspace
+ 'clear'=> [0, sub {
+ #todo: if (val{i}) delete char after cursor
+ @stack = (); %val = (i=>undef, frac=>0)
+ }], # clear all
+
+ 'enter'=> [0, sub {
+ unshift @stack, $val{i};
+ %val = (i=>undef, frac=>0);
+ }], # duplication
+
+ 'swap' => [1, sub {@stack[0, 1] = @stack[1, 0]}], # swap x<->y
+
+ '=' => [1, sub {$var{a} = $stack[0]}], # copy
+ '>' => [1, sub {$var{a} = shift @stack}], # assign
+
+ '+' => [2, sub {$stack[1] += shift @stack}], # addition
+ '-' => [2, sub {$stack[1] -= shift @stack}], # substraction
+ '*' => [2, sub {$stack[1] *= shift @stack}], # multiplication
+ '/' => [2, sub {$stack[1] /= shift @stack}], # division
+ 'mod' => [2, sub {$stack[1] %= shift @stack}], # modulo
+
+ 'sqrt' => [1, sub {$stack[0] = sqrt $stack[0]}], # square root
+ 'sq' => [1, sub {$stack[0] *= $stack[0]}], # squared
+ '^' => [2, sub {$stack[1] **= shift @stack}], # exponentiation
+ 'xroot'=> [2, sub {$stack[1] **= 1 / shift @stack}], # x-root of y
+
+ 'log' => [1, sub {$stack[0] = log($stack[0]) / log(10)}], # logarithm
+ 'alog' => [1, sub {$stack[0] = 10 ** $stack[0]}], # 10^x
+ 'ln' => [1, sub {$stack[0] = log $stack[0]}], # natural logaritm
+ 'lnp1' => [1, sub {$stack[0] = log($stack[0]+1)}], # ln(x+1)
+ 'exp' => [1, sub {$stack[0] = exp($stack[0])}], # e^x
+ 'expm' => [1, sub {$stack[0] = exp($stack[0])-1}], # exp(x)-1
+
+ 'sin' => [1, sub {$stack[0] = sin $stack[0]}], # sine
+ 'asin' => [1, sub {$stack[0] = atan2($stack[0], sqrt(1 - $stack[0]*$stack[0]))}], # inverse sine
+ 'cos' => [1, sub {$stack[0] = cos $stack[0]}], # cosine
+ 'acos' => [1, sub {$stack[0] = atan2(sqrt(1 - $stack[0]*$stack[0]), $stack[0])}], # inverse cosine
+ 'tan' => [1, sub {$stack[0] = sin($stack[0]) / cos($stack[0])}], # tangent
+# 'atan' => [1, sub {}], # arctangent
+
+ '%' => [2, sub {$stack[0] /= shift @stack}], # percentage
+ '%ch' => [2, sub {$val{i} = 100*(shift(@stack)-$val{i})/$val{i}}], # percentage change
+ '%t' => [2, sub {$val{i} = 100*$val{i}/shift(@stack)}], # percentage total
+
+ 'and' => [2, sub {$stack[1] &= shift @stack}], # bitwise and
+ 'or' => [2, sub {$stack[1] |= shift @stack}], # bitwise or
+ 'xor' => [2, sub {$stack[1] ^= shift @stack}], # bitwise xor
+ 'not' => [2, sub {$stack[0] = ~$stack[0]}], # bitwise not
+
+ 'abs' => [1, sub {$stack[0] = abs $stack[0]}], # absolute #todo
+ 'sign' => [1, sub {$stack[0] = $stack[0] <=> 0}], # sign
+ 'ip' => [1, sub {$stack[0] = int $stack[0]}], # integer part
+ 'fp' => [1, sub {$stack[0] -= int $stack[0]}], # fractional part
+
+ 'rnd' => [1, sub {local $_ = 10**shift @stack; $val{i} = int(($val{i}+.5)*$_)/$_}], # round
+ 'trnc' => [1, sub {local $_ = 10**shift @stack; $val{i} = int($val{i}*$_)/$_}], # truncate
+ 'floor'=> [1, sub {$stack[0] = int $stack[0]}], # floor
+ 'ceil' => [1, sub {$stack[0] = int $stack[0]+.9999}], # ceil
+
+ 'min' => [2, sub {
+ local $_ = shift @stack;
+ $stack[0] = $_ if $_<$stack[0];
+ }], # minimum
+ 'max' => [2, sub {
+ local $_ = shift @stack;
+ $stack[0] = $_ if $_>$stack[0];
+ }], # maximum
+
+ 'dec' => [0, sub {$set{base} = 10}], # decimal
+ 'bin' => [0, sub {$set{base} = 2}], # binary
+ 'oct' => [0, sub {$set{base} = 8}], # octal
+ 'hex' => [0, sub {$set{base} = 16}], # hexadecimal
+ 'base' => [1, sub {$set{base} = shift @stack}], # alphanumerical
+); # %action
+
+my %unit;
+{
+my $i = 0;
+$unit{$_->[0]} = { name=>$_->[0], type=>$i, val=>$_->[1] } for map {$i++; @$_} (
+ [
+ ['m', 1],
+ ['cm', .01],
+ ['mm', .001],
+ ['km', 1000],
+ ['ft', .3048],
+ ['in', .0254],
+ ['yd', .9144],
+ ['mile', 1609.344],
+ ['nmile', 1852],
+ ['lyr', 9.46052840488e+15],
+ ['mil', 2.54e-5],
+ # _m _cm _mm _yd _ft _in _Mpc _pc _lyr _au _km _mi
+ # _nmi _miUS _chain _rd _fath _ftUS _Mil _μ _Å _fermi
+ ], # lengths
+ [
+ ['m^3', 1],
+ ['cm^3', 1e-6],
+ ['ft^3', .028316846592],
+ ['in^3', 1.6387064e-5],
+ ], # volume
+);
+} # create unit table
+
+
+sub error($) {
+ attron(A_REVERSE);
+ addstr(0, 0, shift);
+ attroff(A_REVERSE);
+ clrtoeol;
+ refresh;