fREW++ and pmichaud++ have, between them, three versions of the RPN calculator. Here is a fourth, clener in some ways.
You can use it as follows:
> ./perl6 rpn.pl '4 5 9 sqrt + *' 32 > ./perl6 rpn.pl '4 5 9 sqrt rotate3 + *' 35
my %op_dispatch_table = {
'+' => { $^a + $^b },
'-' => { $^a - $^b },
'*' => { $^a * $^b },
'/' => { $^a / $^b },
'sqrt' => { $^a.sqrt },
'say' => { $^a.say; $^a},
'rotate3' => { ($^b, $^c, $^a) },
};
sub evaluate (%odt, $expr) {
my @stack;
my @tokens = $expr.split(/\s+/);
for @tokens {
when /^\d+$/ { @stack.push($_); }
when ?%odt{$_} { my $f = %odt{$_};
my @top_terms = gather {
for 1..$f.arity { take @stack.pop}
};
@top_terms = reverse(@top_terms);
my @to_push = $f.(|@top_terms);
@stack.push(@to_push);
}
default { die "Unrecognized token '$_'; aborting"; }
}
@stack.pop;
}
say "Result: { evaluate(%op_dispatch_table, @*ARGS[0]) }";
I have to say that I've seen the other examples of this and I think this is definitely the cleanest and easiest to understand. Using $^a, $^b and $^c with the arity checks definitely beats all those pops, shifts, etc.
I agree, though I think it might need a special-case for zero-arity so that could could write an arbitrary reduction:
'sum' => { @stack = [+] @stack },
hmm, can that be written as assignment-operator?
'sum' => { @stack [+]= () },
Re:but just one thing more
amahabal on 2009-03-04T04:12:48
I was hoping to use zero arity like so:'pi' => { 3.1415926 }
Perhaps
'sum' => { @stack = [+]@stack; } but WholeStack,
or something along those lines would work.