------------------------------------------------------------------------------ -- -- -- GNAT COMPILER COMPONENTS -- -- -- -- P R J . D E C T -- -- -- -- B o d y -- -- -- -- Copyright (C) 2001-2016, Free Software Foundation, Inc. -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 3, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT 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 GNAT; see file COPYING3. If not, go to -- -- http://www.gnu.org/licenses for a complete copy of the license. -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ with Err_Vars; use Err_Vars; with Opt; use Opt; with Prj.Attr; use Prj.Attr; with Prj.Attr.PM; use Prj.Attr.PM; with Prj.Err; use Prj.Err; with Prj.Strt; use Prj.Strt; with Prj.Tree; use Prj.Tree; with Snames; with Uintp; use Uintp; with GNAT; use GNAT; with GNAT.Case_Util; use GNAT.Case_Util; with GNAT.Spelling_Checker; use GNAT.Spelling_Checker; with GNAT.Strings; package body Prj.Dect is type Zone is (In_Project, In_Package, In_Case_Construction); -- Used to indicate if we are parsing a package (In_Package), a case -- construction (In_Case_Construction) or none of those two (In_Project). procedure Rename_Obsolescent_Attributes (In_Tree : Project_Node_Tree_Ref; Attribute : Project_Node_Id; Current_Package : Project_Node_Id); -- Rename obsolescent attributes in the tree. When the attribute has been -- renamed since its initial introduction in the design of projects, we -- replace the old name in the tree with the new name, so that the code -- does not have to check both names forever. procedure Check_Attribute_Allowed (In_Tree : Project_Node_Tree_Ref; Project : Project_Node_Id; Attribute : Project_Node_Id; Flags : Processing_Flags); -- Check whether the attribute is valid in this project. In particular, -- depending on the type of project (qualifier), some attributes might -- be disabled. procedure Check_Package_Allowed (In_Tree : Project_Node_Tree_Ref; Project : Project_Node_Id; Current_Package : Project_Node_Id; Flags : Processing_Flags); -- Check whether the package is valid in this project procedure Parse_Attribute_Declaration (In_Tree : Project_Node_Tree_Ref; Attribute : out Project_Node_Id; First_Attribute : Attribute_Node_Id; Current_Project : Project_Node_Id; Current_Package : Project_Node_Id; Packages_To_Check : String_List_Access; Flags : Processing_Flags); -- Parse an attribute declaration procedure Parse_Case_Construction (In_Tree : Project_Node_Tree_Ref; Case_Construction : out Project_Node_Id; First_Attribute : Attribute_Node_Id; Current_Project : Project_Node_Id; Current_Package : Project_Node_Id; Packages_To_Check : String_List_Access; Is_Config_File : Boolean; Flags : Processing_Flags); -- Parse a case construction procedure Parse_Declarative_Items (In_Tree : Project_Node_Tree_Ref; Declarations : out Project_Node_Id; In_Zone : Zone; First_Attribute : Attribute_Node_Id; Current_Project : Project_Node_Id; Current_Package : Project_Node_Id; Packages_To_Check : String_List_Access; Is_Config_File : Boolean; Flags : Processing_Flags); -- Parse declarative items. Depending on In_Zone, some declarative items -- may be forbidden. Is_Config_File should be set to True if the project -- represents a config file (.cgpr) since some specific checks apply. procedure Parse_Package_Declaration (In_Tree : Project_Node_Tree_Ref; Package_Declaration : out Project_Node_Id; Current_Project : Project_Node_Id; Packages_To_Check : String_List_Access; Is_Config_File : Boolean; Flags : Processing_Flags); -- Parse a package declaration. -- Is_Config_File should be set to True if the project represents a config -- file (.cgpr) since some specific checks apply. procedure Parse_String_Type_Declaration (In_Tree : Project_Node_Tree_Ref; String_Type : out Project_Node_Id; Current_Project : Project_Node_Id; Flags : Processing_Flags); -- type is ( { , } ) ; procedure Parse_Variable_Declaration (In_Tree : Project_Node_Tree_Ref; Variable : out Project_Node_Id; Current_Project : Project_Node_Id; Current_Package : Project_Node_Id; Flags : Processing_Flags); -- Parse a variable assignment -- := ; OR -- : := ; ----------- -- Parse -- ----------- procedure Parse (In_Tree : Project_Node_Tree_Ref; Declarations : out Project_Node_Id; Current_Project : Project_Node_Id; Extends : Project_Node_Id; Packages_To_Check : String_List_Access; Is_Config_File : Boolean; Flags : Processing_Flags) is First_Declarative_Item : Project_Node_Id := Empty_Node; begin Declarations := Default_Project_Node (Of_Kind => N_Project_Declaration, In_Tree => In_Tree); Set_Location_Of (Declarations, In_Tree, To => Token_Ptr); Set_Extended_Project_Of (Declarations, In_Tree, To => Extends); Set_Project_Declaration_Of (Current_Project, In_Tree, Declarations); Parse_Declarative_Items (Declarations => First_Declarative_Item, In_Tree => In_Tree, In_Zone => In_Project, First_Attribute => Prj.Attr.Attribute_First, Current_Project => Current_Project, Current_Package => Empty_Node, Packages_To_Check => Packages_To_Check, Is_Config_File => Is_Config_File, Flags => Flags); Set_First_Declarative_Item_Of (Declarations, In_Tree, To => First_Declarative_Item); end Parse; ----------------------------------- -- Rename_Obsolescent_Attributes -- ----------------------------------- procedure Rename_Obsolescent_Attributes (In_Tree : Project_Node_Tree_Ref; Attribute : Project_Node_Id; Current_Package : Project_Node_Id) is begin if Present (Current_Package) and then Expression_Kind_Of (Current_Package, In_Tree) /= Ignored then case Name_Of (Attribute, In_Tree) is when Snames.Name_Specification => Set_Name_Of (Attribute, In_Tree, To => Snames.Name_Spec); when Snames.Name_Specification_Suffix => Set_Name_Of (Attribute, In_Tree, To => Snames.Name_Spec_Suffix); when Snames.Name_Implementation => Set_Name_Of (Attribute, In_Tree, To => Snames.Name_Body); when Snames.Name_Implementation_Suffix => Set_Name_Of (Attribute, In_Tree, To => Snames.Name_Body_Suffix); when others => null; end case; end if; end Rename_Obsolescent_Attributes; --------------------------- -- Check_Package_Allowed -- --------------------------- procedure Check_Package_Allowed (In_Tree : Project_Node_Tree_Ref; Project : Project_Node_Id; Current_Package : Project_Node_Id; Flags : Processing_Flags) is Qualif : constant Project_Qualifier := Project_Qualifier_Of (Project, In_Tree); Name : constant Name_Id := Name_Of (Current_Package, In_Tree); begin if Name /= Snames.Name_Ide and then ((Qualif = Aggregate and then Name /= Snames.Name_Builder) or else (Qualif = Aggregate_Library and then Name /= Snames.Name_Builder and then Name /= Snames.Name_Install)) then Error_Msg_Name_1 := Name; Error_Msg (Flags, "package %% is forbidden in aggregate projects", Location_Of (Current_Package, In_Tree)); end if; end Check_Package_Allowed; ----------------------------- -- Check_Attribute_Allowed -- ----------------------------- procedure Check_Attribute_Allowed (In_Tree : Project_Node_Tree_Ref; Project : Project_Node_Id; Attribute : Project_Node_Id; Flags : Processing_Flags) is Qualif : constant Project_Qualifier := Project_Qualifier_Of (Project, In_Tree); Name : constant Name_Id := Name_Of (Attribute, In_Tree); begin case Qualif is when Aggregate | Aggregate_Library => if Name = Snames.Name_Languages or else Name = Snames.Name_Source_Files or else Name = Snames.Name_Source_List_File or else Name = Snames.Name_Locally_Removed_Files or else Name = Snames.Name_Excluded_Source_Files or else Name = Snames.Name_Excluded_Source_List_File or else Name = Snames.Name_Interfaces or else Name = Snames.Name_Object_Dir or else Name = Snames.Name_Exec_Dir or else Name = Snames.Name_Source_Dirs or else Name = Snames.Name_Inherit_Source_Path or else (Qualif = Aggregate and then Name = Snames.Name_Library_Dir) or else (Qualif = Aggregate and then Name = Snames.Name_Library_Name) or else Name = Snames.Name_Main or else Name = Snames.Name_Roots or else Name = Snames.Name_Externally_Built or else Name = Snames.Name_Executable or else Name = Snames.Name_Executable_Suffix or else Name = Snames.Name_Default_Switches then Error_Msg_Name_1 := Name; Error_Msg (Flags, "%% is not valid in aggregate projects", Location_Of (Attribute, In_Tree)); end if; when others => if Name = Snames.Name_Project_Files or else Name = Snames.Name_Project_Path or else Name = Snames.Name_External then Error_Msg_Name_1 := Name; Error_Msg (Flags, "%% is only valid in aggregate projects", Location_Of (Attribute, In_Tree)); end if; end case; end Check_Attribute_Allowed; --------------------------------- -- Parse_Attribute_Declaration -- --------------------------------- procedure Parse_Attribute_Declaration (In_Tree : Project_Node_Tree_Ref; Attribute : out Project_Node_Id; First_Attribute : Attribute_Node_Id; Current_Project : Project_Node_Id; Current_Package : Project_Node_Id; Packages_To_Check : String_List_Access; Flags : Processing_Flags) is Current_Attribute : Attribute_Node_Id := First_Attribute; Full_Associative_Array : Boolean := False; Attribute_Name : Name_Id := No_Name; Optional_Index : Boolean := False; Pkg_Id : Package_Node_Id := Empty_Package; procedure Process_Attribute_Name; -- Read the name of the attribute, and check its type procedure Process_Associative_Array_Index; -- Read the index of the associative array and check its validity ---------------------------- -- Process_Attribute_Name -- ---------------------------- procedure Process_Attribute_Name is Ignore : Boolean; begin Attribute_Name := Token_Name; Set_Name_Of (Attribute, In_Tree, To => Attribute_Name); Set_Location_Of (Attribute, In_Tree, To => Token_Ptr); -- Find the attribute Current_Attribute := Attribute_Node_Id_Of (Attribute_Name, First_Attribute); -- If the attribute cannot be found, create the attribute if inside -- an unknown package. if Current_Attribute = Empty_Attribute then if Present (Current_Package) and then Expression_Kind_Of (Current_Package, In_Tree) = Ignored then Pkg_Id := Package_Id_Of (Current_Package, In_Tree); Add_Attribute (Pkg_Id, Token_Name, Current_Attribute); else -- If not a valid attribute name, issue an error if inside -- a package that need to be checked. Ignore := Present (Current_Package) and then Packages_To_Check /= All_Packages; if Ignore then -- Check that we are not in a package to check Get_Name_String (Name_Of (Current_Package, In_Tree)); for Index in Packages_To_Check'Range loop if Name_Buffer (1 .. Name_Len) = Packages_To_Check (Index).all then Ignore := False; exit; end if; end loop; end if; if not Ignore then Error_Msg_Name_1 := Token_Name; Error_Msg (Flags, "undefined attribute %%", Token_Ptr); end if; end if; -- Set, if appropriate the index case insensitivity flag else if Is_Read_Only (Current_Attribute) then Error_Msg_Name_1 := Token_Name; Error_Msg (Flags, "read-only attribute %% cannot be given a value", Token_Ptr); end if; if Attribute_Kind_Of (Current_Attribute) in All_Case_Insensitive_Associative_Array then Set_Case_Insensitive (Attribute, In_Tree, To => True); end if; end if; Scan (In_Tree); -- past the attribute name -- Set the expression kind of the attribute if Current_Attribute /= Empty_Attribute then Set_Expression_Kind_Of (Attribute, In_Tree, To => Variable_Kind_Of (Current_Attribute)); Optional_Index := Optional_Index_Of (Current_Attribute); end if; end Process_Attribute_Name; ------------------------------------- -- Process_Associative_Array_Index -- ------------------------------------- procedure Process_Associative_Array_Index is begin -- If the attribute is not an associative array attribute, report -- an error. If this information is still unknown, set the kind -- to Associative_Array. if Current_Attribute /= Empty_Attribute and then Attribute_Kind_Of (Current_Attribute) = Single then Error_Msg (Flags, "the attribute """ & Get_Name_String (Attribute_Name_Of (Current_Attribute)) & """ cannot be an associative array", Location_Of (Attribute, In_Tree)); elsif Attribute_Kind_Of (Current_Attribute) = Unknown then Set_Attribute_Kind_Of (Current_Attribute, To => Associative_Array); end if; Scan (In_Tree); -- past the left parenthesis if Others_Allowed_For (Current_Attribute) and then Token = Tok_Others then Set_Associative_Array_Index_Of (Attribute, In_Tree, All_Other_Names); Scan (In_Tree); -- past others else if Others_Allowed_For (Current_Attribute) then Expect (Tok_String_Literal, "literal string or others"); else Expect (Tok_String_Literal, "literal string"); end if; if Token = Tok_String_Literal then Get_Name_String (Token_Name); if Case_Insensitive (Attribute, In_Tree) then To_Lower (Name_Buffer (1 .. Name_Len)); end if; Set_Associative_Array_Index_Of (Attribute, In_Tree, Name_Find); Scan (In_Tree); -- past the literal string index if Token = Tok_At then case Attribute_Kind_Of (Current_Attribute) is when Optional_Index_Associative_Array | Optional_Index_Case_Insensitive_Associative_Array => Scan (In_Tree); Expect (Tok_Integer_Literal, "integer literal"); if Token = Tok_Integer_Literal then -- Set the source index value from given literal declare Index : constant Int := UI_To_Int (Int_Literal_Value); begin if Index = 0 then Error_Msg (Flags, "index cannot be zero", Token_Ptr); else Set_Source_Index_Of (Attribute, In_Tree, To => Index); end if; end; Scan (In_Tree); end if; when others => Error_Msg (Flags, "index not allowed here", Token_Ptr); Scan (In_Tree); if Token = Tok_Integer_Literal then Scan (In_Tree); end if; end case; end if; end if; end if; Expect (Tok_Right_Paren, "`)`"); if Token = Tok_Right_Paren then Scan (In_Tree); -- past the right parenthesis end if; end Process_Associative_Array_Index; begin Attribute := Default_Project_Node (Of_Kind => N_Attribute_Declaration, In_Tree => In_Tree); Set_Location_Of (Attribute, In_Tree, To => Token_Ptr); Set_Previous_Line_Node (Attribute); -- Scan past "for" Scan (In_Tree); -- Body or External may be an attribute name if Token = Tok_Body then Token := Tok_Identifier; Token_Name := Snames.Name_Body; end if; if Token = Tok_External then Token := Tok_Identifier; Token_Name := Snames.Name_External; end if; Expect (Tok_Identifier, "identifier"); Process_Attribute_Name; Rename_Obsolescent_Attributes (In_Tree, Attribute, Current_Package); Check_Attribute_Allowed (In_Tree, Current_Project, Attribute, Flags); -- Associative array attributes if Token = Tok_Left_Paren then Process_Associative_Array_Index; else -- If it is an associative array attribute and there are no left -- parenthesis, then this is a full associative array declaration. -- Flag it as such for later processing of its value. if Current_Attribute /= Empty_Attribute and then Attribute_Kind_Of (Current_Attribute) /= Single then if Attribute_Kind_Of (Current_Attribute) = Unknown then Set_Attribute_Kind_Of (Current_Attribute, To => Single); else Full_Associative_Array := True; end if; end if; end if; Expect (Tok_Use, "USE"); if Token = Tok_Use then Scan (In_Tree); if Full_Associative_Array then -- Expect ', or -- .' declare The_Project : Project_Node_Id := Empty_Node; -- The node of the project where the associative array is -- declared. The_Package : Project_Node_Id := Empty_Node; -- The node of the package where the associative array is -- declared, if any. Project_Name : Name_Id := No_Name; -- The name of the project where the associative array is -- declared. Location : Source_Ptr := No_Location; -- The location of the project name begin Expect (Tok_Identifier, "identifier"); if Token = Tok_Identifier then Location := Token_Ptr; -- Find the project node in the imported project or -- in the project being extended. The_Project := Imported_Or_Extended_Project_Of (Current_Project, In_Tree, Token_Name); if No (The_Project) and then not In_Tree.Incomplete_With then Error_Msg (Flags, "unknown project", Location); Scan (In_Tree); -- past the project name else Project_Name := Token_Name; Scan (In_Tree); -- past the project name -- If this is inside a package, a dot followed by the -- name of the package must followed the project name. if Present (Current_Package) then Expect (Tok_Dot, "`.`"); if Token /= Tok_Dot then The_Project := Empty_Node; else Scan (In_Tree); -- past the dot Expect (Tok_Identifier, "identifier"); if Token /= Tok_Identifier then The_Project := Empty_Node; -- If it is not the same package name, issue error elsif Token_Name /= Name_Of (Current_Package, In_Tree) then The_Project := Empty_Node; Error_Msg (Flags, "not the same package as " & Get_Name_String (Name_Of (Current_Package, In_Tree)), Token_Ptr); Scan (In_Tree); -- past the package name else if Present (The_Project) then The_Package := First_Package_Of (The_Project, In_Tree); -- Look for the package node while Present (The_Package) and then Name_Of (The_Package, In_Tree) /= Token_Name loop The_Package := Next_Package_In_Project (The_Package, In_Tree); end loop; -- If the package cannot be found in the -- project, issue an error. if No (The_Package) then The_Project := Empty_Node; Error_Msg_Name_2 := Project_Name; Error_Msg_Name_1 := Token_Name; Error_Msg (Flags, "package % not declared in project %", Token_Ptr); end if; end if; Scan (In_Tree); -- past the package name end if; end if; end if; end if; end if; if Present (The_Project) or else In_Tree.Incomplete_With then -- Looking for ' Expect (Tok_Apostrophe, "`''`"); if Token /= Tok_Apostrophe then The_Project := Empty_Node; else Scan (In_Tree); -- past the apostrophe Expect (Tok_Identifier, "identifier"); if Token /= Tok_Identifier then The_Project := Empty_Node; else -- If it is not the same attribute name, issue error if Token_Name /= Attribute_Name then The_Project := Empty_Node; Error_Msg_Name_1 := Attribute_Name; Error_Msg (Flags, "invalid name, should be %", Token_Ptr); end if; Scan (In_Tree); -- past the attribute name end if; end if; end if; if No (The_Project) then -- If there were any problem, set the attribute id to null, -- so that the node will not be recorded. Current_Attribute := Empty_Attribute; else -- Set the appropriate field in the node. -- Note that the index and the expression are nil. This -- characterizes full associative array attribute -- declarations. Set_Associative_Project_Of (Attribute, In_Tree, The_Project); Set_Associative_Package_Of (Attribute, In_Tree, The_Package); end if; end; -- Other attribute declarations (not full associative array) else declare Expression_Location : constant Source_Ptr := Token_Ptr; -- The location of the first token of the expression Expression : Project_Node_Id := Empty_Node; -- The expression, value for the attribute declaration begin -- Get the expression value and set it in the attribute node Parse_Expression (In_Tree => In_Tree, Expression => Expression, Flags => Flags, Current_Project => Current_Project, Current_Package => Current_Package, Optional_Index => Optional_Index); Set_Expression_Of (Attribute, In_Tree, To => Expression); -- If the expression is legal, but not of the right kind -- for the attribute, issue an error. if Current_Attribute /= Empty_Attribute and then Present (Expression) and then Variable_Kind_Of (Current_Attribute) /= Expression_Kind_Of (Expression, In_Tree) then if Variable_Kind_Of (Current_Attribute) = Undefined then Set_Variable_Kind_Of (Current_Attribute, To => Expression_Kind_Of (Expression, In_Tree)); else Error_Msg (Flags, "wrong expression kind for attribute """ & Get_Name_String (Attribute_Name_Of (Current_Attribute)) & """", Expression_Location); end if; end if; end; end if; end if; -- If the attribute was not recognized, return an empty node. -- It may be that it is not in a package to check, and the node will -- not be added to the tree. if Current_Attribute = Empty_Attribute then Attribute := Empty_Node; end if; Set_End_Of_Line (Attribute); Set_Previous_Line_Node (Attribute); end Parse_Attribute_Declaration; ----------------------------- -- Parse_Case_Construction -- ----------------------------- procedure Parse_Case_Construction (In_Tree : Project_Node_Tree_Ref; Case_Construction : out Project_Node_Id; First_Attribute : Attribute_Node_Id; Current_Project : Project_Node_Id; Current_Package : Project_Node_Id; Packages_To_Check : String_List_Access; Is_Config_File : Boolean; Flags : Processing_Flags) is Current_Item : Project_Node_Id := Empty_Node; Next_Item : Project_Node_Id := Empty_Node; First_Case_Item : Boolean := True; Variable_Location : Source_Ptr := No_Location; String_Type : Project_Node_Id := Empty_Node; Case_Variable : Project_Node_Id := Empty_Node; First_Declarative_Item : Project_Node_Id := Empty_Node; First_Choice : Project_Node_Id := Empty_Node; When_Others : Boolean := False; -- Set to True when there is a "when others =>" clause begin Case_Construction := Default_Project_Node (Of_Kind => N_Case_Construction, In_Tree => In_Tree); Set_Location_Of (Case_Construction, In_Tree, To => Token_Ptr); -- Scan past "case" Scan (In_Tree); -- Get the switch variable Expect (Tok_Identifier, "identifier"); if Token = Tok_Identifier then Variable_Location := Token_Ptr; Parse_Variable_Reference (In_Tree => In_Tree, Variable => Case_Variable, Flags => Flags, Current_Project => Current_Project, Current_Package => Current_Package); Set_Case_Variable_Reference_Of (Case_Construction, In_Tree, To => Case_Variable); else if Token /= Tok_Is then Scan (In_Tree); end if; end if; if Present (Case_Variable) then String_Type := String_Type_Of (Case_Variable, In_Tree); if Expression_Kind_Of (Case_Variable, In_Tree) /= Single then Error_Msg (Flags, "variable """ & Get_Name_String (Name_Of (Case_Variable, In_Tree)) & """ is not a single string", Variable_Location); end if; end if; Expect (Tok_Is, "IS"); if Token = Tok_Is then Set_End_Of_Line (Case_Construction); Set_Previous_Line_Node (Case_Construction); Set_Next_End_Node (Case_Construction); -- Scan past "is" Scan (In_Tree); end if; Start_New_Case_Construction (In_Tree, String_Type); When_Loop : while Token = Tok_When loop if First_Case_Item then Current_Item := Default_Project_Node (Of_Kind => N_Case_Item, In_Tree => In_Tree); Set_First_Case_Item_Of (Case_Construction, In_Tree, To => Current_Item); First_Case_Item := False; else Next_Item := Default_Project_Node (Of_Kind => N_Case_Item, In_Tree => In_Tree); Set_Next_Case_Item (Current_Item, In_Tree, To => Next_Item); Current_Item := Next_Item; end if; Set_Location_Of (Current_Item, In_Tree, To => Token_Ptr); -- Scan past "when" Scan (In_Tree); if Token = Tok_Others then When_Others := True; -- Scan past "others" Scan (In_Tree); Expect (Tok_Arrow, "`=>`"); Set_End_Of_Line (Current_Item); Set_Previous_Line_Node (Current_Item); -- Empty_Node in Field1 of a Case_Item indicates -- the "when others =>" branch. Set_First_Choice_Of (Current_Item, In_Tree, To => Empty_Node); Parse_Declarative_Items (In_Tree => In_Tree, Declarations => First_Declarative_Item, In_Zone => In_Case_Construction, First_Attribute => First_Attribute, Current_Project => Current_Project, Current_Package => Current_Package, Packages_To_Check => Packages_To_Check, Is_Config_File => Is_Config_File, Flags => Flags); -- "when others =>" must be the last branch, so save the -- Case_Item and exit Set_First_Declarative_Item_Of (Current_Item, In_Tree, To => First_Declarative_Item); exit When_Loop; else Parse_Choice_List (In_Tree => In_Tree, First_Choice => First_Choice, Flags => Flags, String_Type => Present (String_Type)); Set_First_Choice_Of (Current_Item, In_Tree, To => First_Choice); Expect (Tok_Arrow, "`=>`"); Set_End_Of_Line (Current_Item); Set_Previous_Line_Node (Current_Item); Parse_Declarative_Items (In_Tree => In_Tree, Declarations => First_Declarative_Item, In_Zone => In_Case_Construction, First_Attribute => First_Attribute, Current_Project => Current_Project, Current_Package => Current_Package, Packages_To_Check => Packages_To_Check, Is_Config_File => Is_Config_File, Flags => Flags); Set_First_Declarative_Item_Of (Current_Item, In_Tree, To => First_Declarative_Item); end if; end loop When_Loop; End_Case_Construction (Check_All_Labels => not When_Others and not Quiet_Output, Case_Location => Location_Of (Case_Construction, In_Tree), Flags => Flags, String_Type => Present (String_Type)); Expect (Tok_End, "`END CASE`"); Remove_Next_End_Node; if Token = Tok_End then -- Scan past "end" Scan (In_Tree); Expect (Tok_Case, "CASE"); end if; -- Scan past "case" Scan (In_Tree); Expect (Tok_Semicolon, "`;`"); Set_Previous_End_Node (Case_Construction); end Parse_Case_Construction; ----------------------------- -- Parse_Declarative_Items -- ----------------------------- procedure Parse_Declarative_Items (In_Tree : Project_Node_Tree_Ref; Declarations : out Project_Node_Id; In_Zone : Zone; First_Attribute : Attribute_Node_Id; Current_Project : Project_Node_Id; Current_Package : Project_Node_Id; Packages_To_Check : String_List_Access; Is_Config_File : Boolean; Flags : Processing_Flags) is Current_Declarative_Item : Project_Node_Id := Empty_Node; Next_Declarative_Item : Project_Node_Id := Empty_Node; Current_Declaration : Project_Node_Id := Empty_Node; Item_Location : Source_Ptr := No_Location; begin Declarations := Empty_Node; loop -- We are always positioned at the token that precedes the first -- token of the declarative element. Scan past it. Scan (In_Tree); Item_Location := Token_Ptr; case Token is when Tok_Identifier => if In_Zone = In_Case_Construction then -- Check if the variable has already been declared declare The_Variable : Project_Node_Id := Empty_Node; begin if Present (Current_Package) then The_Variable := First_Variable_Of (Current_Package, In_Tree); elsif Present (Current_Project) then The_Variable := First_Variable_Of (Current_Project, In_Tree); end if; while Present (The_Variable) and then Name_Of (The_Variable, In_Tree) /= Token_Name loop The_Variable := Next_Variable (The_Variable, In_Tree); end loop; -- It is an error to declare a variable in a case -- construction for the first time. if No (The_Variable) then Error_Msg (Flags, "a variable cannot be declared for the " & "first time here", Token_Ptr); end if; end; end if; Parse_Variable_Declaration (In_Tree, Current_Declaration, Current_Project => Current_Project, Current_Package => Current_Package, Flags => Flags); Set_End_Of_Line (Current_Declaration); Set_Previous_Line_Node (Current_Declaration); when Tok_For => Parse_Attribute_Declaration (In_Tree => In_Tree, Attribute => Current_Declaration, First_Attribute => First_Attribute, Current_Project => Current_Project, Current_Package => Current_Package, Packages_To_Check => Packages_To_Check, Flags => Flags); Set_End_Of_Line (Current_Declaration); Set_Previous_Line_Node (Current_Declaration); when Tok_Null => Scan (In_Tree); -- past "null" when Tok_Package => -- Package declaration if In_Zone /= In_Project then Error_Msg (Flags, "a package cannot be declared here", Token_Ptr); end if; Parse_Package_Declaration (In_Tree => In_Tree, Package_Declaration => Current_Declaration, Current_Project => Current_Project, Packages_To_Check => Packages_To_Check, Is_Config_File => Is_Config_File, Flags => Flags); Set_Previous_End_Node (Current_Declaration); when Tok_Type => -- Type String Declaration if In_Zone /= In_Project then Error_Msg (Flags, "a string type cannot be declared here", Token_Ptr); end if; Parse_String_Type_Declaration (In_Tree => In_Tree, String_Type => Current_Declaration, Current_Project => Current_Project, Flags => Flags); Set_End_Of_Line (Current_Declaration); Set_Previous_Line_Node (Current_Declaration); when Tok_Case => -- Case construction Parse_Case_Construction (In_Tree => In_Tree, Case_Construction => Current_Declaration, First_Attribute => First_Attribute, Current_Project => Current_Project, Current_Package => Current_Package, Packages_To_Check => Packages_To_Check, Is_Config_File => Is_Config_File, Flags => Flags); Set_Previous_End_Node (Current_Declaration); when others => exit; -- We are leaving Parse_Declarative_Items positioned -- at the first token after the list of declarative items. -- It could be "end" (for a project, a package declaration or -- a case construction) or "when" (for a case construction) end case; Expect (Tok_Semicolon, "`;` after declarative items"); -- Insert an N_Declarative_Item in the tree, but only if -- Current_Declaration is not an empty node. if Present (Current_Declaration) then if No (Current_Declarative_Item) then Current_Declarative_Item := Default_Project_Node (Of_Kind => N_Declarative_Item, In_Tree => In_Tree); Declarations := Current_Declarative_Item; else Next_Declarative_Item := Default_Project_Node (Of_Kind => N_Declarative_Item, In_Tree => In_Tree); Set_Next_Declarative_Item (Current_Declarative_Item, In_Tree, To => Next_Declarative_Item); Current_Declarative_Item := Next_Declarative_Item; end if; Set_Current_Item_Node (Current_Declarative_Item, In_Tree, To => Current_Declaration); Set_Location_Of (Current_Declarative_Item, In_Tree, To => Item_Location); end if; end loop; end Parse_Declarative_Items; ------------------------------- -- Parse_Package_Declaration -- ------------------------------- procedure Parse_Package_Declaration (In_Tree : Project_Node_Tree_Ref; Package_Declaration : out Project_Node_Id; Current_Project : Project_Node_Id; Packages_To_Check : String_List_Access; Is_Config_File : Boolean; Flags : Processing_Flags) is First_Attribute : Attribute_Node_Id := Empty_Attribute; Current_Package : Package_Node_Id := Empty_Package; First_Declarative_Item : Project_Node_Id := Empty_Node; Package_Location : constant Source_Ptr := Token_Ptr; Renaming : Boolean := False; Extending : Boolean := False; begin Package_Declaration := Default_Project_Node (Of_Kind => N_Package_Declaration, In_Tree => In_Tree); Set_Location_Of (Package_Declaration, In_Tree, To => Package_Location); -- Scan past "package" Scan (In_Tree); Expect (Tok_Identifier, "identifier"); if Token = Tok_Identifier then Set_Name_Of (Package_Declaration, In_Tree, To => Token_Name); Current_Package := Package_Node_Id_Of (Token_Name); if Current_Package = Empty_Package then if not Quiet_Output then declare List : constant Strings.String_List := Package_Name_List; Index : Natural; Name : constant String := Get_Name_String (Token_Name); begin -- Check for possible misspelling of a known package name Index := 0; loop if Index >= List'Last then Index := 0; exit; end if; Index := Index + 1; exit when GNAT.Spelling_Checker.Is_Bad_Spelling_Of (Name, List (Index).all); end loop; -- Issue warning(s) in verbose mode or when a possible -- misspelling has been found. if Verbose_Mode or else Index /= 0 then Error_Msg (Flags, "?""" & Get_Name_String (Name_Of (Package_Declaration, In_Tree)) & """ is not a known package name", Token_Ptr); end if; if Index /= 0 then Error_Msg -- CODEFIX (Flags, "\?possible misspelling of """ & List (Index).all & """", Token_Ptr); end if; end; end if; -- Set the package declaration to "ignored" so that it is not -- processed by Prj.Proc.Process. Set_Expression_Kind_Of (Package_Declaration, In_Tree, Ignored); -- Add the unknown package in the list of packages Add_Unknown_Package (Token_Name, Current_Package); elsif Current_Package = Unknown_Package then -- Set the package declaration to "ignored" so that it is not -- processed by Prj.Proc.Process. Set_Expression_Kind_Of (Package_Declaration, In_Tree, Ignored); else First_Attribute := First_Attribute_Of (Current_Package); end if; Set_Package_Id_Of (Package_Declaration, In_Tree, To => Current_Package); declare Current : Project_Node_Id := First_Package_Of (Current_Project, In_Tree); begin while Present (Current) and then Name_Of (Current, In_Tree) /= Token_Name loop Current := Next_Package_In_Project (Current, In_Tree); end loop; if Present (Current) then Error_Msg (Flags, "package """ & Get_Name_String (Name_Of (Package_Declaration, In_Tree)) & """ is declared twice in the same project", Token_Ptr); else -- Add the package to the project list Set_Next_Package_In_Project (Package_Declaration, In_Tree, To => First_Package_Of (Current_Project, In_Tree)); Set_First_Package_Of (Current_Project, In_Tree, To => Package_Declaration); end if; end; -- Scan past the package name Scan (In_Tree); end if; Check_Package_Allowed (In_Tree, Current_Project, Package_Declaration, Flags); if Token = Tok_Renames then Renaming := True; elsif Token = Tok_Extends then Extending := True; end if; if Renaming or else Extending then if Is_Config_File then Error_Msg (Flags, "no package rename or extension in configuration projects", Token_Ptr); end if; -- Scan past "renames" or "extends" Scan (In_Tree); Expect (Tok_Identifier, "identifier"); if Token = Tok_Identifier then declare Project_Name : constant Name_Id := Token_Name; Clause : Project_Node_Id := First_With_Clause_Of (Current_Project, In_Tree); The_Project : Project_Node_Id := Empty_Node; Extended : constant Project_Node_Id := Extended_Project_Of (Project_Declaration_Of (Current_Project, In_Tree), In_Tree); begin while Present (Clause) loop -- Only non limited imported projects may be used in a -- renames declaration. The_Project := Non_Limited_Project_Node_Of (Clause, In_Tree); exit when Present (The_Project) and then Name_Of (The_Project, In_Tree) = Project_Name; Clause := Next_With_Clause_Of (Clause, In_Tree); end loop; if No (Clause) then -- As we have not found the project in the imports, we check -- if it's the name of an eventual extended project. if Present (Extended) and then Name_Of (Extended, In_Tree) = Project_Name then Set_Project_Of_Renamed_Package_Of (Package_Declaration, In_Tree, To => Extended); else Error_Msg_Name_1 := Project_Name; Error_Msg (Flags, "% is not an imported or extended project", Token_Ptr); end if; else Set_Project_Of_Renamed_Package_Of (Package_Declaration, In_Tree, To => The_Project); end if; end; Scan (In_Tree); Expect (Tok_Dot, "`.`"); if Token = Tok_Dot then Scan (In_Tree); Expect (Tok_Identifier, "identifier"); if Token = Tok_Identifier then if Name_Of (Package_Declaration, In_Tree) /= Token_Name then Error_Msg (Flags, "not the same package name", Token_Ptr); elsif Present (Project_Of_Renamed_Package_Of (Package_Declaration, In_Tree)) then declare Current : Project_Node_Id := First_Package_Of (Project_Of_Renamed_Package_Of (Package_Declaration, In_Tree), In_Tree); begin while Present (Current) and then Name_Of (Current, In_Tree) /= Token_Name loop Current := Next_Package_In_Project (Current, In_Tree); end loop; if No (Current) then Error_Msg (Flags, """" & Get_Name_String (Token_Name) & """ is not a package declared by the project", Token_Ptr); end if; end; end if; Scan (In_Tree); end if; end if; end if; end if; if Renaming then Expect (Tok_Semicolon, "`;`"); Set_End_Of_Line (Package_Declaration); Set_Previous_Line_Node (Package_Declaration); elsif Token = Tok_Is then Set_End_Of_Line (Package_Declaration); Set_Previous_Line_Node (Package_Declaration); Set_Next_End_Node (Package_Declaration); Parse_Declarative_Items (In_Tree => In_Tree, Declarations => First_Declarative_Item, In_Zone => In_Package, First_Attribute => First_Attribute, Current_Project => Current_Project, Current_Package => Package_Declaration, Packages_To_Check => Packages_To_Check, Is_Config_File => Is_Config_File, Flags => Flags); Set_First_Declarative_Item_Of (Package_Declaration, In_Tree, To => First_Declarative_Item); Expect (Tok_End, "END"); if Token = Tok_End then -- Scan past "end" Scan (In_Tree); end if; -- We should have the name of the package after "end" Expect (Tok_Identifier, "identifier"); if Token = Tok_Identifier and then Name_Of (Package_Declaration, In_Tree) /= No_Name and then Token_Name /= Name_Of (Package_Declaration, In_Tree) then Error_Msg_Name_1 := Name_Of (Package_Declaration, In_Tree); Error_Msg (Flags, "expected %%", Token_Ptr); end if; if Token /= Tok_Semicolon then -- Scan past the package name Scan (In_Tree); end if; Expect (Tok_Semicolon, "`;`"); Remove_Next_End_Node; else Error_Msg (Flags, "expected IS", Token_Ptr); end if; end Parse_Package_Declaration; ----------------------------------- -- Parse_String_Type_Declaration -- ----------------------------------- procedure Parse_String_Type_Declaration (In_Tree : Project_Node_Tree_Ref; String_Type : out Project_Node_Id; Current_Project : Project_Node_Id; Flags : Processing_Flags) is Current : Project_Node_Id := Empty_Node; First_String : Project_Node_Id := Empty_Node; begin String_Type := Default_Project_Node (Of_Kind => N_String_Type_Declaration, In_Tree => In_Tree); Set_Location_Of (String_Type, In_Tree, To => Token_Ptr); -- Scan past "type" Scan (In_Tree); Expect (Tok_Identifier, "identifier"); if Token = Tok_Identifier then Set_Name_Of (String_Type, In_Tree, To => Token_Name); Current := First_String_Type_Of (Current_Project, In_Tree); while Present (Current) and then Name_Of (Current, In_Tree) /= Token_Name loop Current := Next_String_Type (Current, In_Tree); end loop; if Present (Current) then Error_Msg (Flags, "duplicate string type name """ & Get_Name_String (Token_Name) & """", Token_Ptr); else Current := First_Variable_Of (Current_Project, In_Tree); while Present (Current) and then Name_Of (Current, In_Tree) /= Token_Name loop Current := Next_Variable (Current, In_Tree); end loop; if Present (Current) then Error_Msg (Flags, """" & Get_Name_String (Token_Name) & """ is already a variable name", Token_Ptr); else Set_Next_String_Type (String_Type, In_Tree, To => First_String_Type_Of (Current_Project, In_Tree)); Set_First_String_Type_Of (Current_Project, In_Tree, To => String_Type); end if; end if; -- Scan past the name Scan (In_Tree); end if; Expect (Tok_Is, "IS"); if Token = Tok_Is then Scan (In_Tree); end if; Expect (Tok_Left_Paren, "`(`"); if Token = Tok_Left_Paren then Scan (In_Tree); end if; Parse_String_Type_List (In_Tree => In_Tree, First_String => First_String, Flags => Flags); Set_First_Literal_String (String_Type, In_Tree, To => First_String); Expect (Tok_Right_Paren, "`)`"); if Token = Tok_Right_Paren then Scan (In_Tree); end if; end Parse_String_Type_Declaration; -------------------------------- -- Parse_Variable_Declaration -- -------------------------------- procedure Parse_Variable_Declaration (In_Tree : Project_Node_Tree_Ref; Variable : out Project_Node_Id; Current_Project : Project_Node_Id; Current_Package : Project_Node_Id; Flags : Processing_Flags) is Expression_Location : Source_Ptr; String_Type_Name : Name_Id := No_Name; Project_String_Type_Name : Name_Id := No_Name; Type_Location : Source_Ptr := No_Location; Project_Location : Source_Ptr := No_Location; Expression : Project_Node_Id := Empty_Node; Variable_Name : constant Name_Id := Token_Name; OK : Boolean := True; begin Variable := Default_Project_Node (Of_Kind => N_Variable_Declaration, In_Tree => In_Tree); Set_Name_Of (Variable, In_Tree, To => Variable_Name); Set_Location_Of (Variable, In_Tree, To => Token_Ptr); -- Scan past the variable name Scan (In_Tree); if Token = Tok_Colon then -- Typed string variable declaration Scan (In_Tree); Set_Kind_Of (Variable, In_Tree, N_Typed_Variable_Declaration); Expect (Tok_Identifier, "identifier"); OK := Token = Tok_Identifier; if OK then String_Type_Name := Token_Name; Type_Location := Token_Ptr; Scan (In_Tree); if Token = Tok_Dot then Project_String_Type_Name := String_Type_Name; Project_Location := Type_Location; -- Scan past the dot Scan (In_Tree); Expect (Tok_Identifier, "identifier"); if Token = Tok_Identifier then String_Type_Name := Token_Name; Type_Location := Token_Ptr; Scan (In_Tree); else OK := False; end if; end if; if OK then declare Proj : Project_Node_Id := Current_Project; Current : Project_Node_Id := Empty_Node; begin if Project_String_Type_Name /= No_Name then declare The_Project_Name_And_Node : constant Tree_Private_Part.Project_Name_And_Node := Tree_Private_Part.Projects_Htable.Get (In_Tree.Projects_HT, Project_String_Type_Name); use Tree_Private_Part; begin if The_Project_Name_And_Node = Tree_Private_Part.No_Project_Name_And_Node then Error_Msg (Flags, "unknown project """ & Get_Name_String (Project_String_Type_Name) & """", Project_Location); Current := Empty_Node; else Current := First_String_Type_Of (The_Project_Name_And_Node.Node, In_Tree); while Present (Current) and then Name_Of (Current, In_Tree) /= String_Type_Name loop Current := Next_String_Type (Current, In_Tree); end loop; end if; end; else -- Look for a string type with the correct name in this -- project or in any of its ancestors. loop Current := First_String_Type_Of (Proj, In_Tree); while Present (Current) and then Name_Of (Current, In_Tree) /= String_Type_Name loop Current := Next_String_Type (Current, In_Tree); end loop; exit when Present (Current); Proj := Parent_Project_Of (Proj, In_Tree); exit when No (Proj); end loop; end if; if No (Current) then Error_Msg (Flags, "unknown string type """ & Get_Name_String (String_Type_Name) & """", Type_Location); OK := False; else Set_String_Type_Of (Variable, In_Tree, To => Current); end if; end; end if; end if; end if; Expect (Tok_Colon_Equal, "`:=`"); OK := OK and then Token = Tok_Colon_Equal; if Token = Tok_Colon_Equal then Scan (In_Tree); end if; -- Get the single string or string list value Expression_Location := Token_Ptr; Parse_Expression (In_Tree => In_Tree, Expression => Expression, Flags => Flags, Current_Project => Current_Project, Current_Package => Current_Package, Optional_Index => False); Set_Expression_Of (Variable, In_Tree, To => Expression); if Present (Expression) then -- A typed string must have a single string value, not a list if Kind_Of (Variable, In_Tree) = N_Typed_Variable_Declaration and then Expression_Kind_Of (Expression, In_Tree) = List then Error_Msg (Flags, "expression must be a single string", Expression_Location); end if; Set_Expression_Kind_Of (Variable, In_Tree, To => Expression_Kind_Of (Expression, In_Tree)); end if; if OK then declare The_Variable : Project_Node_Id := Empty_Node; begin if Present (Current_Package) then The_Variable := First_Variable_Of (Current_Package, In_Tree); elsif Present (Current_Project) then The_Variable := First_Variable_Of (Current_Project, In_Tree); end if; while Present (The_Variable) and then Name_Of (The_Variable, In_Tree) /= Variable_Name loop The_Variable := Next_Variable (The_Variable, In_Tree); end loop; if No (The_Variable) then if Present (Current_Package) then Set_Next_Variable (Variable, In_Tree, To => First_Variable_Of (Current_Package, In_Tree)); Set_First_Variable_Of (Current_Package, In_Tree, To => Variable); elsif Present (Current_Project) then Set_Next_Variable (Variable, In_Tree, To => First_Variable_Of (Current_Project, In_Tree)); Set_First_Variable_Of (Current_Project, In_Tree, To => Variable); end if; else if Expression_Kind_Of (Variable, In_Tree) /= Undefined then if Expression_Kind_Of (The_Variable, In_Tree) = Undefined then Set_Expression_Kind_Of (The_Variable, In_Tree, To => Expression_Kind_Of (Variable, In_Tree)); else if Expression_Kind_Of (The_Variable, In_Tree) /= Expression_Kind_Of (Variable, In_Tree) then Error_Msg (Flags, "wrong expression kind for variable """ & Get_Name_String (Name_Of (The_Variable, In_Tree)) & """", Expression_Location); end if; end if; end if; end if; end; end if; end Parse_Variable_Declaration; end Prj.Dect;