用于删除Fortran代码中未使用的局部变量的工具

时间:2010-11-27 10:53:17

标签: fortran compiler-warnings

是否有一些很好的工具可以从自由形式的Fortran代码中删除未使用的局部变量?

背景是我们有一个非常大的代码库,并且过去20年来一直禁用未使用的警告,所以它们中有很多,手动修复太多了。

我知道Photran有这种重构,但我尝试了它并遇到了问题。出于某种原因,它需要解析整个源代码(它不能用我们的代码库来处理)来进行重构,尽管对于这种重构,它应该足以只检查单个文件。

5 个答案:

答案 0 :(得分:2)

我是基于编译器消息手动完成的。一种可能的自动工具:SPAG / plusFORT的写作说:

  

SPAG识别并选择性地删除死代码(永远不会执行的语句)和混乱(声明但从未使用过的变量或PARAMETER)。

我使用了免费的,缩减功能的版本,但不记得该版本是否删除了未使用的变量。

答案 1 :(得分:0)

这是一个答案,因为它不适合评论框 - 不要将其视为一个答案,更多的是作为评论

除此之外,对不起,但我不认为这样的工具存在。 TZXH询问你正在使用什么编译器 - 不是因为它产生了很大的差别,而是(我认为)因为他可能正在考虑解析编译器警告以获取变量列表,然后通过Fortran文件,以及半手动删除这些变量。

我从未做过类似的事情,但这是一个可行的过程。有一些潜在的缺点,但它可以工作。

除此之外,我发现SciTools Understand是一个非常有用的工具,用于Fortran源代码的分析(并编写一个新的,非常好的IDE)。不确定它是否具有执行您所要求的功能,但它可以提供帮助。

答案 2 :(得分:0)

有一个“美化”的Python脚本作为GPL CP2K工具链的一部分。您可以在in the CP2K project source repository中找到它。您将需要prettify.py和normalizeFortranFile.py脚本。由于它也试图“美化”文件,如果你真的只想删除局部变量,你将不得不编辑脚本。

答案 3 :(得分:0)

对于gfortran你可以使用这个perl脚本,参数“build_log”应该是gfortran -Wunused的输出(或任何获得你未使用的变量警告):

#!/usr/bin/perl

use strict;

my $build_log = shift;

open my $build_filehandle, "<", $build_log;

my $file;
my $line_to_edit;
my $col_to_edit;
my $word_to_remove;

my @files;
my @line_nums;
my @unused_variables;
my $line;

my $line_number = 0;
while($line = <$build_filehandle>)
{
    $line_number++;
    chomp($line);
    if($line =~ m/([^:]*):(\d+)\.(\d+):/)
    {
        $file = $1;
        $line_to_edit = $2;
        $col_to_edit = $3;
    }
    elsif($line =~ m/Warning: Unused variable '([^']*)'/)
    {
        $word_to_remove = $1;
        push(@files, $file);
        push(@line_nums, $line_to_edit);
        push(@unused_variables, $word_to_remove);
    }
}

close($build_filehandle);

# sort [file, line_num, word_to_remove] by files then line_nums then word_to_remove
my @merged_columns;
for(my $i = 0; $i < scalar(@files); $i++) # loop over all the replacements to be made
{
    push(@merged_columns, [$files[$i],$line_nums[$i],$unused_variables[$i]]);
}

# if sort is stable, sort by line_nums, then files
sub by_file_then_line
{
    $a->[0] cmp $b->[0] || # by file
    $a->[1] <=> $b->[1];
}

my @sorted_by_line_nums = sort by_file_then_line @merged_columns;

for(my $i = 0; $i < scalar(@files); $i++) # loop over all the replacements to be made
{
    $files[$i] = $sorted_by_line_nums[$i][0];
    $line_nums[$i] = $sorted_by_line_nums[$i][1];
    $unused_variables[$i] = $sorted_by_line_nums[$i][2];
}

my $print_line = 0;
my $last_file = 'null';
my $replacement_filehandle;
for(my $i = 0; $i < scalar(@files); $i++) # loop over all the replacements to be made
{
    if($files[$i] ne $last_file)
    {
        if(defined($replacement_filehandle))
        {
            # dump the line we were working on
            if($print_line == 1) # print the line that we were processing
            {
                print("$line\n");
                $print_line = 0;
            }

            # dump the rest of the file
            while($line = <$replacement_filehandle>)
            {
                chomp($line);
                print("$line\n");
            }
            # then close it
            close($replacement_filehandle);
        }
        open $replacement_filehandle, "+<", $files[$i];
        $line_number = 0;
    }
    $last_file = $files[$i];

# here we are on the right file, but might need to advance to the correct location
    while($line_number < $line_nums[$i]) # might not even enter
    {
        if($print_line == 1) # print the line that we were processing
        {
            print("$line\n");
            $print_line = 0;
        }
        $line = <$replacement_filehandle>;
        $line_number++;
        chomp($line);

        if($line_number < $line_nums[$i])
        {
            print("$line\n");
        }
    }
    $print_line = 1;

    if($line =~ m/^\s+type/i) # don't bother with types, their naming and form is too messed up to make it worth the effort, and there aren't that many
    {
        next;
    }

    $line =~ s/,/, /g; # add spaces after commas
    $line =~ s/,\s+/, /g; # collapse double commas

# case followed by stuff in parens
    $line =~ s/ ${unused_variables[$i]}\([^\)]*\),?//i;

# case followed by comma
    $line =~ s/ ${unused_variables[$i]},//i;

# case end of line
    $line =~ s/ ${unused_variables[$i]}\s*$//i;

# remove trailing commas
    $line =~ s/,\s*$//;

# collapse double commas
    $line =~ s/,\s*,/,/;

# remove empty memory declaration lines
# ie, if it does not have two sets of word characters kill it off
    if(! ($line =~ m/\w[^A-Za-z\*]+\w/))
    {
        $line = '';
    }
}


if(defined($replacement_filehandle))
{
    # dump the line we were working on
    if($print_line == 1) # print the line that we were processing
    {
        print("$line\n");
        $print_line = 0;
    }

    # dump the rest of the file
    while($line = <$replacement_filehandle>)
    {
        chomp($line);
        print("$line\n");
    }
    # then close it
    close($replacement_filehandle);
}

显然,您应该查看源代码并检查它是否符合您的要求。但粗略地说它会读取编译器输出并删除编译器在其抱怨的行上抱怨的变量。

答案 4 :(得分:-1)

PlusFORT是您唯一的选择,并不便宜。但它已被用于数百万行旧Fortran(77)代码并且相当成熟。对于意见,请尝试comp.lang.fortran