2010-08-10 67 views
1

我想以检索无功能(仅定义的函数,而不是调用函数)存在于一个文本文件(计数)发现很难解决通过检查我编辑的代码this.Please引导

的文本文件{} function.txt低于

#include<main.h> 
#include<mncl.h> 
int reg23; 
int refid23; 
int64 AccounntBalance(char *reg12,char *refid,char **id){ //dis is function1 
ref(); 
if(id>100) 
    { 
    do(&ref); 
    } 
}              //dis is end of fucntion1 
void AccountRetrivalForm(char **regid,char **balance,char **id) //dis is function2 
    { 
    doref(); 
    int register; 
    if(refid!=null) 
    { 
    dolog(); 
    } 
    }              //dis is end of function2 

现在程序按照我的逻辑是:

#!C:/strawberry/perl 
use strict; 
use warnings; 
my $filename = 'function_perl.txt'; 
my $function_count = 0; 
open(FILENAME,$filename); 
my @arr = join("\n",<FILENAME>); 
foreach my $string(@arr) 
    { 
if($string =~/(?:int64|void|boolean)\s?(.*?)\(.*?\)\s*\{/) 
    { 
print "HAI"; 
$function_count++; 
print '$function_count'; 
    } 
    } 

这里Function_count是1.It从来没有增量的第二场比赛....请帮助我用同一个鳕鱼é...我想这么久,我很难解决这个问题。

+0

究竟是你想搭配什么?以(int64)或(void)或(boolean)开头的函数? – GorillaPatch 2010-08-10 13:27:31

+0

@gorillaPatch 我尝试匹配所有可能以int64开头的函数或void或布尔值(这是唯一的三个可能性) – Sreeja 2010-08-10 13:29:59

+1

我很好奇,什么语言是“dis”? – Ether 2010-08-10 15:07:18

回答

3

您的正则表达式格式不正确。

^([int64/void/boolean)]/(.*)/\(/\{//\n 

你可能意味着类似:

/^(int64|void|boolean)\s+(\w+)\s*\(.*?\)\s*\{/ 

也就是说,int64一个,void,或者boolean,一些空白,标识符,可选的空格,左括号,一些内容,一个右括号,一些可选的空白(可能是一个换行符)和一个开放的大括号。

3

我想说,你通过这个文件的方式是不寻常的。通常你会使用类似

open my $handle, '<', $filename; 
while (<$handle>) { 
    if (/^(void|boolean|int64).../) { 
     do something; 
    } 
} 
close $handle; 

代码的作用是打开文件并一次读入一行。这与通过获取整个数组,加入并迭代其元素的方式相同。

使用Perl中的无关然而,重要提示:包括你的脚本开始后三条线:

#!/usr/bin/perl 
use strict; 
use warnings; 
use autodie qw(:all); 

此提醒您,如果有您尝试在例如串联使用一些未分配的变量和其他事情。严格的包迫使你用my关键字声明变量。这听起来有点麻烦,但它也可以防止你得到问题,因为你错误地输入了一个变量。严格使用Perl解释器会警告你一个未声明的变量。 autodie编译指示检查系统调用失败,如open

您正在使用的正则表达式是错误的。你必须知道Perl中的正则表达式用斜线括起来,所以/\s+\w*.*/是一个有效的正则表达式。你在这里使用正则表达式的斜杠,它会过早地关闭表达式。如果你必须在你的文本中重新匹配斜线,你将不得不使用反斜线或完全使用不同的分隔符。

顺便说一句,你也有一个错字:@filecontent@file_content。这是一个完美的地方,use strict;会警告你。

+0

@daxim感谢您的编辑。为什么使用$ handle形式的文件句柄而不是FILENAME更好? – GorillaPatch 2010-08-10 13:53:21

+1

http://stackoverflow.com/questions/1479741/why-is-three-argument-open-calls-with-lexical-filehandles-a-perl-best-practice – daxim 2010-08-10 16:20:18

+0

感谢您提供的建议daxim – Sreeja 2010-08-10 16:59:04

4

也许这个例子可以帮助:

use strict; 
use warnings; 

my $n; 

# Supply the input file name as a command-line argument. 
# Perl will open the file and process it line by line. 
# No need to hard-code the file name in the program, which 
# means the script could be reused. 
while (my $line = <>){ 
    # The regex is applied against $line. 
    # It will return the items captured by parentheses. 
    # The /x option causes Perl to ignore whitespace 
    # in our definition of the regex -- for readability. 
    my ($type, $func, $args) = $line =~ /^ 
     (int64|void|boolean) \s+ 
     (\w+)    \s* 
     \((.+?) \) 
    /x; 

    # Skip the line if our regex failed. 
    next unless defined $type; 

    # Keep track of N of functions, print output, whatever... 
    $n ++; 
    print $_, "\n" for '', $type, $func, $args; 
} 

print "\nN of functions = $n\n"; 
+1

不错的一个!我喜欢它如何直接命名正则表达式的匹配。使代码更具可读性。我今天学到了东西。谢谢! +1。 – GorillaPatch 2010-08-10 13:49:05

1

这将这样的伎俩:

#!/usr/bin/env perl 
use strict; 
use warnings; 
use autodie qw(:all); 

my $function_count = 0; 
open my $input, '<', 'function.txt'; 
while (defined(my $line = <$input>)) { 
    chomp($line); 

    if (my ($func) = $line =~ /^(?:int64|void|boolean)\s?(.*?)\(/) { 
     print qq{Found function "$func"\n}; 
     $function_count++; 
    } 
} 
close $input; 
print "$function_count\n"; 

修订答案考虑到函数调用:

#!/usr/bin/env perl 
use strict; 
use warnings; 
use autodie qw(:all); 

my $document; 
{ 
    local $/ = undef; 
    open my $input, '<', 'function.txt'; 
    $document = <$input>; 
    chomp $document; 
    close $input; 
} 

my $function_count = 0; 
while (my ($func) = $document =~ /(?:int64|void|boolean)\s?(.*?)\(.*?\)\s*\{/gs)) { 
    print qq{Found function "$func"\n}; 
    $function_count++; 
} 

print "$function_count\n"; 
+0

不需要chomp我认为这是因为你不匹配行末。 – GorillaPatch 2010-08-10 13:50:46

+0

非常真实的,只是添加chomp作为习惯的力量。 – Narthring 2010-08-10 14:45:30

+0

Thanks.But上面的代码返回甚至函数调用的计数.. int64 AccounntBalance(char * reg12,char * refid,char ** id); – Sreeja 2010-08-10 17:43:22

3

正则表达式是不解析器。如果可以的话,最好使用解析器。

一个简单的办法是在解析器倾身ctags

#! /usr/bin/perl 

use warnings; 
use strict; 

sub usage { "Usage: $0 source-file\n" } 

die usage unless @ARGV == 1; 

open my $ctags, "-|", "ctags", "-f", "-", @ARGV 
    or die "$0: failed to start ctags\n"; 

while (<$ctags>) { 
    chomp; 
    my @fields = split /\t/; 
    next unless $fields[-1] eq "f"; 
    print $fields[0], "\n"; 
} 

采样运行:

$ ./getfuncs prog.cc 
AccounntBalance 
AccountRetrivalForm

另一种方法涉及G ++的选项-fdump-translation-unit,导致它倾倒分析树的表示,你可以像下面的例子那样挖掘它。

我们开始与平常前面的问题:

#! /usr/bin/perl 

use warnings; 
use strict; 

处理需要的源文件和任何必需的编译标记的名称。

sub usage { "Usage: $0 source-file [ cflags ]\n" } 

翻译单元转储具有简单的格式:

@1  namespace_decl name: @2  srcp: :0  
         dcls: @3  
@2  identifier_node strg: ::  lngt: 2  
@3  function_decl name: @4  mngl: @5  type: @6  
         srcp: prog.c:12    chan: @7  
         args: @8  link: extern 
@4  identifier_node strg: AccountRetrivalForm  lngt: 19 

正如你可以看到,每一个记录开始的标识符,后跟一个类型,然后一个或多个属性。正则表达式和一些哈希转换足以给我们一棵树来检查。

sub read_tu { 
    my($path) = @_; 
    my %node; 

    open my $fh, "<", $path or die "$0: open $path: $!"; 
    my $tu = do { local $/; <$fh> }; 

    my $attrname = qr/\b\w+(?=:)/; 
    my $attr = 
    qr/($attrname): \s+ (.+?)  # name-value 
     (?= \s+ $attrname | \s*$) # terminated by whitespace or EOL 
     /xm; 

    my $fullnode = 
    qr/^(@\d+) \s+ (\S+) \s+ # id and type 
     ((?: $attr \s*)+)  # one or more attributes 
     \s*$     # consume entire line 
     /xm; 

    while ($tu =~ /$fullnode/g) { 
    my($id,$type,$attrs) = ($1,$2,$3); 

    $node{$id} = { TYPE => $type }; 
    while ($attrs =~ /$attr \s*/gx) { 
     if (exists $node{$id}{$1}) { 
     $node{$id}{$1} = [ $node{$id}{$1} ] unless ref $node{$id}{$1}; 
     push @{ $node{$id}{$1} } => $2; 
     } 
     else { 
     $node{$id}{$1} = $2; 
     } 
    } 
    } 

    wantarray ? %node : \%node; 
} 

在主程序中,我们喂代码至g ++

die usage unless @ARGV >= 1; 

my($src,@cflags) = @ARGV; 
system("g++", "-c", "-fdump-translation-unit", @cflags, $src) == 0 
    or die "$0: g++ failed\n"; 

my @tu = glob "$src.*.tu"; 
unless (@tu == 1) { 
    die "$0: expected one $src.*.tu file, but found", 
     @tu ? ("\n", map(" - $_\n", @tu)) 
      : " none\n"; 
} 

假设一切顺利,那么我们挖出指定的源文件中给出的函数定义。

my $node = read_tu @tu; 

sub isfunc { 
    my($n) = @_; 
    $n->{TYPE} eq "function_decl" 
      && 
    index($n->{srcp}, "$src:") == 0; 
} 

sub nameof { 
    my($n) = @_; 
    return "<undefined>" unless exists $n->{name}; 
    $n->{name} =~ /^@/ 
    ? $node->{ $n->{name} }{strg} 
    : $n->{name}; 
} 

print "$_\n" for sort 
       map nameof($_), 
       grep isfunc($_), 
       values %$node; 

运行示例:

$ ./getfuncs prog.cc -I. 
AccounntBalance 
AccountRetrivalForm
+0

就是这样做的。不过,我认为你应该把ctags的方式放在前面。 – Svante 2010-08-10 16:31:32

+0

@Svante好的建议!更新。 – 2010-08-10 16:56:40

+0

我同意你的意见。这显然是他想要处理的一个基于c语言的语言......而且用一些完全有效的函数声明来打破任何正则表达式太容易了。最好使用理解语言的工具。 – 2010-08-11 18:27:59