100%, , / :
my %ops = (
average => sub {my $acc; $acc += $_ for @_; $acc / @_},
'+' => sub {$_[0] + $_[1]},
'-' => sub {$_[0] - $_[1]},
'*' => sub {$_[0] * $_[1]},
'mod' => sub {$_[0] % $_[1]},
(map {$_ => sub {$_[1] ? $_[0] / $_[1] : undef}} qw (/ div)),
);
sub Evaluate {
my $ex = shift;
print "evaluating: ", Dumper($ex), "\n" if $debug;
my $node_type = $ex->[0];
if ( $node_type eq 'leaf' ) {
print "returning leaf: $$ex[1]\n" if $debug;
return $$ex[1];
}
elsif ( $node_type ne 'internal' ) {
die "Eval: Strange node type '$node_type' when evaluating tree";
}
my $operation = $ex->[1];
my @values = map {Evaluate($_)} @$ex[2 .. $#$ex];
defined or return for @values;
if (my $op = $ops{$operation}) {
return $op->(@values);
} else {
print "operation $operation not found\n";
return undef;
}
}
if/elsif . . $left_value $right_value @values, n-arity (, average).
Display n-arity:
my %is_infix = map {$_ => 1} qw( * + / - );
sub Display {
my ($ex, $style) = @_;
my $node_type = $ex->[0];
if ( $node_type eq 'leaf' ) {
return $$ex[1];
}
if ( $node_type ne 'internal' ) {
die "Display: Strange node type '$node_type' when evaluating tree";
}
my $operation = $ex->[1];
if ($style and $style eq 'infix') {
my @values = map {Display($_, $style)} @$ex[2 .. $#$ex];
if ($is_infix{$operation}) {
return "$values[0] $operation $values[1]"
} else {
local $" = ', ';
return "$operation( @values )"
}
} else {
my @out;
for (@$ex[2 .. $#$ex]) {
if (@out and $_->[0] eq 'internal') {
push @out, ';'
}
push @out, Display($_, $style)
}
return join ' ' => @out, $operation;
}
}
Display Display($tree) Display($tree, 'postfix') . Display($tree, 'infix') infix.
ex1 is 42
ex1: 42
ex1: 42
ex2 is 52
ex2: 42 10 +
ex2: 42 + 10
ex3 is 26.5
ex3: 42 10 + 1 average
ex3: average( 42 + 10, 1 )
, , .
, 1 + average(3, 4, 5):
my $avg = ['internal', 'average', [leaf => 3], [leaf => 4], [leaf => 5] ];
my $ex4 = ['internal', '+', [leaf => 1], $avg ];
print "ex4 is ", Evaluate($ex4), "\n";
print "ex4: ", Display($ex4), "\n";
print "ex4: ", Display($ex4, 'infix'), "\n";
print "\n";
:
ex4 is 5
ex4: 1 ; 3 4 5 average +
ex4: 1 + average( 3, 4, 5 )