script simples para contar NLOC?
-
11-07-2019 - |
Pergunta
Você conhece um script simples para contar NLOCs (linhas netto de código). O script deve contar linhas de código C. Ele não deve contar linhas vazias ou linhas com apenas chaves. Mas isso não precisa ser excessivamente exata quer.
Solução
eu faria isso usando awk & CPP (pré-processador) e wc . awk remove todas as chaves e espaços em branco, o pré-processador remove todos os comentários e contagens wc as linhas:
find . -name \*.cpp -o -name \*.h | xargs -n1 cpp -fpreprocessed -P |
awk '!/^[{[:space:]}]*$/' | wc -l
Se você quiser fazer comentários incluíram:
find . -name \*.cpp -o -name \*.h | xargs awk '!/^[{[:space:]}]*$/' | wc -l
Outras dicas
Olhando NLOC na net, encontrei principalmente "linhas de código não comentou".
Você não especifica se os comentários devem ser ignorados ...
Então, se eu furar a sua mensagem atual, a seguinte one-liner em Perl deve fazer o trabalho:
perl -pe "s/^\s*[{}]?\s*\n//" Dialog.java | wc -l
Eu posso estendê-lo para lidar com comentários de linha:
perl -pe "s#^\s*[{}]?\s*\n|^\s*//.*\n##" Dialog.java | wc -l
ou talvez
perl -pe "s#^\s*(?:[{}]?\s*|//.*)\n##" Dialog.java | wc -l
Como manusear blocos de comentários é um pouco mais complicado (eu não sou um especialista em Perl!).
[EDIT] Got it ... Primeira parte pode ser provavelmente melhorado (mais curto). Foi divertido para experimentar.
perl -e "$x = join('', <>); $x =~ s#/\*.*?\*/##gs; print $x" Dialog.java | perl -pe "s#^\s*(?:[{}]?\s*|//.*)\n##" | wc -l
PS .: Eu uso aspas porque eu testado no Windows ...
Confira DPACK plug-in para o Visual Studio. Tem um stats relatar para qualquer solução / projeto.
Não é um roteiro, mas você pode tentar isso de linha de comando ferramenta open source: NLOC
monitor Fonte é software de análise de fonte gratuito. É a aplicação das janelas, mas também pode ser executado com parâmetros de linha de comando.
Ele pode analisar C ++, C, C #, VB.NET, Java, Delphi, Visual Basic (VB6) ou HTML.
Se os comentários podem ainda estar em, a ferramenta unix padrão for suficiente:
grep -x -v "[[:space:]}{]*" files.c | wc
sloccount não é um script simples e faz muito mais do que você precisa. No entanto, é uma poderosa alternativa ao já mencionado Ohcount e NLOC. :)
Eu normalmente apenas fazer isso:
grep -vc '^$' (my files)
Funciona apenas se suas linhas vazias são realmente vazios (sem espaços). Suficiente para mim.
Locmetrics funciona bem.
Aqui está um script Perl simples eLOC.pl :
#!/usr/bin/perl -w
# eLOC - Effective Lines of Code Counter
# JFS (2005)
#
# $ perl eLOC.pl --help
#
use strict;
use warnings;
use sigtrap;
use diagnostics;
use warnings::register;
no warnings __PACKAGE__;
sub DEBUG { 0 }
use English qw( -no_match_vars ) ; # Avoids regex performance penalty
use Getopt::Long qw(:config gnu_getopt);
use File::DosGlob 'glob';
use Pod::Usage;
our $VERSION = '0.01';
# globals
use constant NOTFILENAME => undef;
my %counter = (
'PHYS' => 0,
'ELOC' => 0,
'PURE_COMMENT' => 0,
'BLANK' => 0,
'LLOC' => 0,
'INLINE_COMMENT'=> 0,
'LOC' => 0,
);
my %header = (
"eloc" => "eloc",
"lloc" => "lloc",
"loc" => "loc",
"comment" => "comment",
"blank" => "blank",
"newline" => "newline",
"logicline" => "lgcline",
);
my %total = %counter; # copy
my $c = \%counter; # see format below
my $h = \%header; # see top format below
my $inside_multiline_comment = 0;
my $filename = NOTFILENAME;
my $filecount = 0;
my $filename_header = "file name";
# process input args
my $version = '';
my $help = '';
my $man = '';
my $is_deterministic = '';
my $has_header = '';
print STDERR "Input args:'" if DEBUG;
print STDERR (join("|",@ARGV),"'\n") if DEBUG;
my %option = ('version' => \$version,
'help' => \$help,
'man' => \$man,
'deterministic' => \$is_deterministic,
'header' => \$has_header
);
GetOptions( \%option, 'version', 'help', 'man',
'eloc|e', # print the eLOC counts
'lloc|s', # print the lLOC counts (code statements)
'loc|l' , # print the LOC counts (eLOC + lines of a single brace or parenthesis)
'comment|c' , # print the comments counts (count lines which contains a comment)
'blank|b' , # print the blank counts
'newline|n' , # print the newline count
'logicline|g' , # print the logical line count (= LOC + Comment Lines + Blank Lines)
'deterministic', # print the LOC determination for every line in the source file
'header', # print header line
) or invalid_options("$0: invalid options\nTry `$0 --help' for more information.");
version() if $version;
pod2usage(-exitstatus => 0, -verbose => 1) if $help ;
pod2usage(-exitstatus => 0, -verbose => 2) if $man;
#
$has_header = 1 if $is_deterministic && $has_header eq '';
#format for print_loc_metric()
my ($format, $format_top) = make_format();
print STDERR "format:\n" if DEBUG > 10;
print STDERR $format if DEBUG > 10;
eval $format;
die $@ if $@; # $EVAL_ERROR
if(DEBUG>10) {
print STDERR ("format_top:\n", $format_top);
}
if( $has_header) {
eval $format_top;
die $@ if $@; # $EVAL_ERROR
}
# process files
print STDERR ("Input args after Getopts():\n",
join("|",@ARGV),"\n") if DEBUG > 10;
expand_wildcards();
@ARGV = '-' unless @ARGV;
foreach my $fn (@ARGV) {
$filename = $fn;
unless (open(IN, "<$filename")) {
warn "$0: Unable to read from '$filename': $!\n";
next;
}
print STDERR "Scanning $filename...\n" if DEBUG;
clear_counters();
generate_loc_metric();
$filecount++;
print_loc_metric();
close(IN)
or warn "$0: Could not close $filename: $!\n";
}
# print total
if($filecount > 1) {
$filename = "total";
$c = \%total;
print_loc_metric();
}
exit 0;
#-------------------------------------------------
sub wsglob {
my @list = glob;
@list ? @list : @_; #HACK: defence from emtpy list from glob()
}
sub expand_wildcards {
print STDERR ("Input args before expand_wildcards():\n",
join("|",@ARGV),"\n") if DEBUG;
{
@ARGV = map( /['*?']/o ? wsglob($_) : $_ , @ARGV);
}
print STDERR ("Input args after expand_wildcards():\n",
join("|",@ARGV),"\n") if DEBUG;
}
sub clear_counters {
for my $name ( keys %counter) {
$counter{$name} = 0;
}
}
sub make_format {
my $f = 'format STDOUT =' . "\n";
$f .= '# LOC, eLOC, lLOC, comment, blank, newline, logicline and filename' . "\n";
my $f_top = 'format STDOUT_TOP =' . "\n";
my $console_screen_width = (get_terminal_size())[0];
print STDERR '$console_screen_width=' . $console_screen_width ."\n" if DEBUG>10;
$console_screen_width = 100 if $console_screen_width < 0;
my $is_print_specifiers_set =
($option{"eloc"} or
$option{"lloc"} or
$option{"loc"} or
$option{"comment"} or
$option{"blank"} or
$option{"newline"} or
$option{"logicline"});
my %o = %option;
my $fc = 0;
if( $is_print_specifiers_set ) {
$fc++ if $o{"eloc"};
$fc++ if $o{"lloc"};
$fc++ if $o{"loc"};
$fc++ if $o{"comment"};
$fc++ if $o{"blank"};
$fc++ if $o{"newline"};
$fc++ if $o{"logicline"};
if( $fc == 0 ) { die "$0: assertion failed: field count is zero" }
}
else {
# default
$fc = 7;
$o{"loc"} = 1;
$o{"eloc"} = 1;
$o{"lloc"} = 1;
$o{"comment"} = 1;
$o{"blank"} = 1;
$o{"newline"} = 1;
$o{"logicline"} = 1;
}
if (DEBUG > 10) {
while( (my ($name, $value) = each %{o}) ) {
print STDERR "name=$name, value=$value\n";
}
}
# picture line
my $field_format = '@>>>>>> ';
my $field_width = length $field_format;
my $picture_line = $field_format x $fc;
# place for filename
$picture_line .= '^';
$picture_line .= '<' x ($console_screen_width - $field_width * $fc - 2);
$picture_line .= "\n";
$f .= $picture_line;
$f_top .= $picture_line;
# argument line
$f .= '$$c{"LOC"}, ' ,$f_top .= '$$h{"loc"}, ' if $o{"loc"};
$f .= '$$c{"ELOC"}, ' ,$f_top .= '$$h{"eloc"}, ' if $o{"eloc"};
$f .= '$$c{"LLOC"}, ' ,$f_top .= '$$h{"lloc"}, ' if $o{"lloc"};
$f .= '$$c{"comment"}, ' ,$f_top .= '$$h{"comment"}, ' if $o{"comment"};
$f .= '$$c{"BLANK"}, ' ,$f_top .= '$$h{"blank"}, ' if $o{"blank"};
$f .= '$$c{"PHYS"}, ' ,$f_top .= '$$h{"newline"}, ' if $o{"newline"};
$f .= '$$c{"logicline"}, ',$f_top .= '$$h{"logicline"}, ' if $o{"logicline"};
$f .= '$filename' . "\n";
$f_top .= '$filename_header' . "\n";
# 2nd argument line for long file names
$f .= '^';
$f .= '<' x ($console_screen_width-2);
$f .= '~~' . "\n"
.' $filename' . "\n";
$f .='.' . "\n";
$f_top .='.' . "\n";
return ($f, $f_top);
}
sub generate_loc_metric {
my $is_concatinated = 0;
LINE: while(<IN>)
{
chomp;
print if $is_deterministic && !$is_concatinated;
# handle multiline code statements
if ($is_concatinated = s/\\$//) {
warnings::warnif("$0: '\\'-ending line concantinated");
increment('PHYS');
print "\n" if $is_deterministic;
my $line = <IN>;
$_ .= $line;
chomp($line);
print $line if $is_deterministic;
redo unless eof(IN);
}
# blank lines, including inside comments, don't move to next line here
increment('BLANK') if( /^\s*$/ );
# check whether multiline comments finished
if( $inside_multiline_comment && m~\*/\s*(\S*)\s*$~ ) {
$inside_multiline_comment = 0;
# check the rest of the line if it contains non-whitespace characters
#debug $_ = $REDO_LINE . $1, redo LINE if($1);
warnings::warnif("$0: expression '$1' after '*/' discarded") if($1);
# else mark as pure comment
increment('PURE_COMMENT');
next LINE;
}
# inside multiline comments
increment('PURE_COMMENT'), next LINE if( $inside_multiline_comment );
# C++ style comment at the begining of line (except whitespaces)
increment('PURE_COMMENT'), next LINE if( m~^\s*//~ );
# C style comment at the begining of line (except whitespaces)
if ( m~^\s*/\*~ ) {
$inside_multiline_comment = 1 unless( m~\*/~ );
increment('PURE_COMMENT'), next LINE;
}
# inline comment, don't move to next line here
increment('INLINE_COMMENT') if ( is_inline_comment($_) );
# lLOC implicitly incremented inside is_inline_comment($)
#
increment('LOC') unless( /^\s*$/ );
# standalone braces or parenthesis
next LINE if( /^\s*(?:\{|\}|\(|\))+\s*$/ );
# eLOC is not comments, blanks or standalone braces or parenthesis
# therefore just increment eLOC counter here
increment('ELOC'), next LINE unless( /^\s*$/ );
}
continue {
increment('PHYS');
print " [$.]\n" if $is_deterministic; # $INPUT_LINE_NUMBER
}
}
sub print_loc_metric {
$$c{'comment'} = $$c{'PURE_COMMENT'} + $$c{'INLINE_COMMENT'};
# LOC + Comment Lines + Blank Lines
$$c{'logicline'} = $$c{'LOC'} + $$c{'comment'} + $$c{'BLANK'};
unless (defined $filename) {
die "print_loc_metric(): filename is not defined";
}
my $fn = $filename;
$filename = "", $filename_header = ""
unless($#ARGV);
print STDERR ("ARGV in print_loc_metric:" , join('|',@ARGV), "\n")
if DEBUG;
write STDOUT; # replace with printf
$filename = $fn;
}
sub increment {
my $loc_type = shift;
defined $loc_type
or die 'increment(\$): input argument is undefined';
$counter{$loc_type}++;
$total{$loc_type}++;
print "\t#". $loc_type ."#" if $is_deterministic;
}
sub is_inline_comment {
my $line = shift;
defined $line
or die 'is_inline_comment($): $line is not defined';
print "\n$line" if DEBUG > 10;
# here: line is not empty, not begining both C and C++ comments signs,
# not standalone '{}()', not inside multiline comment,
# ending '\' removed (joined line created if needed)
# Possible cases:
# - no C\C++ comment signs => is_inline_comment = 0
# - C++ comment (no C comment sign)
# * no quote characters => is_inline_comment = 1
# * at least one comment sign is not quoted => is_inline_comment = 1
# * all comment signs are quoted => is_inline_comment = 0
# - C comment (no C++ comment sign)
# * no quote characters => is_inline_comment = 1,
# ~ odd number of '/*' and '*/' => $inside_multiple_comment = 1
# ~ even number => $inside_multiple_comment = 0
# * etc...
# - ...
# algorithm: move along the line from left to right
# rule: quoted comments are not counted
# rule: quoted by distinct style quotes are not counted
# rule: commented quotes are not counted
# rule: commented distinct style comments are not counted
# rule: increment('LLOC') if not-quoted, not-commented
# semi-colon presents in the line except that two
# semi-colon in for() counted as one.
#
$_ = $line; #hack: $_ = $line inside sub
# state
my %s = (
'c' => 0, # c slash star - inside c style comments
'cpp' => 0, # c++ slash slash - inside C++ style comment
'qm' => 0, # quoted mark - inside quoted string
'qqm' => 0, # double quoted - inside double quoted string
);
my $has_comment = 0;
# find state
LOOP:
{
/\G\"/gc && do { # match double quote
unless( $s{'qm'} || $s{'c'} || $s{'cpp'} ) {
# toggle
$s{'qqm'} = $s{'qqm'} ? 0 : 1;
}
redo LOOP;
};
/\G\'/gc && do { # match single quote
unless( $s{'qqm'} || $s{'c'} || $s{'cpp'} ) {
# toggle
$s{'qm'} = $s{'qm'} ? 0 : 1;
}
redo LOOP;
};
m~\G//~gc && do { # match C++ comment sign
unless( $s{'qm'} || $s{'qqm'} || $s{'c'} ) {
# on
$has_comment = 1;
$s{'cpp'} = 1;
}
redo LOOP;
};
m~\G/\*~gc && do { # match begining C comment sign
unless( $s{'qm'} || $s{'qqm'} || $s{'cpp'} ) {
# on
$has_comment = 1;
$s{'c'} = $s{'c'} ? 1 : 1;
}
redo LOOP;
};
m~\G\*/~gc && do { # match ending C comment sign
unless( $s{'qm'} || $s{'qqm'} || $s{'cpp'} ) {
# off
if( $s{'c'} ) {
$s{'c'} = 0;
}
else {
die 'is_inline_comment($): unexpected c style ending comment sign'.
"\n'$line'";
}
}
redo LOOP;
};
/\Gfor\s*\(.*\;.*\;.*\)/gc && do { # match for loop
unless( $s{'qm'} || $s{'qqm'} || $s{'cpp'} || $s{'c'} ) {
# not-commented, not-quoted semi-colon
increment('LLOC');
}
redo LOOP;
};
/\G\;/gc && do { # match semi-colon
unless( $s{'qm'} || $s{'qqm'} || $s{'cpp'} || $s{'c'} ) {
# not-commented, not-quoted semi-colon
# not inside for() loop
increment('LLOC');
}
redo LOOP;
};
/\G./gc && do { # match any other character
# skip 1 character
redo LOOP;
};
/\G$/gc && do { # match end of the line
last LOOP;
};
#default
die 'is_inline_comment($): unexpected character in the line:' .
"\n'$line'";
}
# apply state
$inside_multiline_comment = $s{'c'};
return $has_comment;
}
sub version {
# TODO: version implementation
print <<"VERSION";
NAME v$VERSION
Written by AUTHOR
COPYRIGHT AND LICENSE
VERSION
exit 0;
}
sub invalid_options {
print STDERR (@_ ,"\n");
exit 2;
}
sub get_terminal_size {
my ($wchar, $hchar) = ( -1, -1);
my $win32console = <<'WIN32_CONSOLE';
use Win32::Console;
my $CONSOLE = new Win32::Console();
($wchar, $hchar) = $CONSOLE->MaxWindow();
WIN32_CONSOLE
eval($win32console);
return ($wchar, $hchar) unless( $@ );
warnings::warnif($@); # $EVAL_ERROR
my $term_readkey = <<'TERM_READKEY';
use Term::ReadKey;
($wchar,$hchar, $wpixels, $hpixels) = GetTerminalSize();
TERM_READKEY
eval($term_readkey);
return ($wchar, $hchar) unless( $@ );
warnings::warnif($@); # $EVAL_ERROR
my $ioctl = <<'IOCTL';
require 'sys/ioctl.ph';
die "no TIOCGWINSZ " unless defined &TIOCGWINSZ;
open(TTY, "+</dev/tty")
or die "No tty: $!";
unless (ioctl(TTY, &TIOCGWINSZ, $winsize='')) {
die sprintf "$0: ioctl TIOCGWINSZ (%08x: $!)\n",
&TIOCGWINSZ;
}
($hchar, $wchar, $xpixel, $ypixel) =
unpack('S4', $winsize); # probably $hchar & $wchar should be swapped here
IOCTL
eval($ioctl);
warnings::warnif($@) if $@ ; # $EVAL_ERROR
return ($wchar, $hchar);
}
1;
__END__
=head1 NAME
eLOC - Effective Lines of Code Counter
=head1 SYNOPSIS
B<eloc> B<[>OPTIONB<]...> B<[>FILEB<]...>
Print LOC, eLOC, lLOC, comment, blank, newline and logicline counts
for each FILE, and a total line if more than one FILE is specified.
See L</"LOC Specification"> for more info, use `eloc --man'.
-e, --eloc print the {E}LOC counts
-s, --lloc print the lLOC counts (code {S}tatements)
-l, --loc print the {L}OC counts (eLOC + lines of a single brace or parenthesis)
-c, --comment print the {C}omments counts (count lines which contains a comment)
-b, --blank print the {B}lank counts
-n, --newline print the {N}ewline count
-g, --logicline print the lo{G}ical line count (= LOC + Comment Lines + Blank Lines)
--deterministic print the LOC determination for every line in the source file
--header print header line
--help display this help and exit
--man display full help and exit
--version output version information and exit
With no FILE, or when FILE is -, read standard input.
Metrics counted by the program are based on narration from
http://msquaredtechnologies.com/m2rsm/docs/rsm_metrics_narration.htm
=for TODO: Comment Percent = Comment Line Count / Logical Line Count ) x 100
=for TODO: White Space Percentage = (Number of spaces / Number of spaces and characters) * 100
=head1 DESCRIPTION
eLOC is a simple LOC counter. See L</"LOC Specification">.
=head2 LOC Specification
=over 1
=item LOC
Lines Of Code = eLOC + lines of a single brace or parenthesis
=item eLOC
An effective line of code or eLOC is the measurement of all lines that are
not comments, blanks or standalone braces or parenthesis.
This metric more closely represents the quantity of work performed.
RSM introduces eLOC as a metrics standard.
See http://msquaredtechnologies.com/m2rsm/docs/rsm_metrics_narration.htm
=item lLOC
Logical lines of code represent a metrics for those line of code which form
code statements. These statements are terminated with a semi-colon.
The control line for the "for" loop contain two semi-colons but accounts
for only one semi colon.
See http://msquaredtechnologies.com/m2rsm/docs/rsm_metrics_narration.htm
=item comment
comment = pure comment + inline comment
=over
=item pure comment
Comment lines represent a metrics for pure comment line without any code in it.
See L</"inline comment">.
=item inline comment
Inline comment line is a line which contains both LOC line and pure comment.
Inline comment line and pure comment line (see L</"pure comment">)
are mutually exclusive, that is a given physical line cannot be an inline comment
line and a pure comment line simultaneously.
=over
=item Example:
static const int defaultWidth = 400; // value provided in declaration
=back
=back
=item blank
Blank line is a line which contains at most whitespaces.
Blank lines are counted inside comments too.
=item logicline
The logical line count = LOC + Comment Lines + Blank Lines
=back
=head1 KNOWN BUGS AND LIMITATIONS
=over
=item
It supports only C/C++ source files.
=item
Comments inside for(;;) statements are not counted
=over
=item Example:
for(int i = 0; i < N /*comment*/; i++ ); #LLOC# #LLOC# #LOC# #ELOC# #PHYS# [1]
=back
=item
'\'-ending lines are concatinated ( though newline count is valid)
=item
Input from stdin is not supported in the case
the script is envoked solely by name without explicit perl executable.
=item
Wildcards in path with spaces are not supported (like GNU utilities).
=back
=over
=begin fixed
=item Limitation: single source file
Only one source file at time supported
=item Limitation: LLOC is unsupported
The logical lines of code metric is unsupported.
=item missed inline comment for C style comment
#include <math.h> /* comment */ #ELOC# #PHYS# [2]
But must be
#include <math.h> /* comment */ #INLINE_COMMENT# #ELOC# #PHYS# [2]
=item wrong LOC type for the code after '*/'
/* another #PURE_COMMENT# #PHYS# [36]
trick #PURE_COMMENT# #PHYS# [37]
*/ i++; #PURE_COMMENT# #PHYS# [38]
In the last line must be
#INLINE_COMMENT# #PHYS# [38]
=end fixed
=back
=head1 SEE ALSO
Metrics counted by the program are based on narration from L<http://msquaredtechnologies.com/m2rsm/docs/rsm_metrics_narration.htm>
=cut
O script a seguir irá obter a contagem de todos os arquivos correspondentes a um padrão em um determinado diretório.
# INÍCIO DE SCRIPT
arquivos var str
var str dir
Set $ ??files = "* .cpp" # <===================== Defina o seu padrão de nome de arquivo aqui.
set $ dir = "C: / myproject". # <===================== Definir o diretório do projeto aqui
# Get a lista de arquivos em fileList variável.
var str fileList
encontrar arquivos -RN ($ files) dir ($ dir)> $ fileList
variáveis ??# Declare onde vamos salvar a contagem de arquivos individuais.
var int c # todas as linhas
var int nb # linhas não-branco
variáveis ??# Declare onde vamos salvar as contagens totais para todos os arquivos.
var int Totalc # soma total de todas as linhas
var int totalnb # soma total de todas as linhas não estão em branco
variável # Declare onde iremos armazenar contagem de arquivos.
var int fileCount
# Nós iremos guardar o nome do arquivo que estamos a trabalhar actualmente, a seguir.
arquivo var str
# Go através do $ fileList um por um arquivo.
while ($ fileList <> "")
fazer
# Extraia o arquivo seguinte.
lex "1" $ fileList> $ file
# verificar se este é um arquivo simples. Nós não estamos interessados ??em diretórios.
af $ file> nulo # Nós não queremos ver a saída.
# Só queremos definir a variável $ ftype.
if ($ ftype == "f")
fazer
# Sim, este é um arquivo simples.
# Increment file count.<br>
set $fileCount = $fileCount+1<br>
# Collect the content of $file in $content<br>
var str content # Content of one file at a time<br>
repro $file >$content<br>
# Get count and non-blank count.<br>
set $c={len -e $content}<br>
set $nb={len $content}<br>
echo -e "File: " $file ", Total Count: " $c ", Non-blank Count: " $nb<br>
# Update total counts.<br>
set $totalc = $totalc + $c<br>
set $totalnb = $totalnb + $nb<br>
Concluído
endif
feito
Mostrar soma-totais
echo "********************************************* ************************************************** *********************************** "
echo "Contagem Total de todas as linhas: \ t" $ Totalc "\ tTotal Conde de linhas não-branco: \ t" $ totalnb "Total de arquivos:" $ fileCount
echo "************************************************ ************************************************** ******************************** "
# Fim do script
Se você quiser contagens de linha em arquivos modificados no ano de 2008 somente, add ($ fmtime> = "2008"), etc.
Se você não tem biterscripting, obtê-lo de .com.
Não é um script simples, mas CCCC (C e C ++ Código Counter) foi em torno de um tempo e ele funciona muito bem para mim.
Eu tenho um programa chamado scc
que retira comentários C (e comentários C ++, embora com C99 eles são o mesmo). Aplicar que além de um filtro para remover as linhas em branco e, se assim se desejar, as linhas que contêm apenas as cintas de abrir e fechar, para gerar a contagem de linha. Eu usei isso em projetos internos - não é necessário para os aparelhos de abertura / fecho de desconto. Esses scripts eram mais complexas, comparando o código fonte para duas versões diferentes de um projeto substancial armazenados em ClearCase. Eles também fizeram estatísticas sobre os arquivos adicionados e removidos, e em linhas adicionadas e removidas a partir de arquivos comuns, etc.
Sem contar aparelho faz uma grande diferença:
Black JL: co -q -p scc.c | scc | sed '/^[ ]*$/d' | wc -l
208
Black JL: co -q -p scc.c | scc | sed '/^[ {}]*$/d' | wc -l
144
Black JL: co -p -q scc.c | wc -l
271
Black JL:
Assim, 144 linhas sob suas regras; 208 contagem linhas cinta de abrir e fechar; 271 contagem de tudo.
Lemme saber se você quer o código para scc
(Enviar e-mail para o primeiro ponto última at gmail dot com). É 13 KB de arquivo compactado incluindo página do homem, teste de tortura, e alguns arquivos de biblioteca.
@ litb comentou que alças 'cpp -fpreprocessed -P file
' decapagem de
comentários. Na maior parte faz. No entanto, quando eu executá-lo no teste de estresse
para SCC, ele reclama quando (na minha opinião) não deve:
SCC has been trained to handle 'q' single quotes in most of
the aberrant forms that can be used. '\0', '\', '\'', '\\
n' (a valid variant on '\n'), because the backslash followed
by newline is elided by the token scanning code in CPP before
any other processing occurs.
Quando o CPP do GCC 4.3.2 processos disto, ele reclama (alerta):
SCC has been trained to handle 'q' single quotes in most of
<stdin>:2:56: warning: missing terminating ' character
the aberrant forms that can be used. '\0', '\', '\'', '\\
<stdin>:3:27: warning: missing terminating ' character
n' (a valid variant on '\n'), because the backslash followed
by newline is elided by the token scanning code in CPP before
any other processing occurs.
Seção 5.1.1.2 Fases de tradução da norma C99 diz:
A precedência entre as regras de sintaxe de tradução é especificado pelas seguintes fases. ( Nota de rodapé 5 )
caracteres de vários bytes do arquivo de origem física são mapeados, em uma implementação-definido forma, para o conjunto de caracteres fonte (introdução de caracteres de nova linha para indicadores de fim-de-linha), se necessário. Trigraph sequências são substituídos pelos representações internas de um carácter correspondente.
Cada instância de um caractere de barra invertida () imediatamente seguido por uma nova linha personagem é excluído, splicing linhas de código físicas para formar linhas de origem lógicas. Apenas a última barra invertida em qualquer linha fonte física são elegíveis para fazer parte de tal splicing um. Um arquivo de origem que não está vazio deve terminar em um caractere de nova linha, que não será imediatamente precedido por uma barra invertida antes de qualquer splicing ocorre.
Nota de rodapé 5 é:
(5) Implementações deve se comportar como se ocorrer essas fases distintas, mesmo embora muitos são tipicamente dobrada em conjunto na prática.
Por isso, na minha opinião, CPP é manuseio incorreto fase dois no exemplo de texto. Ou, pelo menos, o aviso não é o que eu quero -. A construção é válido C e não é auto-evidente que o aviso é garantido
Com certeza, é um caso extremo, e são permitidos avisos extras. Mas seria irritar The Living Daylights fora de mim. Se eu não tivesse minha própria possivelmente melhor ferramenta, para o trabalho, em seguida, usando 'cpp -fpreprocessed -P
' faria - é um caso extremo de ponta que eu estou reclamando (e, pode ser legítimo argumentar que é mais provável que não é um problema do que não - embora uma heurística melhor seria observar que a linha foi emendado eo resultado foi uma constante caractere único legítimo e, portanto, a reclamação deve ser suprimida, se o resultado não foi uma única constante caráter legítimo, em seguida, o denúncia deve ser produzido (no meu caso de teste - é certo que um teste de tortura -. CPP produz 13 problemas, principalmente relacionados com o que eu estou reclamando, onde SCC produz corretamente 2).
(I observar que o '-P
' consegue suprimir um '#line
' directiva na saída que aparece quando a opção for omitida.)