Perlで中置記法から後置記法(逆ポーランド表記法)への変換

VBScript版、JavaScript版 に続けて Perl版。
中置記法の配列から後置記法の配列を生成します。
(数式の文字列を配列に変換する処理は割愛)


式(expression)と項(term)のサブルーチンが
対象とする演算子と呼び出し先が違うだけで、同じ手順だったのが気になっていたので、
無名サブルーチンを使って、ちょっとコンパクトにした。
しかし、今度は無名サブルーチンへのリファレンス名が変で気になる。


Perl は不慣れなもので、Perl らしい感じというのが掴めない。
「There's More Than One Way To Do It(やり方はいくらでもある)」という
考え方に感動して Perl を勉強中だが、いざ自分で書きだすと、
自分のコード(だいたい他の言語のコピーに近い)が
冗長的でダサイような感じがしてきて、どんどん変な方向へ進もうとする。


たぶん Perlらしさというのは、その人らしさに直結するんだろうから、
多くコーディングしないといけないよ、というメッセージなのだろう。

postfix (.pl)

#!/usr/bin/perl
use strict;
use warnings;

#usage
my @infix = qw{( a + b ) * ( c + d )};
my @postfix = &get_postfix(@infix);
print "@postfix\n";


sub get_postfix {
    my @infix = @_;
    my (@postfix, $factor ,$term, $expression);

    $factor = sub {
        if ($infix[0] eq '(') {
            shift @infix;
            &$expression;
            shift @infix if $infix[0] eq ')';
        } else {
            push @postfix, shift @infix;
        }
    };

    my $create_caller_with_operators = sub {
        my ($op, $call) = @_;
        return sub {
            &$call;
            while (@infix) {
                unless (index($op, my $c = $infix[0]) == -1) {
                    shift @infix; &$call; push @postfix, $c;
                } else {
                    last;
                }
            }
        }
    };

    $term       = &$create_caller_with_operators('*/', $factor);
    $expression = &$create_caller_with_operators('+-', $term  );

    &$expression;
    return @postfix;
}

calc_postfix (.pl)

#!/usr/bin/perl
use strict;
use warnings;

#usage
my @infix = qw{1 2 3 * +};
my $result = &calc_postfix(@infix);
print "$result\n";


sub calc_postfix {
    my @stack;
    my %op = (
        '+' => sub { return   pop(@stack) + pop(@stack) },
        '-' => sub { return  -pop(@stack) + pop(@stack) },
        '*' => sub { return   pop(@stack) * pop(@stack) },
        '/' => sub { return 1/pop(@stack) * pop(@stack) },
    );

    push @stack, (exists $op{$_} ? &{$op{$_}} : $_) for @_;

    return $stack[0];
}