I was searching for a way to solve simple lisp-style terms in prefix-notation. My solution isn't very robust, but it shows a simple way to solve this kind of problem.
#!/usr/bin/perl
use strict;
use warnings;
#use Data::Dumper;
my $operators = {
'+' => sub { my $i = shift @_; $i += $_ for @_; return $i },
'-' => sub { my $i = shift @_; $i -= $_ for @_; return $i },
'*' => sub { my $i = shift @_; $i *= $_ for @_; return $i },
'/' => sub { my $i = shift @_; $i /= $_ for @_; return $i },
};
my $task = "( + 3 4 ( * 2 7 ( + 1 1 ) ) ( / 6 2 ) )";
print calculate( split /\s+/, $task ), "\n";
exit;
sub solve {
my ( $op, @vals ) = @_;
die "solve(): wrong operator or to less values"
unless ( exists $operators->{$op} && $#vals >= 1 );
return $operators->{$op}(@vals);
}
sub calculate {
my @ops = @_;
@ops = @ops[ 1 .. $#ops - 1 ]
if $ops[0] eq '('
and $ops[-1] eq ')'; # remove leading and trailing brackets
my $marker = -1;
my $begin = undef;
my $end = undef;
my @marked = ();
for ( 0 .. $#ops ) {
$begin = $_ if $ops[$_] eq '(' && ++$marker == 0;
$end = $_ if $ops[$_] eq ')' && $marker-- == 0;
if ( defined $begin && defined $end ) {
push @marked, { begin => $begin,
end => $end }; # find balanced brackets on this lev
+el
$marker = -1;
$begin = undef;
$end = undef;
}
}
while (@marked) {
my $current = pop @marked;
splice @ops, $current->{begin}, # recursively solve inner b
+rackets
$current->{end} - $current->{begin} + 1,
calculate( @ops[ $current->{begin} .. $current->{end} ] );
}
#print Dumper \@ops;
return solve(@ops);
}