#!//net/perl/5.10.0/bin/perl use warnings; use strict; use 5.010_000; our @stack; our $result; my %operators = ( '+' => sub { $_[0] += $_[1] }, '-' => sub { $_[0] -= $_[1] }, '/' => sub { $_[0] /= $_[1] }, '*' => sub { $_[0] *= $_[1] }, '^' => sub { $_[0]**= $_[1] }, chs => sub { $_[0] = -$_[0] }, abs => sub { $_[0] = abs $_[0] }, sqr => sub { $_[0] *= $_[0] }, sqrt => sub { $_[0] = sqrt $_[0] }, sin => sub { $_[0] = sin $_[0] }, cos => sub { $_[0] = cos $_[0] }, tan => sub { $_[0] = sin $_[0] / cos $_[0] }, ); my $RPN = qr{ (?{ @stack = () }) (?{ $result = undef }) \A \s* (? \d+ (?: [.] \d* )? | [.] \d+ ) (?{ push @stack, $+{start_number} }) (?> \s+ (?: (? \d+ (?: [.] \d* )? | [.] \d+ ) (?{ push @stack, $+{number} }) | (? chs | abs | sqrt | sqr | sin | cos | tan ) (?(?{ @stack < 1 }) (*FAIL) ) (?{ $operators{ $+{unary_op} }->($stack[-1]) }) | (? [-+/*^] ) (?(?{ @stack < 2 }) (*FAIL) ) (?{ $operators{ $+{binary_op} }->($stack[-2], pop @stack) }) ) )* \s* \z (?(?{ @stack != 1 }) (*FAIL) ) (?{ $result = $stack[0] }) }msx, my %input = ( 'fail' => undef, '1 fail' => undef, '123' => 123, '123.456' => 123.456, '123.456 +' => undef, '.456' => .456, '123.' => 123., '123 /' => undef, ' 123 ' => 123, '123 chs' => -123, '123 chs chs' => 123, '123 chs chs chs' => -123, '123 chs chs chs chs' => 123, '4 2 ^' => 16, '4 2 /' => 2, '4 2 +' => 6, '4 2 *' => 8, '4 2 -' => 2, '12 34+' => undef, '12 34' => undef, '12 34 + +' => undef, '12 34 56 + +' => 102, '12 34 + 56 +' => 102, '123 chs 34 *' => -4_182, '123 34 * chs' => -4_182, '24' => 24, '24 abs' => 24, '24abs' => undef, '24abssqrt' => undef, '1 24abs+sqrt' => undef, '1 24 abs + sqrt' => 5, '24 chs abs' => 24, '24 chs' => -24, '25 abs sqrt' => 5, '25 chs abs sqrt' => 5, '24 4 + chs sqr' => 784, '34 2 / 2 ^' => 289, '3 34 2 / 2 ^ *' => 867, ); foreach my $line ( keys %input ) { my ($expression) = $line =~ /($RPN)/; if ( !defined $result && !defined $input{$line} ) { say "OK: $line is invalid, got no result"; } elsif ( !defined $result ) { say "FAILED: $line expected $input{$line}, got no result"; } elsif ( !defined $input{$line} ) { say "FAILED: $line got $result, expected no result"; } elsif ( $result == $input{$line} ) { say "OK: $expression = $result"; } else { say "FAILED: $line got $result, expected $input{$line}"; } }