in reply to Inputing an Operator is it possible?

Well, you can do this, but it is a sort of silly thing to do. A better solution would be to put the time in to actually evaluate the user's input and act on that. If you really want to build a calculator, I'd suggest using reverse polish notation on your first go (see dc(1)) because it is easier to parse (less ambiguous) than standard notation. Now for the silly way (which is worth seeing since evaluating strings as code is sometimes useful):
#!/usr/bin/perl -w use strict; my $eq = <STDIN>; print eval $eq, "\n";
This will do what you want, but it is very DANGEROUS because any arbitrary code can be embedded in the expression (although this isn't exactly a production project anyway). If you wanted to go to the trouble to catch non-calc-related code, you might as well code up a real calculator. If not, call perl -e and do a calulation on the command line.

Replies are listed 'Best First'.
Re: Re: Inputing an Operator is it possible?
by $Variable_B (Initiate) on Oct 07, 2002 at 03:30 UTC
    Thanks! That's awesome. I don't need all those little variables and perl eval()s for me! Great! -Variable_B
      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

      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.