Инструмент для удаления неиспользуемых локальных переменных в коде Фортрана - PullRequest
1 голос
/ 27 ноября 2010

Есть ли хороший инструмент для удаления неиспользуемых локальных переменных из кода Фортрана свободной формы?

Исходным фоном является то, что у нас очень большая кодовая база, и неиспользуемые предупреждения были отключены в течение последних 20 лет, поэтому их довольно много, их слишком много, чтобы их можно было исправить вручную.

Я знаю, что у Photran такой рефакторинг, но я попробовал его и столкнулся с проблемами. По какой-то причине он требует, чтобы весь исходный код мог быть проанализирован (что он не может сделать с нашей кодовой базой) для выполнения рефакторинга, хотя для этого рефакторинга должно быть достаточно IMO, чтобы просто проверить отдельные файлы.

Ответы [ 5 ]

2 голосов
/ 27 ноября 2010

Я сделал это вручную, основываясь на сообщениях компилятора. Один из возможных автоматических инструментов: запись для SPAG / plusFORT говорит:

SPAG идентифицирует и при необходимости удаляет мертвый код (операторы, которые никогда не могут быть выполнены) и беспорядок (переменные или параметры, которые объявлены, но никогда не используются).

Я использовал бесплатную версию с ограниченной функциональностью, но не помню, удаляла ли эта версия неиспользуемые переменные.

0 голосов
/ 18 июня 2012

Для 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);
}

Очевидно, вы должны посмотреть на источник и убедиться, что он делает то, что вы хотите. Но, грубо говоря, он читает выходные данные компилятора и удаляет переменную, на которую компилятор жалуется, в строке, на которую он жалуется.

0 голосов
/ 07 декабря 2010

Существует сценарий "prettify" Python как часть набора инструментов GPL CP2K.Вы можете найти его в в репозитории исходного кода проекта CP2K .Вам понадобятся сценарии prettify.py и normalizeFortranFile.py.Так как он также пытается «предварительно защитить» файл, вам придется редактировать скрипт, если вы действительно хотите удалить только локальные переменные.

0 голосов
/ 29 ноября 2010

PlusFORT - ваш единственный вариант, и он не дешевый. Но он использовался на миллионах строк старого кода на Fortran (77) и является достаточно зрелым. Для мнений попробуйте comp.lang.fortran

0 голосов
/ 27 ноября 2010

это идет как ответ, потому что он не может поместиться в поле для комментариев - не думайте об этом, как об ответе, а скорее как комментарий

Кроме того, извините, но я не думаю, что такой инструмент существует. TZXH спросил, какой компилятор вы используете - не потому, что это имеет большое значение, а (я думаю), потому что, возможно, он думал о том, что, может быть, он разбирает предупреждения компилятора, чтобы получить список переменных, затем просматривает файлы Fortran и удаление этих переменных вручную.

Я никогда не делал ничего подобного, но этот процесс может сработать. Имеет некоторые потенциальные недостатки, но это может сработать.

Кроме того, для анализа (и написания нового, поскольку это действительно очень хорошая IDE) исходного кода на Фортране я нашел SciTools Understand очень полезным инструментом. Не уверен, что у него есть функция, которая делает то, что вы просите, но это может помочь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...