正則表達式是不解析器。如果可以的話,最好使用解析器。
一個簡單的辦法是在解析器傾身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
究竟是你想搭配什麼?以(int64)或(void)或(boolean)開頭的函數? – GorillaPatch 2010-08-10 13:27:31
@gorillaPatch 我嘗試匹配所有可能以int64開頭的函數或void或布爾值(這是唯一的三個可能性) – Sreeja 2010-08-10 13:29:59
我很好奇,什麼語言是「dis」? – Ether 2010-08-10 15:07:18