After the signature block, please find the new AdaGIDe statistics counter
source (in Ada) that counts semicolons, lines, and other useful things.
Feel free to contribute new statistics.
Note in particular that semicolons inside character literals, strings and
comments are not counted.
This will appear in the next release of AdaGIDE (available at
http://wuarchive.wustl.edu/languages/ada/swtools/adagide)
in a day or so.
--Martin
--------------------------------------
Martin C. Carlisle,
Asst Prof of Computer Science
US Air Force Academy
[log in to unmask]
DISCLAIMER: The content of this message contains the author's opinions, and
does not reflect the policy of the US Air Force Academy or US Government.
---------------------------------------
---------------------------------------------------------------
--
-- ADA GNAT INTEGRATED DEVELOPMENT ENVIRONMENT (AdaGIDE)
--
-- COUNT.ADB
-- Description : compute Ada statistics
--
-- By: Dr. Martin C. Carlisle
--
-- Original Copyright (C) 1999 Martin C. Carlisle
-- This is a derivative work by:
-- US Air Force Academy Department of Computer Science
--
-- AdaGIDE is free software; you can redistribute it and/or
-- modify it under terms of the GNU General Public License
-- as published by the Free Software Foundation and modified
-- below; either version 2, or (at your option) any later version.
-- AdaGIDE is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty
-- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-- See the GNU General Public License for more details.
-- You should have received a copy of the GNU General Public
-- License distributed with AdaGIDE; see file COPYING.HTML. If
-- not, write to the Free Software Foundation, 59 Temple Place,
-- Suite 330, Boston, MA 02111-1307, USA.
--
---------------------------------------------------------------
with Ada.Text_Io;
use Ada.Text_Io;
with Ada.Integer_Text_Io;
use Ada.Integer_Text_Io;
with Ada.Command_Line;
use Ada.Command_Line;
with Ada.Strings.Unbounded;
with Ada.Strings.Fixed;
procedure Count is
procedure Usage is
begin
Put_Line("Usage: " & Command_Name & " file1 [file2...]");
end Usage;
-- Get a line, no matter how long it is.
-- Could use recursion here, but instead I'm using
-- an unbounded string
function Get_Line (
File : File_Type )
return String is
Part : String (1 .. 256);
Last : Natural;
Long : Ada.Strings.Unbounded.Unbounded_String;
use type Ada.Strings.Unbounded.Unbounded_String;
begin
Get_Line(File, Part, Last);
if Last = Part'Last then
Long := Ada.Strings.Unbounded.To_Unbounded_String(Part);
while Last=Part'Last loop
Get_Line(File,Part,Last);
Long := Long & Part(1..Last);
end loop;
return Ada.Strings.Unbounded.To_String(Long);
else
return Part(1..Last);
end if;
end Get_Line;
procedure Process_File (
Name : in String ) is
Semicolons : Natural := 0;
Lines_Ending_In_Semicolon : Natural := 0;
Lines : Natural := 0;
Blank_Lines : Natural := 0;
Comment_Lines : Natural := 0;
File : File_Type;
begin
Put_Line("FILE: " & Name);
Open(
File => File,
Name => Name,
Mode => In_File);
while not End_Of_File(File) loop
declare
Line : String := Get_Line (File);
First_Char : Natural := Ada.Strings.Fixed.Index_Non_Blank
(Line);
Comment_Location : Natural := Ada.Strings.Fixed.Index (Source
=> Line, Pattern => "--");
begin
Lines := Lines + 1;
if First_Char=0 then
Blank_Lines := Blank_Lines + 1;
elsif First_Char = Comment_Location then
Comment_Lines := Comment_Lines + 1;
else
-- we must use a state machine to walk through the string
-- if we're here we know that we have neither a comment
-- nor a blank line
-- count semicolons if not inside strings, stop at comment
declare
type State is
(In_String,
Code,
Minus);
Current_State : State := Code;
I : Natural;
Last_Character : Natural;
begin
I := Line'First;
while I <= Line'Last loop
case Line(I) is
when ''' =>
-- check for character literal
if Current_State/=In_String then
Current_State := Code; -- no longer in minus
if i+2<=Line'Last and then
Line(i+2) = ''' then
i:=i+2; -- go past char literal
end if;
end if;
when '-' =>
if Current_State=Code then
Current_State := Minus;
elsif Current_State = Minus then
I := I - 1; -- see below
exit; -- start of comment
end if;
when '"' =>
if Current_State=In_String then
Current_State := Code;
else
Current_State := In_String;
end if;
when ';' =>
if Current_State /= In_String then
Semicolons := Semicolons + 1;
end if;
when others =>
null;
end case;
I := I + 1;
end loop;
-- at this point, i is either one past end of line
-- or at the first - of a comment
-- in either case, check if semicolon is last
-- non-blank of Line(Line'First..i-1)
-- note we know line has at least one non-blank
Last_Character := Ada.Strings.Fixed.Index_Non_Blank(
Source => Line (Line'First .. I - 1),
Going => Ada.Strings.Backward);
if Line(Last_Character) = ';' then
Lines_Ending_In_Semicolon :=
Lines_Ending_In_Semicolon
+ 1;
end if;
end;
end if;
end;
end loop;
Close(File);
-- now that we have looped through whole file, print out the stats
Put("Total Lines: ");
Put(Lines);
New_Line;
Put("Lines ending w/semicolon: ");
Put(Lines_Ending_In_Semicolon);
New_Line;
Put("Blank Lines: ");
Put(Blank_Lines);
New_Line;
Put("Comment Lines: ");
Put(Comment_Lines);
New_Line;
Put("Non-blank non-comment lines: ");
Put(Lines-(Blank_Lines+Comment_Lines));
New_Line;
Put("Semicolons: ");
Put(Semicolons);
New_Line(2);
exception
when Name_Error =>
Put_Line("File not found");
when Status_Error|Use_Error =>
Put_Line("Error reading file");
end Process_File;
begin
Put_Line("Ada Statistics Counter 1.0");
Put_Line("October 14, 1999");
Put_Line("By: Martin C. Carlisle");
Put_Line("[log in to unmask]");
New_Line;
if Argument_Count < 1 then
Usage;
return;
end if;
for i in 1..Argument_Count loop
Process_File(Argument(i));
end loop;
end Count;
|