3

ifC ソース ファイルのコレクションで単純なステートメントを検索したいと考えています。

これらは次の形式のステートメントです。

if (condition)
    statement;

同じ行のif. 「if(条件)」と「文;」の間にコメントが入る場合があります。

次の形式の複合ステートメントを除外したい:

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 を使用すると、次の方法でこれを行うことができます。

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 に答える
0

awk では、各行がレコードとして扱われ、"\n" がレコード区切りです。すべてのレコードは行ごとに解析されるため、if の後の次の行を追跡する必要があります。awkでこれを行う方法がわかりません..perlでは、次のように簡単に行うことができます

open(INFO,"<file.c");
$フラグ=0;
while($line = <情報>)
{
 if($line =~ m/if\s*\(/ )
  {
    $line を印刷します。
    $フラグ = 1;
  }
 そうしないと
 {
  print $line && $flag ;
  $flag = 0 if($flag);
 }
}
于 2009-07-03T12:27:01.310 に答える