1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
|
use v5.10;
use warnings;
my $calculator = do{
use Regexp::Grammars;
qr{
\A
<Answer>
<rule: Answer>
<[Operand=Mult]>+ % <[Op=(\+|\-)]>
<rule: Mult>
<[Operand=Pow]>+ % <[Op=(\*|/|%)]>
<rule: Pow>
<[Operand=Term]>+ % <Op=(\^)>
<rule: Term>
<MATCH=Literal>
|
\( <MATCH=Answer> \)
<token: Literal>
<MATCH=( [+-]? \d++ (?: \. \d++ )?+ )>
}xms
};
package Calculator_Actions;
use List::Util qw< reduce >;
sub Answer {
my ($self, $MATCH_ref) = @_;
my $value = shift @{$MATCH_ref->{Operand}};
for my $term (@{$MATCH_ref->{Operand}}) {
my $op = shift @{$MATCH_ref->{Op}//=[]};
if ($op eq '+') { $value += $term; }
else { $value -= $term; }
}
return $value;
}
sub Mult {
my ($self, $MATCH_ref) = @_;
reduce { eval($a . shift(@{$MATCH_ref->{Op}}) . $b) }
@{$MATCH_ref->{Operand}};
}
sub Pow {
my ($self, $MATCH_ref) = @_;
reduce { $b ** $a } reverse @{$MATCH_ref->{Operand}};
}
# and later...
while (my $input = <>) {
if ($input =~ $calculator->with_actions('Calculator_Actions') ) {
say '--> ', $/{Answer};
}
}
|