---------------------------------------------------------------------------- -- get_entities (get_entities.adb) -- -- Copyright (C) 2013, Brian Drummond -- -- This file is part of the ghdl-updates project. -- -- get_entities is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 2 of the License, or -- (at your option) any later version. -- -- get_entities 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 -- along with get_entities. If not, see . ---------------------------------------------------------------------------- with Ada.Text_Io; use Ada.Text_IO; with Ada.Characters.Handling; with Ada.Strings.Fixed; with Ada.Strings.Maps; with Ada.Strings.Unbounded; with Ada.Directories; with Ada.Command_Line; procedure get_entities is function Valid_Test(Name : in String) return boolean is use Ada.Directories; use Ada.Characters.Handling; begin return Extension(To_Lower(Name)) = "vhd" or Extension(To_Lower(Name)) = "vhdl"; end Valid_Test; procedure Get_Top_Entities(Test_Name : in String) is use Ada.Text_Io; use Ada.Strings.Fixed; use Ada.Characters.Handling; use Ada.Strings.Unbounded; File : File_Type; function Get_End(Line : in String) return Natural is Comment : natural := Index(Line,"--"); begin if Comment = 0 then return Line'last; else return Comment - 1; end if; end Get_End; type State_Type is (Idle, Have_Entity, Have_Name, In_Entity, Have_End); State : State_Type; Top_Level_Entity : Boolean; Name : Unbounded_String; Last_Entity : Unbounded_String; begin -- Return the name of all top-level entities in the file. -- Report on stderr, a malformed one -- "malformed" means not conforming to the expectations of this simple parser. -- A top level entity has the form -- Entity is -- -- end {entity} Open(File, In_File, Test_Name); State := Idle; loop declare -- strip name of blanks etc... CharSet : constant Ada.Strings.Maps.Character_Ranges := (('A','Z'), ('a','z'), ('0','9'), ('_','_')); function Token(Source, Name : String; From : positive := 1) return natural is use Ada.Strings.Maps; Pos : natural := Index(Source, Name, From => From); begin -- Look in Source for Name, either surrounded by whitespace or at the start or end of a line if Pos = 0 or Pos = 1 or Pos + Name'Length > Source'Length then return Pos; elsif not is_in (Source(Pos - 1), To_Set(CharSet)) and not is_in (Source(Pos + Name'Length), To_Set(CharSet)) then return Pos; else return 0; end if; end Token; function Strip_Quoted(Raw : String) return String is temp : String(Raw'range); t : natural := Raw'first; copy : Boolean := true; begin -- Eliminate quoted text for i in Raw'range loop if copy then if Raw(i) = '"' then copy := not copy; else temp(t) := Raw(i); t := t + 1; end if; else if Raw(i) = '"' then copy := not copy; end if; end if; end loop; if t > Raw'last then t := Raw'last; end if; return temp(Raw'first .. t); end Strip_Quoted; Line : String := Get_Line (File); -- line based to strip off comments EndLine : natural := Get_End (Line); Raw : String := To_Lower(Line (1 .. EndLine)); Code : String := Strip_Quoted(Raw); -- positions of specific strings in a line. Ent : Natural := Token(Code, "entity"); Port : Natural := Token(Code, "port"); End_Pos : Natural := Token(Code, "end"); I : Natural; -- position of "is" in current line Name_s : Natural; -- start of a possible entity name Name_e : Natural; -- end of a possible entity name Name_n : Natural; -- start of next name (should be "is") Dot : Natural; -- position of "." indicating qualified name, e.g. entity instantiation procedure Get_Name is begin Name_e := Index(Code, Ada.Strings.Maps.To_Set(CharSet), Test => Ada.Strings.Outside, From => Name_s); if Name_e = 0 then Name_e := Code'last; end if; --Put_Line("Name : " & To_S(Name) & " " -- & natural'image(Name_s) & " " & natural'image(Name_e) -- & natural'image(Code'last)); if Name_e < Code'last then Name_n := Index(Code, Ada.Strings.Maps.To_Set(CharSet), From => Name_e); else Name_n := 0; end if; I := Token(Code, "is", From => Name_e); Dot := Index(Code, ".", From => Name_e); if Name_e < Name_s then Put_Line(Standard_Error, "Malformed name : " & Code); end if; Name := To_Unbounded_String (Code (Name_s .. Name_e-1)); if I = 0 then -- "is" must be on a subsequent line State := Have_Name; elsif Name_n = I then -- next word is "is" State := In_Entity; elsif Dot < Name_n and Dot >= Name_e then -- direct instantiation ... reject State := Idle; elsif Name_n < I then Put_Line(Standard_Error, "Name error : file " & Test_Name); Put_Line(Standard_Error, "Entity : """ & Code(Name_s .. I-1) & """ not valid"); -- raise Program_Error; end if; end Get_Name; begin case State is when Idle => if Ent /= 0 then -- Put_Line(Code); Top_Level_Entity := True; Name_s := Index(Code, Ada.Strings.Maps.To_Set(CharSet), From => Ent + 6); if Name_s = 0 then -- entity name must be on a subsequent line State := Have_Entity; else Get_Name; end if; end if; when Have_Entity => Name_s := Index(Code, Ada.Strings.Maps.To_Set(CharSet), From => Ent + 6); if Name_s > 0 then Get_Name; end if; when Have_Name => if I > 0 then State := In_Entity; end if; when In_Entity => -- wait for End, handle Port; -- NB the End may not be End Entity, but whatever it Ends, it must follow the port list -- so we may stop looking for a port list when we see it. if Port > 0 then Top_Level_Entity := False; end if; if End_Pos > 0 then State := Have_End; end if; when Have_End => if Top_Level_Entity then -- write name to stdout Last_Entity := Name; end if; State := Idle; end Case; exit when End_Of_File (File); end; end loop; if Last_Entity /= "" then Put_Line (To_String (Last_Entity)); end if; Close(File); end Get_Top_Entities; procedure Usage is begin Put_Line(Standard_Error, "Usage : " & Ada.Command_Line.Command_Name & " "); end Usage; begin if Ada.Command_Line.Argument_Count = 0 then raise Program_Error; end if; Get_Top_Entities(Ada.Command_Line.Argument(1)); exception when Program_Error => Usage; end get_entities;