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

如何在C源代码中搜索简单的if语句?,c,regex,search,awk,C,Regex,Search,Awk,我想在C源文件集合中搜索简单的if语句 以下是以下形式的声明: if (condition) statement; if (condition) { statement; statement; } 任何数量的空白或其他序列(例如“}else”)都可能出现在if前面的同一行中。注释可能出现在“如果(条件)”和“声明;”之间 我想排除以下形式的复合语句: if (condition) statement; if (condition) { stateme

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

以下是以下形式的声明:

if (condition)
    statement;
if (condition)
{
    statement;
    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)给出不同的结果。两者都包括我要查找的项目和我要排除的项目。显然,问题的一部分在于如何处理跨越多条线的模式

可以忽略边缘情况(格式错误的注释、奇数缩进或奇数位置的大括号等)


如何实现这一点?

我不确定如何使用一行程序来实现这一点(我确定可以使用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;
        }
    }
}
#/usr/bin/perl-w
我的$line_编号=0;
如果=0,我的$in_;
我的$if_line=“”;
#浏览每一行
while()
{
#数一数行号
$line_number+=1;
#如果我们在If区
如果($in_-if)
{
#检查是否有打开的大括号(忽略if块的其余部分
#如果有的话)。
if(/{/)
{
$in_,如果=0;
}
#检查分号,并报告是否存在分号
elsif(/;/)
{
打印$if_行编号。“:”$if_行;
$in_,如果=0;
}
}
#如果我们不在If区,寻找一个,然后抓住线的末端
elsif(/^[^#]*\b(?:if | else | while)\(.*)(.*)/)
{
#存储行内容
$if\u line=$\u;
$if_line_number=$line_number;
#如果行尾有分号,请报告它
如果($1=~';'))
{
打印$if_行编号。“:”$if_行;
}
#如果线的末端包含开口大括号,则忽略此项(如果有)
elsif($1=~'{')
{
}
#否则,请在输入时阅读以下行
其他的
{
$in_,如果=1;
}
}
}

如果您愿意,我相信您可以用任何其他语言(包括awk)非常轻松地完成某些操作;我只是想通过一个例子,用perl可以最快地完成这些操作。

在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); } }
使用Awk打开(信息,“您可以通过以下方式完成此操作:

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

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

!/usr/bin/perl-w
我的$line_编号=0;
如果=0,我的$in_;
我的$if_line=“”;
#ifdef新
我的$block=“”;
#endif/*新*/
#浏览每一行
while()
{
#数一数行号
$line_number+=1;
#如果我们在If区
如果($in_-if)
{
$block=$block.$line_编号“+”$\u;
#检查是否有打开的大括号(忽略if块的其余部分
#如果有的话)。
if(/{/)
{
$in_,如果=0;
$block=“”;
}
#检查分号,并报告是否存在分号
elsif(/;/)
{
打印$if_行;
打印$block;
$block=“”;
$in_,如果=0;
}
}
#如果我们不在If区,寻找一个,然后抓住线的末端
elsif(/(如果\(.*\)[^#]其他)(.*/)
{
#存储行内容
$if_line=$line_number.“:”$;
#如果行尾有分号,请报告它
如果($2=~';'))
{
打印$if_行;
}
#如果线的末端包含开口大括号,则忽略此项(如果有)
elsif($2=~'{')
{
}
#否则,请在输入时阅读以下行
其他的
{
$in_,如果=1;
}
}
}

Oops,如果我没记错的话,(B)应该没有分号。我将编辑这个问题以反映这一点。我发布了一个基于你的修改版本。它修复了几个问题。一:你的重复查找行,因为成功查找分号不会终止块(在第一个“elsif”中没有“$in_if=0;”).2:Yours用分号打印带有“if”的行的行号(使“$if\u line=$line\u number.”:“$\u;”并从打印语句中删除它来修复它)。很好的一点,谢谢(我想我只是很快地完成了我的代码,没有太多的顾虑)。我将修改我的源代码以处理这些注释。我故意想打印包含if开头的行,因此我认为它还应该打印if的行号…我还更改了if行的检查以查找else/while,并验证关键字前没有任何“#”字符。这不是理想的方法要做到这一点(一种更健壮的方法是在if/else之前检查(#\s*),但我有点懒。这会导致的唯一明显问题是在这样一行上:/*用#*/if(某物)注释)。显然,有很多方法可以改进它来完成任何你需要它做的事情!是的,注释中的分号也会把它扔掉。这不一定有帮助,但另一个答案是:如果你可以访问支持MISRA-C指南的Lint类型工具,这将为你提供所有类型的if()语句,因为不带括号的if()语句违反了准则。在我看来,这是一个一行程序处理起来太麻烦的问题。