3

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

这些是以下形式的陈述:

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

4 回答 4

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;
        }
    }
}
于 2009-07-03T13:24:00.410 回答
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 中最快地做到这一点。

于 2009-07-03T11:05:52.973 回答
0

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

打开(信息,“<file.c”);
$标志=0;
而($line = <INFO>)
{
 if($line =~ m/if\s*\(/)
  {
    打印$行;
    $标志 = 1;
  }
 别的
 {
  打印 $line && $flag ;
  $flag = 0 if($flag);
 }
}
于 2009-07-03T12:27:01.310 回答
0

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

awk '
BEGIN { flag=0 }
{
    if($0 ~ /if/) {
        print $0;
        flag=NR+1
    }
    if(flag==NR)
        print $0 
}' try.c
于 2009-07-03T12:49:34.470 回答