如何在C源代码中搜索简单的if语句?

时间:2009-07-03 10:27:57

标签: c regex search awk

我想在C源文件集合中搜索简单的if语句。

这些是以下形式的陈述:

if (condition)
    statement;

任何数量的空格或其他序列(例如“} else”)可能会出现在if之前的同一行。评论可能出现在“if(condition)”和“statement;”之间。

我想要排除格式的复合语句:

if (condition)
{
    statement;
    statement;
}

我在awk中尝试了以下各项:

awk  '/if \(.*\)[^{]+;/ {print NR $0}' file.c    # (A) No results
awk  '/if \(.*\)[^{]+/ {print NR $0}' file.c    # (B)
awk  '/if \(.*\)/ {print NR $0}' file.c          # (C)

(B)和(C)给出不同的结果。两者都包括我正在寻找的项目和我想要排除的项目。显然,部分问题在于如何处理跨越多行的模式。

边缘情况(错误形成的注释,奇数位置的奇数缩进或花括号等)可以忽略。

我该如何做到这一点?

4 个答案:

答案 0 :(得分:2)

基于Al的答案,但修复了几个问题(另外我决定检查简单的else子句(同样,它打印完整的if块):

#!/usr/bin/perl -w

my $line_number = 0;
my $in_if = 0;
my $if_line = "";
#ifdef NEW
my $block = "";
#endif /* NEW */
# Scan through each line
while(<>)
{
    # Count the line number
    $line_number += 1;
    # If we're in an if block
    if ($in_if)
    {
        $block = $block . $line_number . "+ " . $_;
        # Check for open braces (and ignore the rest of the if block
        # if there is one).
        if (/{/)
        {
            $in_if = 0;
            $block =  "";
        }
        # Check for semi-colons and report if present
        elsif (/;/)
        {
            print $if_line;
            print $block;
            $block = "";
            $in_if = 0;
        }
    }
    # If we're not in an if block, look for one and catch the end of the line
    elsif (/(if \(.*\)|[^#]else)(.*)/)
    {
        # Store the line contents
        $if_line = $line_number . ": " .  $_;
        # If the end of the line has a semicolon, report it
        if ($2 =~ ';')
        {
            print $if_line;
        }
        # If the end of the line contains the opening brace, ignore this if
        elsif ($2 =~ '{')
        {
        }
        # Otherwise, read the following lines as they come in
        else
        {
            $in_if = 1;
        }
    }
}

答案 1 :(得分:1)

我不确定你是如何使用一个衬垫(我确信你可以使用sed的'n'命令读取下一行,但它会非常复杂),所以你可能想要为此使用脚本。怎么样:

perl parse_if.pl file.c

parse_if.pl包含:

#!/usr/bin/perl -w

my $line_number = 0;
my $in_if = 0;
my $if_line = "";
# Scan through each line
while(<>)
{
    # Count the line number
    $line_number += 1;
    # If we're in an if block
    if ($in_if)
    {
        # Check for open braces (and ignore the rest of the if block
        # if there is one).
        if (/{/)
        {
            $in_if = 0;
        }
        # Check for semi-colons and report if present
        elsif (/;/)
        {
            print $if_line_number . ": " . $if_line;
            $in_if = 0;
        }
    }
    # If we're not in an if block, look for one and catch the end of the line
    elsif (/^[^#]*\b(?:if|else|while) \(.*\)(.*)/)
    {
        # Store the line contents
        $if_line = $_;
        $if_line_number = $line_number;
        # If the end of the line has a semicolon, report it
        if ($1 =~ ';')
        {
            print $if_line_number . ": " . $if_line;
        }
        # If the end of the line contains the opening brace, ignore this if
        elsif ($1 =~ '{')
        {
        }
        # Otherwise, read the following lines as they come in
        else
        {
            $in_if = 1;
        }
    }
}

如果你愿意的话,我相信你可以用任何其他语言(包括awk)轻松地做一些事情。我只是认为可以通过一个例子在perl中最快地完成。

答案 2 :(得分:0)

在awk中,每一行都被视为记录,“\ n”是记录分隔符。由于所有记录都是逐行解析的,因此您需要跟踪if后面的下一行。我不知道你怎么能在awk中做到这一点.. 在perl中,您可以轻松地执行此操作

open(INFO,"<file.c");
$flag=0;
while($line = <INFO>)
{
 if($line =~ m/if\s*\(/ )
  {
    print $line;
    $flag = 1;
  }
 else
 {
  print $line && $flag ;
  $flag = 0 if($flag);
 }
}

答案 3 :(得分:0)

使用Awk,您可以通过以下方式执行此操作:

awk '
BEGIN { flag=0 }
{
    if($0 ~ /if/) {
        print $0;
        flag=NR+1
    }
    if(flag==NR)
        print $0 
}' try.c