[Date Prev][Date Next][Thread Prev][Thread Next] [Search] [Date Index] [Thread Index]

[FWP] Interactive RPN calculator



I've been mildly irritated by that lack of a calculator that I
liked. This sort of thing is a matter of taste, of course, and I
doubt very many peoples' tastes will exactly track mine. But on
those rare occasions when I want to do a little arithmetic, I
haven't found a calculator that I really enjoyed using. I've
periodically dreamed of writing one, but somehow never got around to
it; partially because I didn't have a vision of a user interface
that _really_ appealed to me, and partly because something I need so
rarely, I didn't feel like investing a massive amount of time in U-I
coding.

Last night I got an idea, and it came out so simple and clean that I
had to try it out. I really, really like the result. I'm thinking
about how to extend it; right now I'm considering what sort of stack
ops to add, and how to rig easy interaction with external programs.

But right now it's at a special state where the genuine Fun With
Perl factor seems to be at a local maximum: there's so little perl
doing so much of the basic functionality; that ratio will probably
drop steeply as soon as I touch it again. So I attach the first
prototype.

-Bennett
#!/usr/bin/perl -w
use strict;
use Getopt::Long;
my $linemode = 0;
my $syntax = "syntax: $0 [--[no]linemode]\n";
GetOptions("linemode!" => \$linemode) || die "syntax";

$| = 1;

my $cd = "\e[J"; # clear to end of screen
my $ce = "\e[K"; # clear to end of line
my $ho = "\e[H"; # go home

my @s;
my $done = 0;

while (1) {
	if ($linemode) { print "@{[reverse @s]} " if @s; } else {
		print $ho;
		print $_,$ce,"\n" for reverse @s;
		print $cd;
	}
	pop @s if @s and $s[-1] =~ /^Unknown character: /;
	if ($done) { print "\n" if $linemode; exit 0; }
	$_ = <>;
	while (length) {
		next if s/^\s+//;
		if (s/^0[0-9a-fx]+//) { unshift @s, oct($1); next; }
		if (s/^(-?\d+(?:\.\d+)?)// or s/^(-?\.\d+)//) {
			unshift @s, $1;
			next;
		}
		if (s/^\+//) { splice @s, 0, 2, $s[1]+$s[0]; next; }
		if (s/^\*//) { splice @s, 0, 2, $s[1]*$s[0]; next; }
		if (s/^\-//) { splice @s, 0, 2, $s[1]-$s[0]; next; }
		if (s/^\///) { splice @s, 0, 2, $s[1]/$s[0]; next; }
		if (s/^\^//) { splice @s, 0, 2, $s[1]**$s[0]; next; }
		if (s/^q//) { $done++; next; }
		push @s, "Unknown character: $_"; last;
	}
}

PGP signature