/ / Como posso ignorar comentários C quando eu processar um arquivo de origem C com Perl? - perl

Como posso ignorar comentários C quando eu processar um arquivo de origem C com Perl? - perl

Eu estou executando um código que lê arquivos, faz algumas análises, mas precisa ignorar todos os comentários. Há boas explicações sobre como conduzi-lo, como a resposta para Como posso retirar comentários C de múltiplas linhas de um arquivo usando Perl?

$/ = undef;
$_ = <>;
s#/*[^*]**+([^/*][^*]**+)*/|("(\.|[^"\])*"|"(\.|[^"\])*"|.[^/""\]*)#defined $2 ? $2 : ""#gse;
print;

Meu primeiro problema é que depois de executar esta linha $/ = undef; meu código não funciona corretamente. Na verdade, eu não sei o que isso faz. Mas se eu pudesse voltar atrás depois de ignorar todos os comentários, será útil.

Em geral, qual é a maneira útil de ignorar todos os comentários sem alterar o restante do código?

Respostas:

1 para resposta № 1

Você quer fazer $/ local, como em

$_ = do { local $/; <> };

ou

{
local $/;
$_ = <>;
#...
}

Como alternativa, você poderia usar Arquivo :: Slurp


2 para resposta № 2

awk

$ cat file.c
one
two
three // comment at the back
// comment in front
four /* another comment */
/* comment spanning
multiple
lines
*/  five
six
seven

$ awk -vRS="*/" "{ gsub(//*.*/,"");gsub("//.*","")}1" file.c
one
two
three


five
six
seven

o comando awk define o separador de registro RS para */, que é a tag final para o comentário no estilo multilinha. então itera os registros, checando /*, a tag de abertura, e então pegue o que estiver na frente /*. este conceito é simples e você não precisa criar um regex complicado para isso. Similar, se você fosse fazer com o Python,

>>> data=open("file").read()
>>> for item in data.split("*/"):
...     if "//" in item: item=item.split("//")[0]
...     if "/*" in item: item=item.split("/*")[0]
...     print item
...
one
two
three


five
six
seven

1 para resposta № 3

Se você estiver removendo comentários "aninhados", por exemplo:

/* This is a comment
/* that has been re-commented */ possibly /* due to */
various modifications */

regexp pode não ser a melhor solução. Especialmente se isso envolver várias linhas, como no exemplo acima.

A última vez que eu tive que fazer algo assim, eu lias linhas uma de cada vez, mantendo uma contagem de quantos níveis de "/ *" (ou qualquer que fosse o delimitador para o idioma específico) e não imprimindo nada a menos que a contagem estivesse em 0.

Aqui está um exemplo - peço desculpas antecipadamente porque é muito ruim Perl, mas isso deve lhe dar uma idéia, pelo menos:

use strict;

my $infile = $ARGV[0]; # File name

# Slurp up input file in an array
open (FH, "< $infile")  or die "Opening: $infile";
my @INPUT_ARRAY = <FH>;
my @ARRAY;
my ($i,$j);
my $line;


# Removes all kind of comments (single-line, multi-line, nested).
# Further parsing will be carried on the stripped lines (in @ARRAY) but
# the error messaging routine will reference the original @INPUT_ARRAY
# so line fragments may contain comments.
my $commentLevel = 0;

for ($i=0; $i < @INPUT_ARRAY; $i++)
{
my @explodedLine = split(//,$INPUT_ARRAY[$i]);
my $resultLine ="";

for ($j=0; $j < @explodedLine; $j++)
{
if ($commentLevel > 0)
{
$resultLine .= " ";
}
if ($explodedLine[$j] eq "/" && $explodedLine[($j+1)] eq "*")
{
$commentLevel++;
next;
}
if ($explodedLine[$j] eq "*" && $explodedLine[($j+1)] eq "/")
{
$commentLevel--;
$j++;
next;
}
if (($commentLevel == 0) || ($explodedLine[$j] eq "n"))
{
$resultLine .= $explodedLine[$j];
}
}

$ARRAY[$i]=join(" ",$resultLine);
}


close(FH)   or die "Closing: $!";