sarthak
sarthak

Reputation: 794

Case statement in perl: not able to enter proper case

#!/usr/bin/perl -w
use warnings;
use diagnostics;
use Switch;

open FH, "<$ARGV[0]" or die "$!";

sub commandType{
  print "comm entered for $_";
  switch($_){
    case("add") {print "this is add\n"}
    case("sub") {print "this is sub\n"}
    case("neg") {print "this is neg\n"}
    case("eq") {print "this is eq\n"}
    case("gt") {print "this is gt\n"}
    case("lt") {print "this is lt\n"}
    case("and") {print "this is and\n"}
    case("or") {print "this is or\n"}
    case("not") {print "this is not\n"}
  }
}

while(<FH>){
  next if /^\s*\/\//;
  next if /^\s*$/;
  my $line = "$_";
  $line =~ s/\s+$//;
  print "$line\n";
  commandType($line);
}

Here is my code which takes the input from the following file supplied to it through the command line:

// Pushes and adds two constants.
push constant 7
push constant 8
add

For each line of the file above the perl code will run the subroutine commandType to check if it is among the given cases inside the subroutine and prints if it is. But even though the add command is present in the file above the code still does not print it. I am getting the following output:

push constant 7
comm entered for push constant 7
push constant 8
comm entered for push constant 8
add
comm entered for add`

Why is case "add" not printing anything?

Upvotes: 2

Views: 718

Answers (3)

Chankey Pathak
Chankey Pathak

Reputation: 21676

Starting from Perl 5.10.1 (well, 5.10.0, but it didn't work right), you can say use feature "switch"; to enable an experimental switch feature. Under the "switch" feature, Perl gains the experimental keywords given , when , default , continue, and break.

    #!/usr/bin/perl
    use strict;
    use warnings;
    use feature "switch";
    while(my $line=<DATA>){
        given ($line) {
        when (/push/) { print 'found push' }
        when (/add/) { print 'found add' }
        }
    }
    __DATA__
    push constant 7
    push constant 8
    add

Demo

Also see: Perl 5.20 and the fate of smart matching and given-when?

Upvotes: 1

Borodin
Borodin

Reputation: 126742

It isn't safe to use $_ as you would a normal variable. It has global scope and many built-in Perl operators act on it, so it is likely to be modified without any obvious reason.

In any case, the parameters passed to a subroutine are presented in @_, not in $_ and it is random chance that it seems to contain the right value in this case.

Rewrite your commandType subroutine like this and it should start behaving more sensibly

sub commandType {
  my ($cmd) = @_;
  print "comm entered for $cmd";

  switch ($cmd) {
    case 'add' { print "this is add\n" }
    case 'sub' { print "this is sub\n" }
    case 'neg' { print "this is neg\n" }
    case 'eq'  { print "this is eq\n"  } 
    case 'gt'  { print "this is gt\n"  } 
    case 'lt'  { print "this is lt\n"  }
    case 'and' { print "this is and\n" }
    case 'or'  { print "this is or\n"  }
    case 'not' { print "this is not\n" }
  }
}

You must also always add use strict at the top of every program, especially if you are asking for help with it. It will quickly report trivial errors that you may otherwise spend valuable time tracking down.

The Switch module is also unsafe, and the built-in language construct given/when that has been available since version 10 has been marked as experimental because of a number of arcane shortcomings. You are much better off using a list of if statements as described in the "Basic BLOCKs" section of perlsyn.

Upvotes: 2

Filip Ros&#233;en
Filip Ros&#233;en

Reputation: 63832

EXPLANATION

The problem is that $_ doesn't automatically refer to the first argument passed to a sub, currently you are reading the same $_ as the one in your while-loop.

The value of $_ when inside commandType is the line read, still having the potential new-line attached to it, and since "add\n" isn't equal to "add", your case isn't entered.


SOLUTION

It would be preferred to change the contents of sub commandType to the below:

sub commandType{
  my $cmd = shift; # retrieve first argument
  print "comm entered for $cmd";
  switch($cmd) {
    ...
  }
}

Upvotes: 3

Related Questions