Sunday, March 20, 2011

How can I count number of logical conditions used in if,elseif or while in Perl?

hi all... i have a while,if,elseif statements in a file with multipe conditions inside it... it is a C language...the format is mentioned below is standard for all the multiple conditions.So no worries about the indendation.The only problem is to check how many conditions are there and list as per output format that i have described.... eg if my C file have a code...

while(
      condition1 &&
      condition2 ||
      condition3
     )
{
  #statements; 
}

i want to count how many conditions are there inside the while and my output should be
of like this...

  while(
  1    condition1 &&
  2    condition2 ||
  3    condition3
     )
{
  #statements; 
}

i have written the code and it works fine for simple one.. my code....

open(A,"e:\\a\\a.txt")or die;
@a=<A>;
close(A);
$count=1;
for($i=0;$i<scalar@a;$i++)
{
  if($a[$i]=~m/while/g)
  {
    $line=$i;
    until($a[$line]=~/\{/g)
    {
       if($a[$line]=~/(.*)[\&&\||]/g){print"$count $a[$line]";$count++;}  
       elsif($a[$line]=~/\(.*\)[\&&\||]/g){print"$count $a[$line]";$count++;}  
       else{print$a[$line];}
       $line++;
    }
  }
 last if($a[$line]=~/\{/g);
}

but for complicated conditions like

while(
        ( 
         condition1 &&
         condition2 &&
         condition3
        ) ||
        (
          condition4 ||
          condition5 &&
          condition6
         )

{
  #statements;
}

am getting the output like

while(
        ( 
       1  condition1 &&
       2  condition2 &&
          condition3
       3 ) ||
        (
       4  condition4 ||
       5  condition5 &&
          condition6
         )

which is not desired.... my intension is to count all the conditions regarding however complicated it is..... please help me...

desired output may be

while( ( 1 condition1 && 2 condition2 && 3 condition3 ) || ( 4 condition4 || 5 condition5 && 6 condition6 ) ) since it has used 6 conditions inside... hence forth for any cases.

From stackoverflow
  • What language is this? Are full parsers available for this language? If so, I suggest you use them. If not, I think you'll have a hard time solving this problem reliably. Your approach relies on the specific way the programmer formatted his code.

    Right when you solved your problem for your example, somebody will throw the following at you:

    while(
            ( condition1 && condition2)
              && condition3            )
            ||
            ( condition4 || condition5
              && condition6            )
    
    {
      #statements;
    }
    

    If you insist on writing your own mock-up parser, then I would suggest the following:

    • Do not parse line-wise. Feel free to read line-wise. But don't parse each line separately.
    • Extract the contents of the matching set of parenthesis after the while. The clue here is "matching". Run "perldoc -q matching" and have a look at the first Perl FAQ entry coming up about parsing matching/nesting parenthesis.
    • When you have the code contained in the parenthesis, try to extract the number of operands to the logical operators by splitting on the logical ops.
    • Despair if the operands (conditionX) may contain strings which contain, for example "&&".

    Tools you may find useful in order of sophistication:

    • perldoc -q nesting as mentioned above
    • The Text::Balanced module (Available out of the box with any perl version >= 5.8)
    • The Parse::Yapp and Parse::RecDescent parser generator modules from CPAN. Yapp is underdocumented, but doesn't suffer from some pathological problems P::RD suffers from.
    • Parse::Eyapp presumably combines the good points of both of the above modules.
    lokesh : the format i have send is standard all the multiple conditions will be of same standard so no worries about the indendation.The only problem is to check how many conditions are there and list as per above output format that i have described earlier.
  • I hope you can learn something from this.

    use 5.010;
    use Text::Balanced qw(extract_bracketed);
    my $logical_keywords = join '|', qw(while if);
    my $logical_operators = join '|', map {quotemeta} qw(|| &&);
    
    my $code = do { local $/; <DATA>; }; # slurp the whole thing into a scalar
    
    for my $chunk (split /$logical_keywords \s+/msx, $code) {
        # a chunk is the (...)... part after an »if« or »while«
        # until the next »if« or »while«
    
        next unless $chunk =~ /\A [(]/msx;
        # discard preceding junk
    
        my $balanced_parentheses = extract_bracketed($chunk, '()');
        # only the (...) part after an »if« or »while«
    
        my @conditions = split /(?<=$logical_operators)/msx, $balanced_parentheses;
    
        say scalar(@conditions). " conditions were found. And here's the enumerated code block.";
        my $index = 0;
        for my $condition (@conditions) {
            $index++;
            my ($pre, $post) = $condition =~ /( (?: [(] | \s )* ) (.*)/msx;
            print "$pre $index $post";
        }
        say; # force a new line
    }
    
    __DATA__
    # start of the source code.
    
    while(
          condition1 &&
          condition2 ||
          condition3
         )
    {
      #statements;
    }
    
    # some other code
    
    while(
            (
             condition1 &&
             condition2 &&
             condition3
            ) ||
            (
              condition4 ||
              condition5 &&
              condition6
             )
    )
    {
      #statements;
    }
    
    (some (nested (nonsense))) || (
    );
    
    if (
        (
        condition1 &&
        condition2
        ) ||
        ((
        condition3
        ) ||
        (
        condition4 &&
        condition5
        ))
    )
    {
        ((these parentheses do not count) &&
            neither does this.
        );
    }
    

    Output:

    3 conditions were found. And here's the enumerated code block.
    (
           1 condition1 &&
           2 condition2 ||
           3 condition3
         )
    6 conditions were found. And here's the enumerated code block.
    (
            (
              1 condition1 &&
              2 condition2 &&
              3 condition3
            ) ||
            (
               4 condition4 ||
               5 condition5 &&
               6 condition6
             )
    )
    5 conditions were found. And here's the enumerated code block.
    (
        (
         1 condition1 &&
         2 condition2
        ) ||
        ((
         3 condition3
        ) ||
        (
         4 condition4 &&
         5 condition5
        ))
    )
    
    lokesh : am using perl v5.8.6... will it work in that case????.. i have seen text balanced has been installed by default.
    daxim : No, obviously it won't. Why didn't you just try it instead of asking? It can be easily backported to old Perl. Go accept one of the answers you received.
    lokesh : hi i works great but logically while ( (condition1) && (condition2) || (condition3) ) { statements; } if we have a statements it prints in different manner.. can you help me out..
  • For this I think I'd go with something like PPI, which often does a good enough job of parsing Perl source, and certainly is going to do a better job of most people starting from scratch.

    You might also look at Devel::Cover, which includes such information in its report as part of its conditional coverage metric.

0 comments:

Post a Comment