0

如果.cpp 或.h 文件有#includes(例如#include "ready.h"),我需要制作一个包含这些文件名的文本文件。由于 ready.h 可能有自己的#include,因此必须递归调用。不知道该怎么做。

4

3 回答 3

2

@OneSolitaryNoob 的解决方案可能会正常工作,但有一个问题:对于每次递归,它都会启动另一个进程,这非常浪费。我们可以使用子程序更有效地做到这一点。假设所有头文件都在工作目录中:

sub collect_recursive_includes {
  # Unpack parameter from subroutine
  my ($filename, $seen) = @_;
  # Open the file to lexically scoped filehandle
  # In your script, you'll probably have to transform $filename to correct path
  open my $fh, "<", $filename or do {
    # On failure: Print a warning, and return. I.e. go on with next include
    warn "Can't open $filename: $!";
    return;
  };
  # Loop through each line, recursing as needed
  LINE: while(<$fh>) {
    if (/^\s*#include\s+"([^"]+)"/) {
      my $include = $1;
      # you should probably normalize $include before testing if you've seen it
      next LINE if $seen->{$include}; # skip seen includes
      $seen->{$include} = 1;
      collect_recursive_includes($include, $seen);
    }
  }
}

这个子例程记住它已经看过的文件,并避免在那里再次递归——每个文件只被访问一次。

在顶层,您需要提供一个 hashref 作为第二个参数,它将在 sub 运行后将所有文件名作为键保存:

my %seen = ( $start_filename => 1 );
collect_recursive_includes($start_filename, \%seen);

my @files = sort keys %seen;
# output @files, e.g. print "$_\n" for @files;

我在代码注释中暗示您可能必须规范化文件名。例如,考虑一个起始文件名./foo/bar/baz.h,它指向qux.h. 那么我们不想递归到的实际文件名是./foo/bar/qux.h,而不是./qux.h. 该Cwd模块可以帮助您找到您当前的位置,并将相对路径转换为绝对路径。该File::Spec模块要复杂得多,但对独立于平台的文件名和路径操作有很好的支持。

于 2013-04-29T04:50:52.417 回答
0

在 Perl 中,递归很简单:

sub factorial
{
    my $n = shift;
    if($n <= 1)
        { return 1; }
    else
        { return $n * factorial($n - 1); }
}

print factorial 7;     # prints 7 * 6 * 5 * 4 * 3 * 2 * 1

顺便说一句,我只能想到两件事需要注意:

  • 在 Perl 中,变量默认是全局的,因此默认是静态的。由于您不希望一个函数调用的变量践踏另一个函数调用的变量,因此您需要确保本地化您的变量,例如使用my.
  • 原型和递归存在一些限制。如果你想使用原型(例如sub factorial($),而不是just sub factorial),那么你需要在函数定义之前提供原型,以便它可以在函数体内使用。(或者,您可以&在递归调用函数时使用;这将阻止应用原型。)
于 2013-04-29T01:18:49.250 回答
0

不完全清楚你希望显示的样子,但基本的将是一个名为 follow_includes.pl 的脚本:

#!/usr/bin/perl -w

while(<>) {
      if(/\#include "(\S+)\"/) {
         print STDOUT $1 . "\n";
         system("./follow_includes.pl $1");
      }
}

像这样运行它:

% follow_includes.pl somefile.cpp

如果你想隐藏任何重复的包含,运行它:

% follow_includes.pl somefile.cpp | sort -u

通常,您希望在某种树形打印中使用它。

于 2013-04-29T01:22:02.593 回答