Question

As an exercise, I'm trying to implement a stack to calculate postfix expressions.

use strict;
use warnings;

use Scalar::Util qw(looks_like_number);

my %operators = (
    '+' => \&sum,
    '-' => \&subs,
    '*' => \&mul,
    '/' => \&div,
);

print 'Enter an expression to evaluate : ';
chomp($_ = <STDIN>);
my @lettres=split(//);

my @stack;

for(my $i = 0; $i < @lettres; $i++){
    if(looks_like_number($lettres[$i])){
        unshift @stack, $lettres[$i];
    } else {
        my $nb1 = shift @stack;
        my $nb2 = shift @stack;
        unshift @stack, $operators{$lettres[$i]}->($nb1,$nb2);
    }
}

print 'Answer : ' .shift @stack;

sub sum { return $_[0] + $_[1];}
sub mul { return $_[0] * $_[1];}
sub subs { return $_[0] - $_[1];}
sub div { return $_[0] / $_[1];}

When running it, I got:

Can't use an undefined value as a subroutine reference at polonaise.pl line 25,
<STDIN> line 1.

Line 25 is:

unshift @stack, $operators{$lettres[$i]}->($nb1,$nb2);

I suspect that $operators{$lettres[$i]}->($nb1,$nb2); is causing the issue but I don't know why since I begin with Perl.

Why this happens and how can I fix that?

Was it helpful?

Solution

First, only consider as valid tokens sequences of non-space characters. Second, if a token doesn't look like a number, make sure a handler exists in the %operators hash. I find push and pop more natural when dealing with a stack, but that doesn't really matter;

#!/usr/bin/env perl

use strict;
use warnings;

# Turn on autoflush
local $| = 1;

use Scalar::Util qw(looks_like_number);

my %operators = (
    '+' => \&add,
    '-' => \&subtract,
    '*' => \&multiply,
    '/' => \&divide,
);

print 'Enter an expression to evaluate : ';

my $input = <STDIN>;

my @tokens = split ' ', $input;

my @stack;

for my $token (@tokens) {
    if (looks_like_number($token)) {
        push @stack, $token;
    }
    else {
        if (exists $operators{$token}) {
            my $op = $operators{$token};
            my $x = pop @stack;
            my $y = pop @stack;
            push @stack, $op->($x, $y);
        }
        else {
            warn "Unknown token '$token'\n";
        }
    }
}

print "Answer: $stack[-1]\n";

sub add      { $_[0] + $_[1];}
sub multiply { $_[0] * $_[1];}
sub subtract { $_[0] - $_[1];}
sub divide   { $_[0] / $_[1];}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top