代码之家  ›  专栏  ›  技术社区  ›  Markus Schnell

计算nloc的简单脚本?

  •  6
  • Markus Schnell  · 技术社区  · 17 年前

    你知道一个简单的计算非直瞄系统的脚本吗?脚本应该计算C代码的行数。它不应该只计算空行或带大括号的行。但也不需要过于精确。

    14 回复  |  直到 11 年前
        1
  •  7
  •   Johannes Schaub - litb    17 年前

    我会用 AWK 和; CPP (预处理器)& 厕所 . awk删除所有大括号和空白,预处理器删除所有注释,wc计算行数:

    find . -name \*.cpp -o -name \*.h | xargs -n1 cpp -fpreprocessed -P | 
        awk '!/^[{[:space:]}]*$/' | wc -l
    

    如果要包含评论:

    find . -name \*.cpp -o -name \*.h | xargs awk '!/^[{[:space:]}]*$/' | wc -l
    
        2
  •  2
  •   PhiLho    17 年前

    在网上查找nloc时,我发现大部分是“无注释的代码行”。
    您没有指定是否必须跳过注释…
    因此,如果我坚持您当前的消息,那么Perl中的以下一个行程序应该能够完成这项工作:

    perl -pe "s/^\s*[{}]?\s*\n//" Dialog.java | wc -l
    

    我可以扩展它来处理行注释:

    perl -pe "s#^\s*[{}]?\s*\n|^\s*//.*\n##" Dialog.java | wc -l
    

    或者也许

    perl -pe "s#^\s*(?:[{}]?\s*|//.*)\n##" Dialog.java | wc -l
    

    处理块注释要稍微复杂一些(我不是Perl专家!).

    [编辑]明白了…第一部分可能会改进(更短)。做实验很有趣。

    perl -e "$x = join('', <>); $x =~ s#/\*.*?\*/##gs; print $x" Dialog.java | perl -pe "s#^\s*(?:[{}]?\s*|//.*)\n##" | wc -l
    

    附:我使用双引号是因为我在Windows上测试过…

        3
  •  1
  •   Tim Ring    17 年前

    查看Visual Studio的dpack插件。它具有任何解决方案/项目的统计报告。

        4
  •  1
  •   schnaader    17 年前

    不是脚本,但您可以尝试此命令行开源工具: NLOC

        5
  •  1
  •   zendar    17 年前

    Source monitor 是免费的源代码分析软件。它是Windows应用程序,但也可以使用命令行中的参数运行。

    它可以分析C++、C、C、VB.NET、Java、Delphi、VisualBasic(VB6)或HTML。

        6
  •  1
  •   Greg Hewgill    17 年前

    Ohloh 免费提供 Ohcount 它计算代码行和注释。

        7
  •  1
  •   flolo    17 年前

    如果注释仍然在中,那么标准的Unix工具就足够了:

    grep  -x -v "[[:space:]}{]*" files.c  | wc
    
        8
  •  1
  •   hangy    17 年前

    SLOCCOunt 不是一个简单的脚本,它的功能远远超过了您需要的功能。但是,它是已经提到的ohcount和nloc的一个强大的替代方案。:)

        9
  •  1
  •   jkramer    17 年前

    我通常只是这样做:

    grep -vc '^$' (my files)
    

    只有当空行确实是空的(没有空格)时才有效。对我来说足够了。

        10
  •  1
  •   Steve Fallows    17 年前

    Locmetrics 很好用。

        11
  •  1
  •   jfs    17 年前

    下面是一个简单的Perl脚本 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
    
        12
  •  0
  •   mike    17 年前

    下面的脚本将获取与给定目录中的模式匹配的所有文件的计数。

    #脚本开始

    VAR STR文件
    VAR STR DIR

    设置$files=“*.cpp”<=======set your file name pattern here。
    设置$dir=“c:/myProject”<=================在此处设置项目目录。

    #获取变量文件列表中的文件列表。
    var str文件列表
    查找-rn文件($files)dir($dir)>$filelist

    #声明变量,我们将在其中保存单个文件的计数。
    var int c所有行
    var int nb非空行

    #声明变量,我们将在其中保存所有文件的总计数。
    var int totalc所有行的总和
    var int totalnb所有非空白行的总和

    #声明我们将在其中存储文件计数的变量。
    var int文件计数

    #我们将在下面存储当前正在处理的文件的名称。
    VAR STR文件

    #逐个浏览$filelist文件。
    而($fileList<gt;“)

    #提取下一个文件。
    lex“1”$filelist>$file

    #检查这是否是平面文件。我们对目录不感兴趣。
    af$file>空我们不想看到输出。
    #我们只想设置$ftype变量。
    如果($ftype==“f”)

    #是的,这是一个平面文件。

     # 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>
    

    完成
    菊苣

    完成

    显示总和

    echo“…………………………………………………………………………………………………………………………………………………………………………………………
    echo“所有行的总数:\t”$totalc“,\t非空行的总数:\t”$totalnb“,总文件数:”$filecount
    echo“…………………………………………………………………………………………………………………………………………………………………………………………

    脚本末尾

    如果只想在2008年修改的文件中进行行计数,请添加($fmtime>=“2008”)等。

    如果没有biterscripting,请从.com获取。

        13
  •  0
  •   florin    17 年前

    不是一个简单的脚本,但是 CCCC (C和C++代码计数器)已经有一段时间了,它对我来说非常有用。

        14
  •  0
  •   Jonathan Leffler    17 年前

    我有个节目叫 scc 条带C注释(和C++注释,虽然与C99是相同的)。再加上一个过滤器,删除空白行,如果需要,还可以删除只包含左括号和右括号的行,以生成行计数。我在内部项目中使用过这个方法——不需要对开/闭大括号进行折扣。这些脚本更加复杂,比较了存储在ClearCase中的一个重要项目的两个不同版本的源代码。他们还统计了添加和删除的文件,以及从普通文件中添加和删除的行等。

    不计算大括号有很大不同:

    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:
    

    所以,按照你的规则,144行;208行计算开括号和闭括号;271行计算所有内容。

    让我知道你是否想要密码 鳞癌 (最后在gmail.com向第一个点发送电子邮件)。它是13kb的gzipped tar文件,包括手册页、酷刑测试和一些库文件。


    @李特评论说 cpp -fpreprocessed -P file '处理剥离 评论。主要是这样。但是,当我在压力测试中运行它时 对于SCC,当(在我看来)它不应该:

    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.
    

    当GCC 4.3.2中的CPP处理此问题时,它会抱怨(警告):

    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.
    

    第5.1.1.2节C99标准的翻译阶段规定:

    翻译的语法规则之间的优先顺序由以下阶段指定。( 脚注5 )

    1. 在定义的实现中,物理源文件多字节字符被映射 方式,到源字符集(为 行末指示器)如有必要。三角图序列替换为 相应的单字符内部表示。

    2. 反斜杠字符()的每个实例紧跟一行新行 删除字符,将物理源行拼接成逻辑源行。 只有任何物理源行上的最后一个反斜杠才有资格成为部件。 这种结合。非空的源文件应以新行字符结尾, 其前面不得紧跟反斜杠字符。 进行拼接。

    脚注5是:

    (5)实施应表现为这些单独的阶段发生,甚至 尽管在实践中很多都是折叠在一起的。

    因此,在我看来,CPP在示例文本的第二阶段处理不当。或者,至少,警告不是我想要的-构造是有效的C,并且警告是有必要的,这是不明显的。

    当然,这是一个边缘情况,允许额外的警告。但这会使我的日常生活感到厌烦。如果我没有自己的,可能更好的工作工具,那么使用' cpp -fpreprocessed -P “会的——这是我抱怨的一个极端的边缘情况(而且,有理由认为存在问题的可能性比没有问题的可能性更大——尽管更好的启发式方法可以观察到行是拼接的,结果是一个合法的单字符常量,因此投诉应该被抑制;如果结果是它不是一个合法的单一字符常量,那么应该产生投诉。(在我的测试案例中——诚然是一个酷刑测试——CPP产生了13个问题,主要与我抱怨的问题有关,SCC正确地产生了2个问题。)

    (我观察到 -P '设法抑制a' #line '在省略选项时出现的输出中的指令。)