Мне трудно это исправить. Пожалуйста, ознакомьтесь с моим отредактированным кодом. - PullRequest
1 голос
/ 10 августа 2010

Я хочу получить количество функций (только определенные функции, а не вызывающие функции), присутствующих в текстовом файле (количество)

Текстовый файл {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. Он никогда не увеличивается для второго соответствия .... Пожалуйста, помогите мне с тем же кодом ... Я так долго пытаюсь. Мне трудно это исправить.

Ответы [ 5 ]

4 голосов
/ 10 августа 2010

Возможно, этот пример поможет:

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";
3 голосов
/ 10 августа 2010

Регулярные выражения не являются парсерами.Всегда лучше использовать парсер, если вы можете.

Простой подход состоит в том, чтобы опираться на парсер в 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
3 голосов
/ 10 августа 2010

Я хотел бы сказать, что способ, которым вы просматриваете файл, необычен.Обычно вы используете что-то вроде

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; предупредил бы вас.

3 голосов
/ 10 августа 2010

Ваше регулярное выражение плохо сформировано.

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

Вы, вероятно, имели в виду что-то вроде:

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

То есть один из int64, void или boolean, некоторый пробел, идентификатор, необязательный пробел, открывающая скобка, некоторый контент, закрывающая скобка, некоторый необязательный пробел (который может быть новой строкой ) и открывающая фигурная скобка.

1 голос
/ 10 августа 2010

Это поможет:

#!/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";
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...