in reply to Re: Inputing an Operator is it possible?
in thread Inputing an Operator is it possible?

Thanks! That's awesome. I don't need all those little variables and perl eval()s for me! Great! -Variable_B
  • Comment on Re: Re: Inputing an Operator is it possible?

Replies are listed 'Best First'.
Re: Re: Re: Inputing an Operator is it possible?
by dbp (Pilgrim) on Oct 07, 2002 at 09:50 UTC
    Glad you liked it. As we all know, Laziness is a wonderful virtue. But I figured I should provide you with something more constructive. Here are the basics of that reverse Polish calculator I was rambling about. It supports +, -, *, /. Print the stack with 'p' and quit with 'q'. You could probably make this a bit more concise if you wanted to. In fact, that might make for some pretty good GOLF. Anyway, Enjoy.
    #!/usr/bin/perl -w use strict; my @stack = (); my %ops = ( '+' => \&sum, '-' => \&difference, '*' => \&product, '/' => \&quotient, 'p' => sub { print $_, "\n" foreach @stack; }, 'q' => sub { exit 0; } ); while(<>) { chomp; if (exists $ops{$_}) { $ops{$_}->(); # The badass regex is out of the Perl Cookbook, page 44 # Makes sure non-ops are valid numbers } elsif ($_ =~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/) { push @stack, $_; } else { warn "Bad input: $_\n"; } } sub pop_stack { my $rhs = pop @stack; my $lhs = pop @stack; if ((! defined $lhs) || (! defined $rhs)) { warn "Not enough values on stack!\n"; push @stack, $rhs if defined $rhs; return undef; } return $lhs, $rhs; } sub sum { my ($lhs, $rhs) = pop_stack; return unless defined $lhs; my $res = $lhs + $rhs; print "$res \n"; push @stack, $res; } sub difference { my ($lhs, $rhs) = pop_stack; return unless defined $lhs; my $res = $lhs - $rhs; print "$res \n"; push @stack, $res; } sub product { my ($lhs, $rhs) = pop_stack; return unless defined $lhs; my $res = $lhs * $rhs; print "$res \n"; push @stack, $res; } sub quotient { my ($lhs, $rhs) = pop_stack; return unless defined $lhs; my $res = $lhs / $rhs; print "$res \n"; push @stack, $res; }
      Well, here's a little bit of golf right off the bat. Since we are checking the input, we can get away with an eval without fear:
      #!/usr/bin/perl -w use strict; my @stack = (); my %ops = ( '+' => \&calc, '-' => \&calc, '*' => \&calc, '/' => \&calc, 'p' => sub { print $_, "\n" foreach @stack; }, 'q' => sub { exit 0; } ); while(<>) { chomp; if (exists $ops{$_}) { $ops{$_}->($_); # The badass regex is out of the Perl Cookbook, page 44 } elsif ($_ =~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/) { push @stack, $_; } else { warn "Bad input: $_\n"; } } sub calc { my $op = shift; my $rhs = pop @stack; my $lhs = pop @stack; if ((! defined $lhs) || (! defined $rhs)) { warn "Not enough values on stack!\n"; push @stack, $rhs if defined $rhs; return undef; } my $res = eval $lhs.$op.$rhs; print "$res\n"; push @stack, $res; }
      Fix: I had the rhs and lhs backwards in the eval originally
      That is far above me but I will get there.

      -Variable_B
      That's above me but I am getting there!

      -Variable_B
Re: Re: Re: Inputing an Operator is it possible?
by peschkaj (Pilgrim) on Oct 07, 2002 at 14:30 UTC

    You have to be cautious of using eval(). It's quite possible for some joker to come along and type "rm / -rf" and run your program. That said, it's also the easiest way to get the code to work. Some others have suggested some very good checks to take care of malicious use of eval().



    If you make something idiot-proof, eventually someone will make a better idiot.
    I am that better idiot.
    A reply falls below the community's threshold of quality. You may see it by logging in.