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}; } }