Counting lines of code in Prolog (source code)
Author Message
Counting lines of code in Prolog (source code)

/*
* After looking at the Prolog-1000 listing, I decided to post
* my line-counting program to encourage a consistent method of
* measuring Prolog source-code size.  As everyone knows, a
* "line of code" is a pretty meaningless measurement. However,
* in good Prolog style, a line usually corresponds to a single goal.
*
* Even a cut should be given a line of its own. It is
* certainly as *important* as any other line of code in its
* implications. Just because we get used to seeing something
* doesn't necessarily mean that we should bury it!
*
* As an extreme example, my programs considers the following
* to be seven lines (goals) of code.
*
*  head(X,Y) :- ( X =:= 0 -> p(X,Y) ; q(X,Y) ), !.
*
* Calling this 7 lines of code is my way of saying that it
* should have been written as:
*
*        ( X =:= 0 ->
*          p(X,Y)
*        ;
*          q(X,Y)
*        ),
*        !.
*
*  This is an extreme example and a little misleading since
* the -> is counted as a goal even though it doesn't have its
* own line and the but the final ) is not counted, though it does.
* So the 7 does not correspond to the actual seven lines of
* code shown here, but the correspondence remains close.
* This method of counting still shows me a 10:1 improvement
* in source-codes size over C programming even though it
* is *very* conservative when you contrast it with a
* "line of code" in C which might look like:
*
*   for (i=0,j=MACRO(L,i); i < NCOUNT ; i++, j--)
*
* Here is the source code for a Goal/Clause/Predicate counter
* for Prolog programs. Below is a typical usage:
*
*  % count count.pl
*  count.pl       :  81  Lines(goals)   13 Predicates    29 Clauses
*
*  Total:   29 Clauses 13 Predicates 81 Lines (goals)
*
*  % count count.pl ccount.pl opt.pl
*  count.pl       :   81 Lines(goals)   13  Predicates     29  Clauses
*  ccount.pl      :   28 Lines(goals)   8   Predicates     8   Clauses
*  opt.pl         :   6  Lines(goals)   1   Predicates     1   Clauses
*
*  Total:   38 Clauses 22 Predicates 115 Lines (goals)
*

*/

runtime_entry(start) :-   % Equivalent of C main() entry point
unix(argv(Files)),    % Files = list of the command line arguments
each(Files),
total.

total :-
findall(stat(C,P,L),stat(C,P,L),Stats),
sum(Stats,stat(0,0,0),stat(C,P,L)),
format('~nTotal:~+ ~d Clauses~+ ~d Predicates~+ ~d Lines (goals)~n',[C,P,L]).

sum([],X,X).
sum([stat(A,B,C)|Ss],stat(A1,B1,C1),Total) :-
NA is A+A1,
NB is B+B1,
NC is C+C1,
sum(Ss,stat(NA,NB,NC),Total).

each([]).
each([File|Files]) :-
see(File),
format('~a~20|: ',[File]),
process(T,xxx,0,0,0),
seen,
each(Files).

process(end_of_file,_,Clauses,Predicates,Lines) :- !,
format('~24|~d~29| Lines(goals)   ~d~50| Predicates     ~d~70| Clauses~n',
[Lines, Predicates, Clauses]),
assert(stat(Clauses,Predicates,Lines)).

process(Cl,Prev,Clauses,Predicates,Lines) :-
!,
C is Clauses + 1,
process(Next,Cl,C,Predicates,L).
process(Pr,_,Clauses,Predicates,Lines) :-
P is Predicates + 1,
C is Clauses + 1,
process(Next,Pr,C,P,L).

op(A,B,C),
Out is In + 1.

arg(2,Clause,Body),
nonvar(Body),
( functor(Body,',',2)
; functor(Body,';',2)
; functor(Body,'->',2)
),
!,
Next is In + 1, % One for the head

Out is In + 1.

!,
Out is In + 1.

!,
Next is In + 1,
!,