$ cat ideone-6TneLv.pl #!/usr/bin/perl our @v; # external values stack our ($allnouns, %nouns) = ( qr/\d+(?{'number'})|[-(]/, 'number' => sub { push @v, pop }, '-' => sub { expr( qr/\*{2}/ ); $v[-1] = -$v[-1] }, '(' => sub { expr(); /\G\s*\)/gcx or err("no )") }, ); our ($allverbs, %verbs) = ( qr/[-+\/]|\*{1,2}/, '+' => sub { expr( qr/\*{1,2}|\// ); $v[-2] += pop @v }, '-' => sub { expr( qr/\*{1,2}|\// ); $v[-2] -= pop @v }, '*' => sub { expr( qr/\*{2}/ ); $v[-2] *= pop @v }, '/' => sub { expr( qr/\*{2}/ ); $v[-2] /= pop @v }, '**' => sub { expr( qr/\*{2}/ ); $v[-2] **= pop @v }, ); sub expr # takes regex of verbs that will shift { (my $shifters, $^R) = pop // $allverbs; /\G\s*($allnouns)/gcx ? $nouns{$^R // $1}->($1) : err('bad noun'); $verbs{$1}->() while /\G\s*($shifters)/gcx; } while(<>) { eval { @v = (); expr(); /\G\s*\z/gcx or err('incomplete') } or err($@); print s/\s*\z/ = @v\n/r; } sub err { exit print "ERROR ", s/\G/ <@_> /r, " \n" } $ $ cat ideone-6TneLv.stdin.txt 2 * 3 2+3 2*3-4 (2-3*4) -2**4 1+2+3+4+5+6+7+8+9+10 $ perl ideone-6TneLv.pl < ideone-6TneLv.stdin.txt > ideone-6TneLv.stdout.txt $ cat ideone-6TneLv.stdout.txt 2 * 3 = 6 2+3 = 5 2*3-4 = 2 (2-3*4) = -10 -2**4 = -16 1+2+3+4+5+6+7+8+9+10 = 55