diff options
57 files changed, 38371 insertions, 0 deletions
diff --git a/gcc/ada/par-ch10.adb b/gcc/ada/par-ch10.adb new file mode 100644 index 00000000000..a4fa121ed16 --- /dev/null +++ b/gcc/ada/par-ch10.adb @@ -0,0 +1,1080 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P A R . C H 1 0 -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.115 $ +-- -- +-- Copyright (C) 1992-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +pragma Style_Checks (All_Checks); +-- Turn off subprogram body ordering check. Subprograms are in order +-- by RM section rather than alphabetical + +with Fname; use Fname; +with Fname.UF; use Fname.UF; +with Hostparm; use Hostparm; +with Uname; use Uname; + +separate (Par) +package body Ch10 is + + -- Local functions, used only in this chapter + + function P_Context_Clause return List_Id; + function P_Subunit return Node_Id; + + function Set_Location return Source_Ptr; + -- The current compilation unit starts with Token at Token_Ptr. This + -- function determines the corresponding source location for the start + -- of the unit, including any preceding comment lines. + + procedure Unit_Display + (Cunit : Node_Id; + Loc : Source_Ptr; + SR_Present : Boolean); + -- This procedure is used to generate a line of output for the a unit in + -- the source program. Cunit is the node for the compilation unit, and + -- Loc is the source location for the start of the unit in the source + -- file (which is not necessarily the Sloc of the Cunit node). This + -- output is written to the standard output file for use by gnatchop. + + procedure Unit_Location (Sind : Source_File_Index; Loc : Source_Ptr); + -- This routine has the same calling sequence as Unit_Display, but + -- it outputs only the line number and offset of the location, Loc, + -- using Cunit to obtain the proper source file index. + + ------------------------- + -- 10.1.1 Compilation -- + ------------------------- + + -- COMPILATION ::= {COMPILATION_UNIT} + + -- There is no specific parsing routine for a compilation, since we only + -- permit a single compilation in a source file, so there is no explicit + -- occurrence of compilations as such (our representation of a compilation + -- is a series of separate source files). + + ------------------------------ + -- 10.1.1 Compilation unit -- + ------------------------------ + + -- COMPILATION_UNIT ::= + -- CONTEXT_CLAUSE LIBRARY_ITEM + -- | CONTEXT_CLAUSE SUBUNIT + + -- LIBRARY_ITEM ::= + -- private LIBRARY_UNIT_DECLARATION + -- | LIBRARY_UNIT_BODY + -- | [private] LIBRARY_UNIT_RENAMING_DECLARATION + + -- LIBRARY_UNIT_DECLARATION ::= + -- SUBPROGRAM_DECLARATION | PACKAGE_DECLARATION + -- | GENERIC_DECLARATION | GENERIC_INSTANTIATION + + -- LIBRARY_UNIT_RENAMING_DECLARATION ::= + -- PACKAGE_RENAMING_DECLARATION + -- | GENERIC_RENAMING_DECLARATION + -- | SUBPROGRAM_RENAMING_DECLARATION + + -- LIBRARY_UNIT_BODY ::= SUBPROGRAM_BODY | PACKAGE_BODY + + -- Error recovery: cannot raise Error_Resync. If an error occurs, tokens + -- are skipped up to the next possible beginning of a compilation unit. + + -- Note: if only configuration pragmas are found, Empty is returned + + -- Note: in syntax-only mode, it is possible for P_Compilation_Unit + -- to return strange things that are not really compilation units. + -- This is done to help out gnatchop when it is faced with nonsense. + + function P_Compilation_Unit return Node_Id is + Scan_State : Saved_Scan_State; + Body_Node : Node_Id; + Specification_Node : Node_Id; + Unit_Node : Node_Id; + Comp_Unit_Node : Node_Id; + Name_Node : Node_Id; + Item : Node_Id; + Private_Sloc : Source_Ptr := No_Location; + Config_Pragmas : List_Id; + P : Node_Id; + SR_Present : Boolean; + + Cunit_Error_Flag : Boolean := False; + -- This flag is set True if we have to scan for a compilation unit + -- token. It is used to ensure clean termination in such cases by + -- not insisting on being at the end of file, and, in the sytax only + -- case by not scanning for additional compilation units. + + Cunit_Location : Source_Ptr; + -- Location of unit for unit identification output (List_Unit option) + + begin + Num_Library_Units := Num_Library_Units + 1; + + -- Set location of the compilation unit if unit list option set + -- and we are in syntax check only mode + + if List_Units and then Operating_Mode = Check_Syntax then + Cunit_Location := Set_Location; + else + Cunit_Location := No_Location; + end if; + + -- Deal with initial pragmas + + Config_Pragmas := No_List; + + -- If we have an initial Source_Reference pragma, then remember + -- the fact to generate an NR parameter in the output line. + + SR_Present := False; + + if Token = Tok_Pragma then + Save_Scan_State (Scan_State); + Item := P_Pragma; + + if Item = Error + or else Chars (Item) /= Name_Source_Reference + then + Restore_Scan_State (Scan_State); + + else + SR_Present := True; + + -- If first unit, record the file name for gnatchop use + + if Operating_Mode = Check_Syntax + and then List_Units + and then Num_Library_Units = 1 + then + Write_Str ("Source_Reference pragma for file """); + Write_Name (Full_Ref_Name (Current_Source_File)); + Write_Char ('"'); + Write_Eol; + end if; + + Config_Pragmas := New_List (Item); + end if; + end if; + + -- Scan out any configuration pragmas + + while Token = Tok_Pragma loop + Save_Scan_State (Scan_State); + Item := P_Pragma; + + if Item = Error + or else Chars (Item) > Last_Configuration_Pragma_Name + then + Restore_Scan_State (Scan_State); + exit; + end if; + + if Config_Pragmas = No_List then + Config_Pragmas := Empty_List; + + if Operating_Mode = Check_Syntax and then List_Units then + Write_Str ("Configuration pragmas at"); + Unit_Location (Current_Source_File, Cunit_Location); + Write_Eol; + end if; + end if; + + Append (Item, Config_Pragmas); + Cunit_Location := Set_Location; + end loop; + + -- Establish compilation unit node and scan context items + + Comp_Unit_Node := New_Node (N_Compilation_Unit, No_Location); + Set_Cunit (Current_Source_Unit, Comp_Unit_Node); + Set_Context_Items (Comp_Unit_Node, P_Context_Clause); + Set_Aux_Decls_Node + (Comp_Unit_Node, New_Node (N_Compilation_Unit_Aux, No_Location)); + + if Present (Config_Pragmas) then + + -- Check for case of only configuration pragmas present + + if Token = Tok_EOF + and then Is_Empty_List (Context_Items (Comp_Unit_Node)) + then + if Operating_Mode = Check_Syntax then + return Empty; + + else + Item := First (Config_Pragmas); + Error_Msg_N + ("cannot compile configuration pragmas with gcc", Item); + Error_Msg_N + ("use gnatchop -c to process configuration pragmas!", Item); + raise Unrecoverable_Error; + end if; + + -- Otherwise configuration pragmas are simply prepended to the + -- context of the current unit. + + else + Append_List (Context_Items (Comp_Unit_Node), Config_Pragmas); + Set_Context_Items (Comp_Unit_Node, Config_Pragmas); + end if; + end if; + + -- Check for PRIVATE. Note that for the moment we allow this in + -- Ada_83 mode, since we do not yet know if we are compiling a + -- predefined unit, and if we are then it would be allowed anyway. + + if Token = Tok_Private then + Private_Sloc := Token_Ptr; + Set_Keyword_Casing (Current_Source_File, Determine_Token_Casing); + if Style_Check then Style.Check_Indentation; end if; + + Save_Scan_State (Scan_State); -- at PRIVATE + Scan; -- past PRIVATE + + if Token = Tok_Separate then + Error_Msg_SP ("cannot have private subunits!"); + + elsif Token = Tok_Package then + Scan; -- past PACKAGE + + if Token = Tok_Body then + Restore_Scan_State (Scan_State); -- to PRIVATE + Error_Msg_SC ("cannot have private package body!"); + Scan; -- ignore PRIVATE + + else + Restore_Scan_State (Scan_State); -- to PRIVATE + Scan; -- past PRIVATE + Set_Private_Present (Comp_Unit_Node, True); + end if; + + elsif Token = Tok_Procedure + or else Token = Tok_Function + or else Token = Tok_Generic + then + Set_Private_Present (Comp_Unit_Node, True); + end if; + end if; + + -- Loop to find our way to a compilation unit token + + loop + exit when Token in Token_Class_Cunit and then Token /= Tok_With; + + exit when Bad_Spelling_Of (Tok_Package) + or else Bad_Spelling_Of (Tok_Function) + or else Bad_Spelling_Of (Tok_Generic) + or else Bad_Spelling_Of (Tok_Separate) + or else Bad_Spelling_Of (Tok_Procedure); + + -- Allow task and protected for nice error recovery purposes + + exit when Token = Tok_Task + or else Token = Tok_Protected; + + if Token = Tok_With then + Error_Msg_SC ("misplaced WITH"); + Append_List (P_Context_Clause, Context_Items (Comp_Unit_Node)); + + elsif Bad_Spelling_Of (Tok_With) then + Append_List (P_Context_Clause, Context_Items (Comp_Unit_Node)); + + else + Error_Msg_SC ("compilation unit expected"); + Cunit_Error_Flag := True; + Resync_Cunit; + + -- If we are at an end of file, then just quit, the above error + -- message was complaint enough. + + if Token = Tok_EOF then + return Error; + end if; + end if; + end loop; + + -- We have a compilation unit token, so that's a reasonable choice for + -- determining the standard casing convention used for keywords in case + -- it hasn't already been done on seeing a WITH or PRIVATE. + + Set_Keyword_Casing (Current_Source_File, Determine_Token_Casing); + if Style_Check then Style.Check_Indentation; end if; + + -- Remaining processing depends on particular type of compilation unit + + if Token = Tok_Package then + + -- A common error is to omit the body keyword after package. We can + -- often diagnose this early on (before getting loads of errors from + -- contained subprogram bodies), by knowing that that the file we + -- are compiling has a name that requires a body to be found. + + -- However, we do not do this check if we are operating in syntax + -- checking only mode, because in that case there may be multiple + -- units in the same file, and the file name is not a reliable guide. + + Save_Scan_State (Scan_State); + Scan; -- past Package keyword + + if Token /= Tok_Body + and then Operating_Mode /= Check_Syntax + and then + Get_Expected_Unit_Type + (File_Name (Current_Source_File)) = Expect_Body + then + Error_Msg_BC ("keyword BODY expected here [see file name]"); + Restore_Scan_State (Scan_State); + Set_Unit (Comp_Unit_Node, P_Package (Pf_Pbod)); + else + Restore_Scan_State (Scan_State); + Set_Unit (Comp_Unit_Node, P_Package (Pf_Decl_Gins_Pbod_Rnam)); + end if; + + elsif Token = Tok_Generic then + Set_Unit (Comp_Unit_Node, P_Generic); + + elsif Token = Tok_Separate then + Set_Unit (Comp_Unit_Node, P_Subunit); + + elsif Token = Tok_Procedure + or else Token = Tok_Function + then + Set_Unit (Comp_Unit_Node, P_Subprogram (Pf_Decl_Gins_Pbod_Rnam)); + + -- A little bit of an error recovery check here. If we just scanned + -- a subprogram declaration (as indicated by an SIS entry being + -- active), then if the following token is BEGIN or an identifier, + -- or a token which can reasonably start a declaration but cannot + -- start a compilation unit, then we assume that the semicolon in + -- the declaration should have been IS. + + if SIS_Entry_Active then + + if Token = Tok_Begin + or else Token = Tok_Identifier + or else Token in Token_Class_Deckn + then + Push_Scope_Stack; + Scope.Table (Scope.Last).Etyp := E_Name; + Scope.Table (Scope.Last).Sloc := SIS_Sloc; + Scope.Table (Scope.Last).Ecol := SIS_Ecol; + Scope.Table (Scope.Last).Lreq := False; + SIS_Entry_Active := False; + + -- If we had a missing semicolon in the declaration, then + -- change the message to from <missing ";"> to <missing "is"> + + if SIS_Missing_Semicolon_Message /= No_Error_Msg then + Change_Error_Text -- Replace: "missing "";"" " + (SIS_Missing_Semicolon_Message, "missing IS"); + + -- Otherwise we saved the semicolon position, so complain + + else + Error_Msg (""";"" should be IS", SIS_Semicolon_Sloc); + end if; + + Body_Node := Unit (Comp_Unit_Node); + Specification_Node := Specification (Body_Node); + Change_Node (Body_Node, N_Subprogram_Body); + Set_Specification (Body_Node, Specification_Node); + Parse_Decls_Begin_End (Body_Node); + Set_Unit (Comp_Unit_Node, Body_Node); + end if; + + -- If we scanned a subprogram body, make sure we did not have private + + elsif Private_Sloc /= No_Location + and then Nkind (Unit (Comp_Unit_Node)) /= N_Function_Instantiation + and then Nkind (Unit (Comp_Unit_Node)) /= N_Procedure_Instantiation + then + Error_Msg ("cannot have private subprogram body", Private_Sloc); + + -- P_Subprogram can yield an abstract subprogram, but this cannot + -- be a compilation unit. Treat as a subprogram declaration. + + elsif + Nkind (Unit (Comp_Unit_Node)) = N_Abstract_Subprogram_Declaration + then + Error_Msg_N + ("compilation unit cannot be abstract subprogram", + Unit (Comp_Unit_Node)); + + Unit_Node := + New_Node (N_Subprogram_Declaration, Sloc (Comp_Unit_Node)); + Set_Specification (Unit_Node, + Specification (Unit (Comp_Unit_Node))); + Set_Unit (Comp_Unit_Node, Unit_Node); + end if; + + -- Otherwise we have TASK. This is not really an acceptable token, + -- but we accept it to improve error recovery. + + elsif Token = Tok_Task then + Scan; -- Past TASK + + if Token = Tok_Type then + Error_Msg_SP + ("task type cannot be used as compilation unit"); + else + Error_Msg_SP + ("task declaration cannot be used as compilation unit"); + end if; + + -- If in check syntax mode, accept the task anyway. This is done + -- particularly to improve the behavior of GNATCHOP in this case. + + if Operating_Mode = Check_Syntax then + Set_Unit (Comp_Unit_Node, P_Task); + + -- If not in syntax only mode, treat this as horrible error + + else + Cunit_Error_Flag := True; + return Error; + end if; + + else pragma Assert (Token = Tok_Protected); + Scan; -- Past PROTECTED + + if Token = Tok_Type then + Error_Msg_SP + ("protected type cannot be used as compilation unit"); + else + Error_Msg_SP + ("protected declaration cannot be used as compilation unit"); + end if; + + -- If in check syntax mode, accept protected anyway. This is done + -- particularly to improve the behavior of GNATCHOP in this case. + + if Operating_Mode = Check_Syntax then + Set_Unit (Comp_Unit_Node, P_Protected); + + -- If not in syntax only mode, treat this as horrible error + + else + Cunit_Error_Flag := True; + return Error; + end if; + end if; + + -- Here is where locate the compilation unit entity. This is a little + -- tricky, since it is buried in various places. + + Unit_Node := Unit (Comp_Unit_Node); + + -- Another error from which it is hard to recover + + if Nkind (Unit_Node) = N_Subprogram_Body_Stub + or else Nkind (Unit_Node) = N_Package_Body_Stub + then + Cunit_Error_Flag := True; + return Error; + end if; + + -- Only try this if we got an OK unit! + + if Unit_Node /= Error then + if Nkind (Unit_Node) = N_Subunit then + Unit_Node := Proper_Body (Unit_Node); + end if; + + if Nkind (Unit_Node) in N_Generic_Declaration then + Unit_Node := Specification (Unit_Node); + end if; + + if Nkind (Unit_Node) = N_Package_Declaration + or else Nkind (Unit_Node) = N_Subprogram_Declaration + or else Nkind (Unit_Node) = N_Subprogram_Body + or else Nkind (Unit_Node) = N_Subprogram_Renaming_Declaration + then + Unit_Node := Specification (Unit_Node); + + elsif Nkind (Unit_Node) = N_Subprogram_Renaming_Declaration then + if Ada_83 then + Error_Msg_N + ("(Ada 83) library unit renaming not allowed", Unit_Node); + end if; + end if; + + if Nkind (Unit_Node) = N_Task_Body + or else Nkind (Unit_Node) = N_Protected_Body + or else Nkind (Unit_Node) = N_Task_Type_Declaration + or else Nkind (Unit_Node) = N_Protected_Type_Declaration + or else Nkind (Unit_Node) = N_Single_Task_Declaration + or else Nkind (Unit_Node) = N_Single_Protected_Declaration + then + Name_Node := Defining_Identifier (Unit_Node); + else + Name_Node := Defining_Unit_Name (Unit_Node); + end if; + + Set_Sloc (Comp_Unit_Node, Sloc (Name_Node)); + Set_Sloc (Aux_Decls_Node (Comp_Unit_Node), Sloc (Name_Node)); + + -- Set Entity field in file table. Easier now that we have name! + -- Note that this is also skipped if we had a bad unit + + if Nkind (Name_Node) = N_Defining_Program_Unit_Name then + Set_Cunit_Entity + (Current_Source_Unit, Defining_Identifier (Name_Node)); + else + Set_Cunit_Entity (Current_Source_Unit, Name_Node); + end if; + + Set_Unit_Name + (Current_Source_Unit, Get_Unit_Name (Unit (Comp_Unit_Node))); + + -- If we had a bad unit, make sure the fatal flag is set in the file + -- table entry, since this is surely a fatal error and also set our + -- flag to inhibit the requirement that we be at end of file. + + else + Cunit_Error_Flag := True; + Set_Fatal_Error (Current_Source_Unit); + end if; + + -- Clear away any missing semicolon indication, we are done with that + -- unit, so what's done is done, and we don't want anything hanging + -- around from the attempt to parse it! + + SIS_Entry_Active := False; + + -- Scan out pragmas after unit + + while Token = Tok_Pragma loop + Save_Scan_State (Scan_State); + + -- If we are in syntax scan mode allowing multiple units, then + -- start the next unit if we encounter a configuration pragma, + -- or a source reference pragma. We take care not to actually + -- scan the pragma in this case since we don't want it to take + -- effect for the current unit. + + if Operating_Mode = Check_Syntax then + Scan; -- past Pragma + + if Token = Tok_Identifier + and then + (Token_Name in + First_Pragma_Name .. Last_Configuration_Pragma_Name + or else Token_Name = Name_Source_Reference) + then + Restore_Scan_State (Scan_State); -- to Pragma + exit; + end if; + end if; + + -- Otherwise eat the pragma, it definitely belongs with the + -- current unit, and not with the following unit. + + Restore_Scan_State (Scan_State); -- to Pragma + P := P_Pragma; + + if No (Pragmas_After (Aux_Decls_Node (Comp_Unit_Node))) then + Set_Pragmas_After + (Aux_Decls_Node (Comp_Unit_Node), New_List); + end if; + + Append (P, Pragmas_After (Aux_Decls_Node (Comp_Unit_Node))); + end loop; + + -- Cancel effect of any outstanding pragma Warnings (Off) + + Set_Warnings_Mode_On (Scan_Ptr); + + -- Ada 83 error checks + + if Ada_83 then + + -- Check we did not with any child units + + Item := First (Context_Items (Comp_Unit_Node)); + + while Present (Item) loop + if Nkind (Item) = N_With_Clause + and then Nkind (Name (Item)) /= N_Identifier + then + Error_Msg_N ("(Ada 83) child units not allowed", Item); + end if; + + Next (Item); + end loop; + + -- Check that we did not have a PRIVATE keyword present + + if Private_Present (Comp_Unit_Node) then + Error_Msg + ("(Ada 83) private units not allowed", Private_Sloc); + end if; + end if; + + -- If no serious error, then output possible unit information line + -- for gnatchop if we are in syntax only, list units mode. + + if not Cunit_Error_Flag + and then List_Units + and then Operating_Mode = Check_Syntax + then + Unit_Display (Comp_Unit_Node, Cunit_Location, SR_Present); + end if; + + -- And now we should be at the end of file + + if Token /= Tok_EOF then + + -- If we already had to scan for a compilation unit, then don't + -- give any further error message, since it just sems to make + -- things worse, and we already gave a serious error message. + + if Cunit_Error_Flag then + null; + + -- If we are in check syntax mode, then we allow multiple units + -- so we just return with Token not set to Tok_EOF and no message. + + elsif Operating_Mode = Check_Syntax then + return Comp_Unit_Node; + + -- Otherwise we have an error. We suppress the error message + -- if we already had a fatal error, since this stops junk + -- cascaded messages in some situations. + + else + if not Fatal_Error (Current_Source_Unit) then + + if Token in Token_Class_Cunit then + Error_Msg_SC + ("end of file expected, " & + "file can have only one compilation unit"); + + else + Error_Msg_SC ("end of file expected"); + end if; + end if; + end if; + + -- Skip tokens to end of file, so that the -gnatl listing + -- will be complete in this situation, but no error checking + -- other than that provided at the token level. + + while Token /= Tok_EOF loop + Scan; + end loop; + + return Error; + + -- Normal return (we were at the end of file as expected) + + else + return Comp_Unit_Node; + end if; + + exception + + -- An error resync is a serious bomb, so indicate result unit no good + + when Error_Resync => + Set_Fatal_Error (Current_Source_Unit); + return Error; + + end P_Compilation_Unit; + + -------------------------- + -- 10.1.1 Library Item -- + -------------------------- + + -- Parsed by P_Compilation_Unit (10.1.1) + + -------------------------------------- + -- 10.1.1 Library Unit Declaration -- + -------------------------------------- + + -- Parsed by P_Compilation_Unit (10.1.1) + + ------------------------------------------------ + -- 10.1.1 Library Unit Renaming Declaration -- + ------------------------------------------------ + + -- Parsed by P_Compilation_Unit (10.1.1) + + ------------------------------- + -- 10.1.1 Library Unit Body -- + ------------------------------- + + -- Parsed by P_Compilation_Unit (10.1.1) + + ------------------------------ + -- 10.1.1 Parent Unit Name -- + ------------------------------ + + -- Parsed (as a name) by its parent construct + + ---------------------------- + -- 10.1.2 Context Clause -- + ---------------------------- + + -- CONTEXT_CLAUSE ::= {CONTEXT_ITEM} + + -- CONTEXT_ITEM ::= WITH_CLAUSE | USE_CLAUSE | WITH_TYPE_CLAUSE + + -- WITH_CLAUSE ::= + -- with library_unit_NAME {,library_unit_NAME}; + + -- WITH_TYPE_CLAUSE ::= + -- with type type_NAME is access; | with type type_NAME is tagged; + + -- Error recovery: Cannot raise Error_Resync + + function P_Context_Clause return List_Id is + Item_List : List_Id; + With_Node : Node_Id; + First_Flag : Boolean; + + begin + Item_List := New_List; + + -- Get keyword casing from WITH keyword in case not set yet + + if Token = Tok_With then + Set_Keyword_Casing (Current_Source_File, Determine_Token_Casing); + end if; + + -- Loop through context items + + loop + if Style_Check then Style.Check_Indentation; end if; + + -- Gather any pragmas appearing in the context clause + + P_Pragmas_Opt (Item_List); + + -- Processing for WITH clause + + if Token = Tok_With then + Scan; -- past WITH + + if Token = Tok_Type then + + -- WITH TYPE is an extension + + if not Extensions_Allowed then + Error_Msg_SP ("`WITH TYPE` is a non-standard extension"); + + if OpenVMS then + Error_Msg_SP + ("\unit must be compiled with " & + "'/'E'X'T'E'N'S'I'O'N'S'_'A'L'L'O'W'E'D qualifier"); + else + Error_Msg_SP + ("\unit must be compiled with -gnatX switch"); + end if; + end if; + + Scan; -- past TYPE + With_Node := New_Node (N_With_Type_Clause, Token_Ptr); + Append (With_Node, Item_List); + Set_Name (With_Node, P_Qualified_Simple_Name); + + T_Is; + + if Token = Tok_Tagged then + Set_Tagged_Present (With_Node); + Scan; + + elsif Token = Tok_Access then + Scan; + + else + Error_Msg_SC ("expect tagged or access qualifier"); + end if; + + TF_Semicolon; + + else + First_Flag := True; + + -- Loop through names in one with clause, generating a separate + -- N_With_Clause node for each nam encountered. + + loop + With_Node := New_Node (N_With_Clause, Token_Ptr); + Append (With_Node, Item_List); + + -- Note that we allow with'ing of child units, even in + -- Ada 83 mode, since presumably if this is not desired, + -- then the compilation of the child unit itself is the + -- place where such an "error" should be caught. + + Set_Name (With_Node, P_Qualified_Simple_Name); + Set_First_Name (With_Node, First_Flag); + First_Flag := False; + exit when Token /= Tok_Comma; + Scan; -- past comma + end loop; + + Set_Last_Name (With_Node, True); + TF_Semicolon; + end if; + + -- Processing for USE clause + + elsif Token = Tok_Use then + Append (P_Use_Clause, Item_List); + + -- Anything else is end of context clause + + else + exit; + end if; + end loop; + + return Item_List; + end P_Context_Clause; + + -------------------------- + -- 10.1.2 Context Item -- + -------------------------- + + -- Parsed by P_Context_Clause (10.1.2) + + ------------------------- + -- 10.1.2 With Clause -- + ------------------------- + + -- Parsed by P_Context_Clause (10.1.2) + + ----------------------- + -- 10.1.3 Body Stub -- + ----------------------- + + -- Subprogram stub parsed by P_Subprogram (6.1) + -- Package stub parsed by P_Package (7.1) + -- Task stub parsed by P_Task (9.1) + -- Protected stub parsed by P_Protected (9.4) + + ---------------------------------- + -- 10.1.3 Subprogram Body Stub -- + ---------------------------------- + + -- Parsed by P_Subprogram (6.1) + + ------------------------------- + -- 10.1.3 Package Body Stub -- + ------------------------------- + + -- Parsed by P_Package (7.1) + + ---------------------------- + -- 10.1.3 Task Body Stub -- + ---------------------------- + + -- Parsed by P_Task (9.1) + + --------------------------------- + -- 10.1.3 Protected Body Stub -- + --------------------------------- + + -- Parsed by P_Protected (9.4) + + --------------------- + -- 10.1.3 Subunit -- + --------------------- + + -- SUBUNIT ::= separate (PARENT_UNIT_NAME) PROPER_BODY + + -- PARENT_UNIT_NAME ::= NAME + + -- The caller has checked that the initial token is SEPARATE + + -- Error recovery: cannot raise Error_Resync + + function P_Subunit return Node_Id is + Subunit_Node : Node_Id; + Body_Node : Node_Id; + + begin + Subunit_Node := New_Node (N_Subunit, Token_Ptr); + Body_Node := Error; -- in case no good body found + Scan; -- past SEPARATE; + + T_Left_Paren; + Set_Name (Subunit_Node, P_Qualified_Simple_Name); + T_Right_Paren; + + if Token = Tok_Semicolon then + Error_Msg_SC ("unexpected semicolon ignored"); + Scan; + end if; + + if Token = Tok_Function or else Token = Tok_Procedure then + Body_Node := P_Subprogram (Pf_Pbod); + + elsif Token = Tok_Package then + Body_Node := P_Package (Pf_Pbod); + + elsif Token = Tok_Protected then + Scan; -- past PROTECTED + + if Token = Tok_Body then + Body_Node := P_Protected; + else + Error_Msg_AP ("BODY expected"); + return Error; + end if; + + elsif Token = Tok_Task then + Scan; -- past TASK + + if Token = Tok_Body then + Body_Node := P_Task; + else + Error_Msg_AP ("BODY expected"); + return Error; + end if; + + else + Error_Msg_SC ("proper body expected"); + return Error; + end if; + + Set_Proper_Body (Subunit_Node, Body_Node); + return Subunit_Node; + + end P_Subunit; + + ------------------ + -- Set_Location -- + ------------------ + + function Set_Location return Source_Ptr is + Physical : Boolean; + Loc : Source_Ptr; + Scan_State : Saved_Scan_State; + + begin + -- A special check. If the first token is pragma, and this is a + -- Source_Reference pragma, then do NOT eat previous comments, since + -- the Source_Reference pragma is required to be the first line in + -- the source file. + + if Token = Tok_Pragma then + Save_Scan_State (Scan_State); + Scan; -- past Pragma + + if Token = Tok_Identifier + and then Token_Name = Name_Source_Reference + then + Restore_Scan_State (Scan_State); + return Token_Ptr; + end if; + + Restore_Scan_State (Scan_State); + end if; + + -- Otherwise acquire previous comments and blank lines + + if Prev_Token = No_Token then + return Source_First (Current_Source_File); + + else + Loc := Prev_Token_Ptr; + loop + exit when Loc = Token_Ptr; + + if Source (Loc) in Line_Terminator then + Skip_Line_Terminators (Loc, Physical); + exit when Physical; + end if; + + Loc := Loc + 1; + end loop; + + return Loc; + end if; + end Set_Location; + + ------------------ + -- Unit_Display -- + ------------------ + + -- The format of the generated line, as expected by GNATCHOP is + + -- Unit {unit} line {line}, file offset {offs} [, SR], file name {file} + + -- where + + -- {unit} unit name with terminating (spec) or (body) + -- {line} starting line number + -- {offs} offset to start of text in file + -- {file} source file name + + -- The SR parameter is present only if a source reference pragma was + -- scanned for this unit. The significance is that gnatchop should not + -- attempt to add another one. + + procedure Unit_Display + (Cunit : Node_Id; + Loc : Source_Ptr; + SR_Present : Boolean) + is + Unum : constant Unit_Number_Type := Get_Cunit_Unit_Number (Cunit); + Sind : constant Source_File_Index := Source_Index (Unum); + Unam : constant Unit_Name_Type := Unit_Name (Unum); + + begin + if List_Units then + Write_Str ("Unit "); + Write_Unit_Name (Unit_Name (Unum)); + Unit_Location (Sind, Loc); + + if SR_Present then + Write_Str (", SR"); + end if; + + Write_Str (", file name "); + Write_Name (Get_File_Name (Unam, Nkind (Unit (Cunit)) = N_Subunit)); + Write_Eol; + end if; + end Unit_Display; + + ------------------- + -- Unit_Location -- + ------------------- + + procedure Unit_Location (Sind : Source_File_Index; Loc : Source_Ptr) is + Line : constant Logical_Line_Number := Get_Logical_Line_Number (Loc); + -- Should the above be the physical line number ??? + + begin + Write_Str (" line "); + Write_Int (Int (Line)); + + Write_Str (", file offset "); + Write_Int (Int (Loc) - Int (Source_First (Sind))); + end Unit_Location; + +end Ch10; diff --git a/gcc/ada/par-ch11.adb b/gcc/ada/par-ch11.adb new file mode 100644 index 00000000000..8b59c54ea13 --- /dev/null +++ b/gcc/ada/par-ch11.adb @@ -0,0 +1,246 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P A R . C H 1 1 -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.22 $ +-- -- +-- Copyright (C) 1992-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +pragma Style_Checks (All_Checks); +-- Turn off subprogram body ordering check. Subprograms are in order +-- by RM section rather than alphabetical + +with Sinfo.CN; use Sinfo.CN; + +separate (Par) +package body Ch11 is + + -- Local functions, used only in this chapter + + function P_Exception_Handler return Node_Id; + function P_Exception_Choice return Node_Id; + + --------------------------------- + -- 11.1 Exception Declaration -- + --------------------------------- + + -- Parsed by P_Identifier_Declaration (3.3.1) + + ------------------------------------------ + -- 11.2 Handled Sequence Of Statements -- + ------------------------------------------ + + -- HANDLED_SEQUENCE_OF_STATEMENTS ::= + -- SEQUENCE_OF_STATEMENTS + -- [exception + -- EXCEPTION_HANDLER + -- {EXCEPTION_HANDLER}] + + -- Error_Recovery : Cannot raise Error_Resync + + function P_Handled_Sequence_Of_Statements return Node_Id is + Handled_Stmt_Seq_Node : Node_Id; + + begin + Handled_Stmt_Seq_Node := + New_Node (N_Handled_Sequence_Of_Statements, Token_Ptr); + Set_Statements + (Handled_Stmt_Seq_Node, P_Sequence_Of_Statements (SS_Extm_Sreq)); + + if Token = Tok_Exception then + Scan; -- past EXCEPTION + Set_Exception_Handlers + (Handled_Stmt_Seq_Node, Parse_Exception_Handlers); + end if; + + return Handled_Stmt_Seq_Node; + end P_Handled_Sequence_Of_Statements; + + ----------------------------- + -- 11.2 Exception Handler -- + ----------------------------- + + -- EXCEPTION_HANDLER ::= + -- when [CHOICE_PARAMETER_SPECIFICATION :] + -- EXCEPTION_CHOICE {| EXCEPTION_CHOICE} => + -- SEQUENCE_OF_STATEMENTS + + -- CHOICE_PARAMETER_SPECIFICATION ::= DEFINING_IDENTIFIER + + -- Error recovery: cannot raise Error_Resync + + function P_Exception_Handler return Node_Id is + Scan_State : Saved_Scan_State; + Handler_Node : Node_Id; + Choice_Param_Node : Node_Id; + + begin + Handler_Node := New_Node (N_Exception_Handler, Token_Ptr); + T_When; + + -- Test for possible choice parameter present + + if Token = Tok_Identifier then + Choice_Param_Node := Token_Node; + Save_Scan_State (Scan_State); -- at identifier + Scan; -- past identifier + + if Token = Tok_Colon then + if Ada_83 then + Error_Msg_SP ("(Ada 83) choice parameter not allowed!"); + end if; + + Scan; -- past : + Change_Identifier_To_Defining_Identifier (Choice_Param_Node); + Set_Choice_Parameter (Handler_Node, Choice_Param_Node); + + elsif Token = Tok_Others then + Error_Msg_AP ("missing "":"""); + Change_Identifier_To_Defining_Identifier (Choice_Param_Node); + Set_Choice_Parameter (Handler_Node, Choice_Param_Node); + + else + Restore_Scan_State (Scan_State); -- to identifier + end if; + end if; + + -- Loop through exception choices + + Set_Exception_Choices (Handler_Node, New_List); + + loop + Append (P_Exception_Choice, Exception_Choices (Handler_Node)); + exit when Token /= Tok_Vertical_Bar; + Scan; -- past vertical bar + end loop; + + TF_Arrow; + Set_Statements (Handler_Node, P_Sequence_Of_Statements (SS_Sreq_Whtm)); + return Handler_Node; + end P_Exception_Handler; + + ------------------------------------------ + -- 11.2 Choice Parameter Specification -- + ------------------------------------------ + + -- Parsed by P_Exception_Handler (11.2) + + ---------------------------- + -- 11.2 Exception Choice -- + ---------------------------- + + -- EXCEPTION_CHOICE ::= exception_NAME | others + + -- Error recovery: cannot raise Error_Resync. If an error occurs, then the + -- scan pointer is advanced to the next arrow or vertical bar or semicolon. + + function P_Exception_Choice return Node_Id is + begin + + if Token = Tok_Others then + Scan; -- past OTHERS + return New_Node (N_Others_Choice, Prev_Token_Ptr); + + else + return P_Name; -- exception name + end if; + + exception + when Error_Resync => + Resync_Choice; + return Error; + end P_Exception_Choice; + + --------------------------- + -- 11.3 Raise Statement -- + --------------------------- + + -- RAISE_STATEMENT ::= raise [exception_NAME]; + + -- The caller has verified that the initial token is RAISE + + -- Error recovery: can raise Error_Resync + + function P_Raise_Statement return Node_Id is + Raise_Node : Node_Id; + + begin + Raise_Node := New_Node (N_Raise_Statement, Token_Ptr); + Scan; -- past RAISE + + if Token /= Tok_Semicolon then + Set_Name (Raise_Node, P_Name); + end if; + + TF_Semicolon; + return Raise_Node; + end P_Raise_Statement; + + ------------------------------ + -- Parse_Exception_Handlers -- + ------------------------------ + + -- This routine scans out a list of exception handlers appearing in a + -- construct as: + + -- exception + -- EXCEPTION_HANDLER {EXCEPTION_HANDLER} + + -- The caller has scanned out the EXCEPTION keyword + + -- Control returns after scanning the last exception handler, presumably + -- at the keyword END, but this is not checked in this routine. + + -- Error recovery: cannot raise Error_Resync + + function Parse_Exception_Handlers return List_Id is + Handler : Node_Id; + Handlers_List : List_Id; + Pragmas_List : List_Id; + + begin + Handlers_List := New_List; + P_Pragmas_Opt (Handlers_List); + + if Token = Tok_End then + Error_Msg_SC ("must have at least one exception handler!"); + + else + loop + Handler := P_Exception_Handler; + Pragmas_List := No_List; + Append (Handler, Handlers_List); + + -- Note: no need to check for pragmas here. Although the + -- syntax officially allows them in this position, they + -- will have been swallowed up as part of the statement + -- sequence of the handler we just scanned out. + + exit when Token /= Tok_When; + end loop; + end if; + + return Handlers_List; + end Parse_Exception_Handlers; + +end Ch11; diff --git a/gcc/ada/par-ch12.adb b/gcc/ada/par-ch12.adb new file mode 100644 index 00000000000..139243e67e2 --- /dev/null +++ b/gcc/ada/par-ch12.adb @@ -0,0 +1,882 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P A R . C H 1 2 -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.46 $ +-- -- +-- Copyright (C) 1992-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +pragma Style_Checks (All_Checks); +-- Turn off subprogram body ordering check. Subprograms are in order +-- by RM section rather than alphabetical + +separate (Par) +package body Ch12 is + + -- Local functions, used only in this chapter + + function P_Formal_Derived_Type_Definition return Node_Id; + function P_Formal_Discrete_Type_Definition return Node_Id; + function P_Formal_Fixed_Point_Definition return Node_Id; + function P_Formal_Floating_Point_Definition return Node_Id; + function P_Formal_Modular_Type_Definition return Node_Id; + function P_Formal_Package_Declaration return Node_Id; + function P_Formal_Private_Type_Definition return Node_Id; + function P_Formal_Signed_Integer_Type_Definition return Node_Id; + function P_Formal_Subprogram_Declaration return Node_Id; + function P_Formal_Type_Declaration return Node_Id; + function P_Formal_Type_Definition return Node_Id; + function P_Generic_Association return Node_Id; + + procedure P_Formal_Object_Declarations (Decls : List_Id); + -- Scans one or more formal object declarations and appends them to + -- Decls. Scans more than one declaration only in the case where the + -- source has a declaration with multiple defining identifiers. + + -------------------------------- + -- 12.1 Generic (also 8.5.5) -- + -------------------------------- + + -- This routine parses either one of the forms of a generic declaration + -- or a generic renaming declaration. + + -- GENERIC_DECLARATION ::= + -- GENERIC_SUBPROGRAM_DECLARATION | GENERIC_PACKAGE_DECLARATION + + -- GENERIC_SUBPROGRAM_DECLARATION ::= + -- GENERIC_FORMAL_PART SUBPROGRAM_SPECIFICATION; + + -- GENERIC_PACKAGE_DECLARATION ::= + -- GENERIC_FORMAL_PART PACKAGE_SPECIFICATION; + + -- GENERIC_FORMAL_PART ::= + -- generic {GENERIC_FORMAL_PARAMETER_DECLARATION | USE_CLAUSE} + + -- GENERIC_RENAMING_DECLARATION ::= + -- generic package DEFINING_PROGRAM_UNIT_NAME + -- renames generic_package_NAME + -- | generic procedure DEFINING_PROGRAM_UNIT_NAME + -- renames generic_procedure_NAME + -- | generic function DEFINING_PROGRAM_UNIT_NAME + -- renames generic_function_NAME + + -- GENERIC_FORMAL_PARAMETER_DECLARATION ::= + -- FORMAL_OBJECT_DECLARATION + -- | FORMAL_TYPE_DECLARATION + -- | FORMAL_SUBPROGRAM_DECLARATION + -- | FORMAL_PACKAGE_DECLARATION + + -- The caller has checked that the initial token is GENERIC + + -- Error recovery: can raise Error_Resync + + function P_Generic return Node_Id is + Gen_Sloc : constant Source_Ptr := Token_Ptr; + Gen_Decl : Node_Id; + Decl_Node : Node_Id; + Decls : List_Id; + Def_Unit : Node_Id; + Ren_Token : Token_Type; + Scan_State : Saved_Scan_State; + + begin + Scan; -- past GENERIC + + if Token = Tok_Private then + Error_Msg_SC ("PRIVATE goes before GENERIC, not after"); + Scan; -- past junk PRIVATE token + end if; + + Save_Scan_State (Scan_State); -- at token past GENERIC + + -- Check for generic renaming declaration case + + if Token = Tok_Package + or else Token = Tok_Function + or else Token = Tok_Procedure + then + Ren_Token := Token; + Scan; -- scan past PACKAGE, FUNCTION or PROCEDURE + + if Token = Tok_Identifier then + Def_Unit := P_Defining_Program_Unit_Name; + + Check_Misspelling_Of (Tok_Renames); + + if Token = Tok_Renames then + if Ren_Token = Tok_Package then + Decl_Node := New_Node + (N_Generic_Package_Renaming_Declaration, Gen_Sloc); + + elsif Ren_Token = Tok_Procedure then + Decl_Node := New_Node + (N_Generic_Procedure_Renaming_Declaration, Gen_Sloc); + + else -- Ren_Token = Tok_Function then + Decl_Node := New_Node + (N_Generic_Function_Renaming_Declaration, Gen_Sloc); + end if; + + Scan; -- past RENAMES + Set_Defining_Unit_Name (Decl_Node, Def_Unit); + Set_Name (Decl_Node, P_Name); + TF_Semicolon; + return Decl_Node; + end if; + end if; + end if; + + -- Fall through if this is *not* a generic renaming declaration + + Restore_Scan_State (Scan_State); + Decls := New_List; + + -- Loop through generic parameter declarations and use clauses + + Decl_Loop : loop + P_Pragmas_Opt (Decls); + Ignore (Tok_Private); + + if Token = Tok_Use then + Append (P_Use_Clause, Decls); + else + -- Parse a generic parameter declaration + + if Token = Tok_Identifier then + P_Formal_Object_Declarations (Decls); + + elsif Token = Tok_Type then + Append (P_Formal_Type_Declaration, Decls); + + elsif Token = Tok_With then + Scan; -- past WITH + + if Token = Tok_Package then + Append (P_Formal_Package_Declaration, Decls); + + elsif Token = Tok_Procedure or Token = Tok_Function then + Append (P_Formal_Subprogram_Declaration, Decls); + + else + Error_Msg_BC + ("FUNCTION, PROCEDURE or PACKAGE expected here"); + Resync_Past_Semicolon; + end if; + + elsif Token = Tok_Subtype then + Error_Msg_SC ("subtype declaration not allowed " & + "as generic parameter declaration!"); + Resync_Past_Semicolon; + + else + exit Decl_Loop; + end if; + end if; + + end loop Decl_Loop; + + -- Generic formal part is scanned, scan out subprogram or package spec + + if Token = Tok_Package then + Gen_Decl := New_Node (N_Generic_Package_Declaration, Gen_Sloc); + Set_Specification (Gen_Decl, P_Package (Pf_Spcn)); + else + Gen_Decl := New_Node (N_Generic_Subprogram_Declaration, Gen_Sloc); + Set_Specification (Gen_Decl, P_Subprogram_Specification); + TF_Semicolon; + end if; + + Set_Generic_Formal_Declarations (Gen_Decl, Decls); + return Gen_Decl; + end P_Generic; + + ------------------------------- + -- 12.1 Generic Declaration -- + ------------------------------- + + -- Parsed by P_Generic (12.1) + + ------------------------------------------ + -- 12.1 Generic Subprogram Declaration -- + ------------------------------------------ + + -- Parsed by P_Generic (12.1) + + --------------------------------------- + -- 12.1 Generic Package Declaration -- + --------------------------------------- + + -- Parsed by P_Generic (12.1) + + ------------------------------- + -- 12.1 Generic Formal Part -- + ------------------------------- + + -- Parsed by P_Generic (12.1) + + ------------------------------------------------- + -- 12.1 Generic Formal Parameter Declaration -- + ------------------------------------------------- + + -- Parsed by P_Generic (12.1) + + --------------------------------- + -- 12.3 Generic Instantiation -- + --------------------------------- + + -- Generic package instantiation parsed by P_Package (7.1) + -- Generic procedure instantiation parsed by P_Subprogram (6.1) + -- Generic function instantiation parsed by P_Subprogram (6.1) + + ------------------------------- + -- 12.3 Generic Actual Part -- + ------------------------------- + + -- GENERIC_ACTUAL_PART ::= + -- (GENERIC_ASSOCIATION {, GENERIC_ASSOCIATION}) + + -- Returns a list of generic associations, or Empty if none are present + + -- Error recovery: cannot raise Error_Resync + + function P_Generic_Actual_Part_Opt return List_Id is + Association_List : List_Id; + + begin + -- Figure out if a generic actual part operation is present. Clearly + -- there is no generic actual part if the current token is semicolon + + if Token = Tok_Semicolon then + return No_List; + + -- If we don't have a left paren, then we have an error, and the job + -- is to figure out whether a left paren or semicolon was intended. + -- We assume a missing left paren (and hence a generic actual part + -- present) if the current token is not on a new line, or if it is + -- indented from the subprogram token. Otherwise assume missing + -- semicolon (which will be diagnosed by caller) and no generic part + + elsif Token /= Tok_Left_Paren + and then Token_Is_At_Start_Of_Line + and then Start_Column <= Scope.Table (Scope.Last).Ecol + then + return No_List; + + -- Otherwise we have a generic actual part (either a left paren is + -- present, or we have decided that there must be a missing left paren) + + else + Association_List := New_List; + T_Left_Paren; + + loop + Append (P_Generic_Association, Association_List); + exit when not Comma_Present; + end loop; + + T_Right_Paren; + return Association_List; + end if; + + end P_Generic_Actual_Part_Opt; + + ------------------------------- + -- 12.3 Generic Association -- + ------------------------------- + + -- GENERIC_ASSOCIATION ::= + -- [generic_formal_parameter_SELECTOR_NAME =>] + -- EXPLICIT_GENERIC_ACTUAL_PARAMETER + + -- EXPLICIT_GENERIC_ACTUAL_PARAMETER ::= + -- EXPRESSION | variable_NAME | subprogram_NAME + -- | entry_NAME | SUBTYPE_MARK | package_instance_NAME + + -- Error recovery: cannot raise Error_Resync + + function P_Generic_Association return Node_Id is + Scan_State : Saved_Scan_State; + Param_Name_Node : Node_Id; + Generic_Assoc_Node : Node_Id; + + begin + Generic_Assoc_Node := New_Node (N_Generic_Association, Token_Ptr); + + if Token in Token_Class_Desig then + Param_Name_Node := Token_Node; + Save_Scan_State (Scan_State); -- at designator + Scan; -- past simple name or operator symbol + + if Token = Tok_Arrow then + Scan; -- past arrow + Set_Selector_Name (Generic_Assoc_Node, Param_Name_Node); + else + Restore_Scan_State (Scan_State); -- to designator + end if; + end if; + + Set_Explicit_Generic_Actual_Parameter (Generic_Assoc_Node, P_Expression); + return Generic_Assoc_Node; + end P_Generic_Association; + + --------------------------------------------- + -- 12.3 Explicit Generic Actual Parameter -- + --------------------------------------------- + + -- Parsed by P_Generic_Association (12.3) + + -------------------------------------- + -- 12.4 Formal Object Declarations -- + -------------------------------------- + + -- FORMAL_OBJECT_DECLARATION ::= + -- DEFINING_IDENTIFIER_LIST : + -- MODE SUBTYPE_MARK [:= DEFAULT_EXPRESSION]; + + -- The caller has checked that the initial token is an identifier + + -- Error recovery: cannot raise Error_Resync + + procedure P_Formal_Object_Declarations (Decls : List_Id) is + Decl_Node : Node_Id; + Scan_State : Saved_Scan_State; + Num_Idents : Nat; + Ident : Nat; + + Idents : array (Int range 1 .. 4096) of Entity_Id; + -- This array holds the list of defining identifiers. The upper bound + -- of 4096 is intended to be essentially infinite, and we do not even + -- bother to check for it being exceeded. + + begin + Idents (1) := P_Defining_Identifier; + Num_Idents := 1; + + while Comma_Present loop + Num_Idents := Num_Idents + 1; + Idents (Num_Idents) := P_Defining_Identifier; + end loop; + + T_Colon; + + -- If there are multiple identifiers, we repeatedly scan the + -- type and initialization expression information by resetting + -- the scan pointer (so that we get completely separate trees + -- for each occurrence). + + if Num_Idents > 1 then + Save_Scan_State (Scan_State); + end if; + + -- Loop through defining identifiers in list + + Ident := 1; + Ident_Loop : loop + Decl_Node := New_Node (N_Formal_Object_Declaration, Token_Ptr); + Set_Defining_Identifier (Decl_Node, Idents (Ident)); + P_Mode (Decl_Node); + Set_Subtype_Mark (Decl_Node, P_Subtype_Mark_Resync); + No_Constraint; + Set_Expression (Decl_Node, Init_Expr_Opt); + + if Ident > 1 then + Set_Prev_Ids (Decl_Node, True); + end if; + + if Ident < Num_Idents then + Set_More_Ids (Decl_Node, True); + end if; + + Append (Decl_Node, Decls); + + exit Ident_Loop when Ident = Num_Idents; + Ident := Ident + 1; + Restore_Scan_State (Scan_State); + end loop Ident_Loop; + + TF_Semicolon; + end P_Formal_Object_Declarations; + + ----------------------------------- + -- 12.5 Formal Type Declaration -- + ----------------------------------- + + -- FORMAL_TYPE_DECLARATION ::= + -- type DEFINING_IDENTIFIER [DISCRIMINANT_PART] + -- is FORMAL_TYPE_DEFINITION; + + -- The caller has checked that the initial token is TYPE + + -- Error recovery: cannot raise Error_Resync + + function P_Formal_Type_Declaration return Node_Id is + Decl_Node : Node_Id; + + begin + Decl_Node := New_Node (N_Formal_Type_Declaration, Token_Ptr); + Scan; -- past TYPE + Set_Defining_Identifier (Decl_Node, P_Defining_Identifier); + + if P_Unknown_Discriminant_Part_Opt then + Set_Unknown_Discriminants_Present (Decl_Node, True); + else + Set_Discriminant_Specifications + (Decl_Node, P_Known_Discriminant_Part_Opt); + end if; + + T_Is; + + Set_Formal_Type_Definition (Decl_Node, P_Formal_Type_Definition); + TF_Semicolon; + return Decl_Node; + end P_Formal_Type_Declaration; + + ---------------------------------- + -- 12.5 Formal Type Definition -- + ---------------------------------- + + -- FORMAL_TYPE_DEFINITION ::= + -- FORMAL_PRIVATE_TYPE_DEFINITION + -- | FORMAL_DERIVED_TYPE_DEFINITION + -- | FORMAL_DISCRETE_TYPE_DEFINITION + -- | FORMAL_SIGNED_INTEGER_TYPE_DEFINITION + -- | FORMAL_MODULAR_TYPE_DEFINITION + -- | FORMAL_FLOATING_POINT_DEFINITION + -- | FORMAL_ORDINARY_FIXED_POINT_DEFINITION + -- | FORMAL_DECIMAL_FIXED_POINT_DEFINITION + -- | FORMAL_ARRAY_TYPE_DEFINITION + -- | FORMAL_ACCESS_TYPE_DEFINITION + + -- FORMAL_ARRAY_TYPE_DEFINITION ::= ARRAY_TYPE_DEFINITION + + -- FORMAL_ACCESS_TYPE_DEFINITION ::= ACCESS_TYPE_DEFINITION + + function P_Formal_Type_Definition return Node_Id is + Scan_State : Saved_Scan_State; + + begin + if Token_Name = Name_Abstract then + Check_95_Keyword (Tok_Abstract, Tok_Tagged); + end if; + + if Token_Name = Name_Tagged then + Check_95_Keyword (Tok_Tagged, Tok_Private); + Check_95_Keyword (Tok_Tagged, Tok_Limited); + end if; + + case Token is + + -- Mostly we can tell what we have from the initial token. The one + -- exception is ABSTRACT, where we have to scan ahead to see if we + -- have a formal derived type or a formal private type definition. + + when Tok_Abstract => + Save_Scan_State (Scan_State); + Scan; -- past ABSTRACT + + if Token = Tok_New then + Restore_Scan_State (Scan_State); -- to ABSTRACT + return P_Formal_Derived_Type_Definition; + + else + Restore_Scan_State (Scan_State); -- to ABSTRACT + return P_Formal_Private_Type_Definition; + end if; + + when Tok_Private | Tok_Limited | Tok_Tagged => + return P_Formal_Private_Type_Definition; + + when Tok_New => + return P_Formal_Derived_Type_Definition; + + when Tok_Left_Paren => + return P_Formal_Discrete_Type_Definition; + + when Tok_Range => + return P_Formal_Signed_Integer_Type_Definition; + + when Tok_Mod => + return P_Formal_Modular_Type_Definition; + + when Tok_Digits => + return P_Formal_Floating_Point_Definition; + + when Tok_Delta => + return P_Formal_Fixed_Point_Definition; + + when Tok_Array => + return P_Array_Type_Definition; + + when Tok_Access => + return P_Access_Type_Definition; + + when Tok_Record => + Error_Msg_SC ("record not allowed in generic type definition!"); + Discard_Junk_Node (P_Record_Definition); + return Error; + + when others => + Error_Msg_BC ("expecting generic type definition here"); + Resync_Past_Semicolon; + return Error; + + end case; + end P_Formal_Type_Definition; + + -------------------------------------------- + -- 12.5.1 Formal Private Type Definition -- + -------------------------------------------- + + -- FORMAL_PRIVATE_TYPE_DEFINITION ::= + -- [[abstract] tagged] [limited] private + + -- The caller has checked the initial token is PRIVATE, ABSTRACT, + -- TAGGED or LIMITED + + -- Error recovery: cannot raise Error_Resync + + function P_Formal_Private_Type_Definition return Node_Id is + Def_Node : Node_Id; + + begin + Def_Node := New_Node (N_Formal_Private_Type_Definition, Token_Ptr); + + if Token = Tok_Abstract then + Scan; -- past ABSTRACT + + if Token_Name = Name_Tagged then + Check_95_Keyword (Tok_Tagged, Tok_Private); + Check_95_Keyword (Tok_Tagged, Tok_Limited); + end if; + + if Token /= Tok_Tagged then + Error_Msg_SP ("ABSTRACT must be followed by TAGGED"); + else + Set_Abstract_Present (Def_Node, True); + end if; + end if; + + if Token = Tok_Tagged then + Set_Tagged_Present (Def_Node, True); + Scan; -- past TAGGED + end if; + + if Token = Tok_Limited then + Set_Limited_Present (Def_Node, True); + Scan; -- past LIMITED + end if; + + Set_Sloc (Def_Node, Token_Ptr); + T_Private; + return Def_Node; + end P_Formal_Private_Type_Definition; + + -------------------------------------------- + -- 12.5.1 Formal Derived Type Definition -- + -------------------------------------------- + + -- FORMAL_DERIVED_TYPE_DEFINITION ::= + -- [abstract] new SUBTYPE_MARK [with private] + + -- The caller has checked the initial token(s) is/are NEW or ASTRACT NEW + + -- Error recovery: cannot raise Error_Resync + + function P_Formal_Derived_Type_Definition return Node_Id is + Def_Node : Node_Id; + + begin + Def_Node := New_Node (N_Formal_Derived_Type_Definition, Token_Ptr); + + if Token = Tok_Abstract then + Set_Abstract_Present (Def_Node); + Scan; -- past ABSTRACT + end if; + + Scan; -- past NEW; + Set_Subtype_Mark (Def_Node, P_Subtype_Mark); + No_Constraint; + + if Token = Tok_With then + Scan; -- past WITH + Set_Private_Present (Def_Node, True); + T_Private; + end if; + + return Def_Node; + end P_Formal_Derived_Type_Definition; + + --------------------------------------------- + -- 12.5.2 Formal Discrete Type Definition -- + --------------------------------------------- + + -- FORMAL_DISCRETE_TYPE_DEFINITION ::= (<>) + + -- The caller has checked the initial token is left paren + + -- Error recovery: cannot raise Error_Resync + + function P_Formal_Discrete_Type_Definition return Node_Id is + Def_Node : Node_Id; + + begin + Def_Node := New_Node (N_Formal_Discrete_Type_Definition, Token_Ptr); + Scan; -- past left paren + T_Box; + T_Right_Paren; + return Def_Node; + end P_Formal_Discrete_Type_Definition; + + --------------------------------------------------- + -- 12.5.2 Formal Signed Integer Type Definition -- + --------------------------------------------------- + + -- FORMAL_SIGNED_INTEGER_TYPE_DEFINITION ::= range <> + + -- The caller has checked the initial token is RANGE + + -- Error recovery: cannot raise Error_Resync + + function P_Formal_Signed_Integer_Type_Definition return Node_Id is + Def_Node : Node_Id; + + begin + Def_Node := + New_Node (N_Formal_Signed_Integer_Type_Definition, Token_Ptr); + Scan; -- past RANGE + T_Box; + return Def_Node; + end P_Formal_Signed_Integer_Type_Definition; + + -------------------------------------------- + -- 12.5.2 Formal Modular Type Definition -- + -------------------------------------------- + + -- FORMAL_MODULAR_TYPE_DEFINITION ::= mod <> + + -- The caller has checked the initial token is MOD + + -- Error recovery: cannot raise Error_Resync + + function P_Formal_Modular_Type_Definition return Node_Id is + Def_Node : Node_Id; + + begin + Def_Node := + New_Node (N_Formal_Modular_Type_Definition, Token_Ptr); + Scan; -- past MOD + T_Box; + return Def_Node; + end P_Formal_Modular_Type_Definition; + + ---------------------------------------------- + -- 12.5.2 Formal Floating Point Definition -- + ---------------------------------------------- + + -- FORMAL_FLOATING_POINT_DEFINITION ::= digits <> + + -- The caller has checked the initial token is DIGITS + + -- Error recovery: cannot raise Error_Resync + + function P_Formal_Floating_Point_Definition return Node_Id is + Def_Node : Node_Id; + + begin + Def_Node := + New_Node (N_Formal_Floating_Point_Definition, Token_Ptr); + Scan; -- past DIGITS + T_Box; + return Def_Node; + end P_Formal_Floating_Point_Definition; + + ------------------------------------------- + -- 12.5.2 Formal Fixed Point Definition -- + ------------------------------------------- + + -- This routine parses either a formal ordinary fixed point definition + -- or a formal decimal fixed point definition: + + -- FORMAL_ORDINARY_FIXED_POINT_DEFINITION ::= delta <> + + -- FORMAL_DECIMAL_FIXED_POINT_DEFINITION ::= delta <> digits <> + + -- The caller has checked the initial token is DELTA + + -- Error recovery: cannot raise Error_Resync + + function P_Formal_Fixed_Point_Definition return Node_Id is + Def_Node : Node_Id; + Delta_Sloc : Source_Ptr; + + begin + Delta_Sloc := Token_Ptr; + Scan; -- past DELTA + T_Box; + + if Token = Tok_Digits then + Def_Node := + New_Node (N_Formal_Decimal_Fixed_Point_Definition, Delta_Sloc); + Scan; -- past DIGITS + T_Box; + else + Def_Node := + New_Node (N_Formal_Ordinary_Fixed_Point_Definition, Delta_Sloc); + end if; + + return Def_Node; + end P_Formal_Fixed_Point_Definition; + + ---------------------------------------------------- + -- 12.5.2 Formal Ordinary Fixed Point Definition -- + ---------------------------------------------------- + + -- Parsed by P_Formal_Fixed_Point_Definition (12.5.2) + + --------------------------------------------------- + -- 12.5.2 Formal Decimal Fixed Point Definition -- + --------------------------------------------------- + + -- Parsed by P_Formal_Fixed_Point_Definition (12.5.2) + + ------------------------------------------ + -- 12.5.3 Formal Array Type Definition -- + ------------------------------------------ + + -- Parsed by P_Formal_Type_Definition (12.5) + + ------------------------------------------- + -- 12.5.4 Formal Access Type Definition -- + ------------------------------------------- + + -- Parsed by P_Formal_Type_Definition (12.5) + + ----------------------------------------- + -- 12.6 Formal Subprogram Declaration -- + ----------------------------------------- + + -- FORMAL_SUBPROGRAM_DECLARATION ::= + -- with SUBPROGRAM_SPECIFICATION [is SUBPROGRAM_DEFAULT]; + + -- SUBPROGRAM_DEFAULT ::= DEFAULT_NAME | <> + + -- DEFAULT_NAME ::= NAME + + -- The caller has checked that the initial tokens are WITH FUNCTION or + -- WITH PROCEDURE, and the initial WITH has been scanned out. + + -- Note: we separate this into two procedures because the name is allowed + -- to be an operator symbol for a function, but not for a procedure. + + -- Error recovery: cannot raise Error_Resync + + function P_Formal_Subprogram_Declaration return Node_Id is + Def_Node : Node_Id; + + begin + Def_Node := New_Node (N_Formal_Subprogram_Declaration, Prev_Token_Ptr); + Set_Specification (Def_Node, P_Subprogram_Specification); + + if Token = Tok_Is then + T_Is; -- past IS, skip extra IS or ";" + + if Token = Tok_Box then + Set_Box_Present (Def_Node, True); + Scan; -- past <> + + else + Set_Default_Name (Def_Node, P_Name); + end if; + + end if; + + T_Semicolon; + return Def_Node; + end P_Formal_Subprogram_Declaration; + + ------------------------------ + -- 12.6 Subprogram Default -- + ------------------------------ + + -- Parsed by P_Formal_Procedure_Declaration (12.6) + + ------------------------ + -- 12.6 Default Name -- + ------------------------ + + -- Parsed by P_Formal_Procedure_Declaration (12.6) + + -------------------------------------- + -- 12.7 Formal Package Declaration -- + -------------------------------------- + + -- FORMAL_PACKAGE_DECLARATION ::= + -- with package DEFINING_IDENTIFIER + -- is new generic_package_NAME FORMAL_PACKAGE_ACTUAL_PART; + + -- FORMAL_PACKAGE_ACTUAL_PART ::= + -- (<>) | [GENERIC_ACTUAL_PART] + + -- The caller has checked that the initial tokens are WITH PACKAGE, + -- and the initial WITH has been scanned out (so Token = Tok_Package). + + -- Error recovery: cannot raise Error_Resync + + function P_Formal_Package_Declaration return Node_Id is + Def_Node : Node_Id; + Scan_State : Saved_Scan_State; + + begin + Def_Node := New_Node (N_Formal_Package_Declaration, Prev_Token_Ptr); + Scan; -- past PACKAGE + Set_Defining_Identifier (Def_Node, P_Defining_Identifier); + T_Is; + T_New; + Set_Name (Def_Node, P_Qualified_Simple_Name); + + if Token = Tok_Left_Paren then + Save_Scan_State (Scan_State); -- at the left paren + Scan; -- past the left paren + + if Token = Tok_Box then + Set_Box_Present (Def_Node, True); + Scan; -- past box + T_Right_Paren; + + else + Restore_Scan_State (Scan_State); -- to the left paren + Set_Generic_Associations (Def_Node, P_Generic_Actual_Part_Opt); + end if; + end if; + + T_Semicolon; + return Def_Node; + end P_Formal_Package_Declaration; + + -------------------------------------- + -- 12.7 Formal Package Actual Part -- + -------------------------------------- + + -- Parsed by P_Formal_Package_Declaration (12.7) + +end Ch12; diff --git a/gcc/ada/par-ch13.adb b/gcc/ada/par-ch13.adb new file mode 100644 index 00000000000..03bd7bf1275 --- /dev/null +++ b/gcc/ada/par-ch13.adb @@ -0,0 +1,441 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P A R . C H 1 3 -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.34 $ +-- -- +-- Copyright (C) 1992-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +pragma Style_Checks (All_Checks); +-- Turn off subprogram body ordering check. Subprograms are in order +-- by RM section rather than alphabetical + +separate (Par) +package body Ch13 is + + -- Local functions, used only in this chapter + + function P_Component_Clause return Node_Id; + function P_Mod_Clause return Node_Id; + + -------------------------------------------- + -- 13.1 Representation Clause (also I.7) -- + -------------------------------------------- + + -- REPRESENTATION_CLAUSE ::= + -- ATTRIBUTE_DEFINITION_CLAUSE + -- | ENUMERATION_REPRESENTATION_CLAUSE + -- | RECORD_REPRESENTATION_CLAUSE + -- | AT_CLAUSE + + -- ATTRIBUTE_DEFINITION_CLAUSE ::= + -- for LOCAL_NAME'ATTRIBUTE_DESIGNATOR use EXPRESSION; + -- | for LOCAL_NAME'ATTRIBUTE_DESIGNATOR use NAME; + + -- Note: in Ada 83, the expression must be a simple expression + + -- AT_CLAUSE ::= for DIRECT_NAME use at EXPRESSION; + + -- Note: in Ada 83, the expression must be a simple expression + + -- ENUMERATION_REPRESENTATION_CLAUSE ::= + -- for first_subtype_LOCAL_NAME use ENUMERATION_AGGREGATE; + + -- ENUMERATION_AGGREGATE ::= ARRAY_AGGREGATE + + -- RECORD_REPRESENTATION_CLAUSE ::= + -- for first_subtype_LOCAL_NAME use + -- record [MOD_CLAUSE] + -- {COMPONENT_CLAUSE} + -- end record; + + -- Note: for now we allow only a direct name as the local name in the + -- above constructs. This probably needs changing later on ??? + + -- The caller has checked that the initial token is FOR + + -- Error recovery: cannot raise Error_Resync, if an error occurs, + -- the scan is repositioned past the next semicolon. + + function P_Representation_Clause return Node_Id is + For_Loc : Source_Ptr; + Name_Node : Node_Id; + Prefix_Node : Node_Id; + Attr_Name : Name_Id; + Identifier_Node : Node_Id; + Rep_Clause_Node : Node_Id; + Expr_Node : Node_Id; + Record_Items : List_Id; + + begin + For_Loc := Token_Ptr; + Scan; -- past FOR + + -- Note that the name in a representation clause is always a simple + -- name, even in the attribute case, see AI-300 which made this so! + + Identifier_Node := P_Identifier; + + -- Check case of qualified name to give good error message + + if Token = Tok_Dot then + Error_Msg_SC + ("representation clause requires simple name!"); + + loop + exit when Token /= Tok_Dot; + Scan; -- past dot + Discard_Junk_Node (P_Identifier); + end loop; + end if; + + -- Attribute Definition Clause + + if Token = Tok_Apostrophe then + + -- Allow local names of the form a'b'.... This enables + -- us to parse class-wide streams attributes correctly. + + Name_Node := Identifier_Node; + while Token = Tok_Apostrophe loop + + Scan; -- past apostrophe + + Identifier_Node := Token_Node; + Attr_Name := No_Name; + + if Token = Tok_Identifier then + Attr_Name := Token_Name; + + if not Is_Attribute_Name (Attr_Name) then + Signal_Bad_Attribute; + end if; + + if Style_Check then + Style.Check_Attribute_Name (False); + end if; + + -- Here for case of attribute designator is not an identifier + + else + if Token = Tok_Delta then + Attr_Name := Name_Delta; + + elsif Token = Tok_Digits then + Attr_Name := Name_Digits; + + elsif Token = Tok_Access then + Attr_Name := Name_Access; + + else + Error_Msg_AP ("attribute designator expected"); + raise Error_Resync; + end if; + + if Style_Check then + Style.Check_Attribute_Name (True); + end if; + end if; + + -- We come here with an OK attribute scanned, and the + -- corresponding Attribute identifier node stored in Ident_Node. + + Prefix_Node := Name_Node; + Name_Node := New_Node (N_Attribute_Reference, Prev_Token_Ptr); + Set_Prefix (Name_Node, Prefix_Node); + Set_Attribute_Name (Name_Node, Attr_Name); + Scan; + end loop; + + Rep_Clause_Node := New_Node (N_Attribute_Definition_Clause, For_Loc); + Set_Name (Rep_Clause_Node, Prefix_Node); + Set_Chars (Rep_Clause_Node, Attr_Name); + T_Use; + + Expr_Node := P_Expression_No_Right_Paren; + Check_Simple_Expression_In_Ada_83 (Expr_Node); + Set_Expression (Rep_Clause_Node, Expr_Node); + + else + TF_Use; + Rep_Clause_Node := Empty; + + -- AT follows USE (At Clause) + + if Token = Tok_At then + Scan; -- past AT + Rep_Clause_Node := New_Node (N_At_Clause, For_Loc); + Set_Identifier (Rep_Clause_Node, Identifier_Node); + Expr_Node := P_Expression_No_Right_Paren; + Check_Simple_Expression_In_Ada_83 (Expr_Node); + Set_Expression (Rep_Clause_Node, Expr_Node); + + -- RECORD follows USE (Record Representation Clause) + + elsif Token = Tok_Record then + Record_Items := P_Pragmas_Opt; + Rep_Clause_Node := + New_Node (N_Record_Representation_Clause, For_Loc); + Set_Identifier (Rep_Clause_Node, Identifier_Node); + + Push_Scope_Stack; + Scope.Table (Scope.Last).Etyp := E_Record; + Scope.Table (Scope.Last).Ecol := Start_Column; + Scope.Table (Scope.Last).Sloc := Token_Ptr; + Scan; -- past RECORD + Record_Items := P_Pragmas_Opt; + + -- Possible Mod Clause + + if Token = Tok_At then + Set_Mod_Clause (Rep_Clause_Node, P_Mod_Clause); + Set_Pragmas_Before (Mod_Clause (Rep_Clause_Node), Record_Items); + Record_Items := P_Pragmas_Opt; + end if; + + if No (Record_Items) then + Record_Items := New_List; + end if; + + Set_Component_Clauses (Rep_Clause_Node, Record_Items); + + -- Loop through component clauses + + loop + if Token not in Token_Class_Name then + exit when Check_End; + end if; + + Append (P_Component_Clause, Record_Items); + P_Pragmas_Opt (Record_Items); + end loop; + + -- Left paren follows USE (Enumeration Representation Clause) + + elsif Token = Tok_Left_Paren then + Rep_Clause_Node := + New_Node (N_Enumeration_Representation_Clause, For_Loc); + Set_Identifier (Rep_Clause_Node, Identifier_Node); + Set_Array_Aggregate (Rep_Clause_Node, P_Aggregate); + + -- Some other token follows FOR (invalid representation clause) + + else + Error_Msg_SC ("invalid representation clause"); + raise Error_Resync; + end if; + end if; + + TF_Semicolon; + return Rep_Clause_Node; + + exception + when Error_Resync => + Resync_Past_Semicolon; + return Error; + + end P_Representation_Clause; + + ---------------------- + -- 13.1 Local Name -- + ---------------------- + + -- Local name is always parsed by its parent. In the case of its use in + -- pragmas, the check for a local name is handled in Par.Prag and allows + -- all the possible forms of local name. For the uses in chapter 13, we + -- currently only allow a direct name, but this should probably change??? + + --------------------------- + -- 13.1 At Clause (I.7) -- + --------------------------- + + -- Parsed by P_Representation_Clause (13.1) + + --------------------------------------- + -- 13.3 Attribute Definition Clause -- + --------------------------------------- + + -- Parsed by P_Representation_Clause (13.1) + + --------------------------------------------- + -- 13.4 Enumeration Representation Clause -- + --------------------------------------------- + + -- Parsed by P_Representation_Clause (13.1) + + --------------------------------- + -- 13.4 Enumeration Aggregate -- + --------------------------------- + + -- Parsed by P_Representation_Clause (13.1) + + ------------------------------------------ + -- 13.5.1 Record Representation Clause -- + ------------------------------------------ + + -- Parsed by P_Representation_Clause (13.1) + + ------------------------------ + -- 13.5.1 Mod Clause (I.8) -- + ------------------------------ + + -- MOD_CLAUSE ::= at mod static_EXPRESSION; + + -- Note: in Ada 83, the expression must be a simple expression + + -- The caller has checked that the initial Token is AT + + -- Error recovery: cannot raise Error_Resync + + -- Note: the caller is responsible for setting the Pragmas_Before field + + function P_Mod_Clause return Node_Id is + Mod_Node : Node_Id; + Expr_Node : Node_Id; + + begin + Mod_Node := New_Node (N_Mod_Clause, Token_Ptr); + Scan; -- past AT + T_Mod; + Expr_Node := P_Expression_No_Right_Paren; + Check_Simple_Expression_In_Ada_83 (Expr_Node); + Set_Expression (Mod_Node, Expr_Node); + TF_Semicolon; + return Mod_Node; + end P_Mod_Clause; + + ------------------------------ + -- 13.5.1 Component Clause -- + ------------------------------ + + -- COMPONENT_CLAUSE ::= + -- COMPONENT_CLAUSE_COMPONENT_NAME at POSITION + -- range FIRST_BIT .. LAST_BIT; + + -- COMPONENT_CLAUSE_COMPONENT_NAME ::= + -- component_DIRECT_NAME + -- | component_DIRECT_NAME'ATTRIBUTE_DESIGNATOR + -- | FIRST_SUBTYPE_DIRECT_NAME'ATTRIBUTE_DESIGNATOR + + -- POSITION ::= static_EXPRESSION + + -- Note: in Ada 83, the expression must be a simple expression + + -- FIRST_BIT ::= static_SIMPLE_EXPRESSION + -- LAST_BIT ::= static_SIMPLE_EXPRESSION + + -- Note: the AARM V2.0 grammar has an error at this point, it uses + -- EXPRESSION instead of SIMPLE_EXPRESSION for FIRST_BIT and LAST_BIT + + -- Error recovery: cannot raise Error_Resync + + function P_Component_Clause return Node_Id is + Component_Node : Node_Id; + Comp_Name : Node_Id; + Expr_Node : Node_Id; + + begin + Component_Node := New_Node (N_Component_Clause, Token_Ptr); + Comp_Name := P_Name; + + if Nkind (Comp_Name) = N_Identifier + or else Nkind (Comp_Name) = N_Attribute_Reference + then + Set_Component_Name (Component_Node, Comp_Name); + else + Error_Msg_N + ("component name must be direct name or attribute", Comp_Name); + Set_Component_Name (Component_Node, Error); + end if; + + Set_Sloc (Component_Node, Token_Ptr); + T_At; + Expr_Node := P_Expression_No_Right_Paren; + Check_Simple_Expression_In_Ada_83 (Expr_Node); + Set_Position (Component_Node, Expr_Node); + T_Range; + Expr_Node := P_Expression_No_Right_Paren; + Check_Simple_Expression_In_Ada_83 (Expr_Node); + Set_First_Bit (Component_Node, Expr_Node); + T_Dot_Dot; + Expr_Node := P_Expression_No_Right_Paren; + Check_Simple_Expression_In_Ada_83 (Expr_Node); + Set_Last_Bit (Component_Node, Expr_Node); + TF_Semicolon; + return Component_Node; + end P_Component_Clause; + + ---------------------- + -- 13.5.1 Position -- + ---------------------- + + -- Parsed by P_Component_Clause (13.5.1) + + ----------------------- + -- 13.5.1 First Bit -- + ----------------------- + + -- Parsed by P_Component_Clause (13.5.1) + + ---------------------- + -- 13.5.1 Last Bit -- + ---------------------- + + -- Parsed by P_Component_Clause (13.5.1) + + -------------------------- + -- 13.8 Code Statement -- + -------------------------- + + -- CODE_STATEMENT ::= QUALIFIED_EXPRESSION + + -- On entry the caller has scanned the SUBTYPE_MARK (passed in as the + -- single argument, and the scan points to the apostrophe. + + -- Error recovery: can raise Error_Resync + + function P_Code_Statement (Subtype_Mark : Node_Id) return Node_Id is + Node1 : Node_Id; + + begin + Scan; -- past apostrophe + + -- If left paren, then we have a possible code statement + + if Token = Tok_Left_Paren then + Node1 := New_Node (N_Code_Statement, Sloc (Subtype_Mark)); + Set_Expression (Node1, P_Qualified_Expression (Subtype_Mark)); + TF_Semicolon; + return Node1; + + -- Otherwise we have an illegal range attribute. Note that P_Name + -- ensures that Token = Tok_Range is the only possibility left here. + + else -- Token = Tok_Range + Error_Msg_SC ("RANGE attribute illegal here!"); + raise Error_Resync; + end if; + + end P_Code_Statement; + +end Ch13; diff --git a/gcc/ada/par-ch2.adb b/gcc/ada/par-ch2.adb new file mode 100644 index 00000000000..0eeacead811 --- /dev/null +++ b/gcc/ada/par-ch2.adb @@ -0,0 +1,405 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P A R . C H 2 -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.35 $ -- +-- -- +-- Copyright (C) 1992-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +pragma Style_Checks (All_Checks); +-- Turn off subprogram body ordering check. Subprograms are in order +-- by RM section rather than alphabetical + +separate (Par) +package body Ch2 is + + -- Local functions, used only in this chapter + + function P_Pragma_Argument_Association return Node_Id; + + --------------------- + -- 2.3 Identifier -- + --------------------- + + -- IDENTIFIER ::= LETTER {[UNDERLINE] LETTER_OR_DIGIT} + + -- LETTER_OR_DIGIT ::= IDENTIFIER_LETTER | DIGIT + + -- An IDENTIFIER shall not be a reserved word + + -- Error recovery: can raise Error_Resync (cannot return Error) + + function P_Identifier return Node_Id is + Ident_Node : Node_Id; + + begin + -- All set if we do indeed have an identifier + + if Token = Tok_Identifier then + Ident_Node := Token_Node; + Scan; -- past Identifier + return Ident_Node; + + -- If we have a reserved identifier, manufacture an identifier with + -- a corresponding name after posting an appropriate error message + + elsif Is_Reserved_Identifier then + Scan_Reserved_Identifier (Force_Msg => False); + Ident_Node := Token_Node; + Scan; -- past the node + return Ident_Node; + + -- Otherwise we have junk that cannot be interpreted as an identifier + + else + T_Identifier; -- to give message + raise Error_Resync; + end if; + end P_Identifier; + + -------------------------- + -- 2.3 Letter Or Digit -- + -------------------------- + + -- Parsed by P_Identifier (2.3) + + -------------------------- + -- 2.4 Numeric Literal -- + -------------------------- + + -- NUMERIC_LITERAL ::= DECIMAL_LITERAL | BASED_LITERAL + + -- Numeric literal is returned by the scanner as either + -- Tok_Integer_Literal or Tok_Real_Literal + + ---------------------------- + -- 2.4.1 Decimal Literal -- + ---------------------------- + + -- DECIMAL_LITERAL ::= NUMERAL [.NUMERAL] [EXPONENT] + + -- Handled by scanner as part of numeric lIteral handing (see 2.4) + + -------------------- + -- 2.4.1 Numeral -- + -------------------- + + -- NUMERAL ::= DIGIT {[UNDERLINE] DIGIT} + + -- Handled by scanner as part of numeric literal handling (see 2.4) + + --------------------- + -- 2.4.1 Exponent -- + --------------------- + + -- EXPONENT ::= E [+] NUMERAL | E - NUMERAL + + -- Handled by scanner as part of numeric literal handling (see 2.4) + + -------------------------- + -- 2.4.2 Based Literal -- + -------------------------- + + -- BASED_LITERAL ::= + -- BASE # BASED_NUMERAL [.BASED_NUMERAL] # [EXPONENT] + + -- Handled by scanner as part of numeric literal handling (see 2.4) + + ----------------- + -- 2.4.2 Base -- + ----------------- + + -- BASE ::= NUMERAL + + -- Handled by scanner as part of numeric literal handling (see 2.4) + + -------------------------- + -- 2.4.2 Based Numeral -- + -------------------------- + + -- BASED_NUMERAL ::= + -- EXTENDED_DIGIT {[UNDERLINE] EXTENDED_DIGIT} + + -- Handled by scanner as part of numeric literal handling (see 2.4) + + --------------------------- + -- 2.4.2 Extended Digit -- + --------------------------- + + -- EXTENDED_DIGIT ::= DIGIT | A | B | C | D | E | F + + -- Handled by scanner as part of numeric literal handling (see 2.4) + + ---------------------------- + -- 2.5 Character Literal -- + ---------------------------- + + -- CHARACTER_LITERAL ::= ' GRAPHIC_CHARACTER ' + + -- Handled by the scanner and returned as Tok_Character_Literal + + ------------------------- + -- 2.6 String Literal -- + ------------------------- + + -- STRING LITERAL ::= "{STRING_ELEMENT}" + + -- Handled by the scanner and returned as Tok_Character_Literal + -- or if the string looks like an operator as Tok_Operator_Symbol. + + ------------------------- + -- 2.6 String Element -- + ------------------------- + + -- STRING_ELEMENT ::= "" | non-quotation_mark_GRAPHIC_CHARACTER + + -- A STRING_ELEMENT is either a pair of quotation marks ("), + -- or a single GRAPHIC_CHARACTER other than a quotation mark. + + -- Handled by scanner as part of string literal handling (see 2.4) + + ------------------ + -- 2.7 Comment -- + ------------------ + + -- A COMMENT starts with two adjacent hyphens and extends up to the + -- end of the line. A COMMENT may appear on any line of a program. + + -- Handled by the scanner which simply skips past encountered comments + + ----------------- + -- 2.8 Pragma -- + ----------------- + + -- PRAGMA ::= pragma IDENTIFIER + -- [(PRAGMA_ARGUMENT_ASSOCIATION {, PRAGMA_ARGUMENT_ASSOCIATION})]; + + -- The caller has checked that the initial token is PRAGMA + + -- Error recovery: cannot raise Error_Resync + + -- One special piece of processing is needed in this routine. As described + -- in the section on "Handling semicolon used in place of IS" in module + -- Parse, the parser detects the case of missing subprogram bodies to + -- allow recovery from this syntactic error. Pragma INTERFACE (and, for + -- Ada 95, pragma IMPORT) can appear in place of the body. The parser must + -- recognize the use of these two pragmas in this context, otherwise it + -- will think there are missing bodies, and try to change ; to IS, when + -- in fact the bodies ARE present, supplied by these pragmas. + + function P_Pragma return Node_Id is + + Interface_Check_Required : Boolean := False; + -- Set True if check of pragma INTERFACE is required + + Import_Check_Required : Boolean := False; + -- Set True if check of pragma IMPORT is required + + Arg_Count : Int := 0; + -- Number of argument associations processed + + Pragma_Node : Node_Id; + Pragma_Name : Name_Id; + Semicolon_Loc : Source_Ptr; + Ident_Node : Node_Id; + Assoc_Node : Node_Id; + + begin + Pragma_Node := New_Node (N_Pragma, Token_Ptr); + Scan; -- past PRAGMA + Pragma_Name := Token_Name; + + if Style_Check then + Style.Check_Pragma_Name; + end if; + + Ident_Node := P_Identifier; + Set_Chars (Pragma_Node, Pragma_Name); + Delete_Node (Ident_Node); + + -- See if special INTERFACE/IMPORT check is required + + if SIS_Entry_Active then + Interface_Check_Required := (Pragma_Name = Name_Interface); + Import_Check_Required := (Pragma_Name = Name_Import); + else + Interface_Check_Required := False; + Import_Check_Required := False; + end if; + + -- Scan arguments. We assume that arguments are present if there is + -- a left paren, or if a semicolon is missing and there is another + -- token on the same line as the pragma name. + + if Token = Tok_Left_Paren + or else (Token /= Tok_Semicolon + and then not Token_Is_At_Start_Of_Line) + then + Set_Pragma_Argument_Associations (Pragma_Node, New_List); + T_Left_Paren; + + loop + Arg_Count := Arg_Count + 1; + Assoc_Node := P_Pragma_Argument_Association; + + if Arg_Count = 2 + and then (Interface_Check_Required or else Import_Check_Required) + then + -- Here is where we cancel the SIS active status if this pragma + -- supplies a body for the currently active subprogram spec. + + if Nkind (Expression (Assoc_Node)) in N_Direct_Name + and then Chars (Expression (Assoc_Node)) = Chars (SIS_Labl) + then + SIS_Entry_Active := False; + end if; + end if; + + Append (Assoc_Node, Pragma_Argument_Associations (Pragma_Node)); + exit when Token /= Tok_Comma; + Scan; -- past comma + end loop; + + T_Right_Paren; + end if; + + Semicolon_Loc := Token_Ptr; + + if Token /= Tok_Semicolon then + T_Semicolon; + Resync_Past_Semicolon; + else + Scan; -- past semicolon + end if; + + if Is_Pragma_Name (Chars (Pragma_Node)) then + return Par.Prag (Pragma_Node, Semicolon_Loc); + + else + -- Unrecognized pragma, warning generated in Sem_Prag + + return Pragma_Node; + end if; + + exception + when Error_Resync => + Resync_Past_Semicolon; + return Error; + + end P_Pragma; + + -- This routine is called if a pragma is encountered in an inappropriate + -- position, the pragma is scanned out and control returns to continue. + + -- The caller has checked that the initial token is pragma + + -- Error recovery: cannot raise Error_Resync + + procedure P_Pragmas_Misplaced is + begin + while Token = Tok_Pragma loop + Error_Msg_SC ("pragma not allowed here"); + Discard_Junk_Node (P_Pragma); + end loop; + end P_Pragmas_Misplaced; + + -- This function is called to scan out an optional sequence of pragmas. + -- If no pragmas are found, then No_List is returned. + + -- Error recovery: Cannot raise Error_Resync + + function P_Pragmas_Opt return List_Id is + L : List_Id; + + begin + if Token = Tok_Pragma then + L := New_List; + P_Pragmas_Opt (L); + return L; + + else + return No_List; + end if; + end P_Pragmas_Opt; + + -- This procedure is called to scan out an optional sequence of pragmas. + -- Any pragmas found are appended to the list provided as an argument. + + -- Error recovery: Cannot raise Error_Resync + + procedure P_Pragmas_Opt (List : List_Id) is + P : Node_Id; + + begin + while Token = Tok_Pragma loop + P := P_Pragma; + + if Chars (P) = Name_Assert or else Chars (P) = Name_Debug then + Error_Msg_Name_1 := Chars (P); + Error_Msg_N + ("pragma% must be in declaration/statement context", P); + else + Append (P, List); + end if; + end loop; + end P_Pragmas_Opt; + + -------------------------------------- + -- 2.8 Pragma_Argument Association -- + -------------------------------------- + + -- PRAGMA_ARGUMENT_ASSOCIATION ::= + -- [pragma_argument_IDENTIFIER =>] NAME + -- | [pragma_argument_IDENTIFIER =>] EXPRESSION + + -- Error recovery: cannot raise Error_Resync + + function P_Pragma_Argument_Association return Node_Id is + Scan_State : Saved_Scan_State; + Pragma_Arg_Node : Node_Id; + Identifier_Node : Node_Id; + + begin + Pragma_Arg_Node := New_Node (N_Pragma_Argument_Association, Token_Ptr); + Set_Chars (Pragma_Arg_Node, No_Name); + + if Token = Tok_Identifier then + Identifier_Node := Token_Node; + Save_Scan_State (Scan_State); -- at Identifier + Scan; -- past Identifier + + if Token = Tok_Arrow then + Scan; -- past arrow + Set_Chars (Pragma_Arg_Node, Chars (Identifier_Node)); + Delete_Node (Identifier_Node); + else + Restore_Scan_State (Scan_State); -- to Identifier + end if; + end if; + + Set_Expression (Pragma_Arg_Node, P_Expression); + return Pragma_Arg_Node; + + end P_Pragma_Argument_Association; + +end Ch2; diff --git a/gcc/ada/par-ch3.adb b/gcc/ada/par-ch3.adb new file mode 100644 index 00000000000..937f02d0e7c --- /dev/null +++ b/gcc/ada/par-ch3.adb @@ -0,0 +1,3724 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P A R . C H 3 -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.148 $ +-- -- +-- Copyright (C) 1992-2001, 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +pragma Style_Checks (All_Checks); +-- Turn off subprogram body ordering check. Subprograms are in order +-- by RM section rather than alphabetical + +with Sinfo.CN; use Sinfo.CN; + +separate (Par) + +package body Ch3 is + + ----------------------- + -- Local Subprograms -- + ----------------------- + + function P_Component_List return Node_Id; + function P_Defining_Character_Literal return Node_Id; + function P_Delta_Constraint return Node_Id; + function P_Derived_Type_Def_Or_Private_Ext_Decl return Node_Id; + function P_Digits_Constraint return Node_Id; + function P_Discriminant_Association return Node_Id; + function P_Enumeration_Literal_Specification return Node_Id; + function P_Enumeration_Type_Definition return Node_Id; + function P_Fixed_Point_Definition return Node_Id; + function P_Floating_Point_Definition return Node_Id; + function P_Index_Or_Discriminant_Constraint return Node_Id; + function P_Real_Range_Specification_Opt return Node_Id; + function P_Subtype_Declaration return Node_Id; + function P_Type_Declaration return Node_Id; + function P_Modular_Type_Definition return Node_Id; + function P_Variant return Node_Id; + function P_Variant_Part return Node_Id; + + procedure P_Declarative_Items + (Decls : List_Id; + Done : out Boolean; + In_Spec : Boolean); + -- Scans out a single declarative item, or, in the case of a declaration + -- with a list of identifiers, a list of declarations, one for each of + -- the identifiers in the list. The declaration or declarations scanned + -- are appended to the given list. Done indicates whether or not there + -- may be additional declarative items to scan. If Done is True, then + -- a decision has been made that there are no more items to scan. If + -- Done is False, then there may be additional declarations to scan. + -- In_Spec is true if we are scanning a package declaration, and is used + -- to generate an appropriate message if a statement is encountered in + -- such a context. + + procedure P_Identifier_Declarations + (Decls : List_Id; + Done : out Boolean; + In_Spec : Boolean); + -- Scans out a set of declarations for an identifier or list of + -- identifiers, and appends them to the given list. The parameters have + -- the same significance as for P_Declarative_Items. + + procedure Statement_When_Declaration_Expected + (Decls : List_Id; + Done : out Boolean; + In_Spec : Boolean); + -- Called when a statement is found at a point where a declaration was + -- expected. The parameters are as described for P_Declarative_Items. + + procedure Set_Declaration_Expected; + -- Posts a "declaration expected" error messages at the start of the + -- current token, and if this is the first such message issued, saves + -- the message id in Missing_Begin_Msg, for possible later replacement. + + ------------------- + -- Init_Expr_Opt -- + ------------------- + + function Init_Expr_Opt (P : Boolean := False) return Node_Id is + begin + if Token = Tok_Colon_Equal + or else Token = Tok_Equal + or else Token = Tok_Colon + or else Token = Tok_Is + then + null; + + -- One other possibility. If we have a literal followed by a semicolon, + -- we assume that we have a missing colon-equal. + + elsif Token in Token_Class_Literal then + declare + Scan_State : Saved_Scan_State; + + begin + Save_Scan_State (Scan_State); + Scan; -- past literal or identifier + + if Token = Tok_Semicolon then + Restore_Scan_State (Scan_State); + else + Restore_Scan_State (Scan_State); + return Empty; + end if; + end; + + -- Otherwise we definitely have no initialization expression + + else + return Empty; + end if; + + -- Merge here if we have an initialization expression + + T_Colon_Equal; + + if P then + return P_Expression; + else + return P_Expression_No_Right_Paren; + end if; + end Init_Expr_Opt; + + ---------------------------- + -- 3.1 Basic Declaration -- + ---------------------------- + + -- Parsed by P_Basic_Declarative_Items (3.9) + + ------------------------------ + -- 3.1 Defining Identifier -- + ------------------------------ + + -- DEFINING_IDENTIFIER ::= IDENTIFIER + + -- Error recovery: can raise Error_Resync + + function P_Defining_Identifier return Node_Id is + Ident_Node : Node_Id; + + begin + -- Scan out the identifier. Note that this code is essentially identical + -- to P_Identifier, except that in the call to Scan_Reserved_Identifier + -- we set Force_Msg to True, since we want at least one message for each + -- separate declaration (but not use) of a reserved identifier. + + if Token = Tok_Identifier then + null; + + -- If we have a reserved identifier, manufacture an identifier with + -- a corresponding name after posting an appropriate error message + + elsif Is_Reserved_Identifier then + Scan_Reserved_Identifier (Force_Msg => True); + + -- Otherwise we have junk that cannot be interpreted as an identifier + + else + T_Identifier; -- to give message + raise Error_Resync; + end if; + + Ident_Node := Token_Node; + Scan; -- past the reserved identifier + + if Ident_Node /= Error then + Change_Identifier_To_Defining_Identifier (Ident_Node); + end if; + + return Ident_Node; + end P_Defining_Identifier; + + ----------------------------- + -- 3.2.1 Type Declaration -- + ----------------------------- + + -- TYPE_DECLARATION ::= + -- FULL_TYPE_DECLARATION + -- | INCOMPLETE_TYPE_DECLARATION + -- | PRIVATE_TYPE_DECLARATION + -- | PRIVATE_EXTENSION_DECLARATION + + -- FULL_TYPE_DECLARATION ::= + -- type DEFINING_IDENTIFIER [KNOWN_DISCRIMINANT_PART] is TYPE_DEFINITION; + -- | CONCURRENT_TYPE_DECLARATION + + -- INCOMPLETE_TYPE_DECLARATION ::= + -- type DEFINING_IDENTIFIER [DISCRIMINANT_PART]; + + -- PRIVATE_TYPE_DECLARATION ::= + -- type DEFINING_IDENTIFIER [DISCRIMINANT_PART] + -- is [abstract] [tagged] [limited] private; + + -- PRIVATE_EXTENSION_DECLARATION ::= + -- type DEFINING_IDENTIFIER [DISCRIMINANT_PART] is + -- [abstract] new ancestor_SUBTYPE_INDICATION with private; + + -- TYPE_DEFINITION ::= + -- ENUMERATION_TYPE_DEFINITION | INTEGER_TYPE_DEFINITION + -- | REAL_TYPE_DEFINITION | ARRAY_TYPE_DEFINITION + -- | RECORD_TYPE_DEFINITION | ACCESS_TYPE_DEFINITION + -- | DERIVED_TYPE_DEFINITION + + -- INTEGER_TYPE_DEFINITION ::= + -- SIGNED_INTEGER_TYPE_DEFINITION + -- MODULAR_TYPE_DEFINITION + + -- Error recovery: can raise Error_Resync + + -- Note: The processing for full type declaration, incomplete type + -- declaration, private type declaration and type definition is + -- included in this function. The processing for concurrent type + -- declarations is NOT here, but rather in chapter 9 (i.e. this + -- function handles only declarations starting with TYPE). + + function P_Type_Declaration return Node_Id is + Type_Loc : Source_Ptr; + Type_Start_Col : Column_Number; + Ident_Node : Node_Id; + Decl_Node : Node_Id; + Discr_List : List_Id; + Unknown_Dis : Boolean; + Discr_Sloc : Source_Ptr; + Abstract_Present : Boolean; + Abstract_Loc : Source_Ptr; + End_Labl : Node_Id; + + Typedef_Node : Node_Id; + -- Normally holds type definition, except in the case of a private + -- extension declaration, in which case it holds the declaration itself + + begin + Type_Loc := Token_Ptr; + Type_Start_Col := Start_Column; + T_Type; + Ident_Node := P_Defining_Identifier; + Discr_Sloc := Token_Ptr; + + if P_Unknown_Discriminant_Part_Opt then + Unknown_Dis := True; + Discr_List := No_List; + else + Unknown_Dis := False; + Discr_List := P_Known_Discriminant_Part_Opt; + end if; + + -- Incomplete type declaration. We complete the processing for this + -- case here and return the resulting incomplete type declaration node + + if Token = Tok_Semicolon then + Scan; -- past ; + Decl_Node := New_Node (N_Incomplete_Type_Declaration, Type_Loc); + Set_Defining_Identifier (Decl_Node, Ident_Node); + Set_Unknown_Discriminants_Present (Decl_Node, Unknown_Dis); + Set_Discriminant_Specifications (Decl_Node, Discr_List); + return Decl_Node; + + else + Decl_Node := Empty; + end if; + + -- Full type declaration or private type declaration, must have IS + + if Token = Tok_Equal then + TF_Is; + Scan; -- past = used in place of IS + + elsif Token = Tok_Renames then + Error_Msg_SC ("RENAMES should be IS"); + Scan; -- past RENAMES used in place of IS + + else + TF_Is; + end if; + + -- First an error check, if we have two identifiers in a row, a likely + -- possibility is that the first of the identifiers is an incorrectly + -- spelled keyword. + + if Token = Tok_Identifier then + declare + SS : Saved_Scan_State; + I2 : Boolean; + + begin + Save_Scan_State (SS); + Scan; -- past initial identifier + I2 := (Token = Tok_Identifier); + Restore_Scan_State (SS); + + if I2 + and then + (Bad_Spelling_Of (Tok_Abstract) or else + Bad_Spelling_Of (Tok_Access) or else + Bad_Spelling_Of (Tok_Aliased) or else + Bad_Spelling_Of (Tok_Constant)) + then + null; + end if; + end; + end if; + + -- Check for misuse of Ada 95 keyword abstract in Ada 83 mode + + if Token_Name = Name_Abstract then + Check_95_Keyword (Tok_Abstract, Tok_Tagged); + Check_95_Keyword (Tok_Abstract, Tok_New); + end if; + + -- Check cases of misuse of ABSTRACT + + if Token = Tok_Abstract then + Abstract_Present := True; + Abstract_Loc := Token_Ptr; + Scan; -- past ABSTRACT + + if Token = Tok_Limited + or else Token = Tok_Private + or else Token = Tok_Record + or else Token = Tok_Null + then + Error_Msg_AP ("TAGGED expected"); + end if; + + else + Abstract_Present := False; + Abstract_Loc := No_Location; + end if; + + -- Check for misuse of Ada 95 keyword Tagged + + if Token_Name = Name_Tagged then + Check_95_Keyword (Tok_Tagged, Tok_Private); + Check_95_Keyword (Tok_Tagged, Tok_Limited); + Check_95_Keyword (Tok_Tagged, Tok_Record); + end if; + + -- Special check for misuse of Aliased + + if Token = Tok_Aliased or else Token_Name = Name_Aliased then + Error_Msg_SC ("ALIASED not allowed in type definition"); + Scan; -- past ALIASED + end if; + + -- The following procesing deals with either a private type declaration + -- or a full type declaration. In the private type case, we build the + -- N_Private_Type_Declaration node, setting its Tagged_Present and + -- Limited_Present flags, on encountering the Private keyword, and + -- leave Typedef_Node set to Empty. For the full type declaration + -- case, Typedef_Node gets set to the type definition. + + Typedef_Node := Empty; + + -- Switch on token following the IS. The loop normally runs once. It + -- only runs more than once if an error is detected, to try again after + -- detecting and fixing up the error. + + loop + case Token is + + when Tok_Access => + Typedef_Node := P_Access_Type_Definition; + TF_Semicolon; + exit; + + when Tok_Array => + Typedef_Node := P_Array_Type_Definition; + TF_Semicolon; + exit; + + when Tok_Delta => + Typedef_Node := P_Fixed_Point_Definition; + TF_Semicolon; + exit; + + when Tok_Digits => + Typedef_Node := P_Floating_Point_Definition; + TF_Semicolon; + exit; + + when Tok_In => + Ignore (Tok_In); + + when Tok_Integer_Literal => + T_Range; + Typedef_Node := P_Signed_Integer_Type_Definition; + TF_Semicolon; + exit; + + when Tok_Null => + Typedef_Node := P_Record_Definition; + TF_Semicolon; + exit; + + when Tok_Left_Paren => + Typedef_Node := P_Enumeration_Type_Definition; + TF_Semicolon; + exit; + + when Tok_Mod => + Typedef_Node := P_Modular_Type_Definition; + TF_Semicolon; + exit; + + when Tok_New => + Typedef_Node := P_Derived_Type_Def_Or_Private_Ext_Decl; + TF_Semicolon; + exit; + + when Tok_Range => + Typedef_Node := P_Signed_Integer_Type_Definition; + TF_Semicolon; + exit; + + when Tok_Record => + Typedef_Node := P_Record_Definition; + + End_Labl := + Make_Identifier (Token_Ptr, + Chars => Chars (Ident_Node)); + Set_Comes_From_Source (End_Labl, False); + + Set_End_Label (Typedef_Node, End_Labl); + TF_Semicolon; + exit; + + when Tok_Tagged => + Scan; -- past TAGGED + + if Token = Tok_Abstract then + Error_Msg_SC ("ABSTRACT must come before TAGGED"); + Abstract_Present := True; + Abstract_Loc := Token_Ptr; + Scan; -- past ABSTRACT + end if; + + if Token = Tok_Limited then + Scan; -- past LIMITED + + -- TAGGED LIMITED PRIVATE case + + if Token = Tok_Private then + Decl_Node := + New_Node (N_Private_Type_Declaration, Type_Loc); + Set_Tagged_Present (Decl_Node, True); + Set_Limited_Present (Decl_Node, True); + Scan; -- past PRIVATE + + -- TAGGED LIMITED RECORD + + else + Typedef_Node := P_Record_Definition; + Set_Tagged_Present (Typedef_Node, True); + Set_Limited_Present (Typedef_Node, True); + end if; + + else + -- TAGGED PRIVATE + + if Token = Tok_Private then + Decl_Node := + New_Node (N_Private_Type_Declaration, Type_Loc); + Set_Tagged_Present (Decl_Node, True); + Scan; -- past PRIVATE + + -- TAGGED RECORD + + else + Typedef_Node := P_Record_Definition; + Set_Tagged_Present (Typedef_Node, True); + end if; + end if; + + TF_Semicolon; + exit; + + when Tok_Private => + Decl_Node := New_Node (N_Private_Type_Declaration, Type_Loc); + Scan; -- past PRIVATE + TF_Semicolon; + exit; + + when Tok_Limited => + Scan; -- past LIMITED + + loop + if Token = Tok_Tagged then + Error_Msg_SC ("TAGGED must come before LIMITED"); + Scan; -- past TAGGED + + elsif Token = Tok_Abstract then + Error_Msg_SC ("ABSTRACT must come before LIMITED"); + Scan; -- past ABSTRACT + + else + exit; + end if; + end loop; + + -- LIMITED RECORD or LIMITED NULL RECORD + + if Token = Tok_Record or else Token = Tok_Null then + if Ada_83 then + Error_Msg_SP + ("(Ada 83) limited record declaration not allowed!"); + end if; + + Typedef_Node := P_Record_Definition; + Set_Limited_Present (Typedef_Node, True); + + -- LIMITED PRIVATE is the only remaining possibility here + + else + Decl_Node := New_Node (N_Private_Type_Declaration, Type_Loc); + Set_Limited_Present (Decl_Node, True); + T_Private; -- past PRIVATE (or complain if not there!) + end if; + + TF_Semicolon; + exit; + + -- Here we have an identifier after the IS, which is certainly + -- wrong and which might be one of several different mistakes. + + when Tok_Identifier => + + -- First case, if identifier is on same line, then probably we + -- have something like "type X is Integer .." and the best + -- diagnosis is a missing NEW. Note: the missing new message + -- will be posted by P_Derived_Type_Def_Or_Private_Ext_Decl. + + if not Token_Is_At_Start_Of_Line then + Typedef_Node := P_Derived_Type_Def_Or_Private_Ext_Decl; + TF_Semicolon; + + -- If the identifier is at the start of the line, and is in the + -- same column as the type declaration itself then we consider + -- that we had a missing type definition on the previous line + + elsif Start_Column <= Type_Start_Col then + Error_Msg_AP ("type definition expected"); + Typedef_Node := Error; + + -- If the identifier is at the start of the line, and is in + -- a column to the right of the type declaration line, then we + -- may have something like: + + -- type x is + -- r : integer + + -- and the best diagnosis is a missing record keyword + + else + Typedef_Node := P_Record_Definition; + TF_Semicolon; + end if; + + exit; + + -- Anything else is an error + + when others => + if Bad_Spelling_Of (Tok_Access) + or else + Bad_Spelling_Of (Tok_Array) + or else + Bad_Spelling_Of (Tok_Delta) + or else + Bad_Spelling_Of (Tok_Digits) + or else + Bad_Spelling_Of (Tok_Limited) + or else + Bad_Spelling_Of (Tok_Private) + or else + Bad_Spelling_Of (Tok_Range) + or else + Bad_Spelling_Of (Tok_Record) + or else + Bad_Spelling_Of (Tok_Tagged) + then + null; + + else + Error_Msg_AP ("type definition expected"); + raise Error_Resync; + end if; + + end case; + end loop; + + -- For the private type declaration case, the private type declaration + -- node has been built, with the Tagged_Present and Limited_Present + -- flags set as needed, and Typedef_Node is left set to Empty. + + if No (Typedef_Node) then + Set_Unknown_Discriminants_Present (Decl_Node, Unknown_Dis); + Set_Abstract_Present (Decl_Node, Abstract_Present); + + -- For a private extension declaration, Typedef_Node contains the + -- N_Private_Extension_Declaration node, which we now complete. Note + -- that the private extension declaration, unlike a full type + -- declaration, does permit unknown discriminants. + + elsif Nkind (Typedef_Node) = N_Private_Extension_Declaration then + Decl_Node := Typedef_Node; + Set_Sloc (Decl_Node, Type_Loc); + Set_Unknown_Discriminants_Present (Decl_Node, Unknown_Dis); + Set_Abstract_Present (Typedef_Node, Abstract_Present); + + -- In the full type declaration case, Typedef_Node has the type + -- definition and here is where we build the full type declaration + -- node. This is also where we check for improper use of an unknown + -- discriminant part (not allowed for full type declaration). + + else + if Nkind (Typedef_Node) = N_Record_Definition + or else (Nkind (Typedef_Node) = N_Derived_Type_Definition + and then Present (Record_Extension_Part (Typedef_Node))) + then + Set_Abstract_Present (Typedef_Node, Abstract_Present); + + elsif Abstract_Present then + Error_Msg ("ABSTRACT not allowed here, ignored", Abstract_Loc); + end if; + + Decl_Node := New_Node (N_Full_Type_Declaration, Type_Loc); + Set_Type_Definition (Decl_Node, Typedef_Node); + + if Unknown_Dis then + Error_Msg + ("Full type declaration cannot have unknown discriminants", + Discr_Sloc); + end if; + end if; + + -- Remaining processing is common for all three cases + + Set_Defining_Identifier (Decl_Node, Ident_Node); + Set_Discriminant_Specifications (Decl_Node, Discr_List); + return Decl_Node; + + end P_Type_Declaration; + + ---------------------------------- + -- 3.2.1 Full Type Declaration -- + ---------------------------------- + + -- Parsed by P_Type_Declaration (3.2.1) + + ---------------------------- + -- 3.2.1 Type Definition -- + ---------------------------- + + -- Parsed by P_Type_Declaration (3.2.1) + + -------------------------------- + -- 3.2.2 Subtype Declaration -- + -------------------------------- + + -- SUBTYPE_DECLARATION ::= + -- subtype DEFINING_IDENTIFIER is SUBTYPE_INDICATION; + + -- The caller has checked that the initial token is SUBTYPE + + -- Error recovery: can raise Error_Resync + + function P_Subtype_Declaration return Node_Id is + Decl_Node : Node_Id; + + begin + Decl_Node := New_Node (N_Subtype_Declaration, Token_Ptr); + Scan; -- past SUBTYPE + Set_Defining_Identifier (Decl_Node, P_Defining_Identifier); + TF_Is; + + if Token = Tok_New then + Error_Msg_SC ("NEW ignored (only allowed in type declaration)"); + Scan; -- past NEW + end if; + + Set_Subtype_Indication (Decl_Node, P_Subtype_Indication); + TF_Semicolon; + return Decl_Node; + end P_Subtype_Declaration; + + ------------------------------- + -- 3.2.2 Subtype Indication -- + ------------------------------- + + -- SUBTYPE_INDICATION ::= SUBTYPE_MARK [CONSTRAINT] + + -- Error recovery: can raise Error_Resync + + function P_Subtype_Indication return Node_Id is + Type_Node : Node_Id; + + begin + if Token = Tok_Identifier or else Token = Tok_Operator_Symbol then + Type_Node := P_Subtype_Mark; + return P_Subtype_Indication (Type_Node); + + else + -- Check for error of using record definition and treat it nicely, + -- otherwise things are really messed up, so resynchronize. + + if Token = Tok_Record then + Error_Msg_SC ("anonymous record definitions are not permitted"); + Discard_Junk_Node (P_Record_Definition); + return Error; + + else + Error_Msg_AP ("subtype indication expected"); + raise Error_Resync; + end if; + end if; + end P_Subtype_Indication; + + -- The following function is identical except that it is called with + -- the subtype mark already scanned out, and it scans out the constraint + + -- Error recovery: can raise Error_Resync + + function P_Subtype_Indication (Subtype_Mark : Node_Id) return Node_Id is + Indic_Node : Node_Id; + Constr_Node : Node_Id; + + begin + Constr_Node := P_Constraint_Opt; + + if No (Constr_Node) then + return Subtype_Mark; + else + Indic_Node := New_Node (N_Subtype_Indication, Sloc (Subtype_Mark)); + Set_Subtype_Mark (Indic_Node, Check_Subtype_Mark (Subtype_Mark)); + Set_Constraint (Indic_Node, Constr_Node); + return Indic_Node; + end if; + + end P_Subtype_Indication; + + ------------------------- + -- 3.2.2 Subtype Mark -- + ------------------------- + + -- SUBTYPE_MARK ::= subtype_NAME; + + -- Note: The subtype mark which appears after an IN or NOT IN + -- operator is parsed by P_Range_Or_Subtype_Mark (3.5) + + -- Error recovery: cannot raise Error_Resync + + function P_Subtype_Mark return Node_Id is + begin + return P_Subtype_Mark_Resync; + + exception + when Error_Resync => + return Error; + end P_Subtype_Mark; + + -- This routine differs from P_Subtype_Mark in that it insists that an + -- identifier be present, and if it is not, it raises Error_Resync. + + -- Error recovery: can raise Error_Resync + + function P_Subtype_Mark_Resync return Node_Id is + Type_Node : Node_Id; + + begin + if Token = Tok_Access then + Error_Msg_SC ("anonymous access type definition not allowed here"); + Scan; -- past ACCESS + end if; + + if Token = Tok_Array then + Error_Msg_SC ("anonymous array definition not allowed here"); + Discard_Junk_Node (P_Array_Type_Definition); + return Empty; + + else + Type_Node := P_Qualified_Simple_Name_Resync; + + -- Check for a subtype mark attribute. The only valid possibilities + -- are 'CLASS and 'BASE. Anything else is a definite error. We may + -- as well catch it here. + + if Token = Tok_Apostrophe then + return P_Subtype_Mark_Attribute (Type_Node); + else + return Type_Node; + end if; + end if; + end P_Subtype_Mark_Resync; + + -- The following function is called to scan out a subtype mark attribute. + -- The caller has already scanned out the subtype mark, which is passed in + -- as the argument, and has checked that the current token is apostrophe. + + -- Only a special subclass of attributes, called type attributes + -- (see Snames package) are allowed in this syntactic position. + + -- Note: if the apostrophe is followed by other than an identifier, then + -- the input expression is returned unchanged, and the scan pointer is + -- left pointing to the apostrophe. + + -- Error recovery: can raise Error_Resync + + function P_Subtype_Mark_Attribute (Type_Node : Node_Id) return Node_Id is + Attr_Node : Node_Id := Empty; + Scan_State : Saved_Scan_State; + Prefix : Node_Id; + + begin + Prefix := Check_Subtype_Mark (Type_Node); + + if Prefix = Error then + raise Error_Resync; + end if; + + -- Loop through attributes appearing (more than one can appear as for + -- for example in X'Base'Class). We are at an apostrophe on entry to + -- this loop, and it runs once for each attribute parsed, with + -- Prefix being the current possible prefix if it is an attribute. + + loop + Save_Scan_State (Scan_State); -- at Apostrophe + Scan; -- past apostrophe + + if Token /= Tok_Identifier then + Restore_Scan_State (Scan_State); -- to apostrophe + return Prefix; -- no attribute after all + + elsif not Is_Type_Attribute_Name (Token_Name) then + Error_Msg_N + ("attribute & may not be used in a subtype mark", Token_Node); + raise Error_Resync; + + else + Attr_Node := + Make_Attribute_Reference (Prev_Token_Ptr, + Prefix => Prefix, + Attribute_Name => Token_Name); + Delete_Node (Token_Node); + Scan; -- past type attribute identifier + end if; + + exit when Token /= Tok_Apostrophe; + Prefix := Attr_Node; + end loop; + + -- Fall through here after scanning type attribute + + return Attr_Node; + end P_Subtype_Mark_Attribute; + + ----------------------- + -- 3.2.2 Constraint -- + ----------------------- + + -- CONSTRAINT ::= SCALAR_CONSTRAINT | COMPOSITE_CONSTRAINT + + -- SCALAR_CONSTRAINT ::= + -- RANGE_CONSTRAINT | DIGITS_CONSTRAINT | DELTA_CONSTRAINT + + -- COMPOSITE_CONSTRAINT ::= + -- INDEX_CONSTRAINT | DISCRIMINANT_CONSTRAINT + + -- If no constraint is present, this function returns Empty + + -- Error recovery: can raise Error_Resync + + function P_Constraint_Opt return Node_Id is + begin + if Token = Tok_Range + or else Bad_Spelling_Of (Tok_Range) + then + return P_Range_Constraint; + + elsif Token = Tok_Digits + or else Bad_Spelling_Of (Tok_Digits) + then + return P_Digits_Constraint; + + elsif Token = Tok_Delta + or else Bad_Spelling_Of (Tok_Delta) + then + return P_Delta_Constraint; + + elsif Token = Tok_Left_Paren then + return P_Index_Or_Discriminant_Constraint; + + elsif Token = Tok_In then + Ignore (Tok_In); + return P_Constraint_Opt; + + else + return Empty; + end if; + + end P_Constraint_Opt; + + ------------------------------ + -- 3.2.2 Scalar Constraint -- + ------------------------------ + + -- Parsed by P_Constraint_Opt (3.2.2) + + --------------------------------- + -- 3.2.2 Composite Constraint -- + --------------------------------- + + -- Parsed by P_Constraint_Opt (3.2.2) + + -------------------------------------------------------- + -- 3.3 Identifier Declarations (Also 7.4, 8.5, 11.1) -- + -------------------------------------------------------- + + -- This routine scans out a declaration starting with an identifier: + + -- OBJECT_DECLARATION ::= + -- DEFINING_IDENTIFIER_LIST : [constant] [aliased] + -- SUBTYPE_INDICATION [:= EXPRESSION]; + -- | DEFINING_IDENTIFIER_LIST : [constant] [aliased] + -- ARRAY_TYPE_DEFINITION [:= EXPRESSION]; + + -- NUMBER_DECLARATION ::= + -- DEFINING_IDENTIFIER_LIST : constant ::= static_EXPRESSION; + + -- OBJECT_RENAMING_DECLARATION ::= + -- DEFINING_IDENTIFIER : SUBTYPE_MARK renames object_NAME; + + -- EXCEPTION_RENAMING_DECLARATION ::= + -- DEFINING_IDENTIFIER : exception renames exception_NAME; + + -- EXCEPTION_DECLARATION ::= + -- DEFINING_IDENTIFIER_LIST : exception; + + -- Note that the ALIASED indication in an object declaration is + -- marked by a flag in the parent node. + + -- The caller has checked that the initial token is an identifier + + -- The value returned is a list of declarations, one for each identifier + -- in the list (as described in Sinfo, we always split up multiple + -- declarations into the equivalent sequence of single declarations + -- using the More_Ids and Prev_Ids flags to preserve the source). + + -- If the identifier turns out to be a probable statement rather than + -- an identifier, then the scan is left pointing to the identifier and + -- No_List is returned. + + -- Error recovery: can raise Error_Resync + + procedure P_Identifier_Declarations + (Decls : List_Id; + Done : out Boolean; + In_Spec : Boolean) + is + Decl_Node : Node_Id; + Type_Node : Node_Id; + Ident_Sloc : Source_Ptr; + Scan_State : Saved_Scan_State; + List_OK : Boolean := True; + Ident : Nat; + Init_Expr : Node_Id; + Init_Loc : Source_Ptr; + Con_Loc : Source_Ptr; + + Idents : array (Int range 1 .. 4096) of Entity_Id; + -- Used to save identifiers in the identifier list. The upper bound + -- of 4096 is expected to be infinite in practice, and we do not even + -- bother to check if this upper bound is exceeded. + + Num_Idents : Nat := 1; + -- Number of identifiers stored in Idents + + procedure No_List; + -- This procedure is called in renames cases to make sure that we do + -- not have more than one identifier. If we do have more than one + -- then an error message is issued (and the declaration is split into + -- multiple declarations) + + function Token_Is_Renames return Boolean; + -- Checks if current token is RENAMES, and if so, scans past it and + -- returns True, otherwise returns False. Includes checking for some + -- common error cases. + + procedure No_List is + begin + if Num_Idents > 1 then + Error_Msg ("identifier list not allowed for RENAMES", + Sloc (Idents (2))); + end if; + + List_OK := False; + end No_List; + + function Token_Is_Renames return Boolean is + At_Colon : Saved_Scan_State; + + begin + if Token = Tok_Colon then + Save_Scan_State (At_Colon); + Scan; -- past colon + Check_Misspelling_Of (Tok_Renames); + + if Token = Tok_Renames then + Error_Msg_SP ("extra "":"" ignored"); + Scan; -- past RENAMES + return True; + else + Restore_Scan_State (At_Colon); + return False; + end if; + + else + Check_Misspelling_Of (Tok_Renames); + + if Token = Tok_Renames then + Scan; -- past RENAMES + return True; + else + return False; + end if; + end if; + end Token_Is_Renames; + + -- Start of processing for P_Identifier_Declarations + + begin + Ident_Sloc := Token_Ptr; + Save_Scan_State (Scan_State); -- at first identifier + Idents (1) := P_Defining_Identifier; + + -- If we have a colon after the identifier, then we can assume that + -- this is in fact a valid identifier declaration and can steam ahead. + + if Token = Tok_Colon then + Scan; -- past colon + + -- If we have a comma, then scan out the list of identifiers + + elsif Token = Tok_Comma then + + while Comma_Present loop + Num_Idents := Num_Idents + 1; + Idents (Num_Idents) := P_Defining_Identifier; + end loop; + + Save_Scan_State (Scan_State); -- at colon + T_Colon; + + -- If we have identifier followed by := then we assume that what is + -- really meant is an assignment statement. The assignment statement + -- is scanned out and added to the list of declarations. An exception + -- occurs if the := is followed by the keyword constant, in which case + -- we assume it was meant to be a colon. + + elsif Token = Tok_Colon_Equal then + Scan; -- past := + + if Token = Tok_Constant then + Error_Msg_SP ("colon expected"); + + else + Restore_Scan_State (Scan_State); + Statement_When_Declaration_Expected (Decls, Done, In_Spec); + return; + end if; + + -- If we have an IS keyword, then assume the TYPE keyword was missing + + elsif Token = Tok_Is then + Restore_Scan_State (Scan_State); + Append_To (Decls, P_Type_Declaration); + Done := False; + return; + + -- Otherwise we have an error situation + + else + Restore_Scan_State (Scan_State); + + -- First case is possible misuse of PROTECTED in Ada 83 mode. If + -- so, fix the keyword and return to scan the protected declaration. + + if Token_Name = Name_Protected then + Check_95_Keyword (Tok_Protected, Tok_Identifier); + Check_95_Keyword (Tok_Protected, Tok_Type); + Check_95_Keyword (Tok_Protected, Tok_Body); + + if Token = Tok_Protected then + Done := False; + return; + end if; + + -- Check misspelling possibilities. If so, correct the misspelling + -- and return to scan out the resulting declaration. + + elsif Bad_Spelling_Of (Tok_Function) + or else Bad_Spelling_Of (Tok_Procedure) + or else Bad_Spelling_Of (Tok_Package) + or else Bad_Spelling_Of (Tok_Pragma) + or else Bad_Spelling_Of (Tok_Protected) + or else Bad_Spelling_Of (Tok_Generic) + or else Bad_Spelling_Of (Tok_Subtype) + or else Bad_Spelling_Of (Tok_Type) + or else Bad_Spelling_Of (Tok_Task) + or else Bad_Spelling_Of (Tok_Use) + or else Bad_Spelling_Of (Tok_For) + then + Done := False; + return; + + -- Otherwise we definitely have an ordinary identifier with a junk + -- token after it. Just complain that we expect a declaration, and + -- skip to a semicolon + + else + Set_Declaration_Expected; + Resync_Past_Semicolon; + Done := False; + return; + end if; + end if; + + -- Come here with an identifier list and colon scanned out. We now + -- build the nodes for the declarative items. One node is built for + -- each identifier in the list, with the type information being + -- repeated by rescanning the appropriate section of source. + + -- First an error check, if we have two identifiers in a row, a likely + -- possibility is that the first of the identifiers is an incorrectly + -- spelled keyword. + + if Token = Tok_Identifier then + declare + SS : Saved_Scan_State; + I2 : Boolean; + + begin + Save_Scan_State (SS); + Scan; -- past initial identifier + I2 := (Token = Tok_Identifier); + Restore_Scan_State (SS); + + if I2 + and then + (Bad_Spelling_Of (Tok_Access) or else + Bad_Spelling_Of (Tok_Aliased) or else + Bad_Spelling_Of (Tok_Constant)) + then + null; + end if; + end; + end if; + + -- Loop through identifiers + + Ident := 1; + Ident_Loop : loop + + -- Check for some cases of misused Ada 95 keywords + + if Token_Name = Name_Aliased then + Check_95_Keyword (Tok_Aliased, Tok_Array); + Check_95_Keyword (Tok_Aliased, Tok_Identifier); + Check_95_Keyword (Tok_Aliased, Tok_Constant); + end if; + + -- Constant cases + + if Token = Tok_Constant then + Con_Loc := Token_Ptr; + Scan; -- past CONSTANT + + -- Number declaration, initialization required + + Init_Expr := Init_Expr_Opt; + + if Present (Init_Expr) then + Decl_Node := New_Node (N_Number_Declaration, Ident_Sloc); + Set_Expression (Decl_Node, Init_Expr); + + -- Constant object declaration + + else + Decl_Node := New_Node (N_Object_Declaration, Ident_Sloc); + Set_Constant_Present (Decl_Node, True); + + if Token_Name = Name_Aliased then + Check_95_Keyword (Tok_Aliased, Tok_Array); + Check_95_Keyword (Tok_Aliased, Tok_Identifier); + end if; + + if Token = Tok_Aliased then + Error_Msg_SC ("ALIASED should be before CONSTANT"); + Scan; -- past ALIASED + Set_Aliased_Present (Decl_Node, True); + end if; + + if Token = Tok_Array then + Set_Object_Definition + (Decl_Node, P_Array_Type_Definition); + else + Set_Object_Definition (Decl_Node, P_Subtype_Indication); + end if; + + if Token = Tok_Renames then + Error_Msg + ("CONSTANT not permitted in renaming declaration", + Con_Loc); + Scan; -- Past renames + Discard_Junk_Node (P_Name); + end if; + end if; + + -- Exception cases + + elsif Token = Tok_Exception then + Scan; -- past EXCEPTION + + if Token_Is_Renames then + No_List; + Decl_Node := + New_Node (N_Exception_Renaming_Declaration, Ident_Sloc); + Set_Name (Decl_Node, P_Qualified_Simple_Name_Resync); + No_Constraint; + else + Decl_Node := New_Node (N_Exception_Declaration, Prev_Token_Ptr); + end if; + + -- Aliased case (note that an object definition is required) + + elsif Token = Tok_Aliased then + Scan; -- past ALIASED + Decl_Node := New_Node (N_Object_Declaration, Ident_Sloc); + Set_Aliased_Present (Decl_Node, True); + + if Token = Tok_Constant then + Scan; -- past CONSTANT + Set_Constant_Present (Decl_Node, True); + end if; + + if Token = Tok_Array then + Set_Object_Definition + (Decl_Node, P_Array_Type_Definition); + else + Set_Object_Definition (Decl_Node, P_Subtype_Indication); + end if; + + -- Array case + + elsif Token = Tok_Array then + Decl_Node := New_Node (N_Object_Declaration, Ident_Sloc); + Set_Object_Definition (Decl_Node, P_Array_Type_Definition); + + -- Subtype indication case + + else + Type_Node := P_Subtype_Mark; + + -- Object renaming declaration + + if Token_Is_Renames then + No_List; + Decl_Node := + New_Node (N_Object_Renaming_Declaration, Ident_Sloc); + Set_Subtype_Mark (Decl_Node, Type_Node); + Set_Name (Decl_Node, P_Name); + + -- Object declaration + + else + Decl_Node := New_Node (N_Object_Declaration, Ident_Sloc); + Set_Object_Definition + (Decl_Node, P_Subtype_Indication (Type_Node)); + + -- RENAMES at this point means that we had the combination of + -- a constraint on the Type_Node and renames, which is illegal + + if Token_Is_Renames then + Error_Msg_N + ("constraint not allowed in object renaming declaration", + Constraint (Object_Definition (Decl_Node))); + raise Error_Resync; + end if; + end if; + end if; + + -- Scan out initialization, allowed only for object declaration + + Init_Loc := Token_Ptr; + Init_Expr := Init_Expr_Opt; + + if Present (Init_Expr) then + if Nkind (Decl_Node) = N_Object_Declaration then + Set_Expression (Decl_Node, Init_Expr); + else + Error_Msg ("initialization not allowed here", Init_Loc); + end if; + end if; + + TF_Semicolon; + Set_Defining_Identifier (Decl_Node, Idents (Ident)); + + if List_OK then + if Ident < Num_Idents then + Set_More_Ids (Decl_Node, True); + end if; + + if Ident > 1 then + Set_Prev_Ids (Decl_Node, True); + end if; + end if; + + Append (Decl_Node, Decls); + exit Ident_Loop when Ident = Num_Idents; + Restore_Scan_State (Scan_State); + T_Colon; + Ident := Ident + 1; + end loop Ident_Loop; + + Done := False; + + end P_Identifier_Declarations; + + ------------------------------- + -- 3.3.1 Object Declaration -- + ------------------------------- + + -- OBJECT DECLARATION ::= + -- DEFINING_IDENTIFIER_LIST : [aliased] [constant] + -- SUBTYPE_INDICATION [:= EXPRESSION]; + -- | DEFINING_IDENTIFIER_LIST : [aliased] [constant] + -- ARRAY_TYPE_DEFINITION [:= EXPRESSION]; + -- | SINGLE_TASK_DECLARATION + -- | SINGLE_PROTECTED_DECLARATION + + -- Cases starting with TASK are parsed by P_Task (9.1) + -- Cases starting with PROTECTED are parsed by P_Protected (9.4) + -- All other cases are parsed by P_Identifier_Declarations (3.3) + + ------------------------------------- + -- 3.3.1 Defining Identifier List -- + ------------------------------------- + + -- DEFINING_IDENTIFIER_LIST ::= + -- DEFINING_IDENTIFIER {, DEFINING_IDENTIFIER} + + -- Always parsed by the construct in which it appears. See special + -- section on "Handling of Defining Identifier Lists" in this unit. + + ------------------------------- + -- 3.3.2 Number Declaration -- + ------------------------------- + + -- Parsed by P_Identifier_Declarations (3.3) + + ------------------------------------------------------------------------- + -- 3.4 Derived Type Definition or Private Extension Declaration (7.3) -- + ------------------------------------------------------------------------- + + -- DERIVED_TYPE_DEFINITION ::= + -- [abstract] new parent_SUBTYPE_INDICATION [RECORD_EXTENSION_PART] + + -- PRIVATE_EXTENSION_DECLARATION ::= + -- type DEFINING_IDENTIFIER [DISCRIMINANT_PART] is + -- [abstract] new ancestor_SUBTYPE_INDICATION with PRIVATE; + + -- RECORD_EXTENSION_PART ::= with RECORD_DEFINITION + + -- The caller has already scanned out the part up to the NEW, and Token + -- either contains Tok_New (or ought to, if it doesn't this procedure + -- will post an appropriate "NEW expected" message). + + -- Note: the caller is responsible for filling in the Sloc field of + -- the returned node in the private extension declaration case as + -- well as the stuff relating to the discriminant part. + + -- Error recovery: can raise Error_Resync; + + function P_Derived_Type_Def_Or_Private_Ext_Decl return Node_Id is + Typedef_Node : Node_Id; + Typedecl_Node : Node_Id; + + begin + Typedef_Node := New_Node (N_Derived_Type_Definition, Token_Ptr); + T_New; + + if Token = Tok_Abstract then + Error_Msg_SC ("ABSTRACT must come before NEW, not after"); + Scan; + end if; + + Set_Subtype_Indication (Typedef_Node, P_Subtype_Indication); + + -- Deal with record extension, note that we assume that a WITH is + -- missing in the case of "type X is new Y record ..." or in the + -- case of "type X is new Y null record". + + if Token = Tok_With + or else Token = Tok_Record + or else Token = Tok_Null + then + T_With; -- past WITH or give error message + + if Token = Tok_Limited then + Error_Msg_SC + ("LIMITED keyword not allowed in private extension"); + Scan; -- ignore LIMITED + end if; + + -- Private extension declaration + + if Token = Tok_Private then + Scan; -- past PRIVATE + + -- Throw away the type definition node and build the type + -- declaration node. Note the caller must set the Sloc, + -- Discriminant_Specifications, Unknown_Discriminants_Present, + -- and Defined_Identifier fields in the returned node. + + Typedecl_Node := + Make_Private_Extension_Declaration (No_Location, + Defining_Identifier => Empty, + Subtype_Indication => Subtype_Indication (Typedef_Node), + Abstract_Present => Abstract_Present (Typedef_Node)); + + Delete_Node (Typedef_Node); + return Typedecl_Node; + + -- Derived type definition with record extension part + + else + Set_Record_Extension_Part (Typedef_Node, P_Record_Definition); + return Typedef_Node; + end if; + + -- Derived type definition with no record extension part + + else + return Typedef_Node; + end if; + end P_Derived_Type_Def_Or_Private_Ext_Decl; + + --------------------------- + -- 3.5 Range Constraint -- + --------------------------- + + -- RANGE_CONSTRAINT ::= range RANGE + + -- The caller has checked that the initial token is RANGE + + -- Error recovery: cannot raise Error_Resync + + function P_Range_Constraint return Node_Id is + Range_Node : Node_Id; + + begin + Range_Node := New_Node (N_Range_Constraint, Token_Ptr); + Scan; -- past RANGE + Set_Range_Expression (Range_Node, P_Range); + return Range_Node; + end P_Range_Constraint; + + ---------------- + -- 3.5 Range -- + ---------------- + + -- RANGE ::= + -- RANGE_ATTRIBUTE_REFERENCE | SIMPLE_EXPRESSION .. SIMPLE_EXPRESSION + + -- Note: the range that appears in a membership test is parsed by + -- P_Range_Or_Subtype_Mark (3.5). + + -- Error recovery: cannot raise Error_Resync + + function P_Range return Node_Id is + Expr_Node : Node_Id; + Range_Node : Node_Id; + + begin + Expr_Node := P_Simple_Expression_Or_Range_Attribute; + + if Expr_Form = EF_Range_Attr then + return Expr_Node; + + elsif Token = Tok_Dot_Dot then + Range_Node := New_Node (N_Range, Token_Ptr); + Set_Low_Bound (Range_Node, Expr_Node); + Scan; -- past .. + Expr_Node := P_Expression; + Check_Simple_Expression (Expr_Node); + Set_High_Bound (Range_Node, Expr_Node); + return Range_Node; + + -- Anything else is an error + + else + T_Dot_Dot; -- force missing .. message + return Error; + end if; + end P_Range; + + ---------------------------------- + -- 3.5 P_Range_Or_Subtype_Mark -- + ---------------------------------- + + -- RANGE ::= + -- RANGE_ATTRIBUTE_REFERENCE + -- | SIMPLE_EXPRESSION .. SIMPLE_EXPRESSION + + -- This routine scans out the range or subtype mark that forms the right + -- operand of a membership test. + + -- Note: as documented in the Sinfo interface, although the syntax only + -- allows a subtype mark, we in fact allow any simple expression to be + -- returned from this routine. The semantics is responsible for issuing + -- an appropriate message complaining if the argument is not a name. + -- This simplifies the coding and error recovery processing in the + -- parser, and in any case it is preferable not to consider this a + -- syntax error and to continue with the semantic analysis. + + -- Error recovery: cannot raise Error_Resync + + function P_Range_Or_Subtype_Mark return Node_Id is + Expr_Node : Node_Id; + Range_Node : Node_Id; + + begin + Expr_Node := P_Simple_Expression_Or_Range_Attribute; + + if Expr_Form = EF_Range_Attr then + return Expr_Node; + + -- Simple_Expression .. Simple_Expression + + elsif Token = Tok_Dot_Dot then + Check_Simple_Expression (Expr_Node); + Range_Node := New_Node (N_Range, Token_Ptr); + Set_Low_Bound (Range_Node, Expr_Node); + Scan; -- past .. + Set_High_Bound (Range_Node, P_Simple_Expression); + return Range_Node; + + -- Case of subtype mark (optionally qualified simple name or an + -- attribute whose prefix is an optionally qualifed simple name) + + elsif Expr_Form = EF_Simple_Name + or else Nkind (Expr_Node) = N_Attribute_Reference + then + -- Check for error of range constraint after a subtype mark + + if Token = Tok_Range then + Error_Msg_SC + ("range constraint not allowed in membership test"); + Scan; -- past RANGE + raise Error_Resync; + + -- Check for error of DIGITS or DELTA after a subtype mark + + elsif Token = Tok_Digits or else Token = Tok_Delta then + Error_Msg_SC + ("accuracy definition not allowed in membership test"); + Scan; -- past DIGITS or DELTA + raise Error_Resync; + + elsif Token = Tok_Apostrophe then + return P_Subtype_Mark_Attribute (Expr_Node); + + else + return Expr_Node; + end if; + + -- At this stage, we have some junk following the expression. We + -- really can't tell what is wrong, might be a missing semicolon, + -- or a missing THEN, or whatever. Our caller will figure it out! + + else + return Expr_Node; + end if; + end P_Range_Or_Subtype_Mark; + + ---------------------------------------- + -- 3.5.1 Enumeration Type Definition -- + ---------------------------------------- + + -- ENUMERATION_TYPE_DEFINITION ::= + -- (ENUMERATION_LITERAL_SPECIFICATION + -- {, ENUMERATION_LITERAL_SPECIFICATION}) + + -- The caller has already scanned out the TYPE keyword + + -- Error recovery: can raise Error_Resync; + + function P_Enumeration_Type_Definition return Node_Id is + Typedef_Node : Node_Id; + + begin + Typedef_Node := New_Node (N_Enumeration_Type_Definition, Token_Ptr); + Set_Literals (Typedef_Node, New_List); + + T_Left_Paren; + + loop + Append (P_Enumeration_Literal_Specification, Literals (Typedef_Node)); + exit when not Comma_Present; + end loop; + + T_Right_Paren; + return Typedef_Node; + end P_Enumeration_Type_Definition; + + ---------------------------------------------- + -- 3.5.1 Enumeration Literal Specification -- + ---------------------------------------------- + + -- ENUMERATION_LITERAL_SPECIFICATION ::= + -- DEFINING_IDENTIFIER | DEFINING_CHARACTER_LITERAL + + -- Error recovery: can raise Error_Resync + + function P_Enumeration_Literal_Specification return Node_Id is + begin + if Token = Tok_Char_Literal then + return P_Defining_Character_Literal; + else + return P_Defining_Identifier; + end if; + end P_Enumeration_Literal_Specification; + + --------------------------------------- + -- 3.5.1 Defining_Character_Literal -- + --------------------------------------- + + -- DEFINING_CHARACTER_LITERAL ::= CHARACTER_LITERAL + + -- Error recovery: cannot raise Error_Resync + + -- The caller has checked that the current token is a character literal + + function P_Defining_Character_Literal return Node_Id is + Literal_Node : Node_Id; + + begin + Literal_Node := Token_Node; + Change_Character_Literal_To_Defining_Character_Literal (Literal_Node); + Scan; -- past character literal + return Literal_Node; + end P_Defining_Character_Literal; + + ------------------------------------ + -- 3.5.4 Integer Type Definition -- + ------------------------------------ + + -- Parsed by P_Type_Declaration (3.2.1) + + ------------------------------------------- + -- 3.5.4 Signed Integer Type Definition -- + ------------------------------------------- + + -- SIGNED_INTEGER_TYPE_DEFINITION ::= + -- range static_SIMPLE_EXPRESSION .. static_SIMPLE_EXPRESSION + + -- Normally the initial token on entry is RANGE, but in some + -- error conditions, the range token was missing and control is + -- passed with Token pointing to first token of the first expression. + + -- Error recovery: cannot raise Error_Resync + + function P_Signed_Integer_Type_Definition return Node_Id is + Typedef_Node : Node_Id; + Expr_Node : Node_Id; + + begin + Typedef_Node := New_Node (N_Signed_Integer_Type_Definition, Token_Ptr); + + if Token = Tok_Range then + Scan; -- past RANGE + end if; + + Expr_Node := P_Expression; + Check_Simple_Expression (Expr_Node); + Set_Low_Bound (Typedef_Node, Expr_Node); + T_Dot_Dot; + Expr_Node := P_Expression; + Check_Simple_Expression (Expr_Node); + Set_High_Bound (Typedef_Node, Expr_Node); + return Typedef_Node; + end P_Signed_Integer_Type_Definition; + + ------------------------------------ + -- 3.5.4 Modular Type Definition -- + ------------------------------------ + + -- MODULAR_TYPE_DEFINITION ::= mod static_EXPRESSION + + -- The caller has checked that the initial token is MOD + + -- Error recovery: cannot raise Error_Resync + + function P_Modular_Type_Definition return Node_Id is + Typedef_Node : Node_Id; + + begin + if Ada_83 then + Error_Msg_SC ("(Ada 83): modular types not allowed"); + end if; + + Typedef_Node := New_Node (N_Modular_Type_Definition, Token_Ptr); + Scan; -- past MOD + Set_Expression (Typedef_Node, P_Expression_No_Right_Paren); + + -- Handle mod L..R cleanly + + if Token = Tok_Dot_Dot then + Error_Msg_SC ("range not allowed for modular type"); + Scan; -- past .. + Set_Expression (Typedef_Node, P_Expression_No_Right_Paren); + end if; + + return Typedef_Node; + end P_Modular_Type_Definition; + + --------------------------------- + -- 3.5.6 Real Type Definition -- + --------------------------------- + + -- Parsed by P_Type_Declaration (3.2.1) + + -------------------------------------- + -- 3.5.7 Floating Point Definition -- + -------------------------------------- + + -- FLOATING_POINT_DEFINITION ::= + -- digits static_EXPRESSION [REAL_RANGE_SPECIFICATION] + + -- Note: In Ada-83, the EXPRESSION must be a SIMPLE_EXPRESSION + + -- The caller has checked that the initial token is DIGITS + + -- Error recovery: cannot raise Error_Resync + + function P_Floating_Point_Definition return Node_Id is + Digits_Loc : constant Source_Ptr := Token_Ptr; + Def_Node : Node_Id; + Expr_Node : Node_Id; + + begin + Scan; -- past DIGITS + Expr_Node := P_Expression_No_Right_Paren; + Check_Simple_Expression_In_Ada_83 (Expr_Node); + + -- Handle decimal fixed-point defn with DIGITS/DELTA in wrong order + + if Token = Tok_Delta then + Error_Msg_SC ("DELTA must come before DIGITS"); + Def_Node := New_Node (N_Decimal_Fixed_Point_Definition, Digits_Loc); + Scan; -- past DELTA + Set_Delta_Expression (Def_Node, P_Expression_No_Right_Paren); + + -- OK floating-point definition + + else + Def_Node := New_Node (N_Floating_Point_Definition, Digits_Loc); + end if; + + Set_Digits_Expression (Def_Node, Expr_Node); + Set_Real_Range_Specification (Def_Node, P_Real_Range_Specification_Opt); + return Def_Node; + end P_Floating_Point_Definition; + + ------------------------------------- + -- 3.5.7 Real Range Specification -- + ------------------------------------- + + -- REAL_RANGE_SPECIFICATION ::= + -- range static_SIMPLE_EXPRESSION .. static_SIMPLE_EXPRESSION + + -- Error recovery: cannot raise Error_Resync + + function P_Real_Range_Specification_Opt return Node_Id is + Specification_Node : Node_Id; + Expr_Node : Node_Id; + + begin + if Token = Tok_Range then + Specification_Node := + New_Node (N_Real_Range_Specification, Token_Ptr); + Scan; -- past RANGE + Expr_Node := P_Expression_No_Right_Paren; + Check_Simple_Expression (Expr_Node); + Set_Low_Bound (Specification_Node, Expr_Node); + T_Dot_Dot; + Expr_Node := P_Expression_No_Right_Paren; + Check_Simple_Expression (Expr_Node); + Set_High_Bound (Specification_Node, Expr_Node); + return Specification_Node; + else + return Empty; + end if; + end P_Real_Range_Specification_Opt; + + ----------------------------------- + -- 3.5.9 Fixed Point Definition -- + ----------------------------------- + + -- FIXED_POINT_DEFINITION ::= + -- ORDINARY_FIXED_POINT_DEFINITION | DECIMAL_FIXED_POINT_DEFINITION + + -- ORDINARY_FIXED_POINT_DEFINITION ::= + -- delta static_EXPRESSION REAL_RANGE_SPECIFICATION + + -- DECIMAL_FIXED_POINT_DEFINITION ::= + -- delta static_EXPRESSION + -- digits static_EXPRESSION [REAL_RANGE_SPECIFICATION] + + -- The caller has checked that the initial token is DELTA + + -- Error recovery: cannot raise Error_Resync + + function P_Fixed_Point_Definition return Node_Id is + Delta_Node : Node_Id; + Delta_Loc : Source_Ptr; + Def_Node : Node_Id; + Expr_Node : Node_Id; + + begin + Delta_Loc := Token_Ptr; + Scan; -- past DELTA + Delta_Node := P_Expression_No_Right_Paren; + Check_Simple_Expression_In_Ada_83 (Delta_Node); + + if Token = Tok_Digits then + if Ada_83 then + Error_Msg_SC ("(Ada 83) decimal fixed type not allowed!"); + end if; + + Def_Node := New_Node (N_Decimal_Fixed_Point_Definition, Delta_Loc); + Scan; -- past DIGITS + Expr_Node := P_Expression_No_Right_Paren; + Check_Simple_Expression_In_Ada_83 (Expr_Node); + Set_Digits_Expression (Def_Node, Expr_Node); + + else + Def_Node := New_Node (N_Ordinary_Fixed_Point_Definition, Delta_Loc); + + -- Range is required in ordinary fixed point case + + if Token /= Tok_Range then + Error_Msg_AP ("range must be given for fixed-point type"); + T_Range; + end if; + end if; + + Set_Delta_Expression (Def_Node, Delta_Node); + Set_Real_Range_Specification (Def_Node, P_Real_Range_Specification_Opt); + return Def_Node; + end P_Fixed_Point_Definition; + + -------------------------------------------- + -- 3.5.9 Ordinary Fixed Point Definition -- + -------------------------------------------- + + -- Parsed by P_Fixed_Point_Definition (3.5.9) + + ------------------------------------------- + -- 3.5.9 Decimal Fixed Point Definition -- + ------------------------------------------- + + -- Parsed by P_Decimal_Point_Definition (3.5.9) + + ------------------------------ + -- 3.5.9 Digits Constraint -- + ------------------------------ + + -- DIGITS_CONSTRAINT ::= + -- digits static_EXPRESSION [RANGE_CONSTRAINT] + + -- Note: in Ada 83, the EXPRESSION must be a SIMPLE_EXPRESSION + + -- The caller has checked that the initial token is DIGITS + + function P_Digits_Constraint return Node_Id is + Constraint_Node : Node_Id; + Expr_Node : Node_Id; + + begin + Constraint_Node := New_Node (N_Digits_Constraint, Token_Ptr); + Scan; -- past DIGITS + Expr_Node := P_Expression_No_Right_Paren; + Check_Simple_Expression_In_Ada_83 (Expr_Node); + Set_Digits_Expression (Constraint_Node, Expr_Node); + + if Token = Tok_Range then + Set_Range_Constraint (Constraint_Node, P_Range_Constraint); + end if; + + return Constraint_Node; + end P_Digits_Constraint; + + ----------------------------- + -- 3.5.9 Delta Constraint -- + ----------------------------- + + -- DELTA CONSTRAINT ::= DELTA STATIC_EXPRESSION [RANGE_CONSTRAINT] + + -- Note: this is an obsolescent feature in Ada 95 (I.3) + + -- Note: in Ada 83, the EXPRESSION must be a SIMPLE_EXPRESSION + + -- The caller has checked that the initial token is DELTA + + -- Error recovery: cannot raise Error_Resync + + function P_Delta_Constraint return Node_Id is + Constraint_Node : Node_Id; + Expr_Node : Node_Id; + + begin + Constraint_Node := New_Node (N_Delta_Constraint, Token_Ptr); + Scan; -- past DELTA + Expr_Node := P_Expression_No_Right_Paren; + Check_Simple_Expression_In_Ada_83 (Expr_Node); + Set_Delta_Expression (Constraint_Node, Expr_Node); + + if Token = Tok_Range then + Set_Range_Constraint (Constraint_Node, P_Range_Constraint); + end if; + + return Constraint_Node; + end P_Delta_Constraint; + + -------------------------------- + -- 3.6 Array Type Definition -- + -------------------------------- + + -- ARRAY_TYPE_DEFINITION ::= + -- UNCONSTRAINED_ARRAY_DEFINITION | CONSTRAINED_ARRAY_DEFINITION + + -- UNCONSTRAINED_ARRAY_DEFINITION ::= + -- array (INDEX_SUBTYPE_DEFINITION {, INDEX_SUBTYPE_DEFINITION}) of + -- COMPONENT_DEFINITION + + -- INDEX_SUBTYPE_DEFINITION ::= SUBTYPE_MARK range <> + + -- CONSTRAINED_ARRAY_DEFINITION ::= + -- array (DISCRETE_SUBTYPE_DEFINITION {, DISCRETE_SUBTYPE_DEFINITION}) of + -- COMPONENT_DEFINITION + + -- DISCRETE_SUBTYPE_DEFINITION ::= + -- DISCRETE_SUBTYPE_INDICATION | RANGE + + -- COMPONENT_DEFINITION ::= [aliased] SUBTYPE_INDICATION + + -- The caller has checked that the initial token is ARRAY + + -- Error recovery: can raise Error_Resync + + function P_Array_Type_Definition return Node_Id is + Array_Loc : Source_Ptr; + Def_Node : Node_Id; + Subs_List : List_Id; + Scan_State : Saved_Scan_State; + + begin + Array_Loc := Token_Ptr; + Scan; -- past ARRAY + Subs_List := New_List; + T_Left_Paren; + + -- It's quite tricky to disentangle these two possibilities, so we do + -- a prescan to determine which case we have and then reset the scan. + -- The prescan skips past possible subtype mark tokens. + + Save_Scan_State (Scan_State); -- just after paren + + while Token in Token_Class_Desig or else + Token = Tok_Dot or else + Token = Tok_Apostrophe -- because of 'BASE, 'CLASS + loop + Scan; + end loop; + + -- If we end up on RANGE <> then we have the unconstrained case. We + -- will also allow the RANGE to be omitted, just to improve error + -- handling for a case like array (integer <>) of integer; + + Scan; -- past possible RANGE or <> + + if (Prev_Token = Tok_Range and then Token = Tok_Box) or else + Prev_Token = Tok_Box + then + Def_Node := New_Node (N_Unconstrained_Array_Definition, Array_Loc); + Restore_Scan_State (Scan_State); -- to first subtype mark + + loop + Append (P_Subtype_Mark_Resync, Subs_List); + T_Range; + T_Box; + exit when Token = Tok_Right_Paren or else Token = Tok_Of; + T_Comma; + end loop; + + Set_Subtype_Marks (Def_Node, Subs_List); + + else + Def_Node := New_Node (N_Constrained_Array_Definition, Array_Loc); + Restore_Scan_State (Scan_State); -- to first discrete range + + loop + Append (P_Discrete_Subtype_Definition, Subs_List); + exit when not Comma_Present; + end loop; + + Set_Discrete_Subtype_Definitions (Def_Node, Subs_List); + end if; + + T_Right_Paren; + T_Of; + + if Token = Tok_Aliased then + Set_Aliased_Present (Def_Node, True); + Scan; -- past ALIASED + end if; + + Set_Subtype_Indication (Def_Node, P_Subtype_Indication); + return Def_Node; + end P_Array_Type_Definition; + + ----------------------------------------- + -- 3.6 Unconstrained Array Definition -- + ----------------------------------------- + + -- Parsed by P_Array_Type_Definition (3.6) + + --------------------------------------- + -- 3.6 Constrained Array Definition -- + --------------------------------------- + + -- Parsed by P_Array_Type_Definition (3.6) + + -------------------------------------- + -- 3.6 Discrete Subtype Definition -- + -------------------------------------- + + -- DISCRETE_SUBTYPE_DEFINITION ::= + -- discrete_SUBTYPE_INDICATION | RANGE + + -- Note: the discrete subtype definition appearing in a constrained + -- array definition is parsed by P_Array_Type_Definition (3.6) + + -- Error recovery: cannot raise Error_Resync + + function P_Discrete_Subtype_Definition return Node_Id is + begin + + -- The syntax of a discrete subtype definition is identical to that + -- of a discrete range, so we simply share the same parsing code. + + return P_Discrete_Range; + end P_Discrete_Subtype_Definition; + + ------------------------------- + -- 3.6 Component Definition -- + ------------------------------- + + -- For the array case, parsed by P_Array_Type_Definition (3.6) + -- For the record case, parsed by P_Component_Declaration (3.8) + + ----------------------------- + -- 3.6.1 Index Constraint -- + ----------------------------- + + -- Parsed by P_Index_Or_Discriminant_Constraint (3.7.1) + + --------------------------- + -- 3.6.1 Discrete Range -- + --------------------------- + + -- DISCRETE_RANGE ::= discrete_SUBTYPE_INDICATION | RANGE + + -- The possible forms for a discrete range are: + + -- Subtype_Mark (SUBTYPE_INDICATION, 3.2.2) + -- Subtype_Mark range Range (SUBTYPE_INDICATION, 3.2.2) + -- Range_Attribute (RANGE, 3.5) + -- Simple_Expression .. Simple_Expression (RANGE, 3.5) + + -- Error recovery: cannot raise Error_Resync + + function P_Discrete_Range return Node_Id is + Expr_Node : Node_Id; + Range_Node : Node_Id; + + begin + Expr_Node := P_Simple_Expression_Or_Range_Attribute; + + if Expr_Form = EF_Range_Attr then + return Expr_Node; + + elsif Token = Tok_Range then + if Expr_Form /= EF_Simple_Name then + Error_Msg_SC ("range must be preceded by subtype mark"); + end if; + + return P_Subtype_Indication (Expr_Node); + + -- Check Expression .. Expression case + + elsif Token = Tok_Dot_Dot then + Range_Node := New_Node (N_Range, Token_Ptr); + Set_Low_Bound (Range_Node, Expr_Node); + Scan; -- past .. + Expr_Node := P_Expression; + Check_Simple_Expression (Expr_Node); + Set_High_Bound (Range_Node, Expr_Node); + return Range_Node; + + -- Otherwise we must have a subtype mark + + elsif Expr_Form = EF_Simple_Name then + return Expr_Node; + + -- If incorrect, complain that we expect .. + + else + T_Dot_Dot; + return Expr_Node; + end if; + end P_Discrete_Range; + + ---------------------------- + -- 3.7 Discriminant Part -- + ---------------------------- + + -- DISCRIMINANT_PART ::= + -- UNKNOWN_DISCRIMINANT_PART + -- | KNOWN_DISCRIMINANT_PART + + -- A discriminant part is parsed by P_Known_Discriminant_Part_Opt (3.7) + -- or P_Unknown_Discriminant_Part (3.7), since we know which we want. + + ------------------------------------ + -- 3.7 Unknown Discriminant Part -- + ------------------------------------ + + -- UNKNOWN_DISCRIMINANT_PART ::= (<>) + + -- If no unknown discriminant part is present, then False is returned, + -- otherwise the unknown discriminant is scanned out and True is returned. + + -- Error recovery: cannot raise Error_Resync + + function P_Unknown_Discriminant_Part_Opt return Boolean is + Scan_State : Saved_Scan_State; + + begin + if Token /= Tok_Left_Paren then + return False; + + else + Save_Scan_State (Scan_State); + Scan; -- past the left paren + + if Token = Tok_Box then + + if Ada_83 then + Error_Msg_SC ("(Ada 83) unknown discriminant not allowed!"); + end if; + + Scan; -- past the box + T_Right_Paren; -- must be followed by right paren + return True; + + else + Restore_Scan_State (Scan_State); + return False; + end if; + end if; + end P_Unknown_Discriminant_Part_Opt; + + ---------------------------------- + -- 3.7 Known Discriminant Part -- + ---------------------------------- + + -- KNOWN_DISCRIMINANT_PART ::= + -- (DISCRIMINANT_SPECIFICATION {; DISCRIMINANT_SPECIFICATION}) + + -- DISCRIMINANT_SPECIFICATION ::= + -- DEFINING_IDENTIFIER_LIST : SUBTYPE_MARK + -- [:= DEFAULT_EXPRESSION] + -- | DEFINING_IDENTIFIER_LIST : ACCESS_DEFINITION + -- [:= DEFAULT_EXPRESSION] + + -- If no known discriminant part is present, then No_List is returned + + -- Error recovery: cannot raise Error_Resync + + function P_Known_Discriminant_Part_Opt return List_Id is + Specification_Node : Node_Id; + Specification_List : List_Id; + Ident_Sloc : Source_Ptr; + Scan_State : Saved_Scan_State; + Num_Idents : Nat; + Ident : Nat; + + Idents : array (Int range 1 .. 4096) of Entity_Id; + -- This array holds the list of defining identifiers. The upper bound + -- of 4096 is intended to be essentially infinite, and we do not even + -- bother to check for it being exceeded. + + begin + if Token = Tok_Left_Paren then + Specification_List := New_List; + Scan; -- past ( + P_Pragmas_Misplaced; + + Specification_Loop : loop + + Ident_Sloc := Token_Ptr; + Idents (1) := P_Defining_Identifier; + Num_Idents := 1; + + while Comma_Present loop + Num_Idents := Num_Idents + 1; + Idents (Num_Idents) := P_Defining_Identifier; + end loop; + + T_Colon; + + -- If there are multiple identifiers, we repeatedly scan the + -- type and initialization expression information by resetting + -- the scan pointer (so that we get completely separate trees + -- for each occurrence). + + if Num_Idents > 1 then + Save_Scan_State (Scan_State); + end if; + + -- Loop through defining identifiers in list + + Ident := 1; + Ident_Loop : loop + Specification_Node := + New_Node (N_Discriminant_Specification, Ident_Sloc); + Set_Defining_Identifier (Specification_Node, Idents (Ident)); + + if Token = Tok_Access then + if Ada_83 then + Error_Msg_SC + ("(Ada 83) access discriminant not allowed!"); + end if; + + Set_Discriminant_Type + (Specification_Node, P_Access_Definition); + else + Set_Discriminant_Type + (Specification_Node, P_Subtype_Mark); + No_Constraint; + end if; + + Set_Expression + (Specification_Node, Init_Expr_Opt (True)); + + if Ident > 1 then + Set_Prev_Ids (Specification_Node, True); + end if; + + if Ident < Num_Idents then + Set_More_Ids (Specification_Node, True); + end if; + + Append (Specification_Node, Specification_List); + exit Ident_Loop when Ident = Num_Idents; + Ident := Ident + 1; + Restore_Scan_State (Scan_State); + end loop Ident_Loop; + + exit Specification_Loop when Token /= Tok_Semicolon; + Scan; -- past ; + P_Pragmas_Misplaced; + end loop Specification_Loop; + + T_Right_Paren; + return Specification_List; + + else + return No_List; + end if; + end P_Known_Discriminant_Part_Opt; + + ------------------------------------- + -- 3.7 DIscriminant Specification -- + ------------------------------------- + + -- Parsed by P_Known_Discriminant_Part_Opt (3.7) + + ----------------------------- + -- 3.7 Default Expression -- + ----------------------------- + + -- Always parsed (simply as an Expression) by the parent construct + + ------------------------------------ + -- 3.7.1 Discriminant Constraint -- + ------------------------------------ + + -- Parsed by P_Index_Or_Discriminant_Constraint (3.7.1) + + -------------------------------------------------------- + -- 3.7.1 Index or Discriminant Constraint (also 3.6) -- + -------------------------------------------------------- + + -- DISCRIMINANT_CONSTRAINT ::= + -- (DISCRIMINANT_ASSOCIATION {, DISCRIMINANT_ASSOCIATION}) + + -- DISCRIMINANT_ASSOCIATION ::= + -- [discriminant_SELECTOR_NAME {| discriminant_SELECTOR_NAME} =>] + -- EXPRESSION + + -- This routine parses either an index or a discriminant constraint. As + -- is clear from the above grammar, it is often possible to clearly + -- determine which of the two possibilities we have, but there are + -- cases (those in which we have a series of expressions of the same + -- syntactic form as subtype indications), where we cannot tell. Since + -- this means that in any case the semantic phase has to distinguish + -- between the two, there is not much point in the parser trying to + -- distinguish even those cases where the difference is clear. In any + -- case, if we have a situation like: + + -- (A => 123, 235 .. 500) + + -- it is not clear which of the two items is the wrong one, better to + -- let the semantic phase give a clear message. Consequently, this + -- routine in general returns a list of items which can be either + -- discrete ranges or discriminant associations. + + -- The caller has checked that the initial token is a left paren + + -- Error recovery: can raise Error_Resync + + function P_Index_Or_Discriminant_Constraint return Node_Id is + Scan_State : Saved_Scan_State; + Constr_Node : Node_Id; + Constr_List : List_Id; + Expr_Node : Node_Id; + Result_Node : Node_Id; + + begin + Result_Node := New_Node (N_Index_Or_Discriminant_Constraint, Token_Ptr); + Scan; -- past ( + Constr_List := New_List; + Set_Constraints (Result_Node, Constr_List); + + -- The two syntactic forms are a little mixed up, so what we are doing + -- here is looking at the first entry to determine which case we have + + -- A discriminant constraint is a list of discriminant associations, + -- which have one of the following possible forms: + + -- Expression + -- Id => Expression + -- Id | Id | .. | Id => Expression + + -- An index constraint is a list of discrete ranges which have one + -- of the following possible forms: + + -- Subtype_Mark + -- Subtype_Mark range Range + -- Range_Attribute + -- Simple_Expression .. Simple_Expression + + -- Loop through discriminants in list + + loop + -- Check cases of Id => Expression or Id | Id => Expression + + if Token = Tok_Identifier then + Save_Scan_State (Scan_State); -- at Id + Scan; -- past Id + + if Token = Tok_Arrow or else Token = Tok_Vertical_Bar then + Restore_Scan_State (Scan_State); -- to Id + Append (P_Discriminant_Association, Constr_List); + goto Loop_Continue; + else + Restore_Scan_State (Scan_State); -- to Id + end if; + end if; + + -- Otherwise scan out an expression and see what we have got + + Expr_Node := P_Expression_Or_Range_Attribute; + + if Expr_Form = EF_Range_Attr then + Append (Expr_Node, Constr_List); + + elsif Token = Tok_Range then + if Expr_Form /= EF_Simple_Name then + Error_Msg_SC ("subtype mark required before RANGE"); + end if; + + Append (P_Subtype_Indication (Expr_Node), Constr_List); + goto Loop_Continue; + + -- Check Simple_Expression .. Simple_Expression case + + elsif Token = Tok_Dot_Dot then + Check_Simple_Expression (Expr_Node); + Constr_Node := New_Node (N_Range, Token_Ptr); + Set_Low_Bound (Constr_Node, Expr_Node); + Scan; -- past .. + Expr_Node := P_Expression; + Check_Simple_Expression (Expr_Node); + Set_High_Bound (Constr_Node, Expr_Node); + Append (Constr_Node, Constr_List); + goto Loop_Continue; + + -- Case of an expression which could be either form + + else + Append (Expr_Node, Constr_List); + goto Loop_Continue; + end if; + + -- Here with a single entry scanned + + <<Loop_Continue>> + exit when not Comma_Present; + + end loop; + + T_Right_Paren; + return Result_Node; + + end P_Index_Or_Discriminant_Constraint; + + ------------------------------------- + -- 3.7.1 Discriminant Association -- + ------------------------------------- + + -- DISCRIMINANT_ASSOCIATION ::= + -- [discriminant_SELECTOR_NAME {| discriminant_SELECTOR_NAME} =>] + -- EXPRESSION + + -- This routine is used only when the name list is present and the caller + -- has already checked this (by scanning ahead and repositioning the + -- scan). + + -- Error_Recovery: cannot raise Error_Resync; + + function P_Discriminant_Association return Node_Id is + Discr_Node : Node_Id; + Names_List : List_Id; + Ident_Sloc : Source_Ptr; + + begin + Ident_Sloc := Token_Ptr; + Names_List := New_List; + + loop + Append (P_Identifier, Names_List); + exit when Token /= Tok_Vertical_Bar; + Scan; -- past | + end loop; + + Discr_Node := New_Node (N_Discriminant_Association, Ident_Sloc); + Set_Selector_Names (Discr_Node, Names_List); + TF_Arrow; + Set_Expression (Discr_Node, P_Expression); + return Discr_Node; + end P_Discriminant_Association; + + --------------------------------- + -- 3.8 Record Type Definition -- + --------------------------------- + + -- RECORD_TYPE_DEFINITION ::= + -- [[abstract] tagged] [limited] RECORD_DEFINITION + + -- There is no node in the tree for a record type definition. Instead + -- a record definition node appears, with possible Abstract_Present, + -- Tagged_Present, and Limited_Present flags set appropriately. + + ---------------------------- + -- 3.8 Record Definition -- + ---------------------------- + + -- RECORD_DEFINITION ::= + -- record + -- COMPONENT_LIST + -- end record + -- | null record + + -- Note: in the case where a record definition node is used to represent + -- a record type definition, the caller sets the Tagged_Present and + -- Limited_Present flags in the resulting N_Record_Definition node as + -- required. + + -- Note that the RECORD token at the start may be missing in certain + -- error situations, so this function is expected to post the error + + -- Error recovery: can raise Error_Resync + + function P_Record_Definition return Node_Id is + Rec_Node : Node_Id; + + begin + Rec_Node := New_Node (N_Record_Definition, Token_Ptr); + + -- Null record case + + if Token = Tok_Null then + Scan; -- past NULL + T_Record; + Set_Null_Present (Rec_Node, True); + + -- Case starting with RECORD keyword. Build scope stack entry. For the + -- column, we use the first non-blank character on the line, to deal + -- with situations such as: + + -- type X is record + -- ... + -- end record; + + -- which is not official RM indentation, but is not uncommon usage + + else + Push_Scope_Stack; + Scope.Table (Scope.Last).Etyp := E_Record; + Scope.Table (Scope.Last).Ecol := Start_Column; + Scope.Table (Scope.Last).Sloc := Token_Ptr; + Scope.Table (Scope.Last).Labl := Error; + Scope.Table (Scope.Last).Junk := (Token /= Tok_Record); + + T_Record; + + Set_Component_List (Rec_Node, P_Component_List); + + loop + exit when Check_End; + Discard_Junk_Node (P_Component_List); + end loop; + end if; + + return Rec_Node; + end P_Record_Definition; + + ------------------------- + -- 3.8 Component List -- + ------------------------- + + -- COMPONENT_LIST ::= + -- COMPONENT_ITEM {COMPONENT_ITEM} + -- | {COMPONENT_ITEM} VARIANT_PART + -- | null; + + -- Error recovery: cannot raise Error_Resync + + function P_Component_List return Node_Id is + Component_List_Node : Node_Id; + Decls_List : List_Id; + Scan_State : Saved_Scan_State; + + begin + Component_List_Node := New_Node (N_Component_List, Token_Ptr); + Decls_List := New_List; + + if Token = Tok_Null then + Scan; -- past NULL + TF_Semicolon; + P_Pragmas_Opt (Decls_List); + Set_Null_Present (Component_List_Node, True); + return Component_List_Node; + + else + P_Pragmas_Opt (Decls_List); + + if Token /= Tok_Case then + Component_Scan_Loop : loop + P_Component_Items (Decls_List); + P_Pragmas_Opt (Decls_List); + + exit Component_Scan_Loop when Token = Tok_End + or else Token = Tok_Case + or else Token = Tok_When; + + -- We are done if we do not have an identifier. However, if + -- we have a misspelled reserved identifier that is in a column + -- to the right of the record definition, we will treat it as + -- an identifier. It turns out to be too dangerous in practice + -- to accept such a mis-spelled identifier which does not have + -- this additional clue that confirms the incorrect spelling. + + if Token /= Tok_Identifier then + if Start_Column > Scope.Table (Scope.Last).Ecol + and then Is_Reserved_Identifier + then + Save_Scan_State (Scan_State); -- at reserved id + Scan; -- possible reserved id + + if Token = Tok_Comma or else Token = Tok_Colon then + Restore_Scan_State (Scan_State); + Scan_Reserved_Identifier (Force_Msg => True); + + -- Note reserved identifier used as field name after + -- all because not followed by colon or comma + + else + Restore_Scan_State (Scan_State); + exit Component_Scan_Loop; + end if; + + -- Non-identifier that definitely was not reserved id + + else + exit Component_Scan_Loop; + end if; + end if; + end loop Component_Scan_Loop; + end if; + + if Token = Tok_Case then + Set_Variant_Part (Component_List_Node, P_Variant_Part); + + -- Check for junk after variant part + + if Token = Tok_Identifier then + Save_Scan_State (Scan_State); + Scan; -- past identifier + + if Token = Tok_Colon then + Restore_Scan_State (Scan_State); + Error_Msg_SC ("component may not follow variant part"); + Discard_Junk_Node (P_Component_List); + + elsif Token = Tok_Case then + Restore_Scan_State (Scan_State); + Error_Msg_SC ("only one variant part allowed in a record"); + Discard_Junk_Node (P_Component_List); + + else + Restore_Scan_State (Scan_State); + end if; + end if; + end if; + end if; + + Set_Component_Items (Component_List_Node, Decls_List); + return Component_List_Node; + + end P_Component_List; + + ------------------------- + -- 3.8 Component Item -- + ------------------------- + + -- COMPONENT_ITEM ::= COMPONENT_DECLARATION | REPRESENTATION_CLAUSE + + -- COMPONENT_DECLARATION ::= + -- DEFINING_IDENTIFIER_LIST : COMPONENT_DEFINITION + -- [:= DEFAULT_EXPRESSION]; + + -- COMPONENT_DEFINITION ::= [aliased] SUBTYPE_INDICATION + + -- Error recovery: cannot raise Error_Resync, if an error occurs, + -- the scan is positioned past the following semicolon. + + -- Note: we do not yet allow representation clauses to appear as component + -- items, do we need to add this capability sometime in the future ??? + + procedure P_Component_Items (Decls : List_Id) is + Decl_Node : Node_Id; + Scan_State : Saved_Scan_State; + Num_Idents : Nat; + Ident : Nat; + Ident_Sloc : Source_Ptr; + + Idents : array (Int range 1 .. 4096) of Entity_Id; + -- This array holds the list of defining identifiers. The upper bound + -- of 4096 is intended to be essentially infinite, and we do not even + -- bother to check for it being exceeded. + + begin + if Token /= Tok_Identifier then + Error_Msg_SC ("component declaration expected"); + Resync_Past_Semicolon; + return; + end if; + + Ident_Sloc := Token_Ptr; + Idents (1) := P_Defining_Identifier; + Num_Idents := 1; + + while Comma_Present loop + Num_Idents := Num_Idents + 1; + Idents (Num_Idents) := P_Defining_Identifier; + end loop; + + T_Colon; + + -- If there are multiple identifiers, we repeatedly scan the + -- type and initialization expression information by resetting + -- the scan pointer (so that we get completely separate trees + -- for each occurrence). + + if Num_Idents > 1 then + Save_Scan_State (Scan_State); + end if; + + -- Loop through defining identifiers in list + + Ident := 1; + Ident_Loop : loop + + -- The following block is present to catch Error_Resync + -- which causes the parse to be reset past the semicolon + + begin + Decl_Node := New_Node (N_Component_Declaration, Ident_Sloc); + Set_Defining_Identifier (Decl_Node, Idents (Ident)); + + if Token = Tok_Constant then + Error_Msg_SC ("constant components are not permitted"); + Scan; + end if; + + if Token_Name = Name_Aliased then + Check_95_Keyword (Tok_Aliased, Tok_Identifier); + end if; + + if Token = Tok_Aliased then + Scan; -- past ALIASED + Set_Aliased_Present (Decl_Node, True); + end if; + + if Token = Tok_Array then + Error_Msg_SC ("anonymous arrays not allowed as components"); + raise Error_Resync; + end if; + + Set_Subtype_Indication (Decl_Node, P_Subtype_Indication); + Set_Expression (Decl_Node, Init_Expr_Opt); + + if Ident > 1 then + Set_Prev_Ids (Decl_Node, True); + end if; + + if Ident < Num_Idents then + Set_More_Ids (Decl_Node, True); + end if; + + Append (Decl_Node, Decls); + + exception + when Error_Resync => + if Token /= Tok_End then + Resync_Past_Semicolon; + end if; + end; + + exit Ident_Loop when Ident = Num_Idents; + Ident := Ident + 1; + Restore_Scan_State (Scan_State); + + end loop Ident_Loop; + + TF_Semicolon; + + end P_Component_Items; + + -------------------------------- + -- 3.8 Component Declaration -- + -------------------------------- + + -- Parsed by P_Component_Items (3.8) + + ------------------------- + -- 3.8.1 Variant Part -- + ------------------------- + + -- VARIANT_PART ::= + -- case discriminant_DIRECT_NAME is + -- VARIANT + -- {VARIANT} + -- end case; + + -- The caller has checked that the initial token is CASE + + -- Error recovery: cannot raise Error_Resync + + function P_Variant_Part return Node_Id is + Variant_Part_Node : Node_Id; + Variants_List : List_Id; + Case_Node : Node_Id; + Case_Sloc : Source_Ptr; + + begin + Variant_Part_Node := New_Node (N_Variant_Part, Token_Ptr); + Push_Scope_Stack; + Scope.Table (Scope.Last).Etyp := E_Case; + Scope.Table (Scope.Last).Sloc := Token_Ptr; + Scope.Table (Scope.Last).Ecol := Start_Column; + + Scan; -- past CASE + Case_Node := P_Expression; + Case_Sloc := Token_Ptr; + Set_Name (Variant_Part_Node, Case_Node); + + if Nkind (Case_Node) /= N_Identifier then + Set_Name (Variant_Part_Node, Error); + Error_Msg ("discriminant name expected", Sloc (Case_Node)); + end if; + + TF_Is; + Variants_List := New_List; + P_Pragmas_Opt (Variants_List); + + -- Test missing variant + + if Token = Tok_End then + Error_Msg_BC ("WHEN expected (must have at least one variant)"); + else + Append (P_Variant, Variants_List); + end if; + + -- Loop through variants, note that we allow if in place of when, + -- this error will be detected and handled in P_Variant. + + loop + P_Pragmas_Opt (Variants_List); + + if Token /= Tok_When + and then Token /= Tok_If + and then Token /= Tok_Others + then + exit when Check_End; + end if; + + Append (P_Variant, Variants_List); + end loop; + + Set_Variants (Variant_Part_Node, Variants_List); + return Variant_Part_Node; + + end P_Variant_Part; + + -------------------- + -- 3.8.1 Variant -- + -------------------- + + -- VARIANT ::= + -- when DISCRETE_CHOICE_LIST => + -- COMPONENT_LIST + + -- Error recovery: cannot raise Error_Resync + + -- The initial token on entry is either WHEN, IF or OTHERS + + function P_Variant return Node_Id is + Variant_Node : Node_Id; + + begin + -- Special check to recover nicely from use of IF in place of WHEN + + if Token = Tok_If then + T_When; + Scan; -- past IF + else + T_When; + end if; + + Variant_Node := New_Node (N_Variant, Prev_Token_Ptr); + Set_Discrete_Choices (Variant_Node, P_Discrete_Choice_List); + TF_Arrow; + Set_Component_List (Variant_Node, P_Component_List); + return Variant_Node; + end P_Variant; + + --------------------------------- + -- 3.8.1 Discrete Choice List -- + --------------------------------- + + -- DISCRETE_CHOICE_LIST ::= DISCRETE_CHOICE {| DISCRETE_CHOICE} + + -- DISCRETE_CHOICE ::= EXPRESSION | DISCRETE_RANGE | others + + -- Note: in Ada 83, the expression must be a simple expression + + -- Error recovery: cannot raise Error_Resync + + function P_Discrete_Choice_List return List_Id is + Choices : List_Id; + Expr_Node : Node_Id; + Choice_Node : Node_Id; + + begin + Choices := New_List; + + loop + if Token = Tok_Others then + Append (New_Node (N_Others_Choice, Token_Ptr), Choices); + Scan; -- past OTHERS + + else + begin + Expr_Node := No_Right_Paren (P_Expression_Or_Range_Attribute); + + if Token = Tok_Colon + and then Nkind (Expr_Node) = N_Identifier + then + Error_Msg_SP ("label not permitted in this context"); + Scan; -- past colon + + elsif Expr_Form = EF_Range_Attr then + Append (Expr_Node, Choices); + + elsif Token = Tok_Dot_Dot then + Check_Simple_Expression (Expr_Node); + Choice_Node := New_Node (N_Range, Token_Ptr); + Set_Low_Bound (Choice_Node, Expr_Node); + Scan; -- past .. + Expr_Node := P_Expression_No_Right_Paren; + Check_Simple_Expression (Expr_Node); + Set_High_Bound (Choice_Node, Expr_Node); + Append (Choice_Node, Choices); + + elsif Expr_Form = EF_Simple_Name then + if Token = Tok_Range then + Append (P_Subtype_Indication (Expr_Node), Choices); + + elsif Token in Token_Class_Consk then + Error_Msg_SC + ("the only constraint allowed here " & + "is a range constraint"); + Discard_Junk_Node (P_Constraint_Opt); + Append (Expr_Node, Choices); + + else + Append (Expr_Node, Choices); + end if; + + else + Check_Simple_Expression_In_Ada_83 (Expr_Node); + Append (Expr_Node, Choices); + end if; + + exception + when Error_Resync => + Resync_Choice; + return Error_List; + end; + end if; + + if Token = Tok_Comma then + Error_Msg_SC (""","" should be ""|"""); + else + exit when Token /= Tok_Vertical_Bar; + end if; + + Scan; -- past | or comma + end loop; + + return Choices; + end P_Discrete_Choice_List; + + ---------------------------- + -- 3.8.1 Discrete Choice -- + ---------------------------- + + -- Parsed by P_Discrete_Choice_List (3.8.1) + + ---------------------------------- + -- 3.9.1 Record Extension Part -- + ---------------------------------- + + -- RECORD_EXTENSION_PART ::= with RECORD_DEFINITION + + -- Parsed by P_Derived_Type_Def_Or_Private_Ext_Decl (3.4) + + ---------------------------------- + -- 3.10 Access Type Definition -- + ---------------------------------- + + -- ACCESS_TYPE_DEFINITION ::= + -- ACCESS_TO_OBJECT_DEFINITION + -- | ACCESS_TO_SUBPROGRAM_DEFINITION + + -- ACCESS_TO_OBJECT_DEFINITION ::= + -- access [GENERAL_ACCESS_MODIFIER] SUBTYPE_INDICATION + + -- GENERAL_ACCESS_MODIFIER ::= all | constant + + -- ACCESS_TO_SUBPROGRAM_DEFINITION + -- access [protected] procedure PARAMETER_PROFILE + -- | access [protected] function PARAMETER_AND_RESULT_PROFILE + + -- PARAMETER_PROFILE ::= [FORMAL_PART] + + -- PARAMETER_AND_RESULT_PROFILE ::= [FORMAL_PART] RETURN SUBTYPE_MARK + + -- The caller has checked that the initial token is ACCESS + + -- Error recovery: can raise Error_Resync + + function P_Access_Type_Definition return Node_Id is + Prot_Flag : Boolean; + Access_Loc : Source_Ptr; + Type_Def_Node : Node_Id; + + procedure Check_Junk_Subprogram_Name; + -- Used in access to subprogram definition cases to check for an + -- identifier or operator symbol that does not belong. + + procedure Check_Junk_Subprogram_Name is + Saved_State : Saved_Scan_State; + + begin + if Token = Tok_Identifier or else Token = Tok_Operator_Symbol then + Save_Scan_State (Saved_State); + Scan; -- past possible junk subprogram name + + if Token = Tok_Left_Paren or else Token = Tok_Semicolon then + Error_Msg_SP ("unexpected subprogram name ignored"); + return; + + else + Restore_Scan_State (Saved_State); + end if; + end if; + end Check_Junk_Subprogram_Name; + + -- Start of processing for P_Access_Type_Definition + + begin + Access_Loc := Token_Ptr; + Scan; -- past ACCESS + + if Token_Name = Name_Protected then + Check_95_Keyword (Tok_Protected, Tok_Procedure); + Check_95_Keyword (Tok_Protected, Tok_Function); + end if; + + Prot_Flag := (Token = Tok_Protected); + + if Prot_Flag then + Scan; -- past PROTECTED + if Token /= Tok_Procedure and then Token /= Tok_Function then + Error_Msg_SC ("FUNCTION or PROCEDURE expected"); + end if; + end if; + + if Token = Tok_Procedure then + if Ada_83 then + Error_Msg_SC ("(Ada 83) access to procedure not allowed!"); + end if; + + Type_Def_Node := New_Node (N_Access_Procedure_Definition, Access_Loc); + Scan; -- past PROCEDURE + Check_Junk_Subprogram_Name; + Set_Parameter_Specifications (Type_Def_Node, P_Parameter_Profile); + Set_Protected_Present (Type_Def_Node, Prot_Flag); + + elsif Token = Tok_Function then + if Ada_83 then + Error_Msg_SC ("(Ada 83) access to function not allowed!"); + end if; + + Type_Def_Node := New_Node (N_Access_Function_Definition, Access_Loc); + Scan; -- past FUNCTION + Check_Junk_Subprogram_Name; + Set_Parameter_Specifications (Type_Def_Node, P_Parameter_Profile); + Set_Protected_Present (Type_Def_Node, Prot_Flag); + TF_Return; + Set_Subtype_Mark (Type_Def_Node, P_Subtype_Mark); + No_Constraint; + + else + Type_Def_Node := + New_Node (N_Access_To_Object_Definition, Access_Loc); + + if Token = Tok_All or else Token = Tok_Constant then + if Ada_83 then + Error_Msg_SC ("(Ada 83) access modifier not allowed!"); + end if; + + if Token = Tok_All then + Set_All_Present (Type_Def_Node, True); + + else + Set_Constant_Present (Type_Def_Node, True); + end if; + + Scan; -- past ALL or CONSTANT + end if; + + Set_Subtype_Indication (Type_Def_Node, P_Subtype_Indication); + end if; + + return Type_Def_Node; + end P_Access_Type_Definition; + + --------------------------------------- + -- 3.10 Access To Object Definition -- + --------------------------------------- + + -- Parsed by P_Access_Type_Definition (3.10) + + ----------------------------------- + -- 3.10 General Access Modifier -- + ----------------------------------- + + -- Parsed by P_Access_Type_Definition (3.10) + + ------------------------------------------- + -- 3.10 Access To Subprogram Definition -- + ------------------------------------------- + + -- Parsed by P_Access_Type_Definition (3.10) + + ----------------------------- + -- 3.10 Access Definition -- + ----------------------------- + + -- ACCESS_DEFINITION ::= access SUBTYPE_MARK + + -- The caller has checked that the initial token is ACCESS + + -- Error recovery: cannot raise Error_Resync + + function P_Access_Definition return Node_Id is + Def_Node : Node_Id; + + begin + Def_Node := New_Node (N_Access_Definition, Token_Ptr); + Scan; -- past ACCESS + Set_Subtype_Mark (Def_Node, P_Subtype_Mark); + No_Constraint; + return Def_Node; + end P_Access_Definition; + + ----------------------------------------- + -- 3.10.1 Incomplete Type Declaration -- + ----------------------------------------- + + -- Parsed by P_Type_Declaration (3.2.1) + + ---------------------------- + -- 3.11 Declarative Part -- + ---------------------------- + + -- DECLARATIVE_PART ::= {DECLARATIVE_ITEM} + + -- Error recovery: cannot raise Error_Resync (because P_Declarative_Items + -- handles errors, and returns cleanly after an error has occurred) + + function P_Declarative_Part return List_Id is + Decls : List_Id; + Done : Boolean; + + begin + -- Indicate no bad declarations detected yet. This will be reset by + -- P_Declarative_Items if a bad declaration is discovered. + + Missing_Begin_Msg := No_Error_Msg; + + -- Get rid of active SIS entry from outer scope. This means we will + -- miss some nested cases, but it doesn't seem worth the effort. See + -- discussion in Par for further details + + SIS_Entry_Active := False; + Decls := New_List; + + -- Loop to scan out the declarations + + loop + P_Declarative_Items (Decls, Done, In_Spec => False); + exit when Done; + end loop; + + -- Get rid of active SIS entry which is left set only if we scanned a + -- procedure declaration and have not found the body. We could give + -- an error message, but that really would be usurping the role of + -- semantic analysis (this really is a missing body case). + + SIS_Entry_Active := False; + return Decls; + end P_Declarative_Part; + + ---------------------------- + -- 3.11 Declarative Item -- + ---------------------------- + + -- DECLARATIVE_ITEM ::= BASIC_DECLARATIVE_ITEM | BODY + + -- Can return Error if a junk declaration is found, or Empty if no + -- declaration is found (i.e. a token ending declarations, such as + -- BEGIN or END is encountered). + + -- Error recovery: cannot raise Error_Resync. If an error resync occurs, + -- then the scan is set past the next semicolon and Error is returned. + + procedure P_Declarative_Items + (Decls : List_Id; + Done : out Boolean; + In_Spec : Boolean) + is + Scan_State : Saved_Scan_State; + + begin + if Style_Check then Style.Check_Indentation; end if; + + case Token is + + when Tok_Function => + Check_Bad_Layout; + Append (P_Subprogram (Pf_Decl_Gins_Pbod_Rnam_Stub), Decls); + Done := False; + + when Tok_For => + Check_Bad_Layout; + + -- Check for loop (premature statement) + + Save_Scan_State (Scan_State); + Scan; -- past FOR + + if Token = Tok_Identifier then + Scan; -- past identifier + + if Token = Tok_In then + Restore_Scan_State (Scan_State); + Statement_When_Declaration_Expected (Decls, Done, In_Spec); + return; + end if; + end if; + + -- Not a loop, so must be rep clause + + Restore_Scan_State (Scan_State); + Append (P_Representation_Clause, Decls); + Done := False; + + when Tok_Generic => + Check_Bad_Layout; + Append (P_Generic, Decls); + Done := False; + + when Tok_Identifier => + Check_Bad_Layout; + P_Identifier_Declarations (Decls, Done, In_Spec); + + when Tok_Package => + Check_Bad_Layout; + Append (P_Package (Pf_Decl_Gins_Pbod_Rnam_Stub), Decls); + Done := False; + + when Tok_Pragma => + Append (P_Pragma, Decls); + Done := False; + + when Tok_Procedure => + Check_Bad_Layout; + Append (P_Subprogram (Pf_Decl_Gins_Pbod_Rnam_Stub), Decls); + Done := False; + + when Tok_Protected => + Check_Bad_Layout; + Scan; -- past PROTECTED + Append (P_Protected, Decls); + Done := False; + + when Tok_Subtype => + Check_Bad_Layout; + Append (P_Subtype_Declaration, Decls); + Done := False; + + when Tok_Task => + Check_Bad_Layout; + Scan; -- past TASK + Append (P_Task, Decls); + Done := False; + + when Tok_Type => + Check_Bad_Layout; + Append (P_Type_Declaration, Decls); + Done := False; + + when Tok_Use => + Check_Bad_Layout; + Append (P_Use_Clause, Decls); + Done := False; + + when Tok_With => + Check_Bad_Layout; + Error_Msg_SC ("WITH can only appear in context clause"); + raise Error_Resync; + + -- BEGIN terminates the scan of a sequence of declarations unless + -- there is a missing subprogram body, see section on handling + -- semicolon in place of IS. We only treat the begin as satisfying + -- the subprogram declaration if it falls in the expected column + -- or to its right. + + when Tok_Begin => + if SIS_Entry_Active and then Start_Column >= SIS_Ecol then + + -- Here we have the case where a BEGIN is encountered during + -- declarations in a declarative part, or at the outer level, + -- and there is a subprogram declaration outstanding for which + -- no body has been supplied. This is the case where we assume + -- that the semicolon in the subprogram declaration should + -- really have been is. The active SIS entry describes the + -- subprogram declaration. On return the declaration has been + -- modified to become a body. + + declare + Specification_Node : Node_Id; + Decl_Node : Node_Id; + Body_Node : Node_Id; + + begin + -- First issue the error message. If we had a missing + -- semicolon in the declaration, then change the message + -- to <missing "is"> + + if SIS_Missing_Semicolon_Message /= No_Error_Msg then + Change_Error_Text -- Replace: "missing "";"" " + (SIS_Missing_Semicolon_Message, "missing ""is"""); + + -- Otherwise we saved the semicolon position, so complain + + else + Error_Msg (""";"" should be IS", SIS_Semicolon_Sloc); + end if; + + -- The next job is to fix up any declarations that occurred + -- between the procedure header and the BEGIN. These got + -- chained to the outer declarative region (immediately + -- after the procedure declaration) and they should be + -- chained to the subprogram itself, which is a body + -- rather than a spec. + + Specification_Node := Specification (SIS_Declaration_Node); + Change_Node (SIS_Declaration_Node, N_Subprogram_Body); + Body_Node := SIS_Declaration_Node; + Set_Specification (Body_Node, Specification_Node); + Set_Declarations (Body_Node, New_List); + + loop + Decl_Node := Remove_Next (Body_Node); + exit when Decl_Node = Empty; + Append (Decl_Node, Declarations (Body_Node)); + end loop; + + -- Now make the scope table entry for the Begin-End and + -- scan it out + + Push_Scope_Stack; + Scope.Table (Scope.Last).Sloc := SIS_Sloc; + Scope.Table (Scope.Last).Etyp := E_Name; + Scope.Table (Scope.Last).Ecol := SIS_Ecol; + Scope.Table (Scope.Last).Labl := SIS_Labl; + Scope.Table (Scope.Last).Lreq := False; + SIS_Entry_Active := False; + Scan; -- past BEGIN + Set_Handled_Statement_Sequence (Body_Node, + P_Handled_Sequence_Of_Statements); + End_Statements (Handled_Statement_Sequence (Body_Node)); + end; + + Done := False; + + else + Done := True; + end if; + + -- Normally an END terminates the scan for basic declarative + -- items. The one exception is END RECORD, which is probably + -- left over from some other junk. + + when Tok_End => + Save_Scan_State (Scan_State); -- at END + Scan; -- past END + + if Token = Tok_Record then + Error_Msg_SP ("no RECORD for this `end record`!"); + Scan; -- past RECORD + TF_Semicolon; + + else + Restore_Scan_State (Scan_State); -- to END + Done := True; + end if; + + -- The following tokens which can only be the start of a statement + -- are considered to end a declarative part (i.e. we have a missing + -- BEGIN situation). We are fairly conservative in making this + -- judgment, because it is a real mess to go into statement mode + -- prematurely in reponse to a junk declaration. + + when Tok_Abort | + Tok_Accept | + Tok_Declare | + Tok_Delay | + Tok_Exit | + Tok_Goto | + Tok_If | + Tok_Loop | + Tok_Null | + Tok_Requeue | + Tok_Select | + Tok_While => + + -- But before we decide that it's a statement, let's check for + -- a reserved word misused as an identifier. + + if Is_Reserved_Identifier then + Save_Scan_State (Scan_State); + Scan; -- past the token + + -- If reserved identifier not followed by colon or comma, then + -- this is most likely an assignment statement to the bad id. + + if Token /= Tok_Colon and then Token /= Tok_Comma then + Restore_Scan_State (Scan_State); + Statement_When_Declaration_Expected (Decls, Done, In_Spec); + return; + + -- Otherwise we have a declaration of the bad id + + else + Restore_Scan_State (Scan_State); + Scan_Reserved_Identifier (Force_Msg => True); + P_Identifier_Declarations (Decls, Done, In_Spec); + end if; + + -- If not reserved identifier, then it's definitely a statement + + else + Statement_When_Declaration_Expected (Decls, Done, In_Spec); + return; + end if; + + -- The token RETURN may well also signal a missing BEGIN situation, + -- however, we never let it end the declarative part, because it may + -- also be part of a half-baked function declaration. + + when Tok_Return => + Error_Msg_SC ("misplaced RETURN statement"); + raise Error_Resync; + + -- PRIVATE definitely terminates the declarations in a spec, + -- and is an error in a body. + + when Tok_Private => + if In_Spec then + Done := True; + else + Error_Msg_SC ("PRIVATE not allowed in body"); + Scan; -- past PRIVATE + end if; + + -- An end of file definitely terminates the declarations! + + when Tok_EOF => + Done := True; + + -- The remaining tokens do not end the scan, but cannot start a + -- valid declaration, so we signal an error and resynchronize. + -- But first check for misuse of a reserved identifier. + + when others => + + -- Here we check for a reserved identifier + + if Is_Reserved_Identifier then + Save_Scan_State (Scan_State); + Scan; -- past the token + + if Token /= Tok_Colon and then Token /= Tok_Comma then + Restore_Scan_State (Scan_State); + Set_Declaration_Expected; + raise Error_Resync; + else + Restore_Scan_State (Scan_State); + Scan_Reserved_Identifier (Force_Msg => True); + Check_Bad_Layout; + P_Identifier_Declarations (Decls, Done, In_Spec); + end if; + + else + Set_Declaration_Expected; + raise Error_Resync; + end if; + end case; + + -- To resynchronize after an error, we scan to the next semicolon and + -- return with Done = False, indicating that there may still be more + -- valid declarations to come. + + exception + when Error_Resync => + Resync_Past_Semicolon; + Done := False; + + end P_Declarative_Items; + + ---------------------------------- + -- 3.11 Basic Declarative Item -- + ---------------------------------- + + -- BASIC_DECLARATIVE_ITEM ::= + -- BASIC_DECLARATION | REPRESENTATION_CLAUSE | USE_CLAUSE + + -- Scan zero or more basic declarative items + + -- Error recovery: cannot raise Error_Resync. If an error is detected, then + -- the scan pointer is repositioned past the next semicolon, and the scan + -- for declarative items continues. + + function P_Basic_Declarative_Items return List_Id is + Decl : Node_Id; + Decls : List_Id; + Kind : Node_Kind; + Done : Boolean; + + begin + -- Get rid of active SIS entry from outer scope. This means we will + -- miss some nested cases, but it doesn't seem worth the effort. See + -- discussion in Par for further details + + SIS_Entry_Active := False; + + -- Loop to scan out declarations + + Decls := New_List; + + loop + P_Declarative_Items (Decls, Done, In_Spec => True); + exit when Done; + end loop; + + -- Get rid of active SIS entry. This is set only if we have scanned a + -- procedure declaration and have not found the body. We could give + -- an error message, but that really would be usurping the role of + -- semantic analysis (this really is a case of a missing body). + + SIS_Entry_Active := False; + + -- Test for assorted illegal declarations not diagnosed elsewhere. + + Decl := First (Decls); + + while Present (Decl) loop + Kind := Nkind (Decl); + + -- Test for body scanned, not acceptable as basic decl item + + if Kind = N_Subprogram_Body or else + Kind = N_Package_Body or else + Kind = N_Task_Body or else + Kind = N_Protected_Body + then + Error_Msg + ("proper body not allowed in package spec", Sloc (Decl)); + + -- Test for body stub scanned, not acceptable as basic decl item + + elsif Kind in N_Body_Stub then + Error_Msg + ("body stub not allowed in package spec", Sloc (Decl)); + + elsif Kind = N_Assignment_Statement then + Error_Msg + ("assignment statement not allowed in package spec", + Sloc (Decl)); + end if; + + Next (Decl); + end loop; + + return Decls; + end P_Basic_Declarative_Items; + + ---------------- + -- 3.11 Body -- + ---------------- + + -- For proper body, see below + -- For body stub, see 10.1.3 + + ----------------------- + -- 3.11 Proper Body -- + ----------------------- + + -- Subprogram body is parsed by P_Subprogram (6.1) + -- Package body is parsed by P_Package (7.1) + -- Task body is parsed by P_Task (9.1) + -- Protected body is parsed by P_Protected (9.4) + + ------------------------------ + -- Set_Declaration_Expected -- + ------------------------------ + + procedure Set_Declaration_Expected is + begin + Error_Msg_SC ("declaration expected"); + + if Missing_Begin_Msg = No_Error_Msg then + Missing_Begin_Msg := Get_Msg_Id; + end if; + end Set_Declaration_Expected; + + ---------------------- + -- Skip_Declaration -- + ---------------------- + + procedure Skip_Declaration (S : List_Id) is + Dummy_Done : Boolean; + + begin + P_Declarative_Items (S, Dummy_Done, False); + end Skip_Declaration; + + ----------------------------------------- + -- Statement_When_Declaration_Expected -- + ----------------------------------------- + + procedure Statement_When_Declaration_Expected + (Decls : List_Id; + Done : out Boolean; + In_Spec : Boolean) + is + begin + -- Case of second occurrence of statement in one declaration sequence + + if Missing_Begin_Msg /= No_Error_Msg then + + -- In the procedure spec case, just ignore it, we only give one + -- message for the first occurrence, since otherwise we may get + -- horrible cascading if BODY was missing in the header line. + + if In_Spec then + null; + + -- In the declarative part case, take a second statement as a sure + -- sign that we really have a missing BEGIN, and end the declarative + -- part now. Note that the caller will fix up the first message to + -- say "missing BEGIN" so that's how the error will be signalled. + + else + Done := True; + return; + end if; + + -- Case of first occurrence of unexpected statement + + else + -- If we are in a package spec, then give message of statement + -- not allowed in package spec. This message never gets changed. + + if In_Spec then + Error_Msg_SC ("statement not allowed in package spec"); + + -- If in declarative part, then we give the message complaining + -- about finding a statement when a declaration is expected. This + -- gets changed to a complaint about a missing BEGIN if we later + -- find that no BEGIN is present. + + else + Error_Msg_SC ("statement not allowed in declarative part"); + end if; + + -- Capture message Id. This is used for two purposes, first to + -- stop multiple messages, see test above, and second, to allow + -- the replacement of the message in the declarative part case. + + Missing_Begin_Msg := Get_Msg_Id; + end if; + + -- In all cases except the case in which we decided to terminate the + -- declaration sequence on a second error, we scan out the statement + -- and append it to the list of declarations (note that the semantics + -- can handle statements in a declaration list so if we proceed to + -- call the semantic phase, all will be (reasonably) well! + + Append_List_To (Decls, P_Sequence_Of_Statements (SS_Unco)); + + -- Done is set to False, since we want to continue the scan of + -- declarations, hoping that this statement was a temporary glitch. + -- If we indeed are now in the statement part (i.e. this was a missing + -- BEGIN, then it's not terrible, we will simply keep calling this + -- procedure to process the statements one by one, and then finally + -- hit the missing BEGIN, which will clean up the error message. + + Done := False; + + end Statement_When_Declaration_Expected; + +end Ch3; diff --git a/gcc/ada/par-ch4.adb b/gcc/ada/par-ch4.adb new file mode 100644 index 00000000000..30fba5619cc --- /dev/null +++ b/gcc/ada/par-ch4.adb @@ -0,0 +1,2298 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P A R . C H 4 -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.91 $ +-- -- +-- Copyright (C) 1992-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +pragma Style_Checks (All_Checks); +-- Turn off subprogram body ordering check. Subprograms are in order +-- by RM section rather than alphabetical + +separate (Par) +package body Ch4 is + + ----------------------- + -- Local Subprograms -- + ----------------------- + + function P_Aggregate_Or_Paren_Expr return Node_Id; + function P_Allocator return Node_Id; + function P_Record_Or_Array_Component_Association return Node_Id; + function P_Factor return Node_Id; + function P_Primary return Node_Id; + function P_Relation return Node_Id; + function P_Term return Node_Id; + + function P_Binary_Adding_Operator return Node_Kind; + function P_Logical_Operator return Node_Kind; + function P_Multiplying_Operator return Node_Kind; + function P_Relational_Operator return Node_Kind; + function P_Unary_Adding_Operator return Node_Kind; + + procedure Bad_Range_Attribute (Loc : Source_Ptr); + -- Called to place complaint about bad range attribute at the given + -- source location. Terminates by raising Error_Resync. + + function P_Range_Attribute_Reference + (Prefix_Node : Node_Id) + return Node_Id; + -- Scan a range attribute reference. The caller has scanned out the + -- prefix. The current token is known to be an apostrophe and the + -- following token is known to be RANGE. + + procedure Set_Op_Name (Node : Node_Id); + -- Procedure to set name field (Chars) in operator node + + ------------------------- + -- Bad_Range_Attribute -- + ------------------------- + + procedure Bad_Range_Attribute (Loc : Source_Ptr) is + begin + Error_Msg ("range attribute cannot be used in expression", Loc); + Resync_Expression; + end Bad_Range_Attribute; + + ------------------ + -- Set_Op_Name -- + ------------------ + + procedure Set_Op_Name (Node : Node_Id) is + type Name_Of_Type is array (N_Op) of Name_Id; + Name_Of : Name_Of_Type := Name_Of_Type'( + N_Op_And => Name_Op_And, + N_Op_Or => Name_Op_Or, + N_Op_Xor => Name_Op_Xor, + N_Op_Eq => Name_Op_Eq, + N_Op_Ne => Name_Op_Ne, + N_Op_Lt => Name_Op_Lt, + N_Op_Le => Name_Op_Le, + N_Op_Gt => Name_Op_Gt, + N_Op_Ge => Name_Op_Ge, + N_Op_Add => Name_Op_Add, + N_Op_Subtract => Name_Op_Subtract, + N_Op_Concat => Name_Op_Concat, + N_Op_Multiply => Name_Op_Multiply, + N_Op_Divide => Name_Op_Divide, + N_Op_Mod => Name_Op_Mod, + N_Op_Rem => Name_Op_Rem, + N_Op_Expon => Name_Op_Expon, + N_Op_Plus => Name_Op_Add, + N_Op_Minus => Name_Op_Subtract, + N_Op_Abs => Name_Op_Abs, + N_Op_Not => Name_Op_Not, + + -- We don't really need these shift operators, since they never + -- appear as operators in the source, but the path of least + -- resistance is to put them in (the aggregate must be complete) + + N_Op_Rotate_Left => Name_Rotate_Left, + N_Op_Rotate_Right => Name_Rotate_Right, + N_Op_Shift_Left => Name_Shift_Left, + N_Op_Shift_Right => Name_Shift_Right, + N_Op_Shift_Right_Arithmetic => Name_Shift_Right_Arithmetic); + + begin + if Nkind (Node) in N_Op then + Set_Chars (Node, Name_Of (Nkind (Node))); + end if; + end Set_Op_Name; + + -------------------------- + -- 4.1 Name (also 6.4) -- + -------------------------- + + -- NAME ::= + -- DIRECT_NAME | EXPLICIT_DEREFERENCE + -- | INDEXED_COMPONENT | SLICE + -- | SELECTED_COMPONENT | ATTRIBUTE + -- | TYPE_CONVERSION | FUNCTION_CALL + -- | CHARACTER_LITERAL + + -- DIRECT_NAME ::= IDENTIFIER | OPERATOR_SYMBOL + + -- PREFIX ::= NAME | IMPLICIT_DEREFERENCE + + -- EXPLICIT_DEREFERENCE ::= NAME . all + + -- IMPLICIT_DEREFERENCE ::= NAME + + -- INDEXED_COMPONENT ::= PREFIX (EXPRESSION {, EXPRESSION}) + + -- SLICE ::= PREFIX (DISCRETE_RANGE) + + -- SELECTED_COMPONENT ::= PREFIX . SELECTOR_NAME + + -- SELECTOR_NAME ::= IDENTIFIER | CHARACTER_LITERAL | OPERATOR_SYMBOL + + -- ATTRIBUTE_REFERENCE ::= PREFIX ' ATTRIBUTE_DESIGNATOR + + -- ATTRIBUTE_DESIGNATOR ::= + -- IDENTIFIER [(static_EXPRESSION)] + -- | access | delta | digits + + -- FUNCTION_CALL ::= + -- function_NAME + -- | function_PREFIX ACTUAL_PARAMETER_PART + + -- ACTUAL_PARAMETER_PART ::= + -- (PARAMETER_ASSOCIATION {,PARAMETER_ASSOCIATION}) + + -- PARAMETER_ASSOCIATION ::= + -- [formal_parameter_SELECTOR_NAME =>] EXPLICIT_ACTUAL_PARAMETER + + -- EXPLICIT_ACTUAL_PARAMETER ::= EXPRESSION | variable_NAME + + -- Note: syntactically a procedure call looks just like a function call, + -- so this routine is in practice used to scan out procedure calls as well. + + -- On return, Expr_Form is set to either EF_Name or EF_Simple_Name + + -- Error recovery: can raise Error_Resync + + -- Note: if on return Token = Tok_Apostrophe, then the apostrophe must be + -- followed by either a left paren (qualified expression case), or by + -- range (range attribute case). All other uses of apostrophe (i.e. all + -- other attributes) are handled in this routine. + + -- Error recovery: can raise Error_Resync + + function P_Name return Node_Id is + Scan_State : Saved_Scan_State; + Name_Node : Node_Id; + Prefix_Node : Node_Id; + Ident_Node : Node_Id; + Expr_Node : Node_Id; + Range_Node : Node_Id; + Arg_Node : Node_Id; + + Arg_List : List_Id := No_List; -- kill junk warning + Attr_Name : Name_Id := No_Name; -- kill junk warning + + begin + if Token not in Token_Class_Name then + Error_Msg_AP ("name expected"); + raise Error_Resync; + end if; + + -- Loop through designators in qualified name + + Name_Node := Token_Node; + + loop + Scan; -- past designator + exit when Token /= Tok_Dot; + Save_Scan_State (Scan_State); -- at dot + Scan; -- past dot + + -- If we do not have another designator after the dot, then join + -- the normal circuit to handle a dot extension (may be .all or + -- character literal case). Otherwise loop back to scan the next + -- designator. + + if Token not in Token_Class_Desig then + goto Scan_Name_Extension_Dot; + else + Prefix_Node := Name_Node; + Name_Node := New_Node (N_Selected_Component, Prev_Token_Ptr); + Set_Prefix (Name_Node, Prefix_Node); + Set_Selector_Name (Name_Node, Token_Node); + end if; + end loop; + + -- We have now scanned out a qualified designator. If the last token is + -- an operator symbol, then we certainly do not have the Snam case, so + -- we can just use the normal name extension check circuit + + if Prev_Token = Tok_Operator_Symbol then + goto Scan_Name_Extension; + end if; + + -- We have scanned out a qualified simple name, check for name extension + -- Note that we know there is no dot here at this stage, so the only + -- possible cases of name extension are apostrophe and left paren. + + if Token = Tok_Apostrophe then + Save_Scan_State (Scan_State); -- at apostrophe + Scan; -- past apostrophe + + -- If left paren, then this might be a qualified expression, but we + -- are only in the business of scanning out names, so return with + -- Token backed up to point to the apostrophe. The treatment for + -- the range attribute is similar (we do not consider x'range to + -- be a name in this grammar). + + if Token = Tok_Left_Paren or else Token = Tok_Range then + Restore_Scan_State (Scan_State); -- to apostrophe + Expr_Form := EF_Simple_Name; + return Name_Node; + + -- Otherwise we have the case of a name extended by an attribute + + else + goto Scan_Name_Extension_Apostrophe; + end if; + + -- Check case of qualified simple name extended by a left parenthesis + + elsif Token = Tok_Left_Paren then + Scan; -- past left paren + goto Scan_Name_Extension_Left_Paren; + + -- Otherwise the qualified simple name is not extended, so return + + else + Expr_Form := EF_Simple_Name; + return Name_Node; + end if; + + -- Loop scanning past name extensions. A label is used for control + -- transfer for this loop for ease of interfacing with the finite state + -- machine in the parenthesis scanning circuit, and also to allow for + -- passing in control to the appropriate point from the above code. + + <<Scan_Name_Extension>> + + -- Character literal used as name cannot be extended. Also this + -- cannot be a call, since the name for a call must be a designator. + -- Return in these cases, or if there is no name extension + + if Token not in Token_Class_Namext + or else Prev_Token = Tok_Char_Literal + then + Expr_Form := EF_Name; + return Name_Node; + end if; + + -- Merge here when we know there is a name extension + + <<Scan_Name_Extension_OK>> + + if Token = Tok_Left_Paren then + Scan; -- past left paren + goto Scan_Name_Extension_Left_Paren; + + elsif Token = Tok_Apostrophe then + Save_Scan_State (Scan_State); -- at apostrophe + Scan; -- past apostrophe + goto Scan_Name_Extension_Apostrophe; + + else -- Token = Tok_Dot + Save_Scan_State (Scan_State); -- at dot + Scan; -- past dot + goto Scan_Name_Extension_Dot; + end if; + + -- Case of name extended by dot (selection), dot is already skipped + -- and the scan state at the point of the dot is saved in Scan_State. + + <<Scan_Name_Extension_Dot>> + + -- Explicit dereference case + + if Token = Tok_All then + Prefix_Node := Name_Node; + Name_Node := New_Node (N_Explicit_Dereference, Token_Ptr); + Set_Prefix (Name_Node, Prefix_Node); + Scan; -- past ALL + goto Scan_Name_Extension; + + -- Selected component case + + elsif Token in Token_Class_Name then + Prefix_Node := Name_Node; + Name_Node := New_Node (N_Selected_Component, Prev_Token_Ptr); + Set_Prefix (Name_Node, Prefix_Node); + Set_Selector_Name (Name_Node, Token_Node); + Scan; -- past selector + goto Scan_Name_Extension; + + -- Reserved identifier as selector + + elsif Is_Reserved_Identifier then + Scan_Reserved_Identifier (Force_Msg => False); + Prefix_Node := Name_Node; + Name_Node := New_Node (N_Selected_Component, Prev_Token_Ptr); + Set_Prefix (Name_Node, Prefix_Node); + Set_Selector_Name (Name_Node, Token_Node); + Scan; -- past identifier used as selector + goto Scan_Name_Extension; + + -- If dot is at end of line and followed by nothing legal, + -- then assume end of name and quit (dot will be taken as + -- an erroneous form of some other punctuation by our caller). + + elsif Token_Is_At_Start_Of_Line then + Restore_Scan_State (Scan_State); + return Name_Node; + + -- Here if nothing legal after the dot + + else + Error_Msg_AP ("selector expected"); + raise Error_Resync; + end if; + + -- Here for an apostrophe as name extension. The scan position at the + -- apostrophe has already been saved, and the apostrophe scanned out. + + <<Scan_Name_Extension_Apostrophe>> + + Scan_Apostrophe : declare + function Apostrophe_Should_Be_Semicolon return Boolean; + -- Checks for case where apostrophe should probably be + -- a semicolon, and if so, gives appropriate message, + -- resets the scan pointer to the apostrophe, changes + -- the current token to Tok_Semicolon, and returns True. + -- Otherwise returns False. + + function Apostrophe_Should_Be_Semicolon return Boolean is + begin + if Token_Is_At_Start_Of_Line then + Restore_Scan_State (Scan_State); -- to apostrophe + Error_Msg_SC ("""''"" should be "";"""); + Token := Tok_Semicolon; + return True; + else + return False; + end if; + end Apostrophe_Should_Be_Semicolon; + + -- Start of processing for Scan_Apostrophe + + begin + -- If range attribute after apostrophe, then return with Token + -- pointing to the apostrophe. Note that in this case the prefix + -- need not be a simple name (cases like A.all'range). Similarly + -- if there is a left paren after the apostrophe, then we also + -- return with Token pointing to the apostrophe (this is the + -- qualified expression case). + + if Token = Tok_Range or else Token = Tok_Left_Paren then + Restore_Scan_State (Scan_State); -- to apostrophe + Expr_Form := EF_Name; + return Name_Node; + + -- Here for cases where attribute designator is an identifier + + elsif Token = Tok_Identifier then + Attr_Name := Token_Name; + + if not Is_Attribute_Name (Attr_Name) then + if Apostrophe_Should_Be_Semicolon then + Expr_Form := EF_Name; + return Name_Node; + else + Signal_Bad_Attribute; + end if; + end if; + + if Style_Check then + Style.Check_Attribute_Name (False); + end if; + + Delete_Node (Token_Node); + + -- Here for case of attribute designator is not an identifier + + else + if Token = Tok_Delta then + Attr_Name := Name_Delta; + + elsif Token = Tok_Digits then + Attr_Name := Name_Digits; + + elsif Token = Tok_Access then + Attr_Name := Name_Access; + + elsif Apostrophe_Should_Be_Semicolon then + Expr_Form := EF_Name; + return Name_Node; + + else + Error_Msg_AP ("attribute designator expected"); + raise Error_Resync; + end if; + + if Style_Check then + Style.Check_Attribute_Name (True); + end if; + end if; + + -- We come here with an OK attribute scanned, and the + -- corresponding Attribute identifier node stored in Ident_Node. + + Prefix_Node := Name_Node; + Name_Node := New_Node (N_Attribute_Reference, Prev_Token_Ptr); + Scan; -- past attribute designator + Set_Prefix (Name_Node, Prefix_Node); + Set_Attribute_Name (Name_Node, Attr_Name); + + -- Scan attribute arguments/designator + + if Token = Tok_Left_Paren then + Set_Expressions (Name_Node, New_List); + Scan; -- past left paren + + loop + declare + Expr : constant Node_Id := P_Expression; + + begin + if Token = Tok_Arrow then + Error_Msg_SC + ("named parameters not permitted for attributes"); + Scan; -- past junk arrow + + else + Append (Expr, Expressions (Name_Node)); + exit when not Comma_Present; + end if; + end; + end loop; + + T_Right_Paren; + end if; + + goto Scan_Name_Extension; + end Scan_Apostrophe; + + -- Here for left parenthesis extending name (left paren skipped) + + <<Scan_Name_Extension_Left_Paren>> + + -- We now have to scan through a list of items, terminated by a + -- right parenthesis. The scan is handled by a finite state + -- machine. The possibilities are: + + -- (discrete_range) + + -- This is a slice. This case is handled in LP_State_Init. + + -- (expression, expression, ..) + + -- This is interpreted as an indexed component, i.e. as a + -- case of a name which can be extended in the normal manner. + -- This case is handled by LP_State_Name or LP_State_Expr. + + -- (..., identifier => expression , ...) + + -- If there is at least one occurence of identifier => (but + -- none of the other cases apply), then we have a call. + + -- Test for Id => case + + if Token = Tok_Identifier then + Save_Scan_State (Scan_State); -- at Id + Scan; -- past Id + + -- Test for => (allow := as an error substitute) + + if Token = Tok_Arrow or else Token = Tok_Colon_Equal then + Restore_Scan_State (Scan_State); -- to Id + Arg_List := New_List; + goto LP_State_Call; + + else + Restore_Scan_State (Scan_State); -- to Id + end if; + end if; + + -- Here we have an expression after all + + Expr_Node := P_Expression_Or_Range_Attribute; + + -- Check cases of discrete range for a slice + + -- First possibility: Range_Attribute_Reference + + if Expr_Form = EF_Range_Attr then + Range_Node := Expr_Node; + + -- Second possibility: Simple_expression .. Simple_expression + + elsif Token = Tok_Dot_Dot then + Check_Simple_Expression (Expr_Node); + Range_Node := New_Node (N_Range, Token_Ptr); + Set_Low_Bound (Range_Node, Expr_Node); + Scan; -- past .. + Expr_Node := P_Expression; + Check_Simple_Expression (Expr_Node); + Set_High_Bound (Range_Node, Expr_Node); + + -- Third possibility: Type_name range Range + + elsif Token = Tok_Range then + if Expr_Form /= EF_Simple_Name then + Error_Msg_SC ("subtype mark must precede RANGE"); + raise Error_Resync; + end if; + + Range_Node := P_Subtype_Indication (Expr_Node); + + -- Otherwise we just have an expression. It is true that we might + -- have a subtype mark without a range constraint but this case + -- is syntactically indistinguishable from the expression case. + + else + Arg_List := New_List; + goto LP_State_Expr; + end if; + + -- Fall through here with unmistakable Discrete range scanned, + -- which means that we definitely have the case of a slice. The + -- Discrete range is in Range_Node. + + if Token = Tok_Comma then + Error_Msg_SC ("slice cannot have more than one dimension"); + raise Error_Resync; + + elsif Token /= Tok_Right_Paren then + T_Right_Paren; + raise Error_Resync; + + else + Scan; -- past right paren + Prefix_Node := Name_Node; + Name_Node := New_Node (N_Slice, Sloc (Prefix_Node)); + Set_Prefix (Name_Node, Prefix_Node); + Set_Discrete_Range (Name_Node, Range_Node); + + -- An operator node is legal as a prefix to other names, + -- but not for a slice. + + if Nkind (Prefix_Node) = N_Operator_Symbol then + Error_Msg_N ("illegal prefix for slice", Prefix_Node); + end if; + + -- If we have a name extension, go scan it + + if Token in Token_Class_Namext then + goto Scan_Name_Extension_OK; + + -- Otherwise return (a slice is a name, but is not a call) + + else + Expr_Form := EF_Name; + return Name_Node; + end if; + end if; + + -- In LP_State_Expr, we have scanned one or more expressions, and + -- so we have a call or an indexed component which is a name. On + -- entry we have the expression just scanned in Expr_Node and + -- Arg_List contains the list of expressions encountered so far + + <<LP_State_Expr>> + Append (Expr_Node, Arg_List); + + if Token = Tok_Arrow then + Error_Msg + ("expect identifier in parameter association", + Sloc (Expr_Node)); + Scan; -- past arrow. + + elsif not Comma_Present then + T_Right_Paren; + Prefix_Node := Name_Node; + Name_Node := New_Node (N_Indexed_Component, Sloc (Prefix_Node)); + Set_Prefix (Name_Node, Prefix_Node); + Set_Expressions (Name_Node, Arg_List); + goto Scan_Name_Extension; + end if; + + -- Comma present (and scanned out), test for identifier => case + -- Test for identifer => case + + if Token = Tok_Identifier then + Save_Scan_State (Scan_State); -- at Id + Scan; -- past Id + + -- Test for => (allow := as error substitute) + + if Token = Tok_Arrow or else Token = Tok_Colon_Equal then + Restore_Scan_State (Scan_State); -- to Id + goto LP_State_Call; + + -- Otherwise it's just an expression after all, so backup + + else + Restore_Scan_State (Scan_State); -- to Id + end if; + end if; + + -- Here we have an expression after all, so stay in this state + + Expr_Node := P_Expression; + goto LP_State_Expr; + + -- LP_State_Call corresponds to the situation in which at least + -- one instance of Id => Expression has been encountered, so we + -- know that we do not have a name, but rather a call. We enter + -- it with the scan pointer pointing to the next argument to scan, + -- and Arg_List containing the list of arguments scanned so far. + + <<LP_State_Call>> + + -- Test for case of Id => Expression (named parameter) + + if Token = Tok_Identifier then + Save_Scan_State (Scan_State); -- at Id + Ident_Node := Token_Node; + Scan; -- past Id + + -- Deal with => (allow := as erroneous substitute) + + if Token = Tok_Arrow or else Token = Tok_Colon_Equal then + Arg_Node := + New_Node (N_Parameter_Association, Prev_Token_Ptr); + Set_Selector_Name (Arg_Node, Ident_Node); + T_Arrow; + Set_Explicit_Actual_Parameter (Arg_Node, P_Expression); + Append (Arg_Node, Arg_List); + + -- If a comma follows, go back and scan next entry + + if Comma_Present then + goto LP_State_Call; + + -- Otherwise we have the end of a call + + else + Prefix_Node := Name_Node; + Name_Node := + New_Node (N_Function_Call, Sloc (Prefix_Node)); + Set_Name (Name_Node, Prefix_Node); + Set_Parameter_Associations (Name_Node, Arg_List); + T_Right_Paren; + + if Token in Token_Class_Namext then + goto Scan_Name_Extension_OK; + + -- This is a case of a call which cannot be a name + + else + Expr_Form := EF_Name; + return Name_Node; + end if; + end if; + + -- Not named parameter: Id started an expression after all + + else + Restore_Scan_State (Scan_State); -- to Id + end if; + end if; + + -- Here if entry did not start with Id => which means that it + -- is a positional parameter, which is not allowed, since we + -- have seen at least one named parameter already. + + Error_Msg_SC + ("positional parameter association " & + "not allowed after named one"); + + Expr_Node := P_Expression; + + -- Leaving the '>' in an association is not unusual, so suggest + -- a possible fix. + + if Nkind (Expr_Node) = N_Op_Eq then + Error_Msg_N ("\maybe `=>` was intended", Expr_Node); + end if; + + -- We go back to scanning out expressions, so that we do not get + -- multiple error messages when several positional parameters + -- follow a named parameter. + + goto LP_State_Expr; + + -- End of treatment for name extensions starting with left paren + + -- End of loop through name extensions + + end P_Name; + + -- This function parses a restricted form of Names which are either + -- designators, or designators preceded by a sequence of prefixes + -- that are direct names. + + -- Error recovery: cannot raise Error_Resync + + function P_Function_Name return Node_Id is + Designator_Node : Node_Id; + Prefix_Node : Node_Id; + Selector_Node : Node_Id; + Dot_Sloc : Source_Ptr := No_Location; + + begin + -- Prefix_Node is set to the gathered prefix so far, Empty means that + -- no prefix has been scanned. This allows us to build up the result + -- in the required right recursive manner. + + Prefix_Node := Empty; + + -- Loop through prefixes + + loop + Designator_Node := Token_Node; + + if Token not in Token_Class_Desig then + return P_Identifier; -- let P_Identifier issue the error message + + else -- Token in Token_Class_Desig + Scan; -- past designator + exit when Token /= Tok_Dot; + end if; + + -- Here at a dot, with token just before it in Designator_Node + + if No (Prefix_Node) then + Prefix_Node := Designator_Node; + else + Selector_Node := New_Node (N_Selected_Component, Dot_Sloc); + Set_Prefix (Selector_Node, Prefix_Node); + Set_Selector_Name (Selector_Node, Designator_Node); + Prefix_Node := Selector_Node; + end if; + + Dot_Sloc := Token_Ptr; + Scan; -- past dot + end loop; + + -- Fall out of the loop having just scanned a designator + + if No (Prefix_Node) then + return Designator_Node; + else + Selector_Node := New_Node (N_Selected_Component, Dot_Sloc); + Set_Prefix (Selector_Node, Prefix_Node); + Set_Selector_Name (Selector_Node, Designator_Node); + return Selector_Node; + end if; + + exception + when Error_Resync => + return Error; + + end P_Function_Name; + + -- This function parses a restricted form of Names which are either + -- identifiers, or identifiers preceded by a sequence of prefixes + -- that are direct names. + + -- Error recovery: cannot raise Error_Resync + + function P_Qualified_Simple_Name return Node_Id is + Designator_Node : Node_Id; + Prefix_Node : Node_Id; + Selector_Node : Node_Id; + Dot_Sloc : Source_Ptr := No_Location; + + begin + -- Prefix node is set to the gathered prefix so far, Empty means that + -- no prefix has been scanned. This allows us to build up the result + -- in the required right recursive manner. + + Prefix_Node := Empty; + + -- Loop through prefixes + + loop + Designator_Node := Token_Node; + + if Token = Tok_Identifier then + Scan; -- past identifier + exit when Token /= Tok_Dot; + + elsif Token not in Token_Class_Desig then + return P_Identifier; -- let P_Identifier issue the error message + + else + Scan; -- past designator + + if Token /= Tok_Dot then + Error_Msg_SP ("identifier expected"); + return Error; + end if; + end if; + + -- Here at a dot, with token just before it in Designator_Node + + if No (Prefix_Node) then + Prefix_Node := Designator_Node; + else + Selector_Node := New_Node (N_Selected_Component, Dot_Sloc); + Set_Prefix (Selector_Node, Prefix_Node); + Set_Selector_Name (Selector_Node, Designator_Node); + Prefix_Node := Selector_Node; + end if; + + Dot_Sloc := Token_Ptr; + Scan; -- past dot + end loop; + + -- Fall out of the loop having just scanned an identifier + + if No (Prefix_Node) then + return Designator_Node; + else + Selector_Node := New_Node (N_Selected_Component, Dot_Sloc); + Set_Prefix (Selector_Node, Prefix_Node); + Set_Selector_Name (Selector_Node, Designator_Node); + return Selector_Node; + end if; + + exception + when Error_Resync => + return Error; + + end P_Qualified_Simple_Name; + + -- This procedure differs from P_Qualified_Simple_Name only in that it + -- raises Error_Resync if any error is encountered. It only returns after + -- scanning a valid qualified simple name. + + -- Error recovery: can raise Error_Resync + + function P_Qualified_Simple_Name_Resync return Node_Id is + Designator_Node : Node_Id; + Prefix_Node : Node_Id; + Selector_Node : Node_Id; + Dot_Sloc : Source_Ptr := No_Location; + + begin + Prefix_Node := Empty; + + -- Loop through prefixes + + loop + Designator_Node := Token_Node; + + if Token = Tok_Identifier then + Scan; -- past identifier + exit when Token /= Tok_Dot; + + elsif Token not in Token_Class_Desig then + Discard_Junk_Node (P_Identifier); -- to issue the error message + raise Error_Resync; + + else + Scan; -- past designator + + if Token /= Tok_Dot then + Error_Msg_SP ("identifier expected"); + raise Error_Resync; + end if; + end if; + + -- Here at a dot, with token just before it in Designator_Node + + if No (Prefix_Node) then + Prefix_Node := Designator_Node; + else + Selector_Node := New_Node (N_Selected_Component, Dot_Sloc); + Set_Prefix (Selector_Node, Prefix_Node); + Set_Selector_Name (Selector_Node, Designator_Node); + Prefix_Node := Selector_Node; + end if; + + Dot_Sloc := Token_Ptr; + Scan; -- past period + end loop; + + -- Fall out of the loop having just scanned an identifier + + if No (Prefix_Node) then + return Designator_Node; + else + Selector_Node := New_Node (N_Selected_Component, Dot_Sloc); + Set_Prefix (Selector_Node, Prefix_Node); + Set_Selector_Name (Selector_Node, Designator_Node); + return Selector_Node; + end if; + + end P_Qualified_Simple_Name_Resync; + + ---------------------- + -- 4.1 Direct_Name -- + ---------------------- + + -- Parsed by P_Name and other functions in section 4.1 + + ----------------- + -- 4.1 Prefix -- + ----------------- + + -- Parsed by P_Name (4.1) + + ------------------------------- + -- 4.1 Explicit Dereference -- + ------------------------------- + + -- Parsed by P_Name (4.1) + + ------------------------------- + -- 4.1 Implicit_Dereference -- + ------------------------------- + + -- Parsed by P_Name (4.1) + + ---------------------------- + -- 4.1 Indexed Component -- + ---------------------------- + + -- Parsed by P_Name (4.1) + + ---------------- + -- 4.1 Slice -- + ---------------- + + -- Parsed by P_Name (4.1) + + ----------------------------- + -- 4.1 Selected_Component -- + ----------------------------- + + -- Parsed by P_Name (4.1) + + ------------------------ + -- 4.1 Selector Name -- + ------------------------ + + -- Parsed by P_Name (4.1) + + ------------------------------ + -- 4.1 Attribute Reference -- + ------------------------------ + + -- Parsed by P_Name (4.1) + + ------------------------------- + -- 4.1 Attribute Designator -- + ------------------------------- + + -- Parsed by P_Name (4.1) + + -------------------------------------- + -- 4.1.4 Range Attribute Reference -- + -------------------------------------- + + -- RANGE_ATTRIBUTE_REFERENCE ::= PREFIX ' RANGE_ATTRIBUTE_DESIGNATOR + + -- RANGE_ATTRIBUTE_DESIGNATOR ::= range [(static_EXPRESSION)] + + -- In the grammar, a RANGE attribute is simply a name, but its use is + -- highly restricted, so in the parser, we do not regard it as a name. + -- Instead, P_Name returns without scanning the 'RANGE part of the + -- attribute, and the caller uses the following function to construct + -- a range attribute in places where it is appropriate. + + -- Note that RANGE here is treated essentially as an identifier, + -- rather than a reserved word. + + -- The caller has parsed the prefix, i.e. a name, and Token points to + -- the apostrophe. The token after the apostrophe is known to be RANGE + -- at this point. The prefix node becomes the prefix of the attribute. + + -- Error_Recovery: Cannot raise Error_Resync + + function P_Range_Attribute_Reference + (Prefix_Node : Node_Id) + return Node_Id + is + Attr_Node : Node_Id; + + begin + Attr_Node := New_Node (N_Attribute_Reference, Token_Ptr); + Set_Prefix (Attr_Node, Prefix_Node); + Scan; -- past apostrophe + + if Style_Check then + Style.Check_Attribute_Name (True); + end if; + + Set_Attribute_Name (Attr_Node, Name_Range); + Scan; -- past RANGE + + if Token = Tok_Left_Paren then + Scan; -- past left paren + Set_Expressions (Attr_Node, New_List (P_Expression)); + T_Right_Paren; + end if; + + return Attr_Node; + end P_Range_Attribute_Reference; + + --------------------------------------- + -- 4.1.4 Range Attribute Designator -- + --------------------------------------- + + -- Parsed by P_Range_Attribute_Reference (4.4) + + -------------------- + -- 4.3 Aggregate -- + -------------------- + + -- AGGREGATE ::= RECORD_AGGREGATE | EXTENSION_AGGREGATE | ARRAY_AGGREGATE + + -- Parsed by P_Aggregate_Or_Paren_Expr (4.3), except in the case where + -- an aggregate is known to be required (code statement, extension + -- aggregate), in which cases this routine performs the necessary check + -- that we have an aggregate rather than a parenthesized expression + + -- Error recovery: can raise Error_Resync + + function P_Aggregate return Node_Id is + Aggr_Sloc : constant Source_Ptr := Token_Ptr; + Aggr_Node : constant Node_Id := P_Aggregate_Or_Paren_Expr; + + begin + if Nkind (Aggr_Node) /= N_Aggregate + and then + Nkind (Aggr_Node) /= N_Extension_Aggregate + then + Error_Msg + ("aggregate may not have single positional component", Aggr_Sloc); + return Error; + else + return Aggr_Node; + end if; + end P_Aggregate; + + ------------------------------------------------- + -- 4.3 Aggregate or Parenthesized Expresssion -- + ------------------------------------------------- + + -- This procedure parses out either an aggregate or a parenthesized + -- expression (these two constructs are closely related, since a + -- parenthesized expression looks like an aggregate with a single + -- positional component). + + -- AGGREGATE ::= + -- RECORD_AGGREGATE | EXTENSION_AGGREGATE | ARRAY_AGGREGATE + + -- RECORD_AGGREGATE ::= (RECORD_COMPONENT_ASSOCIATION_LIST) + + -- RECORD_COMPONENT_ASSOCIATION_LIST ::= + -- RECORD_COMPONENT_ASSOCIATION {, RECORD_COMPONENT_ASSOCIATION} + -- | null record + + -- RECORD_COMPONENT_ASSOCIATION ::= + -- [COMPONENT_CHOICE_LIST =>] EXPRESSION + + -- COMPONENT_CHOICE_LIST ::= + -- component_SELECTOR_NAME {| component_SELECTOR_NAME} + -- | others + + -- EXTENSION_AGGREGATE ::= + -- (ANCESTOR_PART with RECORD_COMPONENT_ASSOCIATION_LIST) + + -- ANCESTOR_PART ::= EXPRESSION | SUBTYPE_MARK + + -- ARRAY_AGGREGATE ::= + -- POSITIONAL_ARRAY_AGGREGATE | NAMED_ARRAY_AGGREGATE + + -- POSITIONAL_ARRAY_AGGREGATE ::= + -- (EXPRESSION, EXPRESSION {, EXPRESSION}) + -- | (EXPRESSION {, EXPRESSION}, others => EXPRESSION) + + -- NAMED_ARRAY_AGGREGATE ::= + -- (ARRAY_COMPONENT_ASSOCIATION {, ARRAY_COMPONENT_ASSOCIATION}) + + -- PRIMARY ::= (EXPRESSION); + + -- Error recovery: can raise Error_Resync + + function P_Aggregate_Or_Paren_Expr return Node_Id is + Aggregate_Node : Node_Id; + Expr_List : List_Id; + Assoc_List : List_Id; + Expr_Node : Node_Id; + Lparen_Sloc : Source_Ptr; + Scan_State : Saved_Scan_State; + + begin + Lparen_Sloc := Token_Ptr; + T_Left_Paren; + + -- Note: the mechanism used here of rescanning the initial expression + -- is distinctly unpleasant, but it saves a lot of fiddling in scanning + -- out the discrete choice list. + + -- Deal with expression and extension aggregate cases first + + if Token /= Tok_Others then + Save_Scan_State (Scan_State); -- at start of expression + + -- Deal with (NULL RECORD) case + + if Token = Tok_Null then + Scan; -- past NULL + + if Token = Tok_Record then + Aggregate_Node := New_Node (N_Aggregate, Lparen_Sloc); + Set_Null_Record_Present (Aggregate_Node, True); + Scan; -- past RECORD + T_Right_Paren; + return Aggregate_Node; + else + Restore_Scan_State (Scan_State); -- to NULL that must be expr + end if; + end if; + + Expr_Node := P_Expression_Or_Range_Attribute; + + -- Extension aggregate case + + if Token = Tok_With then + + if Nkind (Expr_Node) = N_Attribute_Reference + and then Attribute_Name (Expr_Node) = Name_Range + then + Bad_Range_Attribute (Sloc (Expr_Node)); + return Error; + end if; + + if Ada_83 then + Error_Msg_SC ("(Ada 83) extension aggregate not allowed"); + end if; + + Aggregate_Node := New_Node (N_Extension_Aggregate, Lparen_Sloc); + Set_Ancestor_Part (Aggregate_Node, Expr_Node); + Scan; -- past WITH + + -- Deal with WITH NULL RECORD case + + if Token = Tok_Null then + Save_Scan_State (Scan_State); -- at NULL + Scan; -- past NULL + + if Token = Tok_Record then + Scan; -- past RECORD + Set_Null_Record_Present (Aggregate_Node, True); + T_Right_Paren; + return Aggregate_Node; + + else + Restore_Scan_State (Scan_State); -- to NULL that must be expr + end if; + end if; + + if Token /= Tok_Others then + Save_Scan_State (Scan_State); + Expr_Node := P_Expression; + else + Expr_Node := Empty; + end if; + + -- Expression case + + elsif Token = Tok_Right_Paren or else Token in Token_Class_Eterm then + + if Nkind (Expr_Node) = N_Attribute_Reference + and then Attribute_Name (Expr_Node) = Name_Range + then + Bad_Range_Attribute (Sloc (Expr_Node)); + return Error; + end if; + + -- Bump paren count of expression, note that if the paren count + -- is already at the maximum, then we leave it alone. This will + -- cause some failures in pathalogical conformance tests, which + -- we do not shed a tear over! + + if Expr_Node /= Error then + if Paren_Count (Expr_Node) /= Paren_Count_Type'Last then + Set_Paren_Count (Expr_Node, Paren_Count (Expr_Node) + 1); + end if; + end if; + + T_Right_Paren; -- past right paren (error message if none) + return Expr_Node; + + -- Normal aggregate case + + else + Aggregate_Node := New_Node (N_Aggregate, Lparen_Sloc); + end if; + + -- Others case + + else + Aggregate_Node := New_Node (N_Aggregate, Lparen_Sloc); + Expr_Node := Empty; + end if; + + -- Prepare to scan list of component associations + + Expr_List := No_List; -- don't set yet, maybe all named entries + Assoc_List := No_List; -- don't set yet, maybe all positional entries + + -- This loop scans through component associations. On entry to the + -- loop, an expression has been scanned at the start of the current + -- association unless initial token was OTHERS, in which case + -- Expr_Node is set to Empty. + + loop + -- Deal with others association first. This is a named association + + if No (Expr_Node) then + if No (Assoc_List) then + Assoc_List := New_List; + end if; + + Append (P_Record_Or_Array_Component_Association, Assoc_List); + + -- Improper use of WITH + + elsif Token = Tok_With then + Error_Msg_SC ("WITH must be preceded by single expression in " & + "extension aggregate"); + raise Error_Resync; + + -- Assume positional case if comma, right paren, or literal or + -- identifier or OTHERS follows (the latter cases are missing + -- comma cases). Also assume positional if a semicolon follows, + -- which can happen if there are missing parens + + elsif Token = Tok_Comma + or else Token = Tok_Right_Paren + or else Token = Tok_Others + or else Token in Token_Class_Lit_Or_Name + or else Token = Tok_Semicolon + then + if Present (Assoc_List) then + Error_Msg_BC + ("""=>"" expected (positional association cannot follow " & + "named association)"); + end if; + + if No (Expr_List) then + Expr_List := New_List; + end if; + + Append (Expr_Node, Expr_List); + + -- Anything else is assumed to be a named association + + else + Restore_Scan_State (Scan_State); -- to start of expression + + if No (Assoc_List) then + Assoc_List := New_List; + end if; + + Append (P_Record_Or_Array_Component_Association, Assoc_List); + end if; + + exit when not Comma_Present; + + -- If we are at an expression terminator, something is seriously + -- wrong, so let's get out now, before we start eating up stuff + -- that doesn't belong to us! + + if Token in Token_Class_Eterm then + Error_Msg_AP ("expecting expression or component association"); + exit; + end if; + + -- Otherwise initiate for reentry to top of loop by scanning an + -- initial expression, unless the first token is OTHERS. + + if Token = Tok_Others then + Expr_Node := Empty; + else + Save_Scan_State (Scan_State); -- at start of expression + Expr_Node := P_Expression; + end if; + end loop; + + -- All component associations (positional and named) have been scanned + + T_Right_Paren; + Set_Expressions (Aggregate_Node, Expr_List); + Set_Component_Associations (Aggregate_Node, Assoc_List); + return Aggregate_Node; + end P_Aggregate_Or_Paren_Expr; + + ------------------------------------------------ + -- 4.3 Record or Array Component Association -- + ------------------------------------------------ + + -- RECORD_COMPONENT_ASSOCIATION ::= + -- [COMPONENT_CHOICE_LIST =>] EXPRESSION + + -- COMPONENT_CHOICE_LIST => + -- component_SELECTOR_NAME {| component_SELECTOR_NAME} + -- | others + + -- ARRAY_COMPONENT_ASSOCIATION ::= + -- DISCRETE_CHOICE_LIST => EXPRESSION + + -- Note: this routine only handles the named cases, including others. + -- Cases where the component choice list is not present have already + -- been handled directly. + + -- Error recovery: can raise Error_Resync + + function P_Record_Or_Array_Component_Association return Node_Id is + Assoc_Node : Node_Id; + + begin + Assoc_Node := New_Node (N_Component_Association, Token_Ptr); + Set_Choices (Assoc_Node, P_Discrete_Choice_List); + Set_Sloc (Assoc_Node, Token_Ptr); + TF_Arrow; + Set_Expression (Assoc_Node, P_Expression); + return Assoc_Node; + end P_Record_Or_Array_Component_Association; + + ----------------------------- + -- 4.3.1 Record Aggregate -- + ----------------------------- + + -- Case of enumeration aggregate is parsed by P_Aggregate (4.3) + -- All other cases are parsed by P_Aggregate_Or_Paren_Expr (4.3) + + ---------------------------------------------- + -- 4.3.1 Record Component Association List -- + ---------------------------------------------- + + -- Parsed by P_Aggregate_Or_Paren_Expr (4.3) + + ---------------------------------- + -- 4.3.1 Component Choice List -- + ---------------------------------- + + -- Parsed by P_Aggregate_Or_Paren_Expr (4.3) + + -------------------------------- + -- 4.3.1 Extension Aggregate -- + -------------------------------- + + -- Parsed by P_Aggregate_Or_Paren_Expr (4.3) + + -------------------------- + -- 4.3.1 Ancestor Part -- + -------------------------- + + -- Parsed by P_Aggregate_Or_Paren_Expr (4.3) + + ---------------------------- + -- 4.3.1 Array Aggregate -- + ---------------------------- + + -- Parsed by P_Aggregate_Or_Paren_Expr (4.3) + + --------------------------------------- + -- 4.3.1 Positional Array Aggregate -- + --------------------------------------- + + -- Parsed by P_Aggregate_Or_Paren_Expr (4.3) + + ---------------------------------- + -- 4.3.1 Named Array Aggregate -- + ---------------------------------- + + -- Parsed by P_Aggregate_Or_Paren_Expr (4.3) + + ---------------------------------------- + -- 4.3.1 Array Component Association -- + ---------------------------------------- + + -- Parsed by P_Aggregate_Or_Paren_Expr (4.3) + + --------------------- + -- 4.4 Expression -- + --------------------- + + -- EXPRESSION ::= + -- RELATION {and RELATION} | RELATION {and then RELATION} + -- | RELATION {or RELATION} | RELATION {or else RELATION} + -- | RELATION {xor RELATION} + + -- On return, Expr_Form indicates the categorization of the expression + -- EF_Range_Attr is not a possible value (if a range attribute is found, + -- an error message is given, and Error is returned). + + -- Error recovery: cannot raise Error_Resync + + function P_Expression return Node_Id is + Logical_Op : Node_Kind; + Prev_Logical_Op : Node_Kind; + Op_Location : Source_Ptr; + Node1 : Node_Id; + Node2 : Node_Id; + + begin + Node1 := P_Relation; + + if Token in Token_Class_Logop then + Prev_Logical_Op := N_Empty; + + loop + Op_Location := Token_Ptr; + Logical_Op := P_Logical_Operator; + + if Prev_Logical_Op /= N_Empty and then + Logical_Op /= Prev_Logical_Op + then + Error_Msg + ("mixed logical operators in expression", Op_Location); + Prev_Logical_Op := N_Empty; + else + Prev_Logical_Op := Logical_Op; + end if; + + Node2 := Node1; + Node1 := New_Node (Logical_Op, Op_Location); + Set_Left_Opnd (Node1, Node2); + Set_Right_Opnd (Node1, P_Relation); + Set_Op_Name (Node1); + exit when Token not in Token_Class_Logop; + end loop; + + Expr_Form := EF_Non_Simple; + end if; + + if Token = Tok_Apostrophe then + Bad_Range_Attribute (Token_Ptr); + return Error; + else + return Node1; + end if; + + end P_Expression; + + -- This function is identical to the normal P_Expression, except that it + -- checks that the expression scan did not stop on a right paren. It is + -- called in all contexts where a right parenthesis cannot legitimately + -- follow an expression. + + function P_Expression_No_Right_Paren return Node_Id is + begin + return No_Right_Paren (P_Expression); + end P_Expression_No_Right_Paren; + + ---------------------------------------- + -- 4.4 Expression_Or_Range_Attribute -- + ---------------------------------------- + + -- EXPRESSION ::= + -- RELATION {and RELATION} | RELATION {and then RELATION} + -- | RELATION {or RELATION} | RELATION {or else RELATION} + -- | RELATION {xor RELATION} + + -- RANGE_ATTRIBUTE_REFERENCE ::= PREFIX ' RANGE_ATTRIBUTE_DESIGNATOR + + -- RANGE_ATTRIBUTE_DESIGNATOR ::= range [(static_EXPRESSION)] + + -- On return, Expr_Form indicates the categorization of the expression + -- and EF_Range_Attr is one of the possibilities. + + -- Error recovery: cannot raise Error_Resync + + -- In the grammar, a RANGE attribute is simply a name, but its use is + -- highly restricted, so in the parser, we do not regard it as a name. + -- Instead, P_Name returns without scanning the 'RANGE part of the + -- attribute, and P_Expression_Or_Range_Attribute handles the range + -- attribute reference. In the normal case where a range attribute is + -- not allowed, an error message is issued by P_Expression. + + function P_Expression_Or_Range_Attribute return Node_Id is + Logical_Op : Node_Kind; + Prev_Logical_Op : Node_Kind; + Op_Location : Source_Ptr; + Node1 : Node_Id; + Node2 : Node_Id; + Attr_Node : Node_Id; + + begin + Node1 := P_Relation; + + if Token = Tok_Apostrophe then + Attr_Node := P_Range_Attribute_Reference (Node1); + Expr_Form := EF_Range_Attr; + return Attr_Node; + + elsif Token in Token_Class_Logop then + Prev_Logical_Op := N_Empty; + + loop + Op_Location := Token_Ptr; + Logical_Op := P_Logical_Operator; + + if Prev_Logical_Op /= N_Empty and then + Logical_Op /= Prev_Logical_Op + then + Error_Msg + ("mixed logical operators in expression", Op_Location); + Prev_Logical_Op := N_Empty; + else + Prev_Logical_Op := Logical_Op; + end if; + + Node2 := Node1; + Node1 := New_Node (Logical_Op, Op_Location); + Set_Left_Opnd (Node1, Node2); + Set_Right_Opnd (Node1, P_Relation); + Set_Op_Name (Node1); + exit when Token not in Token_Class_Logop; + end loop; + + Expr_Form := EF_Non_Simple; + end if; + + if Token = Tok_Apostrophe then + Bad_Range_Attribute (Token_Ptr); + return Error; + else + return Node1; + end if; + end P_Expression_Or_Range_Attribute; + + ------------------- + -- 4.4 Relation -- + ------------------- + + -- RELATION ::= + -- SIMPLE_EXPRESSION [RELATIONAL_OPERATOR SIMPLE_EXPRESSION] + -- | SIMPLE_EXPRESSION [not] in RANGE + -- | SIMPLE_EXPRESSION [not] in SUBTYPE_MARK + + -- On return, Expr_Form indicates the categorization of the expression + + -- Note: if Token = Tok_Apostrophe on return, then Expr_Form is set to + -- EF_Simple_Name and the following token is RANGE (range attribute case). + + -- Error recovery: cannot raise Error_Resync. If an error occurs within an + -- expression, then tokens are scanned until either a non-expression token, + -- a right paren (not matched by a left paren) or a comma, is encountered. + + function P_Relation return Node_Id is + Node1, Node2 : Node_Id; + Optok : Source_Ptr; + + begin + Node1 := P_Simple_Expression; + + if Token not in Token_Class_Relop then + return Node1; + + else + -- Here we have a relational operator following. If so then scan it + -- out. Note that the assignment symbol := is treated as a relational + -- operator to improve the error recovery when it is misused for =. + -- P_Relational_Operator also parses the IN and NOT IN operations. + + Optok := Token_Ptr; + Node2 := New_Node (P_Relational_Operator, Optok); + Set_Left_Opnd (Node2, Node1); + Set_Op_Name (Node2); + + -- Case of IN or NOT IN + + if Prev_Token = Tok_In then + Set_Right_Opnd (Node2, P_Range_Or_Subtype_Mark); + + -- Case of relational operator (= /= < <= > >=) + + else + Set_Right_Opnd (Node2, P_Simple_Expression); + end if; + + Expr_Form := EF_Non_Simple; + + if Token in Token_Class_Relop then + Error_Msg_SC ("unexpected relational operator"); + raise Error_Resync; + end if; + + return Node2; + end if; + + -- If any error occurs, then scan to the next expression terminator symbol + -- or comma or right paren at the outer (i.e. current) parentheses level. + -- The flags are set to indicate a normal simple expression. + + exception + when Error_Resync => + Resync_Expression; + Expr_Form := EF_Simple; + return Error; + end P_Relation; + + ---------------------------- + -- 4.4 Simple Expression -- + ---------------------------- + + -- SIMPLE_EXPRESSION ::= + -- [UNARY_ADDING_OPERATOR] TERM {BINARY_ADDING_OPERATOR TERM} + + -- On return, Expr_Form indicates the categorization of the expression + + -- Note: if Token = Tok_Apostrophe on return, then Expr_Form is set to + -- EF_Simple_Name and the following token is RANGE (range attribute case). + + -- Error recovery: cannot raise Error_Resync. If an error occurs within an + -- expression, then tokens are scanned until either a non-expression token, + -- a right paren (not matched by a left paren) or a comma, is encountered. + + -- Note: P_Simple_Expression is called only internally by higher level + -- expression routines. In cases in the grammar where a simple expression + -- is required, the approach is to scan an expression, and then post an + -- appropriate error message if the expression obtained is not simple. This + -- gives better error recovery and treatment. + + function P_Simple_Expression return Node_Id is + Scan_State : Saved_Scan_State; + Node1 : Node_Id; + Node2 : Node_Id; + Tokptr : Source_Ptr; + + begin + -- Check for cases starting with a name. There are two reasons for + -- special casing. First speed things up by catching a common case + -- without going through several routine layers. Second the caller must + -- be informed via Expr_Form when the simple expression is a name. + + if Token in Token_Class_Name then + Node1 := P_Name; + + -- Deal with apostrophe cases + + if Token = Tok_Apostrophe then + Save_Scan_State (Scan_State); -- at apostrophe + Scan; -- past apostrophe + + -- If qualified expression, scan it out and fall through + + if Token = Tok_Left_Paren then + Node1 := P_Qualified_Expression (Node1); + Expr_Form := EF_Simple; + + -- If range attribute, then we return with Token pointing to the + -- apostrophe. Note: avoid the normal error check on exit. We + -- know that the expression really is complete in this case! + + else -- Token = Tok_Range then + Restore_Scan_State (Scan_State); -- to apostrophe + Expr_Form := EF_Simple_Name; + return Node1; + end if; + end if; + + -- If an expression terminator follows, the previous processing + -- completely scanned out the expression (a common case), and + -- left Expr_Form set appropriately for returning to our caller. + + if Token in Token_Class_Sterm then + null; + + -- If we do not have an expression terminator, then complete the + -- scan of a simple expression. This code duplicates the code + -- found in P_Term and P_Factor. + + else + if Token = Tok_Double_Asterisk then + if Style_Check then Style.Check_Exponentiation_Operator; end if; + Node2 := New_Node (N_Op_Expon, Token_Ptr); + Scan; -- past ** + Set_Left_Opnd (Node2, Node1); + Set_Right_Opnd (Node2, P_Primary); + Set_Op_Name (Node2); + Node1 := Node2; + end if; + + loop + exit when Token not in Token_Class_Mulop; + Tokptr := Token_Ptr; + Node2 := New_Node (P_Multiplying_Operator, Tokptr); + if Style_Check then Style.Check_Binary_Operator; end if; + Scan; -- past operator + Set_Left_Opnd (Node2, Node1); + Set_Right_Opnd (Node2, P_Factor); + Set_Op_Name (Node2); + Node1 := Node2; + end loop; + + loop + exit when Token not in Token_Class_Binary_Addop; + Tokptr := Token_Ptr; + Node2 := New_Node (P_Binary_Adding_Operator, Tokptr); + if Style_Check then Style.Check_Binary_Operator; end if; + Scan; -- past operator + Set_Left_Opnd (Node2, Node1); + Set_Right_Opnd (Node2, P_Term); + Set_Op_Name (Node2); + Node1 := Node2; + end loop; + + Expr_Form := EF_Simple; + end if; + + -- Cases where simple expression does not start with a name + + else + -- Scan initial sign and initial Term + + if Token in Token_Class_Unary_Addop then + Tokptr := Token_Ptr; + Node1 := New_Node (P_Unary_Adding_Operator, Tokptr); + if Style_Check then Style.Check_Unary_Plus_Or_Minus; end if; + Scan; -- past operator + Set_Right_Opnd (Node1, P_Term); + Set_Op_Name (Node1); + else + Node1 := P_Term; + end if; + + -- Scan out sequence of terms separated by binary adding operators + + loop + exit when Token not in Token_Class_Binary_Addop; + Tokptr := Token_Ptr; + Node2 := New_Node (P_Binary_Adding_Operator, Tokptr); + Scan; -- past operator + Set_Left_Opnd (Node2, Node1); + Set_Right_Opnd (Node2, P_Term); + Set_Op_Name (Node2); + Node1 := Node2; + end loop; + + -- All done, we clearly do not have name or numeric literal so this + -- is a case of a simple expression which is some other possibility. + + Expr_Form := EF_Simple; + end if; + + -- Come here at end of simple expression, where we do a couple of + -- special checks to improve error recovery. + + -- Special test to improve error recovery. If the current token + -- is a period, then someone is trying to do selection on something + -- that is not a name, e.g. a qualified expression. + + if Token = Tok_Dot then + Error_Msg_SC ("prefix for selection is not a name"); + raise Error_Resync; + end if; + + -- Special test to improve error recovery: If the current token is + -- not the first token on a line (as determined by checking the + -- previous token position with the start of the current line), + -- then we insist that we have an appropriate terminating token. + -- Consider the following two examples: + + -- 1) if A nad B then ... + + -- 2) A := B + -- C := D + + -- In the first example, we would like to issue a binary operator + -- expected message and resynchronize to the then. In the second + -- example, we do not want to issue a binary operator message, so + -- that instead we will get the missing semicolon message. This + -- distinction is of course a heuristic which does not always work, + -- but in practice it is quite effective. + + -- Note: the one case in which we do not go through this circuit is + -- when we have scanned a range attribute and want to return with + -- Token pointing to the apostrophe. The apostrophe is not normally + -- an expression terminator, and is not in Token_Class_Sterm, but + -- in this special case we know that the expression is complete. + + if not Token_Is_At_Start_Of_Line + and then Token not in Token_Class_Sterm + then + Error_Msg_AP ("binary operator expected"); + raise Error_Resync; + else + return Node1; + end if; + + -- If any error occurs, then scan to next expression terminator symbol + -- or comma, right paren or vertical bar at the outer (i.e. current) paren + -- level. Expr_Form is set to indicate a normal simple expression. + + exception + when Error_Resync => + Resync_Expression; + Expr_Form := EF_Simple; + return Error; + + end P_Simple_Expression; + + ----------------------------------------------- + -- 4.4 Simple Expression or Range Attribute -- + ----------------------------------------------- + + -- SIMPLE_EXPRESSION ::= + -- [UNARY_ADDING_OPERATOR] TERM {BINARY_ADDING_OPERATOR TERM} + + -- RANGE_ATTRIBUTE_REFERENCE ::= PREFIX ' RANGE_ATTRIBUTE_DESIGNATOR + + -- RANGE_ATTRIBUTE_DESIGNATOR ::= range [(static_EXPRESSION)] + + -- Error recovery: cannot raise Error_Resync + + function P_Simple_Expression_Or_Range_Attribute return Node_Id is + Sexpr : Node_Id; + Attr_Node : Node_Id; + + begin + Sexpr := P_Simple_Expression; + + if Token = Tok_Apostrophe then + Attr_Node := P_Range_Attribute_Reference (Sexpr); + Expr_Form := EF_Range_Attr; + return Attr_Node; + + else + return Sexpr; + end if; + end P_Simple_Expression_Or_Range_Attribute; + + --------------- + -- 4.4 Term -- + --------------- + + -- TERM ::= FACTOR {MULTIPLYING_OPERATOR FACTOR} + + -- Error recovery: can raise Error_Resync + + function P_Term return Node_Id is + Node1, Node2 : Node_Id; + Tokptr : Source_Ptr; + + begin + Node1 := P_Factor; + + loop + exit when Token not in Token_Class_Mulop; + Tokptr := Token_Ptr; + Node2 := New_Node (P_Multiplying_Operator, Tokptr); + Scan; -- past operator + Set_Left_Opnd (Node2, Node1); + Set_Right_Opnd (Node2, P_Factor); + Set_Op_Name (Node2); + Node1 := Node2; + end loop; + + return Node1; + end P_Term; + + ----------------- + -- 4.4 Factor -- + ----------------- + + -- FACTOR ::= PRIMARY [** PRIMARY] | abs PRIMARY | not PRIMARY + + -- Error recovery: can raise Error_Resync + + function P_Factor return Node_Id is + Node1 : Node_Id; + Node2 : Node_Id; + + begin + if Token = Tok_Abs then + Node1 := New_Node (N_Op_Abs, Token_Ptr); + if Style_Check then Style.Check_Abs_Not; end if; + Scan; -- past ABS + Set_Right_Opnd (Node1, P_Primary); + Set_Op_Name (Node1); + return Node1; + + elsif Token = Tok_Not then + Node1 := New_Node (N_Op_Not, Token_Ptr); + if Style_Check then Style.Check_Abs_Not; end if; + Scan; -- past NOT + Set_Right_Opnd (Node1, P_Primary); + Set_Op_Name (Node1); + return Node1; + + else + Node1 := P_Primary; + + if Token = Tok_Double_Asterisk then + Node2 := New_Node (N_Op_Expon, Token_Ptr); + Scan; -- past ** + Set_Left_Opnd (Node2, Node1); + Set_Right_Opnd (Node2, P_Primary); + Set_Op_Name (Node2); + return Node2; + else + return Node1; + end if; + end if; + end P_Factor; + + ------------------ + -- 4.4 Primary -- + ------------------ + + -- PRIMARY ::= + -- NUMERIC_LITERAL | null + -- | STRING_LITERAL | AGGREGATE + -- | NAME | QUALIFIED_EXPRESSION + -- | ALLOCATOR | (EXPRESSION) + + -- Error recovery: can raise Error_Resync + + function P_Primary return Node_Id is + Scan_State : Saved_Scan_State; + Node1 : Node_Id; + + begin + -- The loop runs more than once only if misplaced pragmas are found + + loop + case Token is + + -- Name token can start a name, call or qualified expression, all + -- of which are acceptable possibilities for primary. Note also + -- that string literal is included in name (as operator symbol) + -- and type conversion is included in name (as indexed component). + + when Tok_Char_Literal | Tok_Operator_Symbol | Tok_Identifier => + Node1 := P_Name; + + -- All done unless apostrophe follows + + if Token /= Tok_Apostrophe then + return Node1; + + -- Apostrophe following means that we have either just parsed + -- the subtype mark of a qualified expression, or the prefix + -- or a range attribute. + + else -- Token = Tok_Apostrophe + Save_Scan_State (Scan_State); -- at apostrophe + Scan; -- past apostrophe + + -- If range attribute, then this is always an error, since + -- the only legitimate case (where the scanned expression is + -- a qualified simple name) is handled at the level of the + -- Simple_Expression processing. This case corresponds to a + -- usage such as 3 + A'Range, which is always illegal. + + if Token = Tok_Range then + Restore_Scan_State (Scan_State); -- to apostrophe + Bad_Range_Attribute (Token_Ptr); + return Error; + + -- If left paren, then we have a qualified expression. + -- Note that P_Name guarantees that in this case, where + -- Token = Tok_Apostrophe on return, the only two possible + -- tokens following the apostrophe are left paren and + -- RANGE, so we know we have a left paren here. + + else -- Token = Tok_Left_Paren + return P_Qualified_Expression (Node1); + + end if; + end if; + + -- Numeric or string literal + + when Tok_Integer_Literal | + Tok_Real_Literal | + Tok_String_Literal => + + Node1 := Token_Node; + Scan; -- past number + return Node1; + + -- Left paren, starts aggregate or parenthesized expression + + when Tok_Left_Paren => + return P_Aggregate_Or_Paren_Expr; + + -- Allocator + + when Tok_New => + return P_Allocator; + + -- Null + + when Tok_Null => + Scan; -- past NULL + return New_Node (N_Null, Prev_Token_Ptr); + + -- Pragma, not allowed here, so just skip past it + + when Tok_Pragma => + P_Pragmas_Misplaced; + + -- Anything else is illegal as the first token of a primary, but + -- we test for a reserved identifier so that it is treated nicely + + when others => + if Is_Reserved_Identifier then + return P_Identifier; + + elsif Prev_Token = Tok_Comma then + Error_Msg_SP ("extra "","" ignored"); + raise Error_Resync; + + else + Error_Msg_AP ("missing operand"); + raise Error_Resync; + end if; + + end case; + end loop; + end P_Primary; + + --------------------------- + -- 4.5 Logical Operator -- + --------------------------- + + -- LOGICAL_OPERATOR ::= and | or | xor + + -- Note: AND THEN and OR ELSE are also treated as logical operators + -- by the parser (even though they are not operators semantically) + + -- The value returned is the appropriate Node_Kind code for the operator + -- On return, Token points to the token following the scanned operator. + + -- The caller has checked that the first token is a legitimate logical + -- operator token (i.e. is either XOR, AND, OR). + + -- Error recovery: cannot raise Error_Resync + + function P_Logical_Operator return Node_Kind is + begin + if Token = Tok_And then + if Style_Check then Style.Check_Binary_Operator; end if; + Scan; -- past AND + + if Token = Tok_Then then + Scan; -- past THEN + return N_And_Then; + else + return N_Op_And; + end if; + + elsif Token = Tok_Or then + if Style_Check then Style.Check_Binary_Operator; end if; + Scan; -- past OR + + if Token = Tok_Else then + Scan; -- past ELSE + return N_Or_Else; + else + return N_Op_Or; + end if; + + else -- Token = Tok_Xor + if Style_Check then Style.Check_Binary_Operator; end if; + Scan; -- past XOR + return N_Op_Xor; + end if; + end P_Logical_Operator; + + ------------------------------ + -- 4.5 Relational Operator -- + ------------------------------ + + -- RELATIONAL_OPERATOR ::= = | /= | < | <= | > | >= + + -- The value returned is the appropriate Node_Kind code for the operator. + -- On return, Token points to the operator token, NOT past it. + + -- The caller has checked that the first token is a legitimate relational + -- operator token (i.e. is one of the operator tokens listed above). + + -- Error recovery: cannot raise Error_Resync + + function P_Relational_Operator return Node_Kind is + Op_Kind : Node_Kind; + Relop_Node : constant array (Token_Class_Relop) of Node_Kind := + (Tok_Less => N_Op_Lt, + Tok_Equal => N_Op_Eq, + Tok_Greater => N_Op_Gt, + Tok_Not_Equal => N_Op_Ne, + Tok_Greater_Equal => N_Op_Ge, + Tok_Less_Equal => N_Op_Le, + Tok_In => N_In, + Tok_Not => N_Not_In, + Tok_Box => N_Op_Ne); + + begin + if Token = Tok_Box then + Error_Msg_SC ("""<>"" should be ""/="""); + end if; + + Op_Kind := Relop_Node (Token); + if Style_Check then Style.Check_Binary_Operator; end if; + Scan; -- past operator token + + if Prev_Token = Tok_Not then + T_In; + end if; + + return Op_Kind; + end P_Relational_Operator; + + --------------------------------- + -- 4.5 Binary Adding Operator -- + --------------------------------- + + -- BINARY_ADDING_OPERATOR ::= + | - | & + + -- The value returned is the appropriate Node_Kind code for the operator. + -- On return, Token points to the operator token (NOT past it). + + -- The caller has checked that the first token is a legitimate adding + -- operator token (i.e. is one of the operator tokens listed above). + + -- Error recovery: cannot raise Error_Resync + + function P_Binary_Adding_Operator return Node_Kind is + Addop_Node : constant array (Token_Class_Binary_Addop) of Node_Kind := + (Tok_Ampersand => N_Op_Concat, + Tok_Minus => N_Op_Subtract, + Tok_Plus => N_Op_Add); + begin + return Addop_Node (Token); + end P_Binary_Adding_Operator; + + -------------------------------- + -- 4.5 Unary Adding Operator -- + -------------------------------- + + -- UNARY_ADDING_OPERATOR ::= + | - + + -- The value returned is the appropriate Node_Kind code for the operator. + -- On return, Token points to the operator token (NOT past it). + + -- The caller has checked that the first token is a legitimate adding + -- operator token (i.e. is one of the operator tokens listed above). + + -- Error recovery: cannot raise Error_Resync + + function P_Unary_Adding_Operator return Node_Kind is + Addop_Node : constant array (Token_Class_Unary_Addop) of Node_Kind := + (Tok_Minus => N_Op_Minus, + Tok_Plus => N_Op_Plus); + begin + return Addop_Node (Token); + end P_Unary_Adding_Operator; + + ------------------------------- + -- 4.5 Multiplying Operator -- + ------------------------------- + + -- MULTIPLYING_OPERATOR ::= * | / | mod | rem + + -- The value returned is the appropriate Node_Kind code for the operator. + -- On return, Token points to the operator token (NOT past it). + + -- The caller has checked that the first token is a legitimate multiplying + -- operator token (i.e. is one of the operator tokens listed above). + + -- Error recovery: cannot raise Error_Resync + + function P_Multiplying_Operator return Node_Kind is + Mulop_Node : constant array (Token_Class_Mulop) of Node_Kind := + (Tok_Asterisk => N_Op_Multiply, + Tok_Mod => N_Op_Mod, + Tok_Rem => N_Op_Rem, + Tok_Slash => N_Op_Divide); + begin + return Mulop_Node (Token); + end P_Multiplying_Operator; + + -------------------------------------- + -- 4.5 Highest Precedence Operator -- + -------------------------------------- + + -- Parsed by P_Factor (4.4) + + -- Note: this rule is not in fact used by the grammar at any point! + + -------------------------- + -- 4.6 Type Conversion -- + -------------------------- + + -- Parsed by P_Primary as a Name (4.1) + + ------------------------------- + -- 4.7 Qualified Expression -- + ------------------------------- + + -- QUALIFIED_EXPRESSION ::= + -- SUBTYPE_MARK ' (EXPRESSION) | SUBTYPE_MARK ' AGGREGATE + + -- The caller has scanned the name which is the Subtype_Mark parameter + -- and scanned past the single quote following the subtype mark. The + -- caller has not checked that this name is in fact appropriate for + -- a subtype mark name (i.e. it is a selected component or identifier). + + -- Error_Recovery: cannot raise Error_Resync + + function P_Qualified_Expression (Subtype_Mark : Node_Id) return Node_Id is + Qual_Node : Node_Id; + + begin + Qual_Node := New_Node (N_Qualified_Expression, Prev_Token_Ptr); + Set_Subtype_Mark (Qual_Node, Check_Subtype_Mark (Subtype_Mark)); + Set_Expression (Qual_Node, P_Aggregate_Or_Paren_Expr); + return Qual_Node; + end P_Qualified_Expression; + + -------------------- + -- 4.8 Allocator -- + -------------------- + + -- ALLOCATOR ::= + -- new SUBTYPE_INDICATION | new QUALIFIED_EXPRESSION + + -- The caller has checked that the initial token is NEW + + -- Error recovery: can raise Error_Resync + + function P_Allocator return Node_Id is + Alloc_Node : Node_Id; + Type_Node : Node_Id; + + begin + Alloc_Node := New_Node (N_Allocator, Token_Ptr); + T_New; + Type_Node := P_Subtype_Mark_Resync; + + if Token = Tok_Apostrophe then + Scan; -- past apostrophe + Set_Expression (Alloc_Node, P_Qualified_Expression (Type_Node)); + else + Set_Expression (Alloc_Node, P_Subtype_Indication (Type_Node)); + end if; + + return Alloc_Node; + end P_Allocator; + +end Ch4; diff --git a/gcc/ada/par-ch5.adb b/gcc/ada/par-ch5.adb new file mode 100644 index 00000000000..2ec56726e6b --- /dev/null +++ b/gcc/ada/par-ch5.adb @@ -0,0 +1,2184 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P A R . C H 5 -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.95 $ +-- -- +-- Copyright (C) 1992-2001, 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +pragma Style_Checks (All_Checks); +-- Turn off subprogram body ordering check. Subprograms are in order +-- by RM section rather than alphabetical + +separate (Par) +package body Ch5 is + + -- Local functions, used only in this chapter + + function P_Case_Statement return Node_Id; + function P_Case_Statement_Alternative return Node_Id; + function P_Condition return Node_Id; + function P_Exit_Statement return Node_Id; + function P_Goto_Statement return Node_Id; + function P_If_Statement return Node_Id; + function P_Label return Node_Id; + function P_Loop_Parameter_Specification return Node_Id; + function P_Null_Statement return Node_Id; + + function P_Assignment_Statement (LHS : Node_Id) return Node_Id; + -- Parse assignment statement. On entry, the caller has scanned the left + -- hand side (passed in as Lhs), and the colon-equal (or some symbol + -- taken to be an error equivalent such as equal). + + function P_Begin_Statement (Block_Name : Node_Id := Empty) return Node_Id; + -- Parse begin-end statement. If Block_Name is non-Empty on entry, it is + -- the N_Identifier node for the label on the block. If Block_Name is + -- Empty on entry (the default), then the block statement is unlabeled. + + function P_Declare_Statement (Block_Name : Node_Id := Empty) return Node_Id; + -- Parse declare block. If Block_Name is non-Empty on entry, it is + -- the N_Identifier node for the label on the block. If Block_Name is + -- Empty on entry (the default), then the block statement is unlabeled. + + function P_For_Statement (Loop_Name : Node_Id := Empty) return Node_Id; + -- Parse for statement. If Loop_Name is non-Empty on entry, it is + -- the N_Identifier node for the label on the loop. If Loop_Name is + -- Empty on entry (the default), then the for statement is unlabeled. + + function P_Loop_Statement (Loop_Name : Node_Id := Empty) return Node_Id; + -- Parse loop statement. If Loop_Name is non-Empty on entry, it is + -- the N_Identifier node for the label on the loop. If Loop_Name is + -- Empty on entry (the default), then the loop statement is unlabeled. + + function P_While_Statement (Loop_Name : Node_Id := Empty) return Node_Id; + -- Parse while statement. If Loop_Name is non-Empty on entry, it is + -- the N_Identifier node for the label on the loop. If Loop_Name is + -- Empty on entry (the default), then the while statement is unlabeled. + + function Set_Loop_Block_Name (L : Character) return Name_Id; + -- Given a letter 'L' for a loop or 'B' for a block, returns a name + -- of the form L_nn or B_nn where nn is a serial number obtained by + -- incrementing the variable Loop_Block_Count. + + procedure Then_Scan; + -- Scan past THEN token, testing for illegal junk after it + + --------------------------------- + -- 5.1 Sequence of Statements -- + --------------------------------- + + -- SEQUENCE_OF_STATEMENTS ::= STATEMENT {STATEMENT} + + -- STATEMENT ::= + -- {LABEL} SIMPLE_STATEMENT | {LABEL} COMPOUND_STATEMENT + + -- SIMPLE_STATEMENT ::= NULL_STATEMENT + -- | ASSIGNMENT_STATEMENT | EXIT_STATEMENT + -- | GOTO_STATEMENT | PROCEDURE_CALL_STATEMENT + -- | RETURN_STATEMENT | ENTRY_CALL_STATEMENT + -- | REQUEUE_STATEMENT | DELAY_STATEMENT + -- | ABORT_STATEMENT | RAISE_STATEMENT + -- | CODE_STATEMENT + + -- COMPOUND_STATEMENT ::= + -- IF_STATEMENT | CASE_STATEMENT + -- | LOOP_STATEMENT | BLOCK_STATEMENT + -- | ACCEPT_STATEMENT | SELECT_STATEMENT + + -- This procedure scans a sequence of statements. The caller sets SS_Flags + -- to indicate acceptable termination conditions for the sequence: + + -- SS_Flags.Eftm Terminate on ELSIF + -- SS_Flags.Eltm Terminate on ELSE + -- SS_Flags.Extm Terminate on EXCEPTION + -- SS_Flags.Ortm Terminate on OR + -- SS_Flags.Tatm Terminate on THEN ABORT (Token = ABORT on return) + -- SS_Flags.Whtm Terminate on WHEN + -- SS_Flags.Unco Unconditional terminate after scanning one statement + + -- In addition, the scan is always terminated by encountering END or the + -- end of file (EOF) condition. If one of the six above terminators is + -- encountered with the corresponding SS_Flags flag not set, then the + -- action taken is as follows: + + -- If the keyword occurs to the left of the expected column of the end + -- for the current sequence (as recorded in the current end context), + -- then it is assumed to belong to an outer context, and is considered + -- to terminate the sequence of statements. + + -- If the keyword occurs to the right of, or in the expected column of + -- the end for the current sequence, then an error message is output, + -- the keyword together with its associated context is skipped, and + -- the statement scan continues until another terminator is found. + + -- Note that the first action means that control can return to the caller + -- with Token set to a terminator other than one of those specified by the + -- SS parameter. The caller should treat such a case as equivalent to END. + + -- In addition, the flag SS_Flags.Sreq is set to True to indicate that at + -- least one real statement (other than a pragma) is required in the + -- statement sequence. During the processing of the sequence, this + -- flag is manipulated to indicate the current status of the requirement + -- for a statement. For example, it is turned off by the occurrence of a + -- statement, and back on by a label (which requires a following statement) + + -- Error recovery: cannot raise Error_Resync. If an error occurs during + -- parsing a statement, then the scan pointer is advanced past the next + -- semicolon and the parse continues. + + function P_Sequence_Of_Statements (SS_Flags : SS_Rec) return List_Id is + + Statement_Required : Boolean; + -- This flag indicates if a subsequent statement (other than a pragma) + -- is required. It is initialized from the Sreq flag, and modified as + -- statements are scanned (a statement turns it off, and a label turns + -- it back on again since a statement must follow a label). + + Declaration_Found : Boolean := False; + -- This flag is set True if a declaration is encountered, so that the + -- error message about declarations in the statement part is only + -- given once for a given sequence of statements. + + Scan_State_Label : Saved_Scan_State; + Scan_State : Saved_Scan_State; + + Statement_List : List_Id; + Block_Label : Name_Id; + Id_Node : Node_Id; + Name_Node : Node_Id; + + procedure Junk_Declaration; + -- Procedure called to handle error of declaration encountered in + -- statement sequence. + + procedure Test_Statement_Required; + -- Flag error if Statement_Required flag set + + procedure Junk_Declaration is + begin + if (not Declaration_Found) or All_Errors_Mode then + Error_Msg_SC ("declarations must come before BEGIN"); + Declaration_Found := True; + end if; + + Skip_Declaration (Statement_List); + end Junk_Declaration; + + procedure Test_Statement_Required is + begin + if Statement_Required then + Error_Msg_BC ("statement expected"); + end if; + end Test_Statement_Required; + + -- Start of processing for P_Sequence_Of_Statements + + begin + Statement_List := New_List; + Statement_Required := SS_Flags.Sreq; + + loop + while Token = Tok_Semicolon loop + Error_Msg_SC ("unexpected semicolon ignored"); + Scan; -- past junk semicolon + end loop; + + begin + if Style_Check then Style.Check_Indentation; end if; + + -- Deal with reserved identifier (in assignment or call) + + if Is_Reserved_Identifier then + Save_Scan_State (Scan_State); -- at possible bad identifier + Scan; -- and scan past it + + -- We have an reserved word which is spelled in identifier + -- style, so the question is whether it really is intended + -- to be an identifier. + + if + -- If followed by a semicolon, then it is an identifier, + -- with the exception of the cases tested for below. + + (Token = Tok_Semicolon + and then Prev_Token /= Tok_Return + and then Prev_Token /= Tok_Null + and then Prev_Token /= Tok_Raise + and then Prev_Token /= Tok_End + and then Prev_Token /= Tok_Exit) + + -- If followed by colon, colon-equal, or dot, then we + -- definitely have an identifier (could not be reserved) + + or else Token = Tok_Colon + or else Token = Tok_Colon_Equal + or else Token = Tok_Dot + + -- Left paren means we have an identifier except for those + -- reserved words that can legitimately be followed by a + -- left paren. + + or else + (Token = Tok_Left_Paren + and then Prev_Token /= Tok_Case + and then Prev_Token /= Tok_Delay + and then Prev_Token /= Tok_If + and then Prev_Token /= Tok_Elsif + and then Prev_Token /= Tok_Return + and then Prev_Token /= Tok_When + and then Prev_Token /= Tok_While + and then Prev_Token /= Tok_Separate) + then + -- Here we have an apparent reserved identifier and the + -- token past it is appropriate to this usage (and would + -- be a definite error if this is not an identifier). What + -- we do is to use P_Identifier to fix up the identifier, + -- and then fall into the normal processing. + + Restore_Scan_State (Scan_State); -- back to the ID + Scan_Reserved_Identifier (Force_Msg => False); + + -- Not a reserved identifier after all (or at least we can't + -- be sure that it is), so reset the scan and continue. + + else + Restore_Scan_State (Scan_State); -- back to the reserved word + end if; + end if; + + -- Now look to see what kind of statement we have + + case Token is + + -- Case of end or EOF + + when Tok_End | Tok_EOF => + + -- These tokens always terminate the statement sequence + + Test_Statement_Required; + exit; + + -- Case of ELSIF + + when Tok_Elsif => + + -- Terminate if Eftm set or if the ELSIF is to the left + -- of the expected column of the end for this sequence + + if SS_Flags.Eftm + or else Start_Column < Scope.Table (Scope.Last).Ecol + then + Test_Statement_Required; + exit; + + -- Otherwise complain and skip past ELSIF Condition then + + else + Error_Msg_SC ("ELSIF not allowed here"); + Scan; -- past ELSIF + Discard_Junk_Node (P_Expression_No_Right_Paren); + Then_Scan; + Statement_Required := False; + end if; + + -- Case of ELSE + + when Tok_Else => + + -- Terminate if Eltm set or if the else is to the left + -- of the expected column of the end for this sequence + + if SS_Flags.Eltm + or else Start_Column < Scope.Table (Scope.Last).Ecol + then + Test_Statement_Required; + exit; + + -- Otherwise complain and skip past else + + else + Error_Msg_SC ("ELSE not allowed here"); + Scan; -- past ELSE + Statement_Required := False; + end if; + + -- Case of exception + + when Tok_Exception => + Test_Statement_Required; + + -- If Extm not set and the exception is not to the left + -- of the expected column of the end for this sequence, then + -- we assume it belongs to the current sequence, even though + -- it is not permitted. + + if not SS_Flags.Extm and then + Start_Column >= Scope.Table (Scope.Last).Ecol + + then + Error_Msg_SC ("exception handler not permitted here"); + Scan; -- past EXCEPTION + Discard_Junk_List (Parse_Exception_Handlers); + end if; + + -- Always return, in the case where we scanned out handlers + -- that we did not expect, Parse_Exception_Handlers returned + -- with Token being either end or EOF, so we are OK + + exit; + + -- Case of OR + + when Tok_Or => + + -- Terminate if Ortm set or if the or is to the left + -- of the expected column of the end for this sequence + + if SS_Flags.Ortm + or else Start_Column < Scope.Table (Scope.Last).Ecol + then + Test_Statement_Required; + exit; + + -- Otherwise complain and skip past or + + else + Error_Msg_SC ("OR not allowed here"); + Scan; -- past or + Statement_Required := False; + end if; + + -- Case of THEN (deal also with THEN ABORT) + + when Tok_Then => + Save_Scan_State (Scan_State); -- at THEN + Scan; -- past THEN + + -- Terminate if THEN ABORT allowed (ATC case) + + exit when SS_Flags.Tatm and then Token = Tok_Abort; + + -- Otherwise we treat THEN as some kind of mess where we + -- did not see the associated IF, but we pick up assuming + -- it had been there! + + Restore_Scan_State (Scan_State); -- to THEN + Append_To (Statement_List, P_If_Statement); + Statement_Required := False; + + -- Case of WHEN (error because we are not in a case) + + when Tok_When | Tok_Others => + + -- Terminate if Whtm set or if the WHEN is to the left + -- of the expected column of the end for this sequence + + if SS_Flags.Whtm + or else Start_Column < Scope.Table (Scope.Last).Ecol + then + Test_Statement_Required; + exit; + + -- Otherwise complain and skip when Choice {| Choice} => + + else + Error_Msg_SC ("WHEN not allowed here"); + Scan; -- past when + Discard_Junk_List (P_Discrete_Choice_List); + TF_Arrow; + Statement_Required := False; + end if; + + -- Cases of statements starting with an identifier + + when Tok_Identifier => + Check_Bad_Layout; + + -- Save scan pointers and line number in case block label + + Id_Node := Token_Node; + Block_Label := Token_Name; + Save_Scan_State (Scan_State_Label); -- at possible label + Scan; -- past Id + + -- Check for common case of assignment, since it occurs + -- frequently, and we want to process it efficiently. + + if Token = Tok_Colon_Equal then + Scan; -- past the colon-equal + Append_To (Statement_List, + P_Assignment_Statement (Id_Node)); + Statement_Required := False; + + -- Check common case of procedure call, another case that + -- we want to speed up as much as possible. + + elsif Token = Tok_Semicolon then + Append_To (Statement_List, + P_Statement_Name (Id_Node)); + Scan; -- past semicolon + Statement_Required := False; + + -- Check for case of "go to" in place of "goto" + + elsif Token = Tok_Identifier + and then Block_Label = Name_Go + and then Token_Name = Name_To + then + Error_Msg_SP ("goto is one word"); + Append_To (Statement_List, P_Goto_Statement); + Statement_Required := False; + + -- Check common case of = used instead of :=, just so we + -- give a better error message for this special misuse. + + elsif Token = Tok_Equal then + T_Colon_Equal; -- give := expected message + Append_To (Statement_List, + P_Assignment_Statement (Id_Node)); + Statement_Required := False; + + -- Check case of loop label or block label + + elsif Token = Tok_Colon + or else (Token in Token_Class_Labeled_Stmt + and then not Token_Is_At_Start_Of_Line) + then + T_Colon; -- past colon (if there, or msg for missing one) + + -- Test for more than one label + + loop + exit when Token /= Tok_Identifier; + Save_Scan_State (Scan_State); -- at second Id + Scan; -- past Id + + if Token = Tok_Colon then + Error_Msg_SP + ("only one label allowed on block or loop"); + Scan; -- past colon on extra label + + -- Use the second label as the "real" label + + Scan_State_Label := Scan_State; + + -- We will set Error_name as the Block_Label since + -- we really don't know which of the labels might + -- be used at the end of the loop or block! + + Block_Label := Error_Name; + + -- If Id with no colon, then backup to point to the + -- Id and we will issue the message below when we try + -- to scan out the statement as some other form. + + else + Restore_Scan_State (Scan_State); -- to second Id + exit; + end if; + end loop; + + -- Loop_Statement (labeled Loop_Statement) + + if Token = Tok_Loop then + Append_To (Statement_List, + P_Loop_Statement (Id_Node)); + + -- While statement (labeled loop statement with WHILE) + + elsif Token = Tok_While then + Append_To (Statement_List, + P_While_Statement (Id_Node)); + + -- Declare statement (labeled block statement with + -- DECLARE part) + + elsif Token = Tok_Declare then + Append_To (Statement_List, + P_Declare_Statement (Id_Node)); + + -- Begin statement (labeled block statement with no + -- DECLARE part) + + elsif Token = Tok_Begin then + Append_To (Statement_List, + P_Begin_Statement (Id_Node)); + + -- For statement (labeled loop statement with FOR) + + elsif Token = Tok_For then + Append_To (Statement_List, + P_For_Statement (Id_Node)); + + -- Improper statement follows label. If we have an + -- expression token, then assume the colon was part + -- of a misplaced declaration. + + elsif Token not in Token_Class_Eterm then + Restore_Scan_State (Scan_State_Label); + Junk_Declaration; + + -- Otherwise complain we have inappropriate statement + + else + Error_Msg_AP + ("loop or block statement must follow label"); + end if; + + Statement_Required := False; + + -- Here we have an identifier followed by something + -- other than a colon, semicolon or assignment symbol. + -- The only valid possibility is a name extension symbol + + elsif Token in Token_Class_Namext then + Restore_Scan_State (Scan_State_Label); -- to Id + Name_Node := P_Name; + + -- Skip junk right parens in this context + + while Token = Tok_Right_Paren loop + Error_Msg_SC ("extra right paren"); + Scan; -- past ) + end loop; + + -- Check context following call + + if Token = Tok_Colon_Equal then + Scan; -- past colon equal + Append_To (Statement_List, + P_Assignment_Statement (Name_Node)); + Statement_Required := False; + + -- Check common case of = used instead of := + + elsif Token = Tok_Equal then + T_Colon_Equal; -- give := expected message + Append_To (Statement_List, + P_Assignment_Statement (Name_Node)); + Statement_Required := False; + + -- Check apostrophe cases + + elsif Token = Tok_Apostrophe then + Append_To (Statement_List, + P_Code_Statement (Name_Node)); + Statement_Required := False; + + -- The only other valid item after a name is ; which + -- means that the item we just scanned was a call. + + elsif Token = Tok_Semicolon then + Append_To (Statement_List, + P_Statement_Name (Name_Node)); + Scan; -- past semicolon + Statement_Required := False; + + -- Else we have a missing semicolon + + else + TF_Semicolon; + Statement_Required := False; + end if; + + -- If junk after identifier, check if identifier is an + -- instance of an incorrectly spelled keyword. If so, we + -- do nothing. The Bad_Spelling_Of will have reset Token + -- to the appropriate keyword, so the next time round the + -- loop we will process the modified token. Note that we + -- check for ELSIF before ELSE here. That's not accidental. + -- We don't want to identify a misspelling of ELSE as + -- ELSIF, and in particular we do not want to treat ELSEIF + -- as ELSE IF. + + else + Restore_Scan_State (Scan_State_Label); -- to identifier + + if Bad_Spelling_Of (Tok_Abort) + or else Bad_Spelling_Of (Tok_Accept) + or else Bad_Spelling_Of (Tok_Case) + or else Bad_Spelling_Of (Tok_Declare) + or else Bad_Spelling_Of (Tok_Delay) + or else Bad_Spelling_Of (Tok_Elsif) + or else Bad_Spelling_Of (Tok_Else) + or else Bad_Spelling_Of (Tok_End) + or else Bad_Spelling_Of (Tok_Exception) + or else Bad_Spelling_Of (Tok_Exit) + or else Bad_Spelling_Of (Tok_For) + or else Bad_Spelling_Of (Tok_Goto) + or else Bad_Spelling_Of (Tok_If) + or else Bad_Spelling_Of (Tok_Loop) + or else Bad_Spelling_Of (Tok_Or) + or else Bad_Spelling_Of (Tok_Pragma) + or else Bad_Spelling_Of (Tok_Raise) + or else Bad_Spelling_Of (Tok_Requeue) + or else Bad_Spelling_Of (Tok_Return) + or else Bad_Spelling_Of (Tok_Select) + or else Bad_Spelling_Of (Tok_When) + or else Bad_Spelling_Of (Tok_While) + then + null; + + -- If not a bad spelling, then we really have junk + + else + Scan; -- past identifier again + + -- If next token is first token on line, then we + -- consider that we were missing a semicolon after + -- the identifier, and process it as a procedure + -- call with no parameters. + + if Token_Is_At_Start_Of_Line then + Append_To (Statement_List, + P_Statement_Name (Id_Node)); + T_Semicolon; -- to give error message + Statement_Required := False; + + -- Otherwise we give a missing := message and + -- simply abandon the junk that is there now. + + else + T_Colon_Equal; -- give := expected message + raise Error_Resync; + end if; + + end if; + end if; + + -- Statement starting with operator symbol. This could be + -- a call, a name starting an assignment, or a qualified + -- expression. + + when Tok_Operator_Symbol => + Check_Bad_Layout; + Name_Node := P_Name; + + -- An attempt at a range attribute or a qualified expression + -- must be illegal here (a code statement cannot possibly + -- allow qualification by a function name). + + if Token = Tok_Apostrophe then + Error_Msg_SC ("apostrophe illegal here"); + raise Error_Resync; + end if; + + -- Scan possible assignment if we have a name + + if Expr_Form = EF_Name + and then Token = Tok_Colon_Equal + then + Scan; -- past colon equal + Append_To (Statement_List, + P_Assignment_Statement (Name_Node)); + else + Append_To (Statement_List, + P_Statement_Name (Name_Node)); + end if; + + TF_Semicolon; + Statement_Required := False; + + -- Label starting with << which must precede real statement + + when Tok_Less_Less => + Append_To (Statement_List, P_Label); + Statement_Required := True; + + -- Pragma appearing as a statement in a statement sequence + + when Tok_Pragma => + Check_Bad_Layout; + Append_To (Statement_List, P_Pragma); + + -- Abort_Statement + + when Tok_Abort => + Check_Bad_Layout; + Append_To (Statement_List, P_Abort_Statement); + Statement_Required := False; + + -- Accept_Statement + + when Tok_Accept => + Check_Bad_Layout; + Append_To (Statement_List, P_Accept_Statement); + Statement_Required := False; + + -- Begin_Statement (Block_Statement with no declare, no label) + + when Tok_Begin => + Check_Bad_Layout; + Append_To (Statement_List, P_Begin_Statement); + Statement_Required := False; + + -- Case_Statement + + when Tok_Case => + Check_Bad_Layout; + Append_To (Statement_List, P_Case_Statement); + Statement_Required := False; + + -- Block_Statement with DECLARE and no label + + when Tok_Declare => + Check_Bad_Layout; + Append_To (Statement_List, P_Declare_Statement); + Statement_Required := False; + + -- Delay_Statement + + when Tok_Delay => + Check_Bad_Layout; + Append_To (Statement_List, P_Delay_Statement); + Statement_Required := False; + + -- Exit_Statement + + when Tok_Exit => + Check_Bad_Layout; + Append_To (Statement_List, P_Exit_Statement); + Statement_Required := False; + + -- Loop_Statement with FOR and no label + + when Tok_For => + Check_Bad_Layout; + Append_To (Statement_List, P_For_Statement); + Statement_Required := False; + + -- Goto_Statement + + when Tok_Goto => + Check_Bad_Layout; + Append_To (Statement_List, P_Goto_Statement); + Statement_Required := False; + + -- If_Statement + + when Tok_If => + Check_Bad_Layout; + Append_To (Statement_List, P_If_Statement); + Statement_Required := False; + + -- Loop_Statement + + when Tok_Loop => + Check_Bad_Layout; + Append_To (Statement_List, P_Loop_Statement); + Statement_Required := False; + + -- Null_Statement + + when Tok_Null => + Check_Bad_Layout; + Append_To (Statement_List, P_Null_Statement); + Statement_Required := False; + + -- Raise_Statement + + when Tok_Raise => + Check_Bad_Layout; + Append_To (Statement_List, P_Raise_Statement); + Statement_Required := False; + + -- Requeue_Statement + + when Tok_Requeue => + Check_Bad_Layout; + Append_To (Statement_List, P_Requeue_Statement); + Statement_Required := False; + + -- Return_Statement + + when Tok_Return => + Check_Bad_Layout; + Append_To (Statement_List, P_Return_Statement); + Statement_Required := False; + + -- Select_Statement + + when Tok_Select => + Check_Bad_Layout; + Append_To (Statement_List, P_Select_Statement); + Statement_Required := False; + + -- While_Statement (Block_Statement with while and no loop) + + when Tok_While => + Check_Bad_Layout; + Append_To (Statement_List, P_While_Statement); + Statement_Required := False; + + -- Anything else is some kind of junk, signal an error message + -- and then raise Error_Resync, to merge with the normal + -- handling of a bad statement. + + when others => + + if Token in Token_Class_Declk then + Junk_Declaration; + + else + Error_Msg_BC ("statement expected"); + raise Error_Resync; + end if; + end case; + + -- On error resynchronization, skip past next semicolon, and, since + -- we are still in the statement loop, look for next statement. We + -- set Statement_Required False to avoid an unnecessary error message + -- complaining that no statement was found (i.e. we consider the + -- junk to satisfy the requirement for a statement being present). + + exception + when Error_Resync => + Resync_Past_Semicolon_Or_To_Loop_Or_Then; + Statement_Required := False; + end; + + exit when SS_Flags.Unco; + + end loop; + + return Statement_List; + + end P_Sequence_Of_Statements; + + -------------------- + -- 5.1 Statement -- + -------------------- + + -- Parsed by P_Sequence_Of_Statements (5.1), except for the case + -- of a statement of the form of a name, which is handled here. The + -- argument passed in is the tree for the name which has been scanned + -- The returned value is the corresponding statement form. + + -- This routine is also used by Par.Prag for processing the procedure + -- call that appears as the second argument of a pragma Assert. + + -- Error recovery: cannot raise Error_Resync + + function P_Statement_Name (Name_Node : Node_Id) return Node_Id is + Stmt_Node : Node_Id; + + begin + -- Case of Indexed component, which is a procedure call with arguments + + if Nkind (Name_Node) = N_Indexed_Component then + declare + Prefix_Node : Node_Id := Prefix (Name_Node); + Exprs_Node : List_Id := Expressions (Name_Node); + begin + Change_Node (Name_Node, N_Procedure_Call_Statement); + Set_Name (Name_Node, Prefix_Node); + Set_Parameter_Associations (Name_Node, Exprs_Node); + return Name_Node; + end; + + -- Case of function call node, which is a really a procedure call + + elsif Nkind (Name_Node) = N_Function_Call then + declare + Fname_Node : Node_Id := Name (Name_Node); + Params_List : List_Id := Parameter_Associations (Name_Node); + + begin + Change_Node (Name_Node, N_Procedure_Call_Statement); + Set_Name (Name_Node, Fname_Node); + Set_Parameter_Associations (Name_Node, Params_List); + return Name_Node; + end; + + -- Case of call to attribute that denotes a procedure. Here we + -- just leave the attribute reference unchanged. + + elsif Nkind (Name_Node) = N_Attribute_Reference + and then Is_Procedure_Attribute_Name (Attribute_Name (Name_Node)) + then + return Name_Node; + + -- All other cases of names are parameterless procedure calls + + else + Stmt_Node := + New_Node (N_Procedure_Call_Statement, Sloc (Name_Node)); + Set_Name (Stmt_Node, Name_Node); + return Stmt_Node; + end if; + + end P_Statement_Name; + + --------------------------- + -- 5.1 Simple Statement -- + --------------------------- + + -- Parsed by P_Sequence_Of_Statements (5.1) + + ----------------------------- + -- 5.1 Compound Statement -- + ----------------------------- + + -- Parsed by P_Sequence_Of_Statements (5.1) + + ------------------------- + -- 5.1 Null Statement -- + ------------------------- + + -- NULL_STATEMENT ::= null; + + -- The caller has already checked that the current token is null + + -- Error recovery: cannot raise Error_Resync + + function P_Null_Statement return Node_Id is + Null_Stmt_Node : Node_Id; + + begin + Null_Stmt_Node := New_Node (N_Null_Statement, Token_Ptr); + Scan; -- past NULL + TF_Semicolon; + return Null_Stmt_Node; + end P_Null_Statement; + + ---------------- + -- 5.1 Label -- + ---------------- + + -- LABEL ::= <<label_STATEMENT_IDENTIFIER>> + + -- STATEMENT_INDENTIFIER ::= DIRECT_NAME + + -- The IDENTIFIER of a STATEMENT_IDENTIFIER shall be an identifier + -- (not an OPERATOR_SYMBOL) + + -- The caller has already checked that the current token is << + + -- Error recovery: can raise Error_Resync + + function P_Label return Node_Id is + Label_Node : Node_Id; + + begin + Label_Node := New_Node (N_Label, Token_Ptr); + Scan; -- past << + Set_Identifier (Label_Node, P_Identifier); + T_Greater_Greater; + Append_Elmt (Label_Node, Label_List); + return Label_Node; + end P_Label; + + ------------------------------- + -- 5.1 Statement Identifier -- + ------------------------------- + + -- Statement label is parsed by P_Label (5.1) + + -- Loop label is parsed by P_Loop_Statement (5.5), P_For_Statement (5.5) + -- or P_While_Statement (5.5) + + -- Block label is parsed by P_Begin_Statement (5.6) or + -- P_Declare_Statement (5.6) + + ------------------------------- + -- 5.2 Assignment Statement -- + ------------------------------- + + -- ASSIGNMENT_STATEMENT ::= + -- variable_NAME := EXPRESSION; + + -- Error recovery: can raise Error_Resync + + function P_Assignment_Statement (LHS : Node_Id) return Node_Id is + Assign_Node : Node_Id; + + begin + Assign_Node := New_Node (N_Assignment_Statement, Prev_Token_Ptr); + Set_Name (Assign_Node, LHS); + Set_Expression (Assign_Node, P_Expression_No_Right_Paren); + TF_Semicolon; + return Assign_Node; + end P_Assignment_Statement; + + ----------------------- + -- 5.3 If Statement -- + ----------------------- + + -- IF_STATEMENT ::= + -- if CONDITION then + -- SEQUENCE_OF_STATEMENTS + -- {elsif CONDITION then + -- SEQUENCE_OF_STATEMENTS} + -- [else + -- SEQUENCE_OF_STATEMENTS] + -- end if; + + -- The caller has checked that the initial token is IF (or in the error + -- case of a mysterious THEN, the initial token may simply be THEN, in + -- which case, no condition (or IF) was scanned). + + -- Error recovery: can raise Error_Resync + + function P_If_Statement return Node_Id is + If_Node : Node_Id; + Elsif_Node : Node_Id; + Loc : Source_Ptr; + + procedure Add_Elsif_Part; + -- An internal procedure used to scan out a single ELSIF part. On entry + -- the ELSIF (or an ELSE which has been determined should be ELSIF) is + -- scanned out and is in Prev_Token. + + procedure Check_If_Column; + -- An internal procedure used to check that THEN, ELSE ELSE, or ELSIF + -- appear in the right place if column checking is enabled (i.e. if + -- they are the first token on the line, then they must appear in + -- the same column as the opening IF). + + procedure Check_Then_Column; + -- This procedure carries out the style checks for a THEN token + -- Note that the caller has set Loc to the Source_Ptr value for + -- the previous IF or ELSIF token. These checks apply only to a + -- THEN at the start of a line. + + function Else_Should_Be_Elsif return Boolean; + -- An internal routine used to do a special error recovery check when + -- an ELSE is encountered. It determines if the ELSE should be treated + -- as an ELSIF. A positive decision (TRUE returned, is made if the ELSE + -- is followed by a sequence of tokens, starting on the same line as + -- the ELSE, which are not expression terminators, followed by a THEN. + -- On entry, the ELSE has been scanned out. + + procedure Add_Elsif_Part is + begin + if No (Elsif_Parts (If_Node)) then + Set_Elsif_Parts (If_Node, New_List); + end if; + + Elsif_Node := New_Node (N_Elsif_Part, Prev_Token_Ptr); + Loc := Prev_Token_Ptr; + Set_Condition (Elsif_Node, P_Condition); + Check_Then_Column; + Then_Scan; + Set_Then_Statements + (Elsif_Node, P_Sequence_Of_Statements (SS_Eftm_Eltm_Sreq)); + Append (Elsif_Node, Elsif_Parts (If_Node)); + end Add_Elsif_Part; + + procedure Check_If_Column is + begin + if Style.RM_Column_Check and then Token_Is_At_Start_Of_Line + and then Start_Column /= Scope.Table (Scope.Last).Ecol + then + Error_Msg_Col := Scope.Table (Scope.Last).Ecol; + Error_Msg_SC ("(style) this token should be@"); + end if; + end Check_If_Column; + + procedure Check_Then_Column is + begin + if Token_Is_At_Start_Of_Line and then Token = Tok_Then then + Check_If_Column; + if Style_Check then Style.Check_Then (Loc); end if; + end if; + end Check_Then_Column; + + function Else_Should_Be_Elsif return Boolean is + Scan_State : Saved_Scan_State; + + begin + if Token_Is_At_Start_Of_Line then + return False; + + else + Save_Scan_State (Scan_State); + + loop + if Token in Token_Class_Eterm then + Restore_Scan_State (Scan_State); + return False; + else + Scan; -- past non-expression terminating token + + if Token = Tok_Then then + Restore_Scan_State (Scan_State); + return True; + end if; + end if; + end loop; + end if; + end Else_Should_Be_Elsif; + + -- Start of processing for P_If_Statement + + begin + If_Node := New_Node (N_If_Statement, Token_Ptr); + + Push_Scope_Stack; + Scope.Table (Scope.Last).Etyp := E_If; + Scope.Table (Scope.Last).Ecol := Start_Column; + Scope.Table (Scope.Last).Sloc := Token_Ptr; + Scope.Table (Scope.Last).Labl := Error; + Scope.Table (Scope.Last).Node := If_Node; + + if Token = Tok_If then + Loc := Token_Ptr; + Scan; -- past IF + Set_Condition (If_Node, P_Condition); + + -- Deal with misuse of IF expression => used instead + -- of WHEN expression => + + if Token = Tok_Arrow then + Error_Msg_SC ("THEN expected"); + Scan; -- past the arrow + Pop_Scope_Stack; -- remove unneeded entry + raise Error_Resync; + end if; + + Check_Then_Column; + + else + Error_Msg_SC ("no IF for this THEN"); + Set_Condition (If_Node, Error); + end if; + + Then_Scan; + + Set_Then_Statements + (If_Node, P_Sequence_Of_Statements (SS_Eftm_Eltm_Sreq)); + + -- This loop scans out else and elsif parts + + loop + if Token = Tok_Elsif then + Check_If_Column; + + if Present (Else_Statements (If_Node)) then + Error_Msg_SP ("ELSIF cannot appear after ELSE"); + end if; + + Scan; -- past ELSIF + Add_Elsif_Part; + + elsif Token = Tok_Else then + Check_If_Column; + Scan; -- past ELSE + + if Else_Should_Be_Elsif then + Error_Msg_SP ("ELSE should be ELSIF"); + Add_Elsif_Part; + + else + -- Here we have an else that really is an else + + if Present (Else_Statements (If_Node)) then + Error_Msg_SP ("Only one ELSE part allowed"); + Append_List + (P_Sequence_Of_Statements (SS_Eftm_Eltm_Sreq), + Else_Statements (If_Node)); + else + Set_Else_Statements + (If_Node, P_Sequence_Of_Statements (SS_Eftm_Eltm_Sreq)); + end if; + end if; + + -- If anything other than ELSE or ELSIF, exit the loop. The token + -- had better be END (and in fact it had better be END IF), but + -- we will let End_Statements take care of checking that. + + else + exit; + end if; + end loop; + + End_Statements; + return If_Node; + + end P_If_Statement; + + -------------------- + -- 5.3 Condition -- + -------------------- + + -- CONDITION ::= boolean_EXPRESSION + + function P_Condition return Node_Id is + Cond : Node_Id; + + begin + Cond := P_Expression_No_Right_Paren; + + -- It is never possible for := to follow a condition, so if we get + -- a := we assume it is a mistyped equality. Note that we do not try + -- to reconstruct the tree correctly in this case, but we do at least + -- give an accurate error message. + + while Token = Tok_Colon_Equal loop + Error_Msg_SC (""":="" should be ""="""); + Scan; -- past junk := + Discard_Junk_Node (P_Expression_No_Right_Paren); + end loop; + + return Cond; + end P_Condition; + + ------------------------- + -- 5.4 Case Statement -- + ------------------------- + + -- CASE_STATEMENT ::= + -- case EXPRESSION is + -- CASE_STATEMENT_ALTERNATIVE + -- {CASE_STATEMENT_ALTERNATIVE} + -- end case; + + -- The caller has checked that the first token is CASE + + -- Can raise Error_Resync + + function P_Case_Statement return Node_Id is + Case_Node : Node_Id; + Alternatives_List : List_Id; + First_When_Loc : Source_Ptr; + + begin + Case_Node := New_Node (N_Case_Statement, Token_Ptr); + + Push_Scope_Stack; + Scope.Table (Scope.Last).Etyp := E_Case; + Scope.Table (Scope.Last).Ecol := Start_Column; + Scope.Table (Scope.Last).Sloc := Token_Ptr; + Scope.Table (Scope.Last).Labl := Error; + Scope.Table (Scope.Last).Node := Case_Node; + + Scan; -- past CASE + Set_Expression (Case_Node, P_Expression_No_Right_Paren); + TF_Is; + + -- Prepare to parse case statement alternatives + + Alternatives_List := New_List; + P_Pragmas_Opt (Alternatives_List); + First_When_Loc := Token_Ptr; + + -- Loop through case statement alternatives + + loop + -- If we have a WHEN or OTHERS, then that's fine keep going. Note + -- that it is a semantic check to ensure the proper use of OTHERS + + if Token = Tok_When or else Token = Tok_Others then + Append (P_Case_Statement_Alternative, Alternatives_List); + + -- If we have an END, then probably we are at the end of the case + -- but we only exit if Check_End thinks the END was reasonable. + + elsif Token = Tok_End then + exit when Check_End; + + -- Here if token is other than WHEN, OTHERS or END. We definitely + -- have an error, but the question is whether or not to get out of + -- the case statement. We don't want to get out early, or we will + -- get a slew of junk error messages for subsequent when tokens. + + -- If the token is not at the start of the line, or if it is indented + -- with respect to the current case statement, then the best guess is + -- that we are still supposed to be inside the case statement. We + -- complain about the missing WHEN, and discard the junk statements. + + elsif not Token_Is_At_Start_Of_Line + or else Start_Column > Scope.Table (Scope.Last).Ecol + then + Error_Msg_BC ("WHEN (case statement alternative) expected"); + + -- Here is a possibility for infinite looping if we don't make + -- progress. So try to process statements, otherwise exit + + declare + Error_Ptr : constant Source_Ptr := Scan_Ptr; + begin + Discard_Junk_List (P_Sequence_Of_Statements (SS_Whtm)); + exit when Scan_Ptr = Error_Ptr and then Check_End; + end; + + -- Here we have a junk token at the start of the line and it is + -- not indented. If Check_End thinks there is a missing END, then + -- we will get out of the case, otherwise we keep going. + + else + exit when Check_End; + end if; + end loop; + + -- Make sure we have at least one alternative + + if No (First_Non_Pragma (Alternatives_List)) then + Error_Msg + ("WHEN expected, must have at least one alternative in case", + First_When_Loc); + return Error; + + else + Set_Alternatives (Case_Node, Alternatives_List); + return Case_Node; + end if; + end P_Case_Statement; + + ------------------------------------- + -- 5.4 Case Statement Alternative -- + ------------------------------------- + + -- CASE_STATEMENT_ALTERNATIVE ::= + -- when DISCRETE_CHOICE_LIST => + -- SEQUENCE_OF_STATEMENTS + + -- The caller has checked that the initial token is WHEN or OTHERS + -- Error recovery: can raise Error_Resync + + function P_Case_Statement_Alternative return Node_Id is + Case_Alt_Node : Node_Id; + + begin + if Style_Check then Style.Check_Indentation; end if; + Case_Alt_Node := New_Node (N_Case_Statement_Alternative, Token_Ptr); + T_When; -- past WHEN (or give error in OTHERS case) + Set_Discrete_Choices (Case_Alt_Node, P_Discrete_Choice_List); + TF_Arrow; + Set_Statements (Case_Alt_Node, P_Sequence_Of_Statements (SS_Sreq_Whtm)); + return Case_Alt_Node; + end P_Case_Statement_Alternative; + + ------------------------- + -- 5.5 Loop Statement -- + ------------------------- + + -- LOOP_STATEMENT ::= + -- [LOOP_STATEMENT_IDENTIFIER:] + -- [ITERATION_SCHEME] loop + -- SEQUENCE_OF_STATEMENTS + -- end loop [loop_IDENTIFIER]; + + -- ITERATION_SCHEME ::= + -- while CONDITION + -- | for LOOP_PARAMETER_SPECIFICATION + + -- The parsing of loop statements is handled by one of three functions + -- P_Loop_Statement, P_For_Statement or P_While_Statement depending + -- on the initial keyword in the construct (excluding the identifier) + + -- P_Loop_Statement + + -- This function parses the case where no iteration scheme is present + + -- The caller has checked that the initial token is LOOP. The parameter + -- is the node identifiers for the loop label if any (or is set to Empty + -- if there is no loop label). + + -- Error recovery : cannot raise Error_Resync + + function P_Loop_Statement (Loop_Name : Node_Id := Empty) return Node_Id is + Loop_Node : Node_Id; + + begin + Push_Scope_Stack; + Scope.Table (Scope.Last).Labl := Loop_Name; + Scope.Table (Scope.Last).Ecol := Start_Column; + Scope.Table (Scope.Last).Sloc := Token_Ptr; + Scope.Table (Scope.Last).Etyp := E_Loop; + + Loop_Node := New_Node (N_Loop_Statement, Token_Ptr); + TF_Loop; + + if No (Loop_Name) then + Set_Has_Created_Identifier (Loop_Node, True); + Set_Identifier (Loop_Node, + Make_Identifier (Sloc (Loop_Node), Set_Loop_Block_Name ('L'))); + else + Set_Identifier (Loop_Node, Loop_Name); + end if; + + Append_Elmt (Loop_Node, Label_List); + + Set_Statements (Loop_Node, P_Sequence_Of_Statements (SS_Sreq)); + End_Statements (Loop_Node); + return Loop_Node; + end P_Loop_Statement; + + -- P_For_Statement + + -- This function parses a loop statement with a FOR iteration scheme + + -- The caller has checked that the initial token is FOR. The parameter + -- is the node identifier for the block label if any (or is set to Empty + -- if there is no block label). + + -- Note: the caller fills in the Identifier field if a label was present + + -- Error recovery: can raise Error_Resync + + function P_For_Statement (Loop_Name : Node_Id := Empty) return Node_Id is + Loop_Node : Node_Id; + Iter_Scheme_Node : Node_Id; + Loop_For_Flag : Boolean; + + begin + Push_Scope_Stack; + Scope.Table (Scope.Last).Labl := Loop_Name; + Scope.Table (Scope.Last).Ecol := Start_Column; + Scope.Table (Scope.Last).Sloc := Token_Ptr; + Scope.Table (Scope.Last).Etyp := E_Loop; + + Loop_For_Flag := (Prev_Token = Tok_Loop); + Scan; -- past FOR + Iter_Scheme_Node := New_Node (N_Iteration_Scheme, Token_Ptr); + Set_Loop_Parameter_Specification + (Iter_Scheme_Node, P_Loop_Parameter_Specification); + + -- The following is a special test so that a miswritten for loop such + -- as "loop for I in 1..10;" is handled nicely, without making an extra + -- entry in the scope stack. We don't bother to actually fix up the + -- tree in this case since it's not worth the effort. Instead we just + -- eat up the loop junk, leaving the entry for what now looks like an + -- unmodified loop intact. + + if Loop_For_Flag and then Token = Tok_Semicolon then + Error_Msg_SC ("LOOP belongs here, not before FOR"); + Pop_Scope_Stack; + return Error; + + -- Normal case + + else + Loop_Node := New_Node (N_Loop_Statement, Token_Ptr); + TF_Loop; + Set_Statements (Loop_Node, P_Sequence_Of_Statements (SS_Sreq)); + End_Statements (Loop_Node); + Set_Iteration_Scheme (Loop_Node, Iter_Scheme_Node); + + if No (Loop_Name) then + Set_Has_Created_Identifier (Loop_Node, True); + Set_Identifier (Loop_Node, + Make_Identifier (Sloc (Loop_Node), Set_Loop_Block_Name ('L'))); + else + Set_Identifier (Loop_Node, Loop_Name); + end if; + + Append_Elmt (Loop_Node, Label_List); + + return Loop_Node; + end if; + + end P_For_Statement; + + -- P_While_Statement + + -- This procedure scans a loop statement with a WHILE iteration scheme + + -- The caller has checked that the initial token is WHILE. The parameter + -- is the node identifier for the block label if any (or is set to Empty + -- if there is no block label). + + -- Error recovery: cannot raise Error_Resync + + function P_While_Statement (Loop_Name : Node_Id := Empty) return Node_Id is + Loop_Node : Node_Id; + Iter_Scheme_Node : Node_Id; + Loop_While_Flag : Boolean; + + begin + Push_Scope_Stack; + Scope.Table (Scope.Last).Labl := Loop_Name; + Scope.Table (Scope.Last).Ecol := Start_Column; + Scope.Table (Scope.Last).Sloc := Token_Ptr; + Scope.Table (Scope.Last).Etyp := E_Loop; + + Loop_While_Flag := (Prev_Token = Tok_Loop); + Iter_Scheme_Node := New_Node (N_Iteration_Scheme, Token_Ptr); + Scan; -- past WHILE + Set_Condition (Iter_Scheme_Node, P_Condition); + + -- The following is a special test so that a miswritten for loop such + -- as "loop while I > 10;" is handled nicely, without making an extra + -- entry in the scope stack. We don't bother to actually fix up the + -- tree in this case since it's not worth the effort. Instead we just + -- eat up the loop junk, leaving the entry for what now looks like an + -- unmodified loop intact. + + if Loop_While_Flag and then Token = Tok_Semicolon then + Error_Msg_SC ("LOOP belongs here, not before WHILE"); + Pop_Scope_Stack; + return Error; + + -- Normal case + + else + Loop_Node := New_Node (N_Loop_Statement, Token_Ptr); + TF_Loop; + Set_Statements (Loop_Node, P_Sequence_Of_Statements (SS_Sreq)); + End_Statements (Loop_Node); + Set_Iteration_Scheme (Loop_Node, Iter_Scheme_Node); + + if No (Loop_Name) then + Set_Has_Created_Identifier (Loop_Node, True); + Set_Identifier (Loop_Node, + Make_Identifier (Sloc (Loop_Node), Set_Loop_Block_Name ('L'))); + else + Set_Identifier (Loop_Node, Loop_Name); + end if; + + Append_Elmt (Loop_Node, Label_List); + + return Loop_Node; + end if; + + end P_While_Statement; + + --------------------------------------- + -- 5.5 Loop Parameter Specification -- + --------------------------------------- + + -- LOOP_PARAMETER_SPECIFICATION ::= + -- DEFINING_IDENTIFIER in [reverse] DISCRETE_SUBTYPE_DEFINITION + + -- Error recovery: cannot raise Error_Resync + + function P_Loop_Parameter_Specification return Node_Id is + Loop_Param_Specification_Node : Node_Id; + + ID_Node : Node_Id; + Scan_State : Saved_Scan_State; + + begin + Loop_Param_Specification_Node := + New_Node (N_Loop_Parameter_Specification, Token_Ptr); + + Save_Scan_State (Scan_State); + ID_Node := P_Defining_Identifier; + Set_Defining_Identifier (Loop_Param_Specification_Node, ID_Node); + + if Token = Tok_Left_Paren then + Error_Msg_SC ("subscripted loop parameter not allowed"); + Restore_Scan_State (Scan_State); + Discard_Junk_Node (P_Name); + + elsif Token = Tok_Dot then + Error_Msg_SC ("selected loop parameter not allowed"); + Restore_Scan_State (Scan_State); + Discard_Junk_Node (P_Name); + end if; + + T_In; + + if Token = Tok_Reverse then + Scan; -- past REVERSE + Set_Reverse_Present (Loop_Param_Specification_Node, True); + end if; + + Set_Discrete_Subtype_Definition + (Loop_Param_Specification_Node, P_Discrete_Subtype_Definition); + return Loop_Param_Specification_Node; + + exception + when Error_Resync => + return Error; + end P_Loop_Parameter_Specification; + + -------------------------- + -- 5.6 Block Statement -- + -------------------------- + + -- BLOCK_STATEMENT ::= + -- [block_STATEMENT_IDENTIFIER:] + -- [declare + -- DECLARATIVE_PART] + -- begin + -- HANDLED_SEQUENCE_OF_STATEMENTS + -- end [block_IDENTIFIER]; + + -- The parsing of block statements is handled by one of the two functions + -- P_Declare_Statement or P_Begin_Statement depending on whether or not + -- a declare section is present + + -- P_Declare_Statement + + -- This function parses a block statement with DECLARE present + + -- The caller has checked that the initial token is DECLARE. + + -- Error recovery: cannot raise Error_Resync + + function P_Declare_Statement + (Block_Name : Node_Id := Empty) + return Node_Id + is + Block_Node : Node_Id; + + begin + Block_Node := New_Node (N_Block_Statement, Token_Ptr); + + Push_Scope_Stack; + Scope.Table (Scope.Last).Etyp := E_Name; + Scope.Table (Scope.Last).Lreq := Present (Block_Name); + Scope.Table (Scope.Last).Ecol := Start_Column; + Scope.Table (Scope.Last).Labl := Block_Name; + Scope.Table (Scope.Last).Sloc := Token_Ptr; + + Scan; -- past DECLARE + + if No (Block_Name) then + Set_Has_Created_Identifier (Block_Node, True); + Set_Identifier (Block_Node, + Make_Identifier (Sloc (Block_Node), Set_Loop_Block_Name ('B'))); + else + Set_Identifier (Block_Node, Block_Name); + end if; + + Append_Elmt (Block_Node, Label_List); + Parse_Decls_Begin_End (Block_Node); + return Block_Node; + end P_Declare_Statement; + + -- P_Begin_Statement + + -- This function parses a block statement with no DECLARE present + + -- The caller has checked that the initial token is BEGIN + + -- Error recovery: cannot raise Error_Resync + + function P_Begin_Statement + (Block_Name : Node_Id := Empty) + return Node_Id + is + Block_Node : Node_Id; + + begin + Block_Node := New_Node (N_Block_Statement, Token_Ptr); + + Push_Scope_Stack; + Scope.Table (Scope.Last).Etyp := E_Name; + Scope.Table (Scope.Last).Lreq := Present (Block_Name); + Scope.Table (Scope.Last).Ecol := Start_Column; + Scope.Table (Scope.Last).Labl := Block_Name; + Scope.Table (Scope.Last).Sloc := Token_Ptr; + + if No (Block_Name) then + Set_Has_Created_Identifier (Block_Node, True); + Set_Identifier (Block_Node, + Make_Identifier (Sloc (Block_Node), Set_Loop_Block_Name ('B'))); + else + Set_Identifier (Block_Node, Block_Name); + end if; + + Append_Elmt (Block_Node, Label_List); + + Scope.Table (Scope.Last).Ecol := Start_Column; + Scope.Table (Scope.Last).Sloc := Token_Ptr; + Scan; -- past BEGIN + Set_Handled_Statement_Sequence + (Block_Node, P_Handled_Sequence_Of_Statements); + End_Statements (Handled_Statement_Sequence (Block_Node)); + return Block_Node; + end P_Begin_Statement; + + ------------------------- + -- 5.7 Exit Statement -- + ------------------------- + + -- EXIT_STATEMENT ::= + -- exit [loop_NAME] [when CONDITION]; + + -- The caller has checked that the initial token is EXIT + + -- Error recovery: can raise Error_Resync + + function P_Exit_Statement return Node_Id is + Exit_Node : Node_Id; + + function Missing_Semicolon_On_Exit return Boolean; + -- This function deals with the following specialized situation + -- + -- when 'x' => + -- exit [identifier] + -- when 'y' => + -- + -- This looks like a messed up EXIT WHEN, when in fact the problem + -- is a missing semicolon. It is called with Token pointing to the + -- WHEN token, and returns True if a semicolon is missing before + -- the WHEN as in the above example. + + function Missing_Semicolon_On_Exit return Boolean is + State : Saved_Scan_State; + + begin + if not Token_Is_At_Start_Of_Line then + return False; + + elsif Scope.Table (Scope.Last).Etyp /= E_Case then + return False; + + else + Save_Scan_State (State); + Scan; -- past WHEN + Scan; -- past token after WHEN + + if Token = Tok_Arrow then + Restore_Scan_State (State); + return True; + else + Restore_Scan_State (State); + return False; + end if; + end if; + end Missing_Semicolon_On_Exit; + + -- Start of processing for P_Exit_Statement + + begin + Exit_Node := New_Node (N_Exit_Statement, Token_Ptr); + Scan; -- past EXIT + + if Token = Tok_Identifier then + Set_Name (Exit_Node, P_Qualified_Simple_Name); + + elsif Style_Check then + -- This EXIT has no name, so check that + -- the innermost loop is unnamed too. + + Check_No_Exit_Name : + for J in reverse 1 .. Scope.Last loop + if Scope.Table (J).Etyp = E_Loop then + if Present (Scope.Table (J).Labl) then + + -- Innermost loop in fact had a name, style check fails + + Style.No_Exit_Name (Scope.Table (J).Labl); + end if; + + exit Check_No_Exit_Name; + end if; + end loop Check_No_Exit_Name; + end if; + + if Token = Tok_When and then not Missing_Semicolon_On_Exit then + Scan; -- past WHEN + Set_Condition (Exit_Node, P_Condition); + + -- Allow IF instead of WHEN, giving error message + + elsif Token = Tok_If then + T_When; + Scan; -- past IF used in place of WHEN + Set_Condition (Exit_Node, P_Expression_No_Right_Paren); + end if; + + TF_Semicolon; + return Exit_Node; + end P_Exit_Statement; + + ------------------------- + -- 5.8 Goto Statement -- + ------------------------- + + -- GOTO_STATEMENT ::= goto label_NAME; + + -- The caller has checked that the initial token is GOTO (or TO in the + -- error case where GO and TO were incorrectly separated). + + -- Error recovery: can raise Error_Resync + + function P_Goto_Statement return Node_Id is + Goto_Node : Node_Id; + + begin + Goto_Node := New_Node (N_Goto_Statement, Token_Ptr); + Scan; -- past GOTO (or TO) + Set_Name (Goto_Node, P_Qualified_Simple_Name_Resync); + No_Constraint; + TF_Semicolon; + return Goto_Node; + end P_Goto_Statement; + + --------------------------- + -- Parse_Decls_Begin_End -- + --------------------------- + + -- This function parses the construct: + + -- DECLARATIVE_PART + -- begin + -- HANDLED_SEQUENCE_OF_STATEMENTS + -- end [NAME]; + + -- The caller has built the scope stack entry, and created the node to + -- whose Declarations and Handled_Statement_Sequence fields are to be + -- set. On return these fields are filled in (except in the case of a + -- task body, where the handled statement sequence is optional, and may + -- thus be Empty), and the scan is positioned past the End sequence. + + -- If the BEGIN is missing, then the parent node is used to help construct + -- an appropriate missing BEGIN message. Possibilities for the parent are: + + -- N_Block_Statement declare block + -- N_Entry_Body entry body + -- N_Package_Body package body (begin part optional) + -- N_Subprogram_Body procedure or function body + -- N_Task_Body task body + + -- Note: in the case of a block statement, there is definitely a DECLARE + -- present (because a Begin statement without a DECLARE is handled by the + -- P_Begin_Statement procedure, which does not call Parse_Decls_Begin_End. + + -- Error recovery: cannot raise Error_Resync + + procedure Parse_Decls_Begin_End (Parent : Node_Id) is + Body_Decl : Node_Id; + Body_Sloc : Source_Ptr; + Decls : List_Id; + Decl : Node_Id; + Parent_Nkind : Node_Kind; + Spec_Node : Node_Id; + HSS : Node_Id; + + procedure Missing_Begin (Msg : String); + -- Called to post a missing begin message. In the normal case this is + -- posted at the start of the current token. A special case arises when + -- P_Declarative_Items has previously found a missing begin, in which + -- case we replace the original error message. + + procedure Set_Null_HSS (Parent : Node_Id); + -- Construct an empty handled statement sequence and install in Parent + -- Leaves HSS set to reference the newly constructed statement sequence. + + ------------------- + -- Missing_Begin -- + ------------------- + + procedure Missing_Begin (Msg : String) is + begin + if Missing_Begin_Msg = No_Error_Msg then + Error_Msg_BC (Msg); + else + Change_Error_Text (Missing_Begin_Msg, Msg); + + -- Purge any messages issued after than, since a missing begin + -- can cause a lot of havoc, and it is better not to dump these + -- cascaded messages on the user. + + Purge_Messages (Get_Location (Missing_Begin_Msg), Prev_Token_Ptr); + end if; + end Missing_Begin; + + ------------------ + -- Set_Null_HSS -- + ------------------ + + procedure Set_Null_HSS (Parent : Node_Id) is + Null_Stm : Node_Id; + + begin + Null_Stm := + Make_Null_Statement (Token_Ptr); + Set_Comes_From_Source (Null_Stm, False); + + HSS := + Make_Handled_Sequence_Of_Statements (Token_Ptr, + Statements => New_List (Null_Stm)); + Set_Comes_From_Source (HSS, False); + + Set_Handled_Statement_Sequence (Parent, HSS); + end Set_Null_HSS; + + -- Start of processing for Parse_Decls_Begin_End + + begin + Decls := P_Declarative_Part; + + -- Check for misplacement of later vs basic declarations in Ada 83 + + if Ada_83 then + Decl := First (Decls); + + -- Loop through sequence of basic declarative items + + Outer : while Present (Decl) loop + if Nkind (Decl) /= N_Subprogram_Body + and then Nkind (Decl) /= N_Package_Body + and then Nkind (Decl) /= N_Task_Body + and then Nkind (Decl) not in N_Body_Stub + then + Next (Decl); + + -- Once a body is encountered, we only allow later declarative + -- items. The inner loop checks the rest of the list. + + else + Body_Sloc := Sloc (Decl); + + Inner : while Present (Decl) loop + if Nkind (Decl) not in N_Later_Decl_Item + and then Nkind (Decl) /= N_Pragma + then + if Ada_83 then + Error_Msg_Sloc := Body_Sloc; + Error_Msg_N + ("(Ada 83) decl cannot appear after body#", Decl); + end if; + end if; + + Next (Decl); + end loop Inner; + end if; + end loop Outer; + end if; + + -- Here is where we deal with the case of IS used instead of semicolon. + -- Specifically, if the last declaration in the declarative part is a + -- subprogram body still marked as having a bad IS, then this is where + -- we decide that the IS should really have been a semicolon and that + -- the body should have been a declaration. Note that if the bad IS + -- had turned out to be OK (i.e. a decent begin/end was found for it), + -- then the Bad_Is_Detected flag would have been reset by now. + + Body_Decl := Last (Decls); + + if Present (Body_Decl) + and then Nkind (Body_Decl) = N_Subprogram_Body + and then Bad_Is_Detected (Body_Decl) + then + -- OK, we have the case of a bad IS, so we need to fix up the tree. + -- What we have now is a subprogram body with attached declarations + -- and a possible statement sequence. + + -- First step is to take the declarations that were part of the bogus + -- subprogram body and append them to the outer declaration chain. + -- In other words we append them past the body (which we will later + -- convert into a declaration). + + Append_List (Declarations (Body_Decl), Decls); + + -- Now take the handled statement sequence of the bogus body and + -- set it as the statement sequence for the outer construct. Note + -- that it may be empty (we specially allowed a missing BEGIN for + -- a subprogram body marked as having a bad IS -- see below). + + Set_Handled_Statement_Sequence (Parent, + Handled_Statement_Sequence (Body_Decl)); + + -- Next step is to convert the old body node to a declaration node + + Spec_Node := Specification (Body_Decl); + Change_Node (Body_Decl, N_Subprogram_Declaration); + Set_Specification (Body_Decl, Spec_Node); + + -- Final step is to put the declarations for the parent where + -- they belong, and then fall through the IF to scan out the + -- END statements. + + Set_Declarations (Parent, Decls); + + -- This is the normal case (i.e. any case except the bad IS case) + -- If we have a BEGIN, then scan out the sequence of statements, and + -- also reset the expected column for the END to match the BEGIN. + + else + Set_Declarations (Parent, Decls); + + if Token = Tok_Begin then + if Style_Check then Style.Check_Indentation; end if; + + Error_Msg_Col := Scope.Table (Scope.Last).Ecol; + + if Style.RM_Column_Check + and then Token_Is_At_Start_Of_Line + and then Start_Column /= Error_Msg_Col + then + Error_Msg_SC ("(style) BEGIN in wrong column, should be@"); + + else + Scope.Table (Scope.Last).Ecol := Start_Column; + end if; + + Scope.Table (Scope.Last).Sloc := Token_Ptr; + Scan; -- past BEGIN + Set_Handled_Statement_Sequence (Parent, + P_Handled_Sequence_Of_Statements); + + -- No BEGIN present + + else + Parent_Nkind := Nkind (Parent); + + -- A special check for the missing IS case. If we have a + -- subprogram body that was marked as having a suspicious + -- IS, and the current token is END, then we simply confirm + -- the suspicion, and do not require a BEGIN to be present + + if Parent_Nkind = N_Subprogram_Body + and then Token = Tok_End + and then Scope.Table (Scope.Last).Etyp = E_Suspicious_Is + then + Scope.Table (Scope.Last).Etyp := E_Bad_Is; + + -- Otherwise BEGIN is not required for a package body, so we + -- don't mind if it is missing, but we do construct a dummy + -- one (so that we have somewhere to set End_Label). + + -- However if we have something other than a BEGIN which + -- looks like it might be statements, then we signal a missing + -- BEGIN for these cases as well. We define "something which + -- looks like it might be statements" as a token other than + -- END, EOF, or a token which starts declarations. + + elsif Parent_Nkind = N_Package_Body + and then (Token = Tok_End + or else Token = Tok_EOF + or else Token in Token_Class_Declk) + then + Set_Null_HSS (Parent); + + -- These are cases in which a BEGIN is required and not present + + else + Set_Null_HSS (Parent); + + -- Prepare to issue error message + + Error_Msg_Sloc := Scope.Table (Scope.Last).Sloc; + Error_Msg_Node_1 := Scope.Table (Scope.Last).Labl; + + -- Now issue appropriate message + + if Parent_Nkind = N_Block_Statement then + Missing_Begin ("missing BEGIN for DECLARE#!"); + + elsif Parent_Nkind = N_Entry_Body then + Missing_Begin ("missing BEGIN for ENTRY#!"); + + elsif Parent_Nkind = N_Subprogram_Body then + if Nkind (Specification (Parent)) + = N_Function_Specification + then + Missing_Begin ("missing BEGIN for function&#!"); + else + Missing_Begin ("missing BEGIN for procedure&#!"); + end if; + + -- The case for package body arises only when + -- we have possible statement junk present. + + elsif Parent_Nkind = N_Package_Body then + Missing_Begin ("missing BEGIN for package body&#!"); + + else + pragma Assert (Parent_Nkind = N_Task_Body); + Missing_Begin ("missing BEGIN for task body&#!"); + end if; + + -- Here we pick up the statements after the BEGIN that + -- should have been present but was not. We don't insist + -- on statements being present if P_Declarative_Part had + -- already found a missing BEGIN, since it might have + -- swallowed a lone statement into the declarative part. + + if Missing_Begin_Msg /= No_Error_Msg + and then Token = Tok_End + then + null; + else + Set_Handled_Statement_Sequence (Parent, + P_Handled_Sequence_Of_Statements); + end if; + end if; + end if; + end if; + + -- Here with declarations and handled statement sequence scanned + + if Present (Handled_Statement_Sequence (Parent)) then + End_Statements (Handled_Statement_Sequence (Parent)); + else + End_Statements; + end if; + + -- We know that End_Statements removed an entry from the scope stack + -- (because it is required to do so under all circumstances). We can + -- therefore reference the entry it removed one past the stack top. + -- What we are interested in is whether it was a case of a bad IS. + + if Scope.Table (Scope.Last + 1).Etyp = E_Bad_Is then + Error_Msg ("IS should be "";""", Scope.Table (Scope.Last + 1).S_Is); + Set_Bad_Is_Detected (Parent, True); + end if; + + end Parse_Decls_Begin_End; + + ------------------------- + -- Set_Loop_Block_Name -- + ------------------------- + + function Set_Loop_Block_Name (L : Character) return Name_Id is + begin + Name_Buffer (1) := L; + Name_Buffer (2) := '_'; + Name_Len := 2; + Loop_Block_Count := Loop_Block_Count + 1; + Add_Nat_To_Name_Buffer (Loop_Block_Count); + return Name_Find; + end Set_Loop_Block_Name; + + --------------- + -- Then_Scan -- + --------------- + + procedure Then_Scan is + begin + TF_Then; + + while Token = Tok_Then loop + Error_Msg_SC ("redundant THEN"); + TF_Then; + end loop; + + if Token = Tok_And or else Token = Tok_Or then + Error_Msg_SC ("unexpected logical operator"); + Scan; + + if (Prev_Token = Tok_And and then Token = Tok_Then) + or else + (Prev_Token = Tok_Or and then Token = Tok_Else) + then + Scan; + end if; + + Discard_Junk_Node (P_Expression); + end if; + + if Token = Tok_Then then + Scan; + end if; + end Then_Scan; + +end Ch5; diff --git a/gcc/ada/par-ch6.adb b/gcc/ada/par-ch6.adb new file mode 100644 index 00000000000..d5d1d3daaa1 --- /dev/null +++ b/gcc/ada/par-ch6.adb @@ -0,0 +1,1165 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P A R . C H 6 -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.81 $ +-- -- +-- Copyright (C) 1992-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +pragma Style_Checks (All_Checks); +-- Turn off subprogram body ordering check. Subprograms are in order +-- by RM section rather than alphabetical + +with Sinfo.CN; use Sinfo.CN; + +separate (Par) +package body Ch6 is + + -- Local subprograms, used only in this chapter + + function P_Defining_Designator return Node_Id; + function P_Defining_Operator_Symbol return Node_Id; + + procedure Check_Junk_Semicolon_Before_Return; + -- Check for common error of junk semicolon before RETURN keyword of + -- function specification. If present, skip over it with appropriate + -- error message, leaving Scan_Ptr pointing to the RETURN after. This + -- routine also deals with a possibly misspelled version of Return. + + ---------------------------------------- + -- Check_Junk_Semicolon_Before_Return -- + ---------------------------------------- + + procedure Check_Junk_Semicolon_Before_Return is + Scan_State : Saved_Scan_State; + + begin + if Token = Tok_Semicolon then + Save_Scan_State (Scan_State); + Scan; -- past the semicolon + + if Token = Tok_Return then + Restore_Scan_State (Scan_State); + Error_Msg_SC ("Unexpected semicolon ignored"); + Scan; -- rescan past junk semicolon + + else + Restore_Scan_State (Scan_State); + end if; + + elsif Bad_Spelling_Of (Tok_Return) then + null; + end if; + end Check_Junk_Semicolon_Before_Return; + + ----------------------------------------------------- + -- 6.1 Subprogram (Also 6.3, 8.5.4, 10.1.3, 12.3) -- + ----------------------------------------------------- + + -- This routine scans out a subprogram declaration, subprogram body, + -- subprogram renaming declaration or subprogram generic instantiation. + + -- SUBPROGRAM_DECLARATION ::= SUBPROGRAM_SPECIFICATION; + + -- ABSTRACT_SUBPROGRAM_DECLARATION ::= + -- SUBPROGRAM_SPECIFICATION is abstract; + + -- SUBPROGRAM_SPECIFICATION ::= + -- procedure DEFINING_PROGRAM_UNIT_NAME PARAMETER_PROFILE + -- | function DEFINING_DESIGNATOR PARAMETER_AND_RESULT_PROFILE + + -- PARAMETER_PROFILE ::= [FORMAL_PART] + + -- PARAMETER_AND_RESULT_PROFILE ::= [FORMAL_PART] return SUBTYPE_MARK + + -- SUBPROGRAM_BODY ::= + -- SUBPROGRAM_SPECIFICATION is + -- DECLARATIVE_PART + -- begin + -- HANDLED_SEQUENCE_OF_STATEMENTS + -- end [DESIGNATOR]; + + -- SUBPROGRAM_RENAMING_DECLARATION ::= + -- SUBPROGRAM_SPECIFICATION renames callable_entity_NAME; + + -- SUBPROGRAM_BODY_STUB ::= + -- SUBPROGRAM_SPECIFICATION is separate; + + -- GENERIC_INSTANTIATION ::= + -- procedure DEFINING_PROGRAM_UNIT_NAME is + -- new generic_procedure_NAME [GENERIC_ACTUAL_PART]; + -- | function DEFINING_DESIGNATOR is + -- new generic_function_NAME [GENERIC_ACTUAL_PART]; + + -- The value in Pf_Flags indicates which of these possible declarations + -- is acceptable to the caller: + + -- Pf_Flags.Decl Set if declaration OK + -- Pf_Flags.Gins Set if generic instantiation OK + -- Pf_Flags.Pbod Set if proper body OK + -- Pf_Flags.Rnam Set if renaming declaration OK + -- Pf_Flags.Stub Set if body stub OK + + -- If an inappropriate form is encountered, it is scanned out but an + -- error message indicating that it is appearing in an inappropriate + -- context is issued. The only possible values for Pf_Flags are those + -- defined as constants in the Par package. + + -- The caller has checked that the initial token is FUNCTION or PROCEDURE + + -- Error recovery: cannot raise Error_Resync + + function P_Subprogram (Pf_Flags : Pf_Rec) return Node_Id is + Specification_Node : Node_Id; + Name_Node : Node_Id; + Fpart_List : List_Id; + Fpart_Sloc : Source_Ptr; + Return_Node : Node_Id; + Inst_Node : Node_Id; + Body_Node : Node_Id; + Decl_Node : Node_Id; + Rename_Node : Node_Id; + Absdec_Node : Node_Id; + Stub_Node : Node_Id; + Fproc_Sloc : Source_Ptr; + Func : Boolean; + Scan_State : Saved_Scan_State; + + begin + -- Set up scope stack entry. Note that the Labl field will be set later + + SIS_Entry_Active := False; + SIS_Missing_Semicolon_Message := No_Error_Msg; + Push_Scope_Stack; + Scope.Table (Scope.Last).Sloc := Token_Ptr; + Scope.Table (Scope.Last).Etyp := E_Name; + Scope.Table (Scope.Last).Ecol := Start_Column; + Scope.Table (Scope.Last).Lreq := False; + + Func := (Token = Tok_Function); + Fproc_Sloc := Token_Ptr; + Scan; -- past FUNCTION or PROCEDURE + Ignore (Tok_Type); + Ignore (Tok_Body); + + if Func then + Name_Node := P_Defining_Designator; + + if Nkind (Name_Node) = N_Defining_Operator_Symbol + and then Scope.Last = 1 + then + Error_Msg_SP ("operator symbol not allowed at library level"); + Name_Node := New_Entity (N_Defining_Identifier, Sloc (Name_Node)); + + -- Set name from file name, we need some junk name, and that's + -- as good as anything. This is only approximate, since we do + -- not do anything with non-standard name translations. + + Get_Name_String (File_Name (Current_Source_File)); + + for J in 1 .. Name_Len loop + if Name_Buffer (J) = '.' then + Name_Len := J - 1; + exit; + end if; + end loop; + + Set_Chars (Name_Node, Name_Find); + Set_Error_Posted (Name_Node); + end if; + + else + Name_Node := P_Defining_Program_Unit_Name; + end if; + + Scope.Table (Scope.Last).Labl := Name_Node; + + if Token = Tok_Colon then + Error_Msg_SC ("redundant colon ignored"); + Scan; -- past colon + end if; + + -- Deal with generic instantiation, the one case in which we do not + -- have a subprogram specification as part of whatever we are parsing + + if Token = Tok_Is then + Save_Scan_State (Scan_State); -- at the IS + T_Is; -- checks for redundant IS's + + if Token = Tok_New then + if not Pf_Flags.Gins then + Error_Msg_SC ("generic instantation not allowed here!"); + end if; + + Scan; -- past NEW + + if Func then + Inst_Node := New_Node (N_Function_Instantiation, Fproc_Sloc); + Set_Name (Inst_Node, P_Function_Name); + else + Inst_Node := New_Node (N_Procedure_Instantiation, Fproc_Sloc); + Set_Name (Inst_Node, P_Qualified_Simple_Name); + end if; + + Set_Defining_Unit_Name (Inst_Node, Name_Node); + Set_Generic_Associations (Inst_Node, P_Generic_Actual_Part_Opt); + TF_Semicolon; + Pop_Scope_Stack; -- Don't need scope stack entry in this case + return Inst_Node; + + else + Restore_Scan_State (Scan_State); -- to the IS + end if; + end if; + + -- If not a generic instantiation, then we definitely have a subprogram + -- specification (all possibilities at this stage include one here) + + Fpart_Sloc := Token_Ptr; + + Check_Misspelling_Of (Tok_Return); + + -- Scan formal part. First a special error check. If we have an + -- identifier here, then we have a definite error. If this identifier + -- is on the same line as the designator, then we assume it is the + -- first formal after a missing left parenthesis + + if Token = Tok_Identifier + and then not Token_Is_At_Start_Of_Line + then + T_Left_Paren; -- to generate message + Fpart_List := P_Formal_Part; + + -- Otherwise scan out an optional formal part in the usual manner + + else + Fpart_List := P_Parameter_Profile; + end if; + + -- We treat what we have as a function specification if FUNCTION was + -- used, or if a RETURN is present. This gives better error recovery + -- since later RETURN statements will be valid in either case. + + Check_Junk_Semicolon_Before_Return; + Return_Node := Error; + + if Token = Tok_Return then + if not Func then + Error_Msg ("PROCEDURE should be FUNCTION", Fproc_Sloc); + Func := True; + end if; + + Scan; -- past RETURN + Return_Node := P_Subtype_Mark; + No_Constraint; + + else + if Func then + Ignore (Tok_Right_Paren); + TF_Return; + end if; + end if; + + if Func then + Specification_Node := + New_Node (N_Function_Specification, Fproc_Sloc); + Set_Subtype_Mark (Specification_Node, Return_Node); + + else + Specification_Node := + New_Node (N_Procedure_Specification, Fproc_Sloc); + end if; + + Set_Defining_Unit_Name (Specification_Node, Name_Node); + Set_Parameter_Specifications (Specification_Node, Fpart_List); + + -- Error check: barriers not allowed on protected functions/procedures + + if Token = Tok_When then + if Func then + Error_Msg_SC ("barrier not allowed on function, only on entry"); + else + Error_Msg_SC ("barrier not allowed on procedure, only on entry"); + end if; + + Scan; -- past WHEN + Discard_Junk_Node (P_Expression); + end if; + + -- Deal with case of semicolon ending a subprogram declaration + + if Token = Tok_Semicolon then + if not Pf_Flags.Decl then + T_Is; + end if; + + Scan; -- past semicolon + + -- If semicolon is immediately followed by IS, then ignore the + -- semicolon, and go process the body. + + if Token = Tok_Is then + Error_Msg_SP ("unexpected semicolon ignored"); + T_Is; -- ignroe redundant IS's + goto Subprogram_Body; + + -- If BEGIN follows in an appropriate column, we immediately + -- commence the error action of assuming that the previous + -- subprogram declaration should have been a subprogram body, + -- i.e. that the terminating semicolon should have been IS. + + elsif Token = Tok_Begin + and then Start_Column >= Scope.Table (Scope.Last).Ecol + then + Error_Msg_SP (""";"" should be IS!"); + goto Subprogram_Body; + + else + goto Subprogram_Declaration; + end if; + + -- Case of not followed by semicolon + + else + -- Subprogram renaming declaration case + + Check_Misspelling_Of (Tok_Renames); + + if Token = Tok_Renames then + if not Pf_Flags.Rnam then + Error_Msg_SC ("renaming declaration not allowed here!"); + end if; + + Rename_Node := + New_Node (N_Subprogram_Renaming_Declaration, Token_Ptr); + Scan; -- past RENAMES + Set_Name (Rename_Node, P_Name); + Set_Specification (Rename_Node, Specification_Node); + TF_Semicolon; + Pop_Scope_Stack; + return Rename_Node; + + -- Case of IS following subprogram specification + + elsif Token = Tok_Is then + T_Is; -- ignore redundant Is's + + if Token_Name = Name_Abstract then + Check_95_Keyword (Tok_Abstract, Tok_Semicolon); + end if; + + -- Deal nicely with (now obsolete) use of <> in place of abstract + + if Token = Tok_Box then + Error_Msg_SC ("ABSTRACT expected"); + Token := Tok_Abstract; + end if; + + -- Abstract subprogram declaration case + + if Token = Tok_Abstract then + Absdec_Node := + New_Node (N_Abstract_Subprogram_Declaration, Token_Ptr); + Set_Specification (Absdec_Node, Specification_Node); + Pop_Scope_Stack; -- discard unneeded entry + Scan; -- past ABSTRACT + TF_Semicolon; + return Absdec_Node; + + -- Check for IS NEW with Formal_Part present and handle nicely + + elsif Token = Tok_New then + Error_Msg + ("formal part not allowed in instantiation", Fpart_Sloc); + Scan; -- past NEW + + if Func then + Inst_Node := New_Node (N_Function_Instantiation, Fproc_Sloc); + else + Inst_Node := + New_Node (N_Procedure_Instantiation, Fproc_Sloc); + end if; + + Set_Defining_Unit_Name (Inst_Node, Name_Node); + Set_Name (Inst_Node, P_Name); + Set_Generic_Associations (Inst_Node, P_Generic_Actual_Part_Opt); + TF_Semicolon; + Pop_Scope_Stack; -- Don't need scope stack entry in this case + return Inst_Node; + + else + goto Subprogram_Body; + end if; + + -- Here we have a missing IS or missing semicolon, we always guess + -- a missing semicolon, since we are pretty good at fixing up a + -- semicolon which should really be an IS + + else + Error_Msg_AP ("missing "";"""); + SIS_Missing_Semicolon_Message := Get_Msg_Id; + goto Subprogram_Declaration; + end if; + end if; + + -- Processing for subprogram body + + <<Subprogram_Body>> + if not Pf_Flags.Pbod then + Error_Msg_SP ("subprogram body not allowed here!"); + end if; + + -- Subprogram body stub case + + if Separate_Present then + if not Pf_Flags.Stub then + Error_Msg_SC ("body stub not allowed here!"); + end if; + + if Nkind (Name_Node) = N_Defining_Operator_Symbol then + Error_Msg + ("operator symbol cannot be used as subunit name", + Sloc (Name_Node)); + end if; + + Stub_Node := + New_Node (N_Subprogram_Body_Stub, Sloc (Specification_Node)); + Set_Specification (Stub_Node, Specification_Node); + Scan; -- past SEPARATE + Pop_Scope_Stack; + TF_Semicolon; + return Stub_Node; + + -- Subprogram body case + + else + -- Here is the test for a suspicious IS (i.e. one that looks + -- like it might more properly be a semicolon). See separate + -- section discussing use of IS instead of semicolon in + -- package Parse. + + if (Token in Token_Class_Declk + or else + Token = Tok_Identifier) + and then Start_Column <= Scope.Table (Scope.Last).Ecol + and then Scope.Last /= 1 + then + Scope.Table (Scope.Last).Etyp := E_Suspicious_Is; + Scope.Table (Scope.Last).S_Is := Prev_Token_Ptr; + end if; + + Body_Node := + New_Node (N_Subprogram_Body, Sloc (Specification_Node)); + Set_Specification (Body_Node, Specification_Node); + Parse_Decls_Begin_End (Body_Node); + return Body_Node; + end if; + + -- Processing for subprogram declaration + + <<Subprogram_Declaration>> + Decl_Node := + New_Node (N_Subprogram_Declaration, Sloc (Specification_Node)); + Set_Specification (Decl_Node, Specification_Node); + + -- If this is a context in which a subprogram body is permitted, + -- set active SIS entry in case (see section titled "Handling + -- Semicolon Used in Place of IS" in body of Parser package) + -- Note that SIS_Missing_Semicolon_Message is already set properly. + + if Pf_Flags.Pbod then + SIS_Labl := Scope.Table (Scope.Last).Labl; + SIS_Sloc := Scope.Table (Scope.Last).Sloc; + SIS_Ecol := Scope.Table (Scope.Last).Ecol; + SIS_Declaration_Node := Decl_Node; + SIS_Semicolon_Sloc := Prev_Token_Ptr; + SIS_Entry_Active := True; + end if; + + Pop_Scope_Stack; + return Decl_Node; + + end P_Subprogram; + + --------------------------------- + -- 6.1 Subprogram Declaration -- + --------------------------------- + + -- Parsed by P_Subprogram (6.1) + + ------------------------------------------ + -- 6.1 Abstract Subprogram Declaration -- + ------------------------------------------ + + -- Parsed by P_Subprogram (6.1) + + ----------------------------------- + -- 6.1 Subprogram Specification -- + ----------------------------------- + + -- SUBPROGRAM_SPECIFICATION ::= + -- procedure DEFINING_PROGRAM_UNIT_NAME PARAMETER_PROFILE + -- | function DEFINING_DESIGNATOR PARAMETER_AND_RESULT_PROFILE + + -- PARAMETER_PROFILE ::= [FORMAL_PART] + + -- PARAMETER_AND_RESULT_PROFILE ::= [FORMAL_PART] return SUBTYPE_MARK + + -- Subprogram specifications that appear in subprogram declarations + -- are parsed by P_Subprogram (6.1). This routine is used in other + -- contexts where subprogram specifications occur. + + -- Note: this routine does not affect the scope stack in any way + + -- Error recovery: can raise Error_Resync + + function P_Subprogram_Specification return Node_Id is + Specification_Node : Node_Id; + + begin + if Token = Tok_Function then + Specification_Node := New_Node (N_Function_Specification, Token_Ptr); + Scan; -- past FUNCTION + Ignore (Tok_Body); + Set_Defining_Unit_Name (Specification_Node, P_Defining_Designator); + Set_Parameter_Specifications + (Specification_Node, P_Parameter_Profile); + Check_Junk_Semicolon_Before_Return; + TF_Return; + Set_Subtype_Mark (Specification_Node, P_Subtype_Mark); + No_Constraint; + return Specification_Node; + + elsif Token = Tok_Procedure then + Specification_Node := New_Node (N_Procedure_Specification, Token_Ptr); + Scan; -- past PROCEDURE + Ignore (Tok_Body); + Set_Defining_Unit_Name + (Specification_Node, P_Defining_Program_Unit_Name); + Set_Parameter_Specifications + (Specification_Node, P_Parameter_Profile); + return Specification_Node; + + else + Error_Msg_SC ("subprogram specification expected"); + raise Error_Resync; + end if; + end P_Subprogram_Specification; + + --------------------- + -- 6.1 Designator -- + --------------------- + + -- DESIGNATOR ::= + -- [PARENT_UNIT_NAME .] IDENTIFIER | OPERATOR_SYMBOL + + -- The caller has checked that the initial token is an identifier, + -- operator symbol, or string literal. Note that we don't bother to + -- do much error diagnosis in this routine, since it is only used for + -- the label on END lines, and the routines in package Par.Endh will + -- check that the label is appropriate. + + -- Error recovery: cannot raise Error_Resync + + function P_Designator return Node_Id is + Ident_Node : Node_Id; + Name_Node : Node_Id; + Prefix_Node : Node_Id; + + function Real_Dot return Boolean; + -- Tests if a current token is an interesting period, i.e. is followed + -- by an identifier or operator symbol or string literal. If not, it is + -- probably just incorrect punctuation to be caught by our caller. Note + -- that the case of an operator symbol or string literal is also an + -- error, but that is an error that we catch here. If the result is + -- True, a real dot has been scanned and we are positioned past it, + -- if the result is False, the scan position is unchanged. + + function Real_Dot return Boolean is + Scan_State : Saved_Scan_State; + + begin + if Token /= Tok_Dot then + return False; + + else + Save_Scan_State (Scan_State); + Scan; -- past dot + + if Token = Tok_Identifier + or else Token = Tok_Operator_Symbol + or else Token = Tok_String_Literal + then + return True; + + else + Restore_Scan_State (Scan_State); + return False; + end if; + end if; + end Real_Dot; + + -- Start of processing for P_Designator + + begin + Ident_Node := Token_Node; + Scan; -- past initial token + + if Prev_Token = Tok_Operator_Symbol + or else Prev_Token = Tok_String_Literal + or else not Real_Dot + then + return Ident_Node; + + -- Child name case + + else + Prefix_Node := Ident_Node; + + -- Loop through child names, on entry to this loop, Prefix contains + -- the name scanned so far, and Ident_Node is the last identifier. + + loop + Name_Node := New_Node (N_Selected_Component, Prev_Token_Ptr); + Set_Prefix (Name_Node, Prefix_Node); + Ident_Node := P_Identifier; + Set_Selector_Name (Name_Node, Ident_Node); + Prefix_Node := Name_Node; + exit when not Real_Dot; + end loop; + + -- On exit from the loop, Ident_Node is the last identifier scanned, + -- i.e. the defining identifier, and Prefix_Node is a node for the + -- entire name, structured (incorrectly!) as a selected component. + + Name_Node := Prefix (Prefix_Node); + Change_Node (Prefix_Node, N_Designator); + Set_Name (Prefix_Node, Name_Node); + Set_Identifier (Prefix_Node, Ident_Node); + return Prefix_Node; + end if; + + exception + when Error_Resync => + while Token = Tok_Dot or else Token = Tok_Identifier loop + Scan; + end loop; + + return Error; + end P_Designator; + + ------------------------------ + -- 6.1 Defining Designator -- + ------------------------------ + + -- DEFINING_DESIGNATOR ::= + -- DEFINING_PROGRAM_UNIT_NAME | DEFINING_OPERATOR_SYMBOL + + -- Error recovery: cannot raise Error_Resync + + function P_Defining_Designator return Node_Id is + begin + if Token = Tok_Operator_Symbol then + return P_Defining_Operator_Symbol; + + elsif Token = Tok_String_Literal then + Error_Msg_SC ("invalid operator name"); + Scan; -- past junk string + return Error; + + else + return P_Defining_Program_Unit_Name; + end if; + end P_Defining_Designator; + + ------------------------------------- + -- 6.1 Defining Program Unit Name -- + ------------------------------------- + + -- DEFINING_PROGRAM_UNIT_NAME ::= + -- [PARENT_UNIT_NAME .] DEFINING_IDENTIFIER + + -- Note: PARENT_UNIT_NAME may be present only in 95 mode at the outer level + + -- Error recovery: cannot raise Error_Resync + + function P_Defining_Program_Unit_Name return Node_Id is + Ident_Node : Node_Id; + Name_Node : Node_Id; + Prefix_Node : Node_Id; + + begin + -- Set identifier casing if not already set and scan initial identifier + + if Token = Tok_Identifier + and then Identifier_Casing (Current_Source_File) = Unknown + then + Set_Identifier_Casing (Current_Source_File, Determine_Token_Casing); + end if; + + Ident_Node := P_Identifier; + Merge_Identifier (Ident_Node, Tok_Return); + + -- Normal case (not child library unit name) + + if Token /= Tok_Dot then + Change_Identifier_To_Defining_Identifier (Ident_Node); + return Ident_Node; + + -- Child library unit name case + + else + if Scope.Last > 1 then + Error_Msg_SP ("child unit allowed only at library level"); + raise Error_Resync; + + elsif Ada_83 then + Error_Msg_SP ("(Ada 83) child unit not allowed!"); + + end if; + + Prefix_Node := Ident_Node; + + -- Loop through child names, on entry to this loop, Prefix contains + -- the name scanned so far, and Ident_Node is the last identifier. + + loop + exit when Token /= Tok_Dot; + Name_Node := New_Node (N_Selected_Component, Token_Ptr); + Scan; -- past period + Set_Prefix (Name_Node, Prefix_Node); + Ident_Node := P_Identifier; + Set_Selector_Name (Name_Node, Ident_Node); + Prefix_Node := Name_Node; + end loop; + + -- On exit from the loop, Ident_Node is the last identifier scanned, + -- i.e. the defining identifier, and Prefix_Node is a node for the + -- entire name, structured (incorrectly!) as a selected component. + + Name_Node := Prefix (Prefix_Node); + Change_Node (Prefix_Node, N_Defining_Program_Unit_Name); + Set_Name (Prefix_Node, Name_Node); + Change_Identifier_To_Defining_Identifier (Ident_Node); + Set_Defining_Identifier (Prefix_Node, Ident_Node); + + -- All set with unit name parsed + + return Prefix_Node; + end if; + + exception + when Error_Resync => + while Token = Tok_Dot or else Token = Tok_Identifier loop + Scan; + end loop; + + return Error; + end P_Defining_Program_Unit_Name; + + -------------------------- + -- 6.1 Operator Symbol -- + -------------------------- + + -- OPERATOR_SYMBOL ::= STRING_LITERAL + + -- Operator symbol is returned by the scanner as Tok_Operator_Symbol + + ----------------------------------- + -- 6.1 Defining Operator Symbol -- + ----------------------------------- + + -- DEFINING_OPERATOR_SYMBOL ::= OPERATOR_SYMBOL + + -- The caller has checked that the initial symbol is an operator symbol + + function P_Defining_Operator_Symbol return Node_Id is + Op_Node : Node_Id; + + begin + Op_Node := Token_Node; + Change_Operator_Symbol_To_Defining_Operator_Symbol (Op_Node); + Scan; -- past operator symbol + return Op_Node; + end P_Defining_Operator_Symbol; + + ---------------------------- + -- 6.1 Parameter_Profile -- + ---------------------------- + + -- PARAMETER_PROFILE ::= [FORMAL_PART] + + -- Empty is returned if no formal part is present + + -- Error recovery: cannot raise Error_Resync + + function P_Parameter_Profile return List_Id is + begin + if Token = Tok_Left_Paren then + Scan; -- part left paren + return P_Formal_Part; + else + return No_List; + end if; + end P_Parameter_Profile; + + --------------------------------------- + -- 6.1 Parameter And Result Profile -- + --------------------------------------- + + -- Parsed by its parent construct, which uses P_Parameter_Profile to + -- parse the parameters, and P_Subtype_Mark to parse the return type. + + ---------------------- + -- 6.1 Formal part -- + ---------------------- + + -- FORMAL_PART ::= (PARAMETER_SPECIFICATION {; PARAMETER_SPECIFICATION}) + + -- PARAMETER_SPECIFICATION ::= + -- DEFINING_IDENTIFIER_LIST : MODE SUBTYPE_MARK + -- [:= DEFAULT_EXPRESSION] + -- | DEFINING_IDENTIFIER_LIST : ACCESS_DEFINITION + -- [:= DEFAULT_EXPRESSION] + + -- This scans the construct Formal_Part. The caller has already checked + -- that the initial token is a left parenthesis, and skipped past it, so + -- that on entry Token is the first token following the left parenthesis. + + -- Error recovery: cannot raise Error_Resync + + function P_Formal_Part return List_Id is + Specification_List : List_Id; + Specification_Node : Node_Id; + Scan_State : Saved_Scan_State; + Num_Idents : Nat; + Ident : Nat; + Ident_Sloc : Source_Ptr; + + Idents : array (Int range 1 .. 4096) of Entity_Id; + -- This array holds the list of defining identifiers. The upper bound + -- of 4096 is intended to be essentially infinite, and we do not even + -- bother to check for it being exceeded. + + begin + Specification_List := New_List; + + Specification_Loop : loop + begin + if Token = Tok_Pragma then + P_Pragmas_Misplaced; + end if; + + Ignore (Tok_Left_Paren); + Ident_Sloc := Token_Ptr; + Idents (1) := P_Defining_Identifier; + Num_Idents := 1; + + Ident_Loop : loop + exit Ident_Loop when Token = Tok_Colon; + + -- The only valid tokens are colon and comma, so if we have + -- neither do a bit of investigation to see which is the + -- better choice for insertion. + + if Token /= Tok_Comma then + + -- Assume colon if IN or OUT keyword found + + exit Ident_Loop when Token = Tok_In or else Token = Tok_Out; + + -- Otherwise scan ahead + + Save_Scan_State (Scan_State); + Look_Ahead : loop + + -- If we run into a semicolon, then assume that a + -- colon was missing, e.g. Parms (X Y; ...). Also + -- assume missing colon on EOF (a real disaster!) + -- and on a right paren, e.g. Parms (X Y), and also + -- on an assignment symbol, e.g. Parms (X Y := ..) + + if Token = Tok_Semicolon + or else Token = Tok_Right_Paren + or else Token = Tok_EOF + or else Token = Tok_Colon_Equal + then + Restore_Scan_State (Scan_State); + exit Ident_Loop; + + -- If we run into a colon, assume that we had a missing + -- comma, e.g. Parms (A B : ...). Also assume a missing + -- comma if we hit another comma, e.g. Parms (A B, C ..) + + elsif Token = Tok_Colon + or else Token = Tok_Comma + then + Restore_Scan_State (Scan_State); + exit Look_Ahead; + end if; + + Scan; + end loop Look_Ahead; + end if; + + -- Here if a comma is present, or to be assumed + + T_Comma; + Num_Idents := Num_Idents + 1; + Idents (Num_Idents) := P_Defining_Identifier; + end loop Ident_Loop; + + -- Fall through the loop on encountering a colon, or deciding + -- that there is a missing colon. + + T_Colon; + + -- If there are multiple identifiers, we repeatedly scan the + -- type and initialization expression information by resetting + -- the scan pointer (so that we get completely separate trees + -- for each occurrence). + + if Num_Idents > 1 then + Save_Scan_State (Scan_State); + end if; + + -- Loop through defining identifiers in list + + Ident := 1; + + Ident_List_Loop : loop + Specification_Node := + New_Node (N_Parameter_Specification, Ident_Sloc); + Set_Defining_Identifier (Specification_Node, Idents (Ident)); + + if Token = Tok_Access then + if Ada_83 then + Error_Msg_SC ("(Ada 83) access parameters not allowed"); + end if; + + Set_Parameter_Type + (Specification_Node, P_Access_Definition); + + else + P_Mode (Specification_Node); + + if Token = Tok_Procedure + or else + Token = Tok_Function + then + Error_Msg_SC ("formal subprogram parameter not allowed"); + Scan; + + if Token = Tok_Left_Paren then + Discard_Junk_List (P_Formal_Part); + end if; + + if Token = Tok_Return then + Scan; + Discard_Junk_Node (P_Subtype_Mark); + end if; + + Set_Parameter_Type (Specification_Node, Error); + + else + Set_Parameter_Type (Specification_Node, P_Subtype_Mark); + No_Constraint; + end if; + end if; + + Set_Expression (Specification_Node, Init_Expr_Opt (True)); + + if Ident > 1 then + Set_Prev_Ids (Specification_Node, True); + end if; + + if Ident < Num_Idents then + Set_More_Ids (Specification_Node, True); + end if; + + Append (Specification_Node, Specification_List); + exit Ident_List_Loop when Ident = Num_Idents; + Ident := Ident + 1; + Restore_Scan_State (Scan_State); + end loop Ident_List_Loop; + + exception + when Error_Resync => + Resync_Semicolon_List; + end; + + if Token = Tok_Semicolon then + Scan; -- past semicolon + + -- If we have RETURN or IS after the semicolon, then assume + -- that semicolon should have been a right parenthesis and exit + + if Token = Tok_Is or else Token = Tok_Return then + Error_Msg_SP ("expected "")"" in place of "";"""); + exit Specification_Loop; + end if; + + elsif Token = Tok_Right_Paren then + Scan; -- past right paren + exit Specification_Loop; + + -- Special check for common error of using comma instead of semicolon + + elsif Token = Tok_Comma then + T_Semicolon; + Scan; -- past comma + + -- Special check for omitted separator + + elsif Token = Tok_Identifier then + T_Semicolon; + + -- If nothing sensible, skip to next semicolon or right paren + + else + T_Semicolon; + Resync_Semicolon_List; + + if Token = Tok_Semicolon then + Scan; -- past semicolon + else + T_Right_Paren; + exit Specification_Loop; + end if; + end if; + end loop Specification_Loop; + + return Specification_List; + end P_Formal_Part; + + ---------------------------------- + -- 6.1 Parameter Specification -- + ---------------------------------- + + -- Parsed by P_Formal_Part (6.1) + + --------------- + -- 6.1 Mode -- + --------------- + + -- MODE ::= [in] | in out | out + + -- There is no explicit node in the tree for the Mode. Instead the + -- In_Present and Out_Present flags are set in the parent node to + -- record the presence of keywords specifying the mode. + + -- Error_Recovery: cannot raise Error_Resync + + procedure P_Mode (Node : Node_Id) is + begin + if Token = Tok_In then + Scan; -- past IN + Set_In_Present (Node, True); + end if; + + if Token = Tok_Out then + Scan; -- past OUT + Set_Out_Present (Node, True); + end if; + + if Token = Tok_In then + Error_Msg_SC ("IN must preceed OUT in parameter mode"); + Scan; -- past IN + Set_In_Present (Node, True); + end if; + end P_Mode; + + -------------------------- + -- 6.3 Subprogram Body -- + -------------------------- + + -- Parsed by P_Subprogram (6.1) + + ----------------------------------- + -- 6.4 Procedure Call Statement -- + ----------------------------------- + + -- Parsed by P_Sequence_Of_Statements (5.1) + + ------------------------ + -- 6.4 Function Call -- + ------------------------ + + -- Parsed by P_Call_Or_Name (4.1) + + -------------------------------- + -- 6.4 Actual Parameter Part -- + -------------------------------- + + -- Parsed by P_Call_Or_Name (4.1) + + -------------------------------- + -- 6.4 Parameter Association -- + -------------------------------- + + -- Parsed by P_Call_Or_Name (4.1) + + ------------------------------------ + -- 6.4 Explicit Actual Parameter -- + ------------------------------------ + + -- Parsed by P_Call_Or_Name (4.1) + + --------------------------- + -- 6.5 Return Statement -- + --------------------------- + + -- RETURN_STATEMENT ::= return [EXPRESSION]; + + -- The caller has checked that the initial token is RETURN + + -- Error recovery: can raise Error_Resync + + function P_Return_Statement return Node_Id is + Return_Node : Node_Id; + + begin + Return_Node := New_Node (N_Return_Statement, Token_Ptr); + + -- Sloc points to RETURN + -- Expression (Op3) + + Scan; -- past RETURN + + if Token /= Tok_Semicolon then + + -- If no semicolon, then scan an expression, except that + -- we avoid trying to scan an expression if we are at an + -- expression terminator since in that case the best error + -- message is probably that we have a missing semicolon. + + if Token not in Token_Class_Eterm then + Set_Expression (Return_Node, P_Expression_No_Right_Paren); + end if; + end if; + + TF_Semicolon; + return Return_Node; + end P_Return_Statement; + +end Ch6; diff --git a/gcc/ada/par-ch7.adb b/gcc/ada/par-ch7.adb new file mode 100644 index 00000000000..de632133f4b --- /dev/null +++ b/gcc/ada/par-ch7.adb @@ -0,0 +1,282 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P A R . C H 7 -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.29 $ +-- -- +-- Copyright (C) 1992-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +pragma Style_Checks (All_Checks); +-- Turn off subprogram body ordering check. Subprograms are in order +-- by RM section rather than alphabetical + +separate (Par) +package body Ch7 is + + --------------------------------------------- + -- 7.1 Package (also 8.5.3, 10.1.3, 12.3) -- + --------------------------------------------- + + -- This routine scans out a package declaration, package body, or a + -- renaming declaration or generic instantiation starting with PACKAGE + + -- PACKAGE_DECLARATION ::= PACKAGE_SPECIFICATION; + + -- PACKAGE_SPECIFICATION ::= + -- package DEFINING_PROGRAM_UNIT_NAME is + -- {BASIC_DECLARATIVE_ITEM} + -- [private + -- {BASIC_DECLARATIVE_ITEM}] + -- end [[PARENT_UNIT_NAME .] IDENTIFIER] + + -- PACKAGE_BODY ::= + -- package body DEFINING_PROGRAM_UNIT_NAME is + -- DECLARATIVE_PART + -- [begin + -- HANDLED_SEQUENCE_OF_STATEMENTS] + -- end [[PARENT_UNIT_NAME .] IDENTIFIER] + + -- PACKAGE_RENAMING_DECLARATION ::= + -- package DEFINING_IDENTIFIER renames package_NAME; + + -- PACKAGE_BODY_STUB ::= + -- package body DEFINING_IDENTIFIER is separate; + + -- The value in Pf_Flags indicates which of these possible declarations + -- is acceptable to the caller: + + -- Pf_Flags.Spcn Set if specification OK + -- Pf_Flags.Decl Set if declaration OK + -- Pf_Flags.Gins Set if generic instantiation OK + -- Pf_Flags.Pbod Set if proper body OK + -- Pf_Flags.Rnam Set if renaming declaration OK + -- Pf_Flags.Stub Set if body stub OK + + -- If an inappropriate form is encountered, it is scanned out but an + -- error message indicating that it is appearing in an inappropriate + -- context is issued. The only possible settings for Pf_Flags are those + -- defined as constants in package Par. + + -- Note: in all contexts where a package specification is required, there + -- is a terminating semicolon. This semicolon is scanned out in the case + -- where Pf_Flags is set to Pf_Spcn, even though it is not strictly part + -- of the package specification (it's just too much trouble, and really + -- quite unnecessary, to deal with scanning out an END where the semicolon + -- after the END is not considered to be part of the END. + + -- The caller has checked that the initial token is PACKAGE + + -- Error recovery: cannot raise Error_Resync + + function P_Package (Pf_Flags : Pf_Rec) return Node_Id is + Package_Node : Node_Id; + Specification_Node : Node_Id; + Name_Node : Node_Id; + Package_Sloc : Source_Ptr; + + begin + Push_Scope_Stack; + Scope.Table (Scope.Last).Etyp := E_Name; + Scope.Table (Scope.Last).Ecol := Start_Column; + Scope.Table (Scope.Last).Lreq := False; + + Package_Sloc := Token_Ptr; + Scan; -- past PACKAGE + + if Token = Tok_Type then + Error_Msg_SC ("TYPE not allowed here"); + Scan; -- past TYPE + end if; + + -- Case of package body. Note that we demand a package body if that + -- is the only possibility (even if the BODY keyword is not present) + + if Token = Tok_Body or else Pf_Flags = Pf_Pbod then + if not Pf_Flags.Pbod then + Error_Msg_SC ("package body cannot appear here!"); + end if; + + T_Body; + Name_Node := P_Defining_Program_Unit_Name; + Scope.Table (Scope.Last).Labl := Name_Node; + TF_Is; + + if Separate_Present then + if not Pf_Flags.Stub then + Error_Msg_SC ("body stub cannot appear here!"); + end if; + + Scan; -- past SEPARATE + TF_Semicolon; + Pop_Scope_Stack; + + Package_Node := New_Node (N_Package_Body_Stub, Package_Sloc); + Set_Defining_Identifier (Package_Node, Name_Node); + + else + Package_Node := New_Node (N_Package_Body, Package_Sloc); + Set_Defining_Unit_Name (Package_Node, Name_Node); + Parse_Decls_Begin_End (Package_Node); + end if; + + return Package_Node; + + -- Cases other than Package_Body + + else + Name_Node := P_Defining_Program_Unit_Name; + Scope.Table (Scope.Last).Labl := Name_Node; + + -- Case of renaming declaration + + Check_Misspelling_Of (Tok_Renames); + + if Token = Tok_Renames then + if not Pf_Flags.Rnam then + Error_Msg_SC ("renaming declaration cannot appear here!"); + end if; + + Scan; -- past RENAMES; + + Package_Node := + New_Node (N_Package_Renaming_Declaration, Package_Sloc); + Set_Defining_Unit_Name (Package_Node, Name_Node); + Set_Name (Package_Node, P_Qualified_Simple_Name); + + No_Constraint; + TF_Semicolon; + Pop_Scope_Stack; + return Package_Node; + + else + TF_Is; + + -- Case of generic instantiation + + if Token = Tok_New then + if not Pf_Flags.Gins then + Error_Msg_SC + ("generic instantiation cannot appear here!"); + end if; + + Scan; -- past NEW + + Package_Node := + New_Node (N_Package_Instantiation, Package_Sloc); + Set_Defining_Unit_Name (Package_Node, Name_Node); + Set_Name (Package_Node, P_Qualified_Simple_Name); + Set_Generic_Associations + (Package_Node, P_Generic_Actual_Part_Opt); + TF_Semicolon; + Pop_Scope_Stack; + + -- Case of package declaration or package specification + + else + Specification_Node := + New_Node (N_Package_Specification, Package_Sloc); + + Set_Defining_Unit_Name (Specification_Node, Name_Node); + Set_Visible_Declarations + (Specification_Node, P_Basic_Declarative_Items); + + if Token = Tok_Private then + Error_Msg_Col := Scope.Table (Scope.Last).Ecol; + + if Style.RM_Column_Check then + if Token_Is_At_Start_Of_Line + and then Start_Column /= Error_Msg_Col + then + Error_Msg_SC + ("(style) PRIVATE in wrong column, should be@"); + end if; + end if; + + Scan; -- past PRIVATE + Set_Private_Declarations + (Specification_Node, P_Basic_Declarative_Items); + + -- Deal gracefully with multiple PRIVATE parts + + while Token = Tok_Private loop + Error_Msg_SC + ("only one private part allowed per package"); + Scan; -- past PRIVATE + Append_List (P_Basic_Declarative_Items, + Private_Declarations (Specification_Node)); + end loop; + end if; + + if Pf_Flags = Pf_Spcn then + Package_Node := Specification_Node; + else + Package_Node := + New_Node (N_Package_Declaration, Package_Sloc); + Set_Specification (Package_Node, Specification_Node); + end if; + + if Token = Tok_Begin then + Error_Msg_SC ("begin block not allowed in package spec"); + Scan; -- past BEGIN + Discard_Junk_List (P_Sequence_Of_Statements (SS_None)); + end if; + + End_Statements (Specification_Node); + end if; + + return Package_Node; + end if; + end if; + end P_Package; + + ------------------------------ + -- 7.1 Package Declaration -- + ------------------------------ + + -- Parsed by P_Package (7.1) + + -------------------------------- + -- 7.1 Package Specification -- + -------------------------------- + + -- Parsed by P_Package (7.1) + + ----------------------- + -- 7.1 Package Body -- + ----------------------- + + -- Parsed by P_Package (7.1) + + ----------------------------------- + -- 7.3 Private Type Declaration -- + ----------------------------------- + + -- Parsed by P_Type_Declaration (3.2.1) + + ---------------------------------------- + -- 7.3 Private Extension Declaration -- + ---------------------------------------- + + -- Parsed by P_Type_Declaration (3.2.1) + +end Ch7; diff --git a/gcc/ada/par-ch8.adb b/gcc/ada/par-ch8.adb new file mode 100644 index 00000000000..9d1b386280d --- /dev/null +++ b/gcc/ada/par-ch8.adb @@ -0,0 +1,175 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P A R . C H 8 -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.16 $ +-- -- +-- Copyright (C) 1992-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +pragma Style_Checks (All_Checks); +-- Turn off subprogram body ordering check. Subprograms are in order +-- by RM section rather than alphabetical + +separate (Par) +package body Ch8 is + + ----------------------- + -- Local Subprograms -- + ----------------------- + + function P_Use_Package_Clause return Node_Id; + function P_Use_Type_Clause return Node_Id; + + --------------------- + -- 8.4 Use Clause -- + --------------------- + + -- USE_CLAUSE ::= USE_PACKAGE_CLAUSE | USE_TYPE_CLAUSE + + -- The caller has checked that the initial token is USE + + -- Error recovery: cannot raise Error_Resync + + function P_Use_Clause return Node_Id is + begin + Scan; -- past USE + + if Token = Tok_Type then + return P_Use_Type_Clause; + + else + return P_Use_Package_Clause; + end if; + end P_Use_Clause; + + ----------------------------- + -- 8.4 Use Package Clause -- + ----------------------------- + + -- USE_PACKAGE_CLAUSE ::= use package_NAME {, package_NAME}; + + -- The caller has scanned out the USE keyword + + -- Error recovery: cannot raise Error_Resync + + function P_Use_Package_Clause return Node_Id is + Use_Node : Node_Id; + + begin + Use_Node := New_Node (N_Use_Package_Clause, Prev_Token_Ptr); + Set_Names (Use_Node, New_List); + + if Token = Tok_Package then + Error_Msg_SC ("PACKAGE should not appear here"); + Scan; -- past PACKAGE + end if; + + loop + Append (P_Qualified_Simple_Name, Names (Use_Node)); + exit when Token /= Tok_Comma; + Scan; -- past comma + end loop; + + TF_Semicolon; + return Use_Node; + end P_Use_Package_Clause; + + -------------------------- + -- 8.4 Use Type Clause -- + -------------------------- + + -- USE_TYPE_CLAUSE ::= use type SUBTYPE_MARK {, SUBTYPE_MARK}; + + -- The caller has checked that the initial token is USE, scanned it out + -- and that the current token is TYPE. + + -- Error recovery: cannot raise Error_Resync + + function P_Use_Type_Clause return Node_Id is + Use_Node : Node_Id; + + begin + Use_Node := New_Node (N_Use_Type_Clause, Prev_Token_Ptr); + Set_Subtype_Marks (Use_Node, New_List); + + if Ada_83 then + Error_Msg_SC ("(Ada 83) use type not allowed!"); + end if; + + Scan; -- past TYPE + + loop + Append (P_Subtype_Mark, Subtype_Marks (Use_Node)); + No_Constraint; + exit when Token /= Tok_Comma; + Scan; -- past comma + end loop; + + TF_Semicolon; + return Use_Node; + end P_Use_Type_Clause; + + ------------------------------- + -- 8.5 Renaming Declaration -- + ------------------------------- + + -- Object renaming declarations and exception renaming declarations + -- are parsed by P_Identifier_Declaration (3.3.1) + + -- Subprogram renaming declarations are parsed by P_Subprogram (6.1) + + -- Package renaming declarations are parsed by P_Package (7.1) + + -- Generic renaming declarations are parsed by P_Generic (12.1) + + ---------------------------------------- + -- 8.5.1 Object Renaming Declaration -- + ---------------------------------------- + + -- Parsed by P_Identifier_Declarations (3.3.1) + + ---------------------------------------- + -- 8.5.2 Exception Renaming Declaration -- + ---------------------------------------- + + -- Parsed by P_Identifier_Declarations (3.3.1) + + ----------------------------------------- + -- 8.5.3 Package Renaming Declaration -- + ----------------------------------------- + + -- Parsed by P_Package (7.1) + + -------------------------------------------- + -- 8.5.4 Subprogram Renaming Declaration -- + -------------------------------------------- + + -- Parsed by P_Subprogram (6.1) + + ----------------------------------------- + -- 8.5.2 Generic Renaming Declaration -- + ----------------------------------------- + + -- Parsed by P_Generic (12.1) + +end Ch8; diff --git a/gcc/ada/par-ch9.adb b/gcc/ada/par-ch9.adb new file mode 100644 index 00000000000..87d6be6ae5f --- /dev/null +++ b/gcc/ada/par-ch9.adb @@ -0,0 +1,1616 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P A R . C H 9 -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.82 $ +-- -- +-- Copyright (C) 1992-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +pragma Style_Checks (All_Checks); +-- Turn off subprogram body ordering check. Subprograms are in order +-- by RM section rather than alphabetical + +separate (Par) +package body Ch9 is + + -- Local subprograms, used only in this chapter + + function P_Accept_Alternative return Node_Id; + function P_Delay_Alternative return Node_Id; + function P_Delay_Relative_Statement return Node_Id; + function P_Delay_Until_Statement return Node_Id; + function P_Entry_Barrier return Node_Id; + function P_Entry_Body_Formal_Part return Node_Id; + function P_Entry_Declaration return Node_Id; + function P_Entry_Index_Specification return Node_Id; + function P_Protected_Definition return Node_Id; + function P_Protected_Operation_Declaration_Opt return Node_Id; + function P_Protected_Operation_Items return List_Id; + function P_Task_Definition return Node_Id; + function P_Task_Items return List_Id; + + ----------------------------- + -- 9.1 Task (also 10.1.3) -- + ----------------------------- + + -- TASK_TYPE_DECLARATION ::= + -- task type DEFINING_IDENTIFIER [KNOWN_DISCRIMINANT_PART] + -- [is TASK_DEFINITION]; + + -- SINGLE_TASK_DECLARATION ::= + -- task DEFINING_IDENTIFIER [is TASK_DEFINITION]; + + -- TASK_BODY ::= + -- task body DEFINING_IDENTIFIER is + -- DECLARATIVE_PART + -- begin + -- HANDLED_SEQUENCE_OF_STATEMENTS + -- end [task_IDENTIFIER] + + -- TASK_BODY_STUB ::= + -- task body DEFINING_IDENTIFIER is separate; + + -- This routine scans out a task declaration, task body, or task stub + + -- The caller has checked that the initial token is TASK and scanned + -- past it, so that Token is set to the token after TASK + + -- Error recovery: cannot raise Error_Resync + + function P_Task return Node_Id is + Name_Node : Node_Id; + Task_Node : Node_Id; + Task_Sloc : Source_Ptr; + + begin + Push_Scope_Stack; + Scope.Table (Scope.Last).Etyp := E_Name; + Scope.Table (Scope.Last).Ecol := Start_Column; + Scope.Table (Scope.Last).Sloc := Token_Ptr; + Scope.Table (Scope.Last).Lreq := False; + Task_Sloc := Prev_Token_Ptr; + + if Token = Tok_Body then + Scan; -- past BODY + Name_Node := P_Defining_Identifier; + Scope.Table (Scope.Last).Labl := Name_Node; + + if Token = Tok_Left_Paren then + Error_Msg_SC ("discriminant part not allowed in task body"); + Discard_Junk_List (P_Known_Discriminant_Part_Opt); + end if; + + TF_Is; + + -- Task stub + + if Token = Tok_Separate then + Scan; -- past SEPARATE + Task_Node := New_Node (N_Task_Body_Stub, Task_Sloc); + Set_Defining_Identifier (Task_Node, Name_Node); + TF_Semicolon; + Pop_Scope_Stack; -- remove unused entry + + -- Task body + + else + Task_Node := New_Node (N_Task_Body, Task_Sloc); + Set_Defining_Identifier (Task_Node, Name_Node); + Parse_Decls_Begin_End (Task_Node); + end if; + + return Task_Node; + + -- Otherwise we must have a task declaration + + else + if Token = Tok_Type then + Scan; -- past TYPE + Task_Node := New_Node (N_Task_Type_Declaration, Task_Sloc); + Name_Node := P_Defining_Identifier; + Set_Defining_Identifier (Task_Node, Name_Node); + Scope.Table (Scope.Last).Labl := Name_Node; + Set_Discriminant_Specifications + (Task_Node, P_Known_Discriminant_Part_Opt); + + else + Task_Node := New_Node (N_Single_Task_Declaration, Task_Sloc); + Name_Node := P_Defining_Identifier; + Set_Defining_Identifier (Task_Node, Name_Node); + Scope.Table (Scope.Last).Labl := Name_Node; + + if Token = Tok_Left_Paren then + Error_Msg_SC ("discriminant part not allowed for single task"); + Discard_Junk_List (P_Known_Discriminant_Part_Opt); + end if; + + end if; + + -- Parse optional task definition. Note that P_Task_Definition scans + -- out the semicolon as well as the task definition itself. + + if Token = Tok_Semicolon then + + -- A little check, if the next token after semicolon is + -- Entry, then surely the semicolon should really be IS + + Scan; -- past semicolon + + if Token = Tok_Entry then + Error_Msg_SP (""";"" should be IS"); + Set_Task_Definition (Task_Node, P_Task_Definition); + else + Pop_Scope_Stack; -- Remove unused entry + end if; + else + TF_Is; -- must have IS if no semicolon + Set_Task_Definition (Task_Node, P_Task_Definition); + end if; + + return Task_Node; + end if; + end P_Task; + + -------------------------------- + -- 9.1 Task Type Declaration -- + -------------------------------- + + -- Parsed by P_Task (9.1) + + ---------------------------------- + -- 9.1 Single Task Declaration -- + ---------------------------------- + + -- Parsed by P_Task (9.1) + + -------------------------- + -- 9.1 Task Definition -- + -------------------------- + + -- TASK_DEFINITION ::= + -- {TASK_ITEM} + -- [private + -- {TASK_ITEM}] + -- end [task_IDENTIFIER]; + + -- The caller has already made the scope stack entry + + -- Note: there is a small deviation from official syntax here in that we + -- regard the semicolon after end as part of the Task_Definition, and in + -- the official syntax, it's part of the enclosing declaration. The reason + -- for this deviation is that otherwise the end processing would have to + -- be special cased, which would be a nuisance! + + -- Error recovery: cannot raise Error_Resync + + function P_Task_Definition return Node_Id is + Def_Node : Node_Id; + + begin + Def_Node := New_Node (N_Task_Definition, Token_Ptr); + Set_Visible_Declarations (Def_Node, P_Task_Items); + + if Token = Tok_Private then + Scan; -- past PRIVATE + Set_Private_Declarations (Def_Node, P_Task_Items); + + -- Deal gracefully with multiple PRIVATE parts + + while Token = Tok_Private loop + Error_Msg_SC ("Only one private part allowed per task"); + Scan; -- past PRIVATE + Append_List (P_Task_Items, Private_Declarations (Def_Node)); + end loop; + end if; + + End_Statements (Def_Node); + return Def_Node; + end P_Task_Definition; + + -------------------- + -- 9.1 Task Item -- + -------------------- + + -- TASK_ITEM ::= ENTRY_DECLARATION | REPRESENTATION_CLAUSE + + -- This subprogram scans a (possibly empty) list of task items and pragmas + + -- Error recovery: cannot raise Error_Resync + + -- Note: a pragma can also be returned in this position + + function P_Task_Items return List_Id is + Items : List_Id; + Item_Node : Node_Id; + Decl_Sloc : Source_Ptr; + + begin + -- Get rid of active SIS entry from outer scope. This means we will + -- miss some nested cases, but it doesn't seem worth the effort. See + -- discussion in Par for further details + + SIS_Entry_Active := False; + + -- Loop to scan out task items + + Items := New_List; + + Decl_Loop : loop + Decl_Sloc := Token_Ptr; + + if Token = Tok_Pragma then + Append (P_Pragma, Items); + + elsif Token = Tok_Entry then + Append (P_Entry_Declaration, Items); + + elsif Token = Tok_For then + -- Representation clause in task declaration. The only rep + -- clause which is legal in a protected is an address clause, + -- so that is what we try to scan out. + + Item_Node := P_Representation_Clause; + + if Nkind (Item_Node) = N_At_Clause then + Append (Item_Node, Items); + + elsif Nkind (Item_Node) = N_Attribute_Definition_Clause + and then Chars (Item_Node) = Name_Address + then + Append (Item_Node, Items); + + else + Error_Msg + ("the only representation clause " & + "allowed here is an address clause!", Decl_Sloc); + end if; + + elsif Token = Tok_Identifier + or else Token in Token_Class_Declk + then + Error_Msg_SC ("Illegal declaration in task definition"); + Resync_Past_Semicolon; + + else + exit Decl_Loop; + end if; + end loop Decl_Loop; + + return Items; + end P_Task_Items; + + -------------------- + -- 9.1 Task Body -- + -------------------- + + -- Parsed by P_Task (9.1) + + ---------------------------------- + -- 9.4 Protected (also 10.1.3) -- + ---------------------------------- + + -- PROTECTED_TYPE_DECLARATION ::= + -- protected type DEFINING_IDENTIFIER [KNOWN_DISCRIMINANT_PART] + -- is PROTECTED_DEFINITION; + + -- SINGLE_PROTECTED_DECLARATION ::= + -- protected DEFINING_IDENTIFIER is PROTECTED_DEFINITION; + + -- PROTECTED_BODY ::= + -- protected body DEFINING_IDENTIFIER is + -- {PROTECTED_OPERATION_ITEM} + -- end [protected_IDENTIFIER]; + + -- PROTECTED_BODY_STUB ::= + -- protected body DEFINING_IDENTIFIER is separate; + + -- This routine scans out a protected declaration, protected body + -- or a protected stub. + + -- The caller has checked that the initial token is PROTECTED and + -- scanned past it, so Token is set to the following token. + + -- Error recovery: cannot raise Error_Resync + + function P_Protected return Node_Id is + Name_Node : Node_Id; + Protected_Node : Node_Id; + Protected_Sloc : Source_Ptr; + + begin + Push_Scope_Stack; + Scope.Table (Scope.Last).Etyp := E_Name; + Scope.Table (Scope.Last).Ecol := Start_Column; + Scope.Table (Scope.Last).Lreq := False; + Protected_Sloc := Prev_Token_Ptr; + + if Token = Tok_Body then + Scan; -- past BODY + Name_Node := P_Defining_Identifier; + Scope.Table (Scope.Last).Labl := Name_Node; + + if Token = Tok_Left_Paren then + Error_Msg_SC ("discriminant part not allowed in protected body"); + Discard_Junk_List (P_Known_Discriminant_Part_Opt); + end if; + + TF_Is; + + -- Protected stub + + if Token = Tok_Separate then + Scan; -- past SEPARATE + Protected_Node := New_Node (N_Protected_Body_Stub, Protected_Sloc); + Set_Defining_Identifier (Protected_Node, Name_Node); + TF_Semicolon; + Pop_Scope_Stack; -- remove unused entry + + -- Protected body + + else + Protected_Node := New_Node (N_Protected_Body, Protected_Sloc); + Set_Defining_Identifier (Protected_Node, Name_Node); + Set_Declarations (Protected_Node, P_Protected_Operation_Items); + End_Statements (Protected_Node); + end if; + + return Protected_Node; + + -- Otherwise we must have a protected declaration + + else + if Token = Tok_Type then + Scan; -- past TYPE + Protected_Node := + New_Node (N_Protected_Type_Declaration, Protected_Sloc); + Name_Node := P_Defining_Identifier; + Set_Defining_Identifier (Protected_Node, Name_Node); + Scope.Table (Scope.Last).Labl := Name_Node; + Set_Discriminant_Specifications + (Protected_Node, P_Known_Discriminant_Part_Opt); + + else + Protected_Node := + New_Node (N_Single_Protected_Declaration, Protected_Sloc); + Name_Node := P_Defining_Identifier; + Set_Defining_Identifier (Protected_Node, Name_Node); + + if Token = Tok_Left_Paren then + Error_Msg_SC + ("discriminant part not allowed for single protected"); + Discard_Junk_List (P_Known_Discriminant_Part_Opt); + end if; + + Scope.Table (Scope.Last).Labl := Name_Node; + end if; + + T_Is; + Set_Protected_Definition (Protected_Node, P_Protected_Definition); + return Protected_Node; + end if; + end P_Protected; + + ------------------------------------- + -- 9.4 Protected Type Declaration -- + ------------------------------------- + + -- Parsed by P_Protected (9.4) + + --------------------------------------- + -- 9.4 Single Protected Declaration -- + --------------------------------------- + + -- Parsed by P_Protected (9.4) + + ------------------------------- + -- 9.4 Protected Definition -- + ------------------------------- + + -- PROTECTED_DEFINITION ::= + -- {PROTECTED_OPERATION_DECLARATION} + -- [private + -- {PROTECTED_ELEMENT_DECLARATION}] + -- end [protected_IDENTIFIER] + + -- PROTECTED_ELEMENT_DECLARATION ::= + -- PROTECTED_OPERATION_DECLARATION + -- | COMPONENT_DECLARATION + + -- The caller has already established the scope stack entry + + -- Error recovery: cannot raise Error_Resync + + function P_Protected_Definition return Node_Id is + Def_Node : Node_Id; + Item_Node : Node_Id; + + begin + Def_Node := New_Node (N_Protected_Definition, Token_Ptr); + + -- Get rid of active SIS entry from outer scope. This means we will + -- miss some nested cases, but it doesn't seem worth the effort. See + -- discussion in Par for further details + + SIS_Entry_Active := False; + + -- Loop to scan visible declarations (protected operation declarations) + + Set_Visible_Declarations (Def_Node, New_List); + + loop + Item_Node := P_Protected_Operation_Declaration_Opt; + exit when No (Item_Node); + Append (Item_Node, Visible_Declarations (Def_Node)); + end loop; + + -- Deal with PRIVATE part (including graceful handling + -- of multiple PRIVATE parts). + + Private_Loop : while Token = Tok_Private loop + if No (Private_Declarations (Def_Node)) then + Set_Private_Declarations (Def_Node, New_List); + else + Error_Msg_SC ("duplicate private part"); + end if; + + Scan; -- past PRIVATE + + Declaration_Loop : loop + if Token = Tok_Identifier then + P_Component_Items (Private_Declarations (Def_Node)); + else + Item_Node := P_Protected_Operation_Declaration_Opt; + exit Declaration_Loop when No (Item_Node); + Append (Item_Node, Private_Declarations (Def_Node)); + end if; + end loop Declaration_Loop; + end loop Private_Loop; + + End_Statements (Def_Node); + return Def_Node; + end P_Protected_Definition; + + ------------------------------------------ + -- 9.4 Protected Operation Declaration -- + ------------------------------------------ + + -- PROTECTED_OPERATION_DECLARATION ::= + -- SUBPROGRAM_DECLARATION + -- | ENTRY_DECLARATION + -- | REPRESENTATION_CLAUSE + + -- Error recovery: cannot raise Error_Resync + + -- Note: a pragma can also be returned in this position + + -- We are not currently permitting representation clauses to appear as + -- protected operation declarations, do we have to rethink this??? + + function P_Protected_Operation_Declaration_Opt return Node_Id is + L : List_Id; + P : Source_Ptr; + + begin + -- This loop runs more than once only when a junk declaration + -- is skipped. + + loop + if Token = Tok_Pragma then + return P_Pragma; + + elsif Token = Tok_Entry then + return P_Entry_Declaration; + + elsif Token = Tok_Function or else Token = Tok_Procedure then + return P_Subprogram (Pf_Decl); + + elsif Token = Tok_Identifier then + L := New_List; + P := Token_Ptr; + Skip_Declaration (L); + + if Nkind (First (L)) = N_Object_Declaration then + Error_Msg + ("component must be declared in private part of " & + "protected type", P); + else + Error_Msg + ("illegal declaration in protected definition", P); + end if; + + elsif Token in Token_Class_Declk then + Error_Msg_SC ("illegal declaration in protected definition"); + Resync_Past_Semicolon; + + -- Return now to avoid cascaded messages if next declaration + -- is a valid component declaration. + + return Error; + + elsif Token = Tok_For then + Error_Msg_SC + ("representation clause not allowed in protected definition"); + Resync_Past_Semicolon; + + else + return Empty; + end if; + end loop; + end P_Protected_Operation_Declaration_Opt; + + ----------------------------------- + -- 9.4 Protected Operation Item -- + ----------------------------------- + + -- PROTECTED_OPERATION_ITEM ::= + -- SUBPROGRAM_DECLARATION + -- | SUBPROGRAM_BODY + -- | ENTRY_BODY + -- | REPRESENTATION_CLAUSE + + -- This procedure parses and returns a list of protected operation items + + -- We are not currently permitting representation clauses to appear + -- as protected operation items, do we have to rethink this??? + + function P_Protected_Operation_Items return List_Id is + Item_List : List_Id; + + begin + Item_List := New_List; + + loop + if Token = Tok_Entry or else Bad_Spelling_Of (Tok_Entry) then + Append (P_Entry_Body, Item_List); + + elsif Token = Tok_Function or else Bad_Spelling_Of (Tok_Function) + or else + Token = Tok_Procedure or else Bad_Spelling_Of (Tok_Procedure) + then + Append (P_Subprogram (Pf_Decl_Pbod), Item_List); + + elsif Token = Tok_Pragma or else Bad_Spelling_Of (Tok_Pragma) then + P_Pragmas_Opt (Item_List); + + elsif Token = Tok_Private or else Bad_Spelling_Of (Tok_Private) then + Error_Msg_SC ("PRIVATE not allowed in protected body"); + Scan; -- past PRIVATE + + elsif Token = Tok_Identifier then + Error_Msg_SC + ("all components must be declared in spec!"); + Resync_Past_Semicolon; + + elsif Token in Token_Class_Declk then + Error_Msg_SC ("this declaration not allowed in protected body"); + Resync_Past_Semicolon; + + else + exit; + end if; + end loop; + + return Item_List; + end P_Protected_Operation_Items; + + ------------------------------ + -- 9.5.2 Entry Declaration -- + ------------------------------ + + -- ENTRY_DECLARATION ::= + -- entry DEFINING_IDENTIFIER [(DISCRETE_SUBTYPE_DEFINITION)] + -- PARAMETER_PROFILE; + + -- The caller has checked that the initial token is ENTRY + + -- Error recovery: cannot raise Error_Resync + + function P_Entry_Declaration return Node_Id is + Decl_Node : Node_Id; + Scan_State : Saved_Scan_State; + + begin + Decl_Node := New_Node (N_Entry_Declaration, Token_Ptr); + Scan; -- past ENTRY + + Set_Defining_Identifier (Decl_Node, P_Defining_Identifier); + + -- If left paren, could be (Discrete_Subtype_Definition) or Formal_Part + + if Token = Tok_Left_Paren then + Scan; -- past ( + + -- If identifier after left paren, could still be either + + if Token = Tok_Identifier then + Save_Scan_State (Scan_State); -- at Id + Scan; -- past Id + + -- If comma or colon after Id, must be Formal_Part + + if Token = Tok_Comma or else Token = Tok_Colon then + Restore_Scan_State (Scan_State); -- to Id + Set_Parameter_Specifications (Decl_Node, P_Formal_Part); + + -- Else if Id wi no comma or colon, must be discrete subtype defn + + else + Restore_Scan_State (Scan_State); -- to Id + Set_Discrete_Subtype_Definition + (Decl_Node, P_Discrete_Subtype_Definition); + T_Right_Paren; + Set_Parameter_Specifications (Decl_Node, P_Parameter_Profile); + end if; + + -- If no Id, must be discrete subtype definition + + else + Set_Discrete_Subtype_Definition + (Decl_Node, P_Discrete_Subtype_Definition); + T_Right_Paren; + Set_Parameter_Specifications (Decl_Node, P_Parameter_Profile); + end if; + end if; + + -- Error recovery check for illegal return + + if Token = Tok_Return then + Error_Msg_SC ("entry cannot have return value!"); + Scan; + Discard_Junk_Node (P_Subtype_Indication); + end if; + + -- Error recovery check for improper use of entry barrier in spec + + if Token = Tok_When then + Error_Msg_SC ("barrier not allowed here (belongs in body)"); + Scan; -- past WHEN; + Discard_Junk_Node (P_Expression_No_Right_Paren); + end if; + + TF_Semicolon; + return Decl_Node; + end P_Entry_Declaration; + + ----------------------------- + -- 9.5.2 Accept Statement -- + ----------------------------- + + -- ACCEPT_STATEMENT ::= + -- accept entry_DIRECT_NAME + -- [(ENTRY_INDEX)] PARAMETER_PROFILE [do + -- HANDLED_SEQUENCE_OF_STATEMENTS + -- end [entry_IDENTIFIER]]; + + -- The caller has checked that the initial token is ACCEPT + + -- Error recovery: cannot raise Error_Resync. If an error occurs, the + -- scan is resynchronized past the next semicolon and control returns. + + function P_Accept_Statement return Node_Id is + Scan_State : Saved_Scan_State; + Accept_Node : Node_Id; + Hand_Seq : Node_Id; + + begin + Push_Scope_Stack; + Scope.Table (Scope.Last).Sloc := Token_Ptr; + Scope.Table (Scope.Last).Ecol := Start_Column; + + Accept_Node := New_Node (N_Accept_Statement, Token_Ptr); + Scan; -- past ACCEPT + Scope.Table (Scope.Last).Labl := Token_Node; + + Set_Entry_Direct_Name (Accept_Node, P_Identifier); + + -- Left paren could be (Entry_Index) or Formal_Part, determine which + + if Token = Tok_Left_Paren then + Save_Scan_State (Scan_State); -- at left paren + Scan; -- past left paren + + -- If first token after left paren not identifier, then Entry_Index + + if Token /= Tok_Identifier then + Set_Entry_Index (Accept_Node, P_Expression); + T_Right_Paren; + Set_Parameter_Specifications (Accept_Node, P_Parameter_Profile); + + -- First token after left paren is identifier, could be either case + + else -- Token = Tok_Identifier + Scan; -- past identifier + + -- If identifier followed by comma or colon, must be Formal_Part + + if Token = Tok_Comma or else Token = Tok_Colon then + Restore_Scan_State (Scan_State); -- to left paren + Set_Parameter_Specifications (Accept_Node, P_Parameter_Profile); + + -- If identifier not followed by comma/colon, must be entry index + + else + Restore_Scan_State (Scan_State); -- to left paren + Scan; -- past left paren (again!) + Set_Entry_Index (Accept_Node, P_Expression); + T_Right_Paren; + Set_Parameter_Specifications (Accept_Node, P_Parameter_Profile); + end if; + end if; + end if; + + -- Scan out DO if present + + if Token = Tok_Do then + Scope.Table (Scope.Last).Etyp := E_Name; + Scope.Table (Scope.Last).Lreq := False; + Scan; -- past DO + Hand_Seq := P_Handled_Sequence_Of_Statements; + Set_Handled_Statement_Sequence (Accept_Node, Hand_Seq); + End_Statements (Handled_Statement_Sequence (Accept_Node)); + + -- Exception handlers not allowed in Ada 95 node + + if Present (Exception_Handlers (Hand_Seq)) then + if Ada_83 then + Error_Msg_N + ("(Ada 83) exception handlers in accept not allowed", + First_Non_Pragma (Exception_Handlers (Hand_Seq))); + end if; + end if; + + else + Pop_Scope_Stack; -- discard unused entry + TF_Semicolon; + end if; + + return Accept_Node; + + -- If error, resynchronize past semicolon + + exception + when Error_Resync => + Resync_Past_Semicolon; + return Error; + + end P_Accept_Statement; + + ------------------------ + -- 9.5.2 Entry Index -- + ------------------------ + + -- Parsed by P_Expression (4.4) + + ----------------------- + -- 9.5.2 Entry Body -- + ----------------------- + + -- ENTRY_BODY ::= + -- entry DEFINING_IDENTIFIER ENTRY_BODY_FORMAL_PART ENTRY_BARRIER is + -- DECLARATIVE_PART + -- begin + -- HANDLED_SEQUENCE_OF_STATEMENTS + -- end [entry_IDENTIFIER]; + + -- The caller has checked that the initial token is ENTRY + + -- Error_Recovery: cannot raise Error_Resync + + function P_Entry_Body return Node_Id is + Entry_Node : Node_Id; + Formal_Part_Node : Node_Id; + Name_Node : Node_Id; + + begin + Push_Scope_Stack; + Entry_Node := New_Node (N_Entry_Body, Token_Ptr); + Scan; -- past ENTRY + + Scope.Table (Scope.Last).Ecol := Start_Column; + Scope.Table (Scope.Last).Lreq := False; + Scope.Table (Scope.Last).Etyp := E_Name; + + Name_Node := P_Defining_Identifier; + Set_Defining_Identifier (Entry_Node, Name_Node); + Scope.Table (Scope.Last).Labl := Name_Node; + + Formal_Part_Node := P_Entry_Body_Formal_Part; + Set_Entry_Body_Formal_Part (Entry_Node, Formal_Part_Node); + + Set_Condition (Formal_Part_Node, P_Entry_Barrier); + Parse_Decls_Begin_End (Entry_Node); + return Entry_Node; + end P_Entry_Body; + + ----------------------------------- + -- 9.5.2 Entry Body Formal Part -- + ----------------------------------- + + -- ENTRY_BODY_FORMAL_PART ::= + -- [(ENTRY_INDEX_SPECIFICATION)] [PARAMETER_PART] + + -- Error_Recovery: cannot raise Error_Resync + + function P_Entry_Body_Formal_Part return Node_Id is + Fpart_Node : Node_Id; + Scan_State : Saved_Scan_State; + + begin + Fpart_Node := New_Node (N_Entry_Body_Formal_Part, Token_Ptr); + + -- See if entry index specification present, and if so parse it + + if Token = Tok_Left_Paren then + Save_Scan_State (Scan_State); -- at left paren + Scan; -- past left paren + + if Token = Tok_For then + Set_Entry_Index_Specification + (Fpart_Node, P_Entry_Index_Specification); + T_Right_Paren; + else + Restore_Scan_State (Scan_State); -- to left paren + end if; + + -- Check for (common?) case of left paren omitted before FOR. This + -- is a tricky case, because the corresponding missing left paren + -- can cause real havoc if a formal part is present which gets + -- treated as part of the discrete subtype definition of the + -- entry index specification, so just give error and resynchronize + + elsif Token = Tok_For then + T_Left_Paren; -- to give error message + Resync_To_When; + end if; + + Set_Parameter_Specifications (Fpart_Node, P_Parameter_Profile); + return Fpart_Node; + end P_Entry_Body_Formal_Part; + + -------------------------- + -- 9.5.2 Entry Barrier -- + -------------------------- + + -- ENTRY_BARRIER ::= when CONDITION + + -- Error_Recovery: cannot raise Error_Resync + + function P_Entry_Barrier return Node_Id is + Bnode : Node_Id; + + begin + if Token = Tok_When then + Scan; -- past WHEN; + Bnode := P_Expression_No_Right_Paren; + + if Token = Tok_Colon_Equal then + Error_Msg_SC (""":="" should be ""="""); + Scan; + Bnode := P_Expression_No_Right_Paren; + end if; + + else + T_When; -- to give error message + Bnode := Error; + end if; + + TF_Is; + return Bnode; + end P_Entry_Barrier; + + -------------------------------------- + -- 9.5.2 Entry Index Specification -- + -------------------------------------- + + -- ENTRY_INDEX_SPECIFICATION ::= + -- for DEFINING_IDENTIFIER in DISCRETE_SUBTYPE_DEFINITION + + -- Error recovery: can raise Error_Resync + + function P_Entry_Index_Specification return Node_Id is + Iterator_Node : Node_Id; + + begin + Iterator_Node := New_Node (N_Entry_Index_Specification, Token_Ptr); + T_For; -- past FOR + Set_Defining_Identifier (Iterator_Node, P_Defining_Identifier); + T_In; + Set_Discrete_Subtype_Definition + (Iterator_Node, P_Discrete_Subtype_Definition); + return Iterator_Node; + end P_Entry_Index_Specification; + + --------------------------------- + -- 9.5.3 Entry Call Statement -- + --------------------------------- + + -- Parsed by P_Name (4.1). Within a select, an entry call is parsed + -- by P_Select_Statement (9.7) + + ------------------------------ + -- 9.5.4 Requeue Statement -- + ------------------------------ + + -- REQUEUE_STATEMENT ::= requeue entry_NAME [with abort]; + + -- The caller has checked that the initial token is requeue + + -- Error recovery: can raise Error_Resync + + function P_Requeue_Statement return Node_Id is + Requeue_Node : Node_Id; + + begin + Requeue_Node := New_Node (N_Requeue_Statement, Token_Ptr); + Scan; -- past REQUEUE + Set_Name (Requeue_Node, P_Name); + + if Token = Tok_With then + Scan; -- past WITH + T_Abort; + Set_Abort_Present (Requeue_Node, True); + end if; + + TF_Semicolon; + return Requeue_Node; + end P_Requeue_Statement; + + -------------------------- + -- 9.6 Delay Statement -- + -------------------------- + + -- DELAY_STATEMENT ::= + -- DELAY_UNTIL_STATEMENT + -- | DELAY_RELATIVE_STATEMENT + + -- The caller has checked that the initial token is DELAY + + -- Error recovery: cannot raise Error_Resync + + function P_Delay_Statement return Node_Id is + begin + Scan; -- past DELAY + + -- The following check for delay until misused in Ada 83 doesn't catch + -- all cases, but it's good enough to catch most of them! + + if Token_Name = Name_Until then + Check_95_Keyword (Tok_Until, Tok_Left_Paren); + Check_95_Keyword (Tok_Until, Tok_Identifier); + end if; + + if Token = Tok_Until then + return P_Delay_Until_Statement; + else + return P_Delay_Relative_Statement; + end if; + end P_Delay_Statement; + + -------------------------------- + -- 9.6 Delay Until Statement -- + -------------------------------- + + -- DELAY_UNTIL_STATEMENT ::= delay until delay_EXPRESSION; + + -- The caller has checked that the initial token is DELAY, scanned it + -- out and checked that the current token is UNTIL + + -- Error recovery: cannot raise Error_Resync + + function P_Delay_Until_Statement return Node_Id is + Delay_Node : Node_Id; + + begin + Delay_Node := New_Node (N_Delay_Until_Statement, Prev_Token_Ptr); + Scan; -- past UNTIL + Set_Expression (Delay_Node, P_Expression_No_Right_Paren); + TF_Semicolon; + return Delay_Node; + end P_Delay_Until_Statement; + + ----------------------------------- + -- 9.6 Delay Relative Statement -- + ----------------------------------- + + -- DELAY_RELATIVE_STATEMENT ::= delay delay_EXPRESSION; + + -- The caller has checked that the initial token is DELAY, scanned it + -- out and determined that the current token is not UNTIL + + -- Error recovery: cannot raise Error_Resync + + function P_Delay_Relative_Statement return Node_Id is + Delay_Node : Node_Id; + + begin + Delay_Node := New_Node (N_Delay_Relative_Statement, Prev_Token_Ptr); + Set_Expression (Delay_Node, P_Expression_No_Right_Paren); + Check_Simple_Expression_In_Ada_83 (Expression (Delay_Node)); + TF_Semicolon; + return Delay_Node; + end P_Delay_Relative_Statement; + + --------------------------- + -- 9.7 Select Statement -- + --------------------------- + + -- SELECT_STATEMENT ::= + -- SELECTIVE_ACCEPT + -- | TIMED_ENTRY_CALL + -- | CONDITIONAL_ENTRY_CALL + -- | ASYNCHRONOUS_SELECT + + -- SELECTIVE_ACCEPT ::= + -- select + -- [GUARD] + -- SELECT_ALTERNATIVE + -- {or + -- [GUARD] + -- SELECT_ALTERNATIVE + -- [else + -- SEQUENCE_OF_STATEMENTS] + -- end select; + + -- GUARD ::= when CONDITION => + + -- Note: the guard preceding a select alternative is included as part + -- of the node generated for a selective accept alternative. + + -- SELECT_ALTERNATIVE ::= + -- ACCEPT_ALTERNATIVE + -- | DELAY_ALTERNATIVE + -- | TERMINATE_ALTERNATIVE + + -- TIMED_ENTRY_CALL ::= + -- select + -- ENTRY_CALL_ALTERNATIVE + -- or + -- DELAY_ALTERNATIVE + -- end select; + + -- CONDITIONAL_ENTRY_CALL ::= + -- select + -- ENTRY_CALL_ALTERNATIVE + -- else + -- SEQUENCE_OF_STATEMENTS + -- end select; + + -- ENTRY_CALL_ALTERNATIVE ::= + -- ENTRY_CALL_STATEMENT [SEQUENCE_OF_STATEMENTS] + + -- ASYNCHRONOUS_SELECT ::= + -- select + -- TRIGGERING_ALTERNATIVE + -- then abort + -- ABORTABLE_PART + -- end select; + + -- TRIGGERING_ALTERNATIVE ::= + -- TRIGGERING_STATEMENT [SEQUENCE_OF_STATEMENTS] + + -- TRIGGERING_STATEMENT ::= ENTRY_CALL_STATEMENT | DELAY_STATEMENT + + -- The caller has checked that the initial token is SELECT + + -- Error recovery: can raise Error_Resync + + function P_Select_Statement return Node_Id is + Select_Node : Node_Id; + Select_Sloc : Source_Ptr; + Stmnt_Sloc : Source_Ptr; + Ecall_Node : Node_Id; + Alternative : Node_Id; + Select_Pragmas : List_Id; + Alt_Pragmas : List_Id; + Statement_List : List_Id; + Alt_List : List_Id; + Cond_Expr : Node_Id; + Delay_Stmnt : Node_Id; + + begin + Push_Scope_Stack; + Scope.Table (Scope.Last).Etyp := E_Select; + Scope.Table (Scope.Last).Ecol := Start_Column; + Scope.Table (Scope.Last).Sloc := Token_Ptr; + Scope.Table (Scope.Last).Labl := Error; + + Select_Sloc := Token_Ptr; + Scan; -- past SELECT + Stmnt_Sloc := Token_Ptr; + Select_Pragmas := P_Pragmas_Opt; + + -- If first token after select is designator, then we have an entry + -- call, which must be the start of a conditional entry call, timed + -- entry call or asynchronous select + + if Token in Token_Class_Desig then + + -- Scan entry call statement + + begin + Ecall_Node := P_Name; + + -- ?? The following two clauses exactly parallel code in ch5 + -- and should be commoned sometime + + if Nkind (Ecall_Node) = N_Indexed_Component then + declare + Prefix_Node : Node_Id := Prefix (Ecall_Node); + Exprs_Node : List_Id := Expressions (Ecall_Node); + begin + Change_Node (Ecall_Node, N_Procedure_Call_Statement); + Set_Name (Ecall_Node, Prefix_Node); + Set_Parameter_Associations (Ecall_Node, Exprs_Node); + end; + + elsif Nkind (Ecall_Node) = N_Function_Call then + declare + Fname_Node : Node_Id := Name (Ecall_Node); + Params_List : List_Id := Parameter_Associations (Ecall_Node); + + begin + Change_Node (Ecall_Node, N_Procedure_Call_Statement); + Set_Name (Ecall_Node, Fname_Node); + Set_Parameter_Associations (Ecall_Node, Params_List); + end; + + elsif Nkind (Ecall_Node) = N_Identifier + or else Nkind (Ecall_Node) = N_Selected_Component + then + -- Case of a call to a parameterless entry. + + declare + C_Node : constant Node_Id := + New_Node (N_Procedure_Call_Statement, Stmnt_Sloc); + begin + Set_Name (C_Node, Ecall_Node); + Set_Parameter_Associations (C_Node, No_List); + Ecall_Node := C_Node; + end; + end if; + + TF_Semicolon; + + exception + when Error_Resync => + Resync_Past_Semicolon; + return Error; + end; + + Statement_List := P_Sequence_Of_Statements (SS_Eltm_Ortm_Tatm); + + -- OR follows, we have a timed entry call + + if Token = Tok_Or then + Scan; -- past OR + Alt_Pragmas := P_Pragmas_Opt; + + Select_Node := New_Node (N_Timed_Entry_Call, Select_Sloc); + Set_Entry_Call_Alternative (Select_Node, + Make_Entry_Call_Alternative (Stmnt_Sloc, + Entry_Call_Statement => Ecall_Node, + Pragmas_Before => Select_Pragmas, + Statements => Statement_List)); + + -- Only possibility is delay alternative. If we have anything + -- else, give message, and treat as conditional entry call. + + if Token /= Tok_Delay then + Error_Msg_SC + ("only allowed alternative in timed entry call is delay!"); + Discard_Junk_List (P_Sequence_Of_Statements (SS_Sreq)); + Set_Delay_Alternative (Select_Node, Error); + + else + Set_Delay_Alternative (Select_Node, P_Delay_Alternative); + Set_Pragmas_Before + (Delay_Alternative (Select_Node), Alt_Pragmas); + end if; + + -- ELSE follows, we have a conditional entry call + + elsif Token = Tok_Else then + Scan; -- past ELSE + Select_Node := New_Node (N_Conditional_Entry_Call, Select_Sloc); + + Set_Entry_Call_Alternative (Select_Node, + Make_Entry_Call_Alternative (Stmnt_Sloc, + Entry_Call_Statement => Ecall_Node, + Pragmas_Before => Select_Pragmas, + Statements => Statement_List)); + + Set_Else_Statements + (Select_Node, P_Sequence_Of_Statements (SS_Sreq)); + + -- Only remaining case is THEN ABORT (asynchronous select) + + elsif Token = Tok_Abort then + Select_Node := + Make_Asynchronous_Select (Select_Sloc, + Triggering_Alternative => + Make_Triggering_Alternative (Stmnt_Sloc, + Triggering_Statement => Ecall_Node, + Pragmas_Before => Select_Pragmas, + Statements => Statement_List), + Abortable_Part => P_Abortable_Part); + + -- Else error + + else + if Ada_83 then + Error_Msg_BC ("OR or ELSE expected"); + else + Error_Msg_BC ("OR or ELSE or THEN ABORT expected"); + end if; + + Select_Node := Error; + end if; + + End_Statements; + + -- Here we have a selective accept or an an asynchronous select (first + -- token after SELECT is other than a designator token). + + else + -- If we have delay with no guard, could be asynchronous select + + if Token = Tok_Delay then + Delay_Stmnt := P_Delay_Statement; + Statement_List := P_Sequence_Of_Statements (SS_Eltm_Ortm_Tatm); + + -- Asynchronous select + + if Token = Tok_Abort then + Select_Node := + Make_Asynchronous_Select (Select_Sloc, + Triggering_Alternative => + Make_Triggering_Alternative (Stmnt_Sloc, + Triggering_Statement => Delay_Stmnt, + Pragmas_Before => Select_Pragmas, + Statements => Statement_List), + Abortable_Part => P_Abortable_Part); + + End_Statements; + return Select_Node; + + -- Delay which was not an asynchronous select. Must be a selective + -- accept, and since at least one accept statement is required, + -- we must have at least one OR phrase present. + + else + Alt_List := New_List ( + Make_Delay_Alternative (Stmnt_Sloc, + Delay_Statement => Delay_Stmnt, + Pragmas_Before => Select_Pragmas, + Statements => Statement_List)); + T_Or; + Alt_Pragmas := P_Pragmas_Opt; + end if; + + -- If not a delay statement, then must be another possibility for + -- a selective accept alternative, or perhaps a guard is present + + else + Alt_List := New_List; + Alt_Pragmas := Select_Pragmas; + end if; + + Select_Node := New_Node (N_Selective_Accept, Select_Sloc); + Set_Select_Alternatives (Select_Node, Alt_List); + + -- Scan out selective accept alternatives. On entry to this loop, + -- we are just past a SELECT or OR token, and any pragmas that + -- immediately follow the SELECT or OR are in Alt_Pragmas. + + loop + if Token = Tok_When then + + if Present (Alt_Pragmas) then + Error_Msg_SC ("pragmas may not precede guard"); + end if; + + Scan; -- past WHEN + Cond_Expr := P_Expression_No_Right_Paren; + T_Arrow; + Alt_Pragmas := P_Pragmas_Opt; + + else + Cond_Expr := Empty; + end if; + + if Token = Tok_Accept then + Alternative := P_Accept_Alternative; + + -- Check for junk attempt at asynchronous select using + -- an Accept alternative as the triggering statement + + if Token = Tok_Abort + and then Is_Empty_List (Alt_List) + and then No (Cond_Expr) + then + Error_Msg + ("triggering statement must be entry call or delay", + Sloc (Alternative)); + Scan; -- past junk ABORT + Discard_Junk_List (P_Sequence_Of_Statements (SS_Sreq)); + End_Statements; + return Error; + end if; + + elsif Token = Tok_Delay then + Alternative := P_Delay_Alternative; + + elsif Token = Tok_Terminate then + Alternative := P_Terminate_Alternative; + + else + Error_Msg_SC + ("Select alternative (ACCEPT, ABORT, DELAY) expected"); + Alternative := Error; + + if Token = Tok_Semicolon then + Scan; -- past junk semicolon + end if; + end if; + + -- THEN ABORT at this stage is just junk + + if Token = Tok_Abort then + Error_Msg_SP ("misplaced `THEN ABORT`"); + Scan; -- past junk ABORT + Discard_Junk_List (P_Sequence_Of_Statements (SS_Sreq)); + End_Statements; + return Error; + + else + if Alternative /= Error then + Set_Condition (Alternative, Cond_Expr); + Set_Pragmas_Before (Alternative, Alt_Pragmas); + Append (Alternative, Alt_List); + end if; + + exit when Token /= Tok_Or; + end if; + + T_Or; + Alt_Pragmas := P_Pragmas_Opt; + end loop; + + if Token = Tok_Else then + Scan; -- past ELSE + Set_Else_Statements + (Select_Node, P_Sequence_Of_Statements (SS_Ortm_Sreq)); + + if Token = Tok_Or then + Error_Msg_SC ("select alternative cannot follow else part!"); + end if; + end if; + + End_Statements; + end if; + + return Select_Node; + end P_Select_Statement; + + ----------------------------- + -- 9.7.1 Selective Accept -- + ----------------------------- + + -- Parsed by P_Select_Statement (9.7) + + ------------------ + -- 9.7.1 Guard -- + ------------------ + + -- Parsed by P_Select_Statement (9.7) + + ------------------------------- + -- 9.7.1 Select Alternative -- + ------------------------------- + + -- SELECT_ALTERNATIVE ::= + -- ACCEPT_ALTERNATIVE + -- | DELAY_ALTERNATIVE + -- | TERMINATE_ALTERNATIVE + + -- Note: the guard preceding a select alternative is included as part + -- of the node generated for a selective accept alternative. + + -- Error recovery: cannot raise Error_Resync + + ------------------------------- + -- 9.7.1 Accept Alternative -- + ------------------------------- + + -- ACCEPT_ALTERNATIVE ::= + -- ACCEPT_STATEMENT [SEQUENCE_OF_STATEMENTS] + + -- Error_Recovery: Cannot raise Error_Resync + + -- Note: the caller is responsible for setting the Pragmas_Before + -- field of the returned N_Terminate_Alternative node. + + function P_Accept_Alternative return Node_Id is + Accept_Alt_Node : Node_Id; + + begin + Accept_Alt_Node := New_Node (N_Accept_Alternative, Token_Ptr); + Set_Accept_Statement (Accept_Alt_Node, P_Accept_Statement); + + -- Note: the reason that we accept THEN ABORT as a terminator for + -- the sequence of statements is for error recovery which allows + -- for misuse of an accept statement as a triggering statememt. + + Set_Statements + (Accept_Alt_Node, P_Sequence_Of_Statements (SS_Eltm_Ortm_Tatm)); + return Accept_Alt_Node; + end P_Accept_Alternative; + + ------------------------------ + -- 9.7.1 Delay Alternative -- + ------------------------------ + + -- DELAY_ALTERNATIVE ::= + -- DELAY_STATEMENT [SEQUENCE_OF_STATEMENTS] + + -- Error_Recovery: Cannot raise Error_Resync + + -- Note: the caller is responsible for setting the Pragmas_Before + -- field of the returned N_Terminate_Alternative node. + + function P_Delay_Alternative return Node_Id is + Delay_Alt_Node : Node_Id; + + begin + Delay_Alt_Node := New_Node (N_Delay_Alternative, Token_Ptr); + Set_Delay_Statement (Delay_Alt_Node, P_Delay_Statement); + + -- Note: the reason that we accept THEN ABORT as a terminator for + -- the sequence of statements is for error recovery which allows + -- for misuse of an accept statement as a triggering statememt. + + Set_Statements + (Delay_Alt_Node, P_Sequence_Of_Statements (SS_Eltm_Ortm_Tatm)); + return Delay_Alt_Node; + end P_Delay_Alternative; + + ---------------------------------- + -- 9.7.1 Terminate Alternative -- + ---------------------------------- + + -- TERMINATE_ALTERNATIVE ::= terminate; + + -- Error_Recovery: Cannot raise Error_Resync + + -- Note: the caller is responsible for setting the Pragmas_Before + -- field of the returned N_Terminate_Alternative node. + + function P_Terminate_Alternative return Node_Id is + Terminate_Alt_Node : Node_Id; + + begin + Terminate_Alt_Node := New_Node (N_Terminate_Alternative, Token_Ptr); + Scan; -- past TERMINATE + TF_Semicolon; + + -- For all other select alternatives, the sequence of statements + -- after the alternative statement will swallow up any pragmas + -- coming in this position. But the terminate alternative has no + -- sequence of statements, so the pragmas here must be treated + -- specially. + + Set_Pragmas_After (Terminate_Alt_Node, P_Pragmas_Opt); + return Terminate_Alt_Node; + end P_Terminate_Alternative; + + ----------------------------- + -- 9.7.2 Timed Entry Call -- + ----------------------------- + + -- Parsed by P_Select_Statement (9.7) + + ----------------------------------- + -- 9.7.2 Entry Call Alternative -- + ----------------------------------- + + -- Parsed by P_Select_Statement (9.7) + + ----------------------------------- + -- 9.7.3 Conditional Entry Call -- + ----------------------------------- + + -- Parsed by P_Select_Statement (9.7) + + -------------------------------- + -- 9.7.4 Asynchronous Select -- + -------------------------------- + + -- Parsed by P_Select_Statement (9.7) + + ----------------------------------- + -- 9.7.4 Triggering Alternative -- + ----------------------------------- + + -- Parsed by P_Select_Statement (9.7) + + --------------------------------- + -- 9.7.4 Triggering Statement -- + --------------------------------- + + -- Parsed by P_Select_Statement (9.7) + + --------------------------- + -- 9.7.4 Abortable Part -- + --------------------------- + + -- ABORTABLE_PART ::= SEQUENCE_OF_STATEMENTS + + -- The caller has verified that THEN ABORT is present, and Token is + -- pointing to the ABORT on entry (or if not, then we have an error) + + -- Error recovery: cannot raise Error_Resync + + function P_Abortable_Part return Node_Id is + Abortable_Part_Node : Node_Id; + + begin + Abortable_Part_Node := New_Node (N_Abortable_Part, Token_Ptr); + T_Abort; -- scan past ABORT + + if Ada_83 then + Error_Msg_SP ("(Ada 83) asynchronous select not allowed!"); + end if; + + Set_Statements (Abortable_Part_Node, P_Sequence_Of_Statements (SS_Sreq)); + return Abortable_Part_Node; + end P_Abortable_Part; + + -------------------------- + -- 9.8 Abort Statement -- + -------------------------- + + -- ABORT_STATEMENT ::= abort task_NAME {, task_NAME}; + + -- The caller has checked that the initial token is ABORT + + -- Error recovery: cannot raise Error_Resync + + function P_Abort_Statement return Node_Id is + Abort_Node : Node_Id; + + begin + Abort_Node := New_Node (N_Abort_Statement, Token_Ptr); + Scan; -- past ABORT + Set_Names (Abort_Node, New_List); + + loop + Append (P_Name, Names (Abort_Node)); + exit when Token /= Tok_Comma; + Scan; -- past comma + end loop; + + TF_Semicolon; + return Abort_Node; + end P_Abort_Statement; + +end Ch9; diff --git a/gcc/ada/par-endh.adb b/gcc/ada/par-endh.adb new file mode 100644 index 00000000000..fa5b8c20a1a --- /dev/null +++ b/gcc/ada/par-endh.adb @@ -0,0 +1,1191 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P A R . E N D H -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.61 $ +-- -- +-- Copyright (C) 1992-2001, 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +with Stringt; use Stringt; +with Uintp; use Uintp; + +with GNAT.Spelling_Checker; use GNAT.Spelling_Checker; + +separate (Par) +package body Endh is + + ---------------- + -- Local Data -- + ---------------- + + type End_Action_Type is ( + -- Type used to describe the result of the Pop_End_Context call + + Accept_As_Scanned, + -- Current end sequence is entirely c correct. In this case Token and + -- the scan pointer are left pointing past the end sequence (i.e. they + -- are unchanged from the values set on entry to Pop_End_Context). + + Insert_And_Accept, + -- Current end sequence is to be left in place to satisfy some outer + -- scope. Token and the scan pointer are set to point to the end + -- token, and should be left there. A message has been generated + -- indicating a missing end sequence. This status is also used for + -- the case when no end token is present. + + Skip_And_Accept, + -- The end sequence is incorrect (and an error message has been + -- posted), but it will still be accepted. In this case Token and + -- the scan pointer point back to the end token, and the caller + -- should skip past the end sequence before proceeding. + + Skip_And_Reject); + -- The end sequence is judged to belong to an unrecognized inner + -- scope. An appropriate message has been issued and the caller + -- should skip past the end sequence and then proceed as though + -- no end sequence had been encountered. + + End_Action : End_Action_Type; + -- The variable set by Pop_End_Context call showing which of the four + -- decisions described above is judged the best. + + End_Sloc : Source_Ptr; + -- Source location of END token + + End_OK : Boolean; + -- Set False if error is found in END line + + End_Column : Column_Number; + -- Column of END line + + End_Type : SS_End_Type; + -- Type of END expected. The special value E_Dummy is set to indicate that + -- no END token was present (so a missing END inserted message is needed) + + End_Labl : Node_Id; + -- Node_Id value for explicit name on END line, or for compiler supplied + -- name in the case where an optional name is not given. Empty if no name + -- appears. If non-empty, then it is either an N_Designator node for a + -- child unit or a node with a Chars field identifying the actual label. + + End_Labl_Present : Boolean; + -- Indicates that the value in End_Labl was for an explicit label. + + Syntax_OK : Boolean; + -- Set True if the entry is syntactically correct + + Token_OK : Boolean; + -- Set True if the keyword in the END sequence matches, or if neither + -- the END sequence nor the END stack entry has a keyword. + + Label_OK : Boolean; + -- Set True if both the END sequence and the END stack entry contained + -- labels (other than No_Name or Error_Name) and the labels matched. + -- This is a stronger condition than SYNTAX_OK, since it means that a + -- label was present, even in a case where it was optional. Note that + -- the case of no label required, and no label present does NOT set + -- Label_OK to True, it is True only if a positive label match is found. + + Column_OK : Boolean; + -- Column_OK is set True if the END sequence appears in the expected column + + Scan_State : Saved_Scan_State; + -- Save state at start of END sequence, in case we decide not to eat it up + + ----------------------- + -- Local Subprograms -- + ----------------------- + + procedure Evaluate_End_Entry (SS_Index : Int); + -- Compare scanned END entry (as recorded by a prior call to P_End_Scan) + -- with a specified entry in the scope stack (the single parameter is the + -- entry index in the scope stack). Note that Scan is not called. The above + -- variables xxx_OK are set to indicate the result of the evaluation. + + procedure Output_End_Deleted; + -- Output a message complaining that the current END structure does not + -- match anything and is being deleted. + + procedure Output_End_Expected (Ins : Boolean); + -- Output a message at the start of the current token which is always an + -- END, complaining that the END is not of the right form. The message + -- indicates the expected form. The information for the message is taken + -- from the top entry in the scope stack. The Ins parameter is True if + -- an end is being inserted, and false if an existing end is being + -- replaced. Note that in the case of a suspicious IS for the Ins case, + -- we do not output the message, but instead simply mark the scope stack + -- entry as being a case of a bad IS. + + procedure Output_End_Missing; + -- Output a message just before the current token, complaining that the + -- END is not of the right form. The message indicates the expected form. + -- The information for the message is taken from the top entry in the + -- scope stack. Note that in the case of a suspicious IS, we do not output + -- the message, but instead simply mark the scope stack entry as a bad IS. + + procedure Pop_End_Context; + -- Pop_End_Context is called after processing a construct, to pop the + -- top entry off the end stack. It decides on the appropriate action to + -- to take, signalling the result by setting End_Action as described in + -- the global variable section. + + function Same_Label (Label1, Label2 : Node_Id) return Boolean; + -- This function compares the two names associated with the given nodes. + -- If they are both simple (i.e. have Chars fields), then they have to + -- be the same name. Otherwise they must both be N_Selected_Component + -- nodes, referring to the same set of names, or Label1 is an N_Designator + -- referring to the same set of names as the N_Defining_Program_Unit_Name + -- in Label2. Any other combination returns False. This routine is used + -- to compare the End_Labl scanned from the End line with the saved label + -- value in the scope stack. + + --------------- + -- Check_End -- + --------------- + + function Check_End return Boolean is + Name_On_Separate_Line : Boolean; + -- Set True if the name on an END line is on a separate source line + -- from the END. This is highly suspicious, but is allowed. The point + -- is that we want to make sure that we don't just have a missing + -- semicolon misleading us into swallowing an identifier from the + -- following line. + + Name_Scan_State : Saved_Scan_State; + -- Save state at start of name if Name_On_Separate_Line is TRUE + + Span_Node : constant Node_Id := Scope.Table (Scope.Last).Node; + + begin + End_Labl_Present := False; + End_Labl := Empty; + + -- Our first task is to scan out the END sequence if one is present. + -- If none is present, signal by setting End_Type to E_Dummy. + + if Token /= Tok_End then + End_Type := E_Dummy; + + else + Save_Scan_State (Scan_State); -- at END + End_Sloc := Token_Ptr; + End_Column := Start_Column; + End_OK := True; + Scan; -- past END + + -- Set End_Span if expected. note that this will be useless + -- if we do not have the right ending keyword, but in this + -- case we have a malformed program anyway, and the setting + -- of End_Span will simply be unreliable in this case anyway. + + if Present (Span_Node) then + Set_End_Location (Span_Node, Token_Ptr); + end if; + + -- Cases of keywords where no label is allowed + + if Token = Tok_Case then + End_Type := E_Case; + Scan; -- past CASE + + elsif Token = Tok_If then + End_Type := E_If; + Scan; -- past IF + + elsif Token = Tok_Record then + End_Type := E_Record; + Scan; -- past RECORD + + elsif Token = Tok_Select then + End_Type := E_Select; + Scan; -- past SELECT + + -- Cases which do allow labels + + else + -- LOOP + + if Token = Tok_Loop then + Scan; -- past LOOP + End_Type := E_Loop; + + -- FOR or WHILE allowed (signalling error) to substitute for LOOP + -- if on the same line as the END + + elsif (Token = Tok_For or else Token = Tok_While) + and then not Token_Is_At_Start_Of_Line + then + Scan; -- past FOR or WHILE + End_Type := E_Loop; + End_OK := False; + + -- Cases with no keyword + + else + End_Type := E_Name; + end if; + + -- Now see if a name is present + + if Token = Tok_Identifier or else + Token = Tok_String_Literal or else + Token = Tok_Operator_Symbol + then + if Token_Is_At_Start_Of_Line then + Name_On_Separate_Line := True; + Save_Scan_State (Name_Scan_State); + else + Name_On_Separate_Line := False; + end if; + + End_Labl := P_Designator; + End_Labl_Present := True; + + -- We have now scanned out a name. Here is where we do a check + -- to catch the cases like: + -- + -- end loop + -- X := 3; + -- + -- where the missing semicolon might make us swallow up the X + -- as a bogus end label. In a situation like this, where the + -- apparent name is on a separate line, we accept it only if + -- it matches the label and is followed by a semicolon. + + if Name_On_Separate_Line then + if Token /= Tok_Semicolon or else + not Same_Label (End_Labl, Scope.Table (Scope.Last).Labl) + then + Restore_Scan_State (Name_Scan_State); + End_Labl := Empty; + End_Labl_Present := False; + end if; + end if; + + -- Here for case of name allowed, but no name present. We will + -- supply an implicit matching name, with source location set + -- to the scan location past the END token. + + else + End_Labl := Scope.Table (Scope.Last).Labl; + + if End_Labl > Empty_Or_Error then + + -- The task here is to construct a designator from the + -- opening label, with the components all marked as not + -- from source, and Is_End_Label set in the identifier + -- or operator symbol. The location for all components + -- is the curent token location. + + -- Case of child unit name + + if Nkind (End_Labl) = N_Defining_Program_Unit_Name then + declare + Eref : constant Node_Id := + Make_Identifier (Token_Ptr, + Chars => + Chars (Defining_Identifier (End_Labl))); + + function Copy_Name (N : Node_Id) return Node_Id; + -- Copies a selected component or identifier + + function Copy_Name (N : Node_Id) return Node_Id is + R : Node_Id; + + begin + if Nkind (N) = N_Selected_Component then + return + Make_Selected_Component (Token_Ptr, + Prefix => + Copy_Name (Prefix (N)), + Selector_Name => + Copy_Name (Selector_Name (N))); + + else + R := + Make_Identifier (Token_Ptr, + Chars => Chars (N)); + Set_Comes_From_Source (N, False); + return R; + end if; + end Copy_Name; + + begin + Set_Comes_From_Source (Eref, False); + + End_Labl := + Make_Designator (Token_Ptr, + Name => Copy_Name (Name (End_Labl)), + Identifier => Eref); + end; + + -- Simple identifier case + + elsif Nkind (End_Labl) = N_Defining_Identifier + or else Nkind (End_Labl) = N_Identifier + then + End_Labl := + Make_Identifier (Token_Ptr, + Chars => Chars (End_Labl)); + + elsif Nkind (End_Labl) = N_Defining_Operator_Symbol + or else Nkind (End_Labl) = N_Operator_Symbol + then + Get_Decoded_Name_String (Chars (End_Labl)); + + End_Labl := + Make_Operator_Symbol (Token_Ptr, + Chars => Chars (End_Labl), + Strval => String_From_Name_Buffer); + end if; + + Set_Comes_From_Source (End_Labl, False); + End_Labl_Present := False; + + -- Do style check for missing label + + if Style_Check + and then End_Type = E_Name + and then Present (Scope.Table (Scope.Last).Labl) + then + Style.No_End_Name (Scope.Table (Scope.Last).Labl); + end if; + end if; + end if; + end if; + + -- Except in case of END RECORD, semicolon must follow. For END + -- RECORD, a semicolon does follow, but it is part of a higher level + -- construct. In any case, a missing semicolon is not serious enough + -- to consider the END statement to be bad in the sense that we + -- are dealing with (i.e. to be suspicious that it is not in fact + -- the END statement we are looking for!) + + if End_Type /= E_Record then + if Token = Tok_Semicolon then + T_Semicolon; + + -- Semicolon is missing. If the missing semicolon is at the end + -- of the line, i.e. we are at the start of the line now, then + -- a missing semicolon gets flagged, but is not serious enough + -- to consider the END statement to be bad in the sense that we + -- are dealing with (i.e. to be suspicious that this END is not + -- the END statement we are looking for). + + -- Similarly, if we are at a colon, we flag it but a colon for + -- a semicolon is not serious enough to consider the END to be + -- incorrect. Same thing for a period in place of a semicolon. + + elsif Token_Is_At_Start_Of_Line + or else Token = Tok_Colon + or else Token = Tok_Dot + then + T_Semicolon; + + -- If the missing semicolon is not at the start of the line, + -- then we do consider the END line to be dubious in this sense. + + else + End_OK := False; + end if; + end if; + end if; + + -- Now we call the Pop_End_Context routine to get a recommendation + -- as to what should be done with the END sequence we have scanned. + + Pop_End_Context; + + -- Remaining action depends on End_Action set by Pop_End_Context + + case End_Action is + + -- Accept_As_Scanned. In this case, Pop_End_Context left Token + -- pointing past the last token of a syntactically correct END + + when Accept_As_Scanned => + + -- Syntactically correct included the possibility of a missing + -- semicolon. If we do have a missing semicolon, then we have + -- already given a message, but now we scan out possible rubbish + -- on the same line as the END + + while not Token_Is_At_Start_Of_Line + and then Prev_Token /= Tok_Record + and then Prev_Token /= Tok_Semicolon + and then Token /= Tok_End + and then Token /= Tok_EOF + loop + Scan; -- past junk + end loop; + + return True; + + -- Insert_And_Accept. In this case, Pop_End_Context has reset Token + -- to point to the start of the END sequence, and recommends that it + -- be left in place to satisfy an outer scope level END. This means + -- that we proceed as though an END were present, and leave the scan + -- pointer unchanged. + + when Insert_And_Accept => + return True; + + -- Skip_And_Accept. In this case, Pop_End_Context has reset Token + -- to point to the start of the END sequence. This END sequence is + -- syntactically incorrect, and an appropriate error message has + -- already been posted. Pop_End_Context recommends accepting the + -- END sequence as the one we want, so we skip past it and then + -- proceed as though an END were present. + + when Skip_And_Accept => + End_Skip; + return True; + + -- Skip_And_Reject. In this case, Pop_End_Context has reset Token + -- to point to the start of the END sequence. This END sequence is + -- syntactically incorrect, and an appropriate error message has + -- already been posted. Pop_End_Context recommends entirely ignoring + -- this END sequence, so we skip past it and then return False, since + -- as far as the caller is concerned, no END sequence is present. + + when Skip_And_Reject => + End_Skip; + return False; + end case; + end Check_End; + + -------------- + -- End Skip -- + -------------- + + -- This procedure skips past an END sequence. On entry Token contains + -- Tok_End, and we know that the END sequence is syntactically incorrect, + -- and that an appropriate error message has already been posted. The + -- mission is simply to position the scan pointer to be the best guess of + -- the position after the END sequence. We do not issue any additional + -- error messages while carrying this out. + + -- Error recovery: does not raise Error_Resync + + procedure End_Skip is + begin + Scan; -- past END + + -- If the scan past the END leaves us on the next line, that's probably + -- where we should quit the scan, since it is likely that what we have + -- is a missing semicolon. Consider the following: + + -- END + -- Process_Input; + + -- This will have looked like a syntactically valid END sequence to the + -- initial scan of the END, but subsequent checking will have determined + -- that the label Process_Input is not an appropriate label. The real + -- error is a missing semicolon after the END, and by leaving the scan + -- pointer just past the END, we will improve the error recovery. + + if Token_Is_At_Start_Of_Line then + return; + end if; + + -- If there is a semicolon after the END, scan it out and we are done + + if Token = Tok_Semicolon then + T_Semicolon; + return; + end if; + + -- Otherwise skip past a token after the END on the same line. Note + -- that we do not eat a token on the following line since it seems + -- very unlikely in any case that the END gets separated from its + -- token, and we do not want to swallow up a keyword that starts a + -- legitimate construct following the bad END. + + if not Token_Is_At_Start_Of_Line + and then + + -- Cases of normal tokens following an END + + (Token = Tok_Case or else + Token = Tok_For or else + Token = Tok_If or else + Token = Tok_Loop or else + Token = Tok_Record or else + Token = Tok_Select or else + + -- Cases of bogus keywords ending loops + + Token = Tok_For or else + Token = Tok_While or else + + -- Cases of operator symbol names without quotes + + Token = Tok_Abs or else + Token = Tok_And or else + Token = Tok_Mod or else + Token = Tok_Not or else + Token = Tok_Or or else + Token = Tok_Xor) + + then + Scan; -- past token after END + + -- If that leaves us on the next line, then we are done. This is the + -- same principle described above for the case of END at line end + + if Token_Is_At_Start_Of_Line then + return; + + -- If we just scanned out record, then we are done, since the + -- semicolon after END RECORD is not part of the END sequence + + elsif Prev_Token = Tok_Record then + return; + + -- If we have a semicolon, scan it out and we are done + + elsif Token = Tok_Semicolon then + T_Semicolon; + return; + end if; + end if; + + -- Check for a label present on the same line + + loop + if Token_Is_At_Start_Of_Line then + return; + end if; + + if Token /= Tok_Identifier + and then Token /= Tok_Operator_Symbol + and then Token /= Tok_String_Literal + then + exit; + end if; + + Scan; -- past identifier, operator symbol or string literal + + if Token_Is_At_Start_Of_Line then + return; + elsif Token = Tok_Dot then + Scan; -- past dot + end if; + end loop; + + -- Skip final semicolon + + if Token = Tok_Semicolon then + T_Semicolon; + + -- If we don't have a final semicolon, skip until we either encounter + -- an END token, or a semicolon or the start of the next line. This + -- allows general junk to follow the end line (normally it is hard to + -- think that anyone will put anything deliberate here, and remember + -- that we know there is a missing semicolon in any case). We also + -- quite on an EOF (or else we would get stuck in an infinite loop + -- if there is no line end at the end of the last line of the file) + + else + while Token /= Tok_End + and then Token /= Tok_EOF + and then Token /= Tok_Semicolon + and then not Token_Is_At_Start_Of_Line + loop + Scan; -- past junk token on same line + end loop; + end if; + + return; + end End_Skip; + + -------------------- + -- End Statements -- + -------------------- + + -- This procedure is called when END is required or expected to terminate + -- a sequence of statements. The caller has already made an appropriate + -- entry on the scope stack to describe the expected form of the END. + -- End_Statements should only be used in cases where the only appropriate + -- terminator is END. + + -- Error recovery: cannot raise Error_Resync; + + procedure End_Statements (Parent : Node_Id := Empty) is + begin + -- This loop runs more than once in the case where Check_End rejects + -- the END sequence, as indicated by Check_End returning False. + + loop + if Check_End then + if Present (Parent) then + Set_End_Label (Parent, End_Labl); + end if; + + return; + end if; + + -- Extra statements past the bogus END are discarded. This is not + -- ideal for maximum error recovery, but it's too much trouble to + -- find an appropriate place to put them! + + Discard_Junk_List (P_Sequence_Of_Statements (SS_None)); + end loop; + end End_Statements; + + ------------------------ + -- Evaluate End Entry -- + ------------------------ + + procedure Evaluate_End_Entry (SS_Index : Int) is + begin + Column_OK := (End_Column = Scope.Table (SS_Index).Ecol); + + Token_OK := (End_Type = Scope.Table (SS_Index).Etyp or else + (End_Type = E_Name and then + Scope.Table (SS_Index).Etyp >= E_Name)); + + Label_OK := End_Labl_Present + and then + (Same_Label (End_Labl, Scope.Table (SS_Index).Labl) + or else Scope.Table (SS_Index).Labl = Error); + + -- Compute setting of Syntax_OK. We definitely have a syntax error + -- if the Token does not match properly or if P_End_Scan detected + -- a syntax error such as a missing semicolon. + + if not Token_OK or not End_OK then + Syntax_OK := False; + + -- Final check is that label is OK. Certainly it is OK if there + -- was an exact match on the label (the END label = the stack label) + + elsif Label_OK then + Syntax_OK := True; + + -- Case of label present + + elsif End_Labl_Present then + + -- If probably misspelling, then complain, and pretend it is OK + + declare + Nam : constant Node_Or_Entity_Id := Scope.Table (SS_Index).Labl; + + begin + if Nkind (End_Labl) in N_Has_Chars + and then Nkind (Nam) in N_Has_Chars + and then Chars (End_Labl) > Error_Name + and then Chars (Nam) > Error_Name + then + Get_Name_String (Chars (End_Labl)); + Error_Msg_Name_1 := Chars (Nam); + + if Error_Msg_Name_1 > Error_Name then + declare + S : String (1 .. Name_Len) := Name_Buffer (1 .. Name_Len); + + begin + Get_Name_String (Error_Msg_Name_1); + + if Is_Bad_Spelling_Of + (Name_Buffer (1 .. Name_Len), S) + then + Error_Msg_N ("misspelling of %", End_Labl); + Syntax_OK := True; + return; + end if; + end; + end if; + end if; + end; + + Syntax_OK := False; + + -- Otherwise we have cases of no label on the END line. For the loop + -- case, this is acceptable only if the loop is unlabeled. + + elsif End_Type = E_Loop then + Syntax_OK := (Scope.Table (SS_Index).Labl = Empty); + + -- Cases where a label is definitely allowed on the END line + + elsif End_Type = E_Name then + Syntax_OK := (Scope.Table (SS_Index).Labl = Empty or else + not Scope.Table (SS_Index).Lreq); + + -- Otherwise we have cases which don't allow labels anyway, so we + -- certainly accept an END which does not have a label. + + else + Syntax_OK := True; + end if; + end Evaluate_End_Entry; + + ------------------------ + -- Output End Deleted -- + ------------------------ + + procedure Output_End_Deleted is + begin + + if End_Type = E_Loop then + Error_Msg_SC ("no LOOP for this `END LOOP`!"); + + elsif End_Type = E_Case then + Error_Msg_SC ("no CASE for this `END CASE`"); + + elsif End_Type = E_If then + Error_Msg_SC ("no IF for this `END IF`!"); + + elsif End_Type = E_Record then + Error_Msg_SC ("no RECORD for this `END RECORD`!"); + + elsif End_Type = E_Select then + Error_Msg_SC ("no SELECT for this `END SELECT`!"); + + else + Error_Msg_SC ("no BEGIN for this END!"); + end if; + end Output_End_Deleted; + + ------------------------- + -- Output End Expected -- + ------------------------- + + procedure Output_End_Expected (Ins : Boolean) is + End_Type : SS_End_Type; + + begin + -- Suppress message if this was a potentially junk entry (e.g. a + -- record entry where no record keyword was present. + + if Scope.Table (Scope.Last).Junk then + return; + end if; + + End_Type := Scope.Table (Scope.Last).Etyp; + Error_Msg_Col := Scope.Table (Scope.Last).Ecol; + Error_Msg_Node_1 := Scope.Table (Scope.Last).Labl; + Error_Msg_Sloc := Scope.Table (Scope.Last).Sloc; + + -- Suppress message if error was posted on opening label + + if Present (Error_Msg_Node_1) + and then Error_Posted (Error_Msg_Node_1) + then + return; + end if; + + if End_Type = E_Case then + Error_Msg_SC ("`END CASE;` expected@ for CASE#!"); + + elsif End_Type = E_If then + Error_Msg_SC ("`END IF;` expected@ for IF#!"); + + elsif End_Type = E_Loop then + if Error_Msg_Node_1 = Empty then + Error_Msg_SC + ("`END LOOP;` expected@ for LOOP#!"); + else + Error_Msg_SC ("`END LOOP &;` expected@!"); + end if; + + elsif End_Type = E_Record then + Error_Msg_SC + ("`END RECORD;` expected@ for RECORD#!"); + + elsif End_Type = E_Select then + Error_Msg_SC + ("`END SELECT;` expected@ for SELECT#!"); + + -- All remaining cases are cases with a name (we do not treat + -- the suspicious is cases specially for a replaced end, only + -- for an inserted end). + + elsif End_Type = E_Name or else (not Ins) then + if Error_Msg_Node_1 = Empty then + Error_Msg_SC ("`END;` expected@ for BEGIN#!"); + else + Error_Msg_SC ("`END &;` expected@!"); + end if; + + -- The other possibility is a missing END for a subprogram with a + -- suspicious IS (that probably should have been a semicolon). The + -- Missing IS confirms the suspicion! + + else -- End_Type = E_Suspicious_Is or E_Bad_Is + Scope.Table (Scope.Last).Etyp := E_Bad_Is; + end if; + end Output_End_Expected; + + ------------------------ + -- Output End Missing -- + ------------------------ + + procedure Output_End_Missing is + End_Type : SS_End_Type; + + begin + -- Suppress message if this was a potentially junk entry (e.g. a + -- record entry where no record keyword was present. + + if Scope.Table (Scope.Last).Junk then + return; + end if; + + End_Type := Scope.Table (Scope.Last).Etyp; + Error_Msg_Node_1 := Scope.Table (Scope.Last).Labl; + Error_Msg_Sloc := Scope.Table (Scope.Last).Sloc; + + if End_Type = E_Case then + Error_Msg_BC ("missing `END CASE;` for CASE#!"); + + elsif End_Type = E_If then + Error_Msg_BC ("missing `END IF;` for IF#!"); + + elsif End_Type = E_Loop then + if Error_Msg_Node_1 = Empty then + Error_Msg_BC ("missing `END LOOP;` for LOOP#!"); + else + Error_Msg_BC ("missing `END LOOP &;`!"); + end if; + + elsif End_Type = E_Record then + Error_Msg_SC + ("missing `END RECORD;` for RECORD#!"); + + elsif End_Type = E_Select then + Error_Msg_BC + ("missing `END SELECT;` for SELECT#!"); + + elsif End_Type = E_Name then + if Error_Msg_Node_1 = Empty then + Error_Msg_BC ("missing `END;` for BEGIN#!"); + else + Error_Msg_BC ("missing `END &;`!"); + end if; + + else -- End_Type = E_Suspicious_Is or E_Bad_Is + Scope.Table (Scope.Last).Etyp := E_Bad_Is; + end if; + end Output_End_Missing; + + --------------------- + -- Pop End Context -- + --------------------- + + procedure Pop_End_Context is + + Pretty_Good : Boolean; + -- This flag is set True if the END sequence is syntactically incorrect, + -- but is (from a heuristic point of view), pretty likely to be simply + -- a misspelling of the intended END. + + Outer_Match : Boolean; + -- This flag is set True if we decide that the current END sequence + -- belongs to some outer level entry in the scope stack, and thus + -- we will NOT eat it up in matching the current expected END. + + begin + -- If not at END, then output END expected message + + if End_Type = E_Dummy then + Output_End_Missing; + Pop_Scope_Stack; + End_Action := Insert_And_Accept; + return; + + -- Otherwise we do have an END present + + else + -- A special check. If we have END; followed by an end of file, + -- WITH or SEPARATE, then if we are not at the outer level, then + -- we have a sytax error. Consider the example: + + -- ... + -- declare + -- X : Integer; + -- begin + -- X := Father (A); + -- Process (X, X); + -- end; + -- with Package1; + -- ... + + -- Now the END; here is a syntactically correct closer for the + -- declare block, but if we eat it up, then we obviously have + -- a missing END for the outer context (since WITH can only appear + -- at the outer level. + + -- In this situation, we always reserve the END; for the outer level, + -- even if it is in the wrong column. This is because it's much more + -- useful to have the error message point to the DECLARE than to the + -- package header in this case. + + -- We also reserve an end with a name before the end of file if the + -- name is the one we expect at the outer level. + + if (Token = Tok_EOF or else + Token = Tok_With or else + Token = Tok_Separate) + and then End_Type >= E_Name + and then (not End_Labl_Present + or else Same_Label (End_Labl, Scope.Table (1).Labl)) + and then Scope.Last > 1 + then + Restore_Scan_State (Scan_State); -- to END + Output_End_Expected (Ins => True); + Pop_Scope_Stack; + End_Action := Insert_And_Accept; + return; + end if; + + -- Otherwise we go through the normal END evaluation procedure + + Evaluate_End_Entry (Scope.Last); + + -- If top entry in stack is syntactically correct, then we have + -- scanned it out and everything is fine. This is the required + -- action to properly process correct Ada programs. + + if Syntax_OK then + + -- Complain if checking columns and END is not in right column. + -- Right in this context means exactly right, or on the same + -- line as the opener. + + if Style.RM_Column_Check then + if End_Column /= Scope.Table (Scope.Last).Ecol + and then Current_Line_Start > Scope.Table (Scope.Last).Sloc + then + Error_Msg_Col := Scope.Table (Scope.Last).Ecol; + Error_Msg + ("(style) END in wrong column, should be@", End_Sloc); + end if; + end if; + + -- One final check. If the end had a label, check for an exact + -- duplicate of this end sequence, and if so, skip it with an + -- appropriate message. + + if End_Labl_Present and then Token = Tok_End then + declare + Scan_State : Saved_Scan_State; + End_Loc : constant Source_Ptr := Token_Ptr; + Nxt_Labl : Node_Id; + Dup_Found : Boolean := False; + + begin + Save_Scan_State (Scan_State); + + Scan; -- past END + + if Token = Tok_Identifier + or else Token = Tok_Operator_Symbol + then + Nxt_Labl := P_Designator; + + -- We only consider it an error if the label is a match + -- and would be wrong for the level one above us, and + -- the indentation is the same. + + if Token = Tok_Semicolon + and then Same_Label (End_Labl, Nxt_Labl) + and then End_Column = Start_Column + and then + (Scope.Last = 1 + or else + (No (Scope.Table (Scope.Last - 1).Labl) + or else + not Same_Label + (End_Labl, + Scope.Table (Scope.Last - 1).Labl))) + then + T_Semicolon; + Error_Msg ("duplicate end line ignored", End_Loc); + Dup_Found := True; + end if; + end if; + + if not Dup_Found then + Restore_Scan_State (Scan_State); + end if; + end; + end if; + + -- All OK, so return to caller indicating END is OK + + Pop_Scope_Stack; + End_Action := Accept_As_Scanned; + return; + end if; + + -- If that check failed, then we definitely have an error. The issue + -- is how to choose among three possible courses of action: + + -- 1. Ignore the current END text completely, scanning past it, + -- deciding that it belongs neither to the current context, + -- nor to any outer context. + + -- 2. Accept the current END text, scanning past it, and issuing + -- an error message that it does not have the right form. + + -- 3. Leave the current END text in place, NOT scanning past it, + -- issuing an error message indicating the END expected for the + -- current context. In this case, the END is available to match + -- some outer END context. + + -- From a correct functioning point of view, it does not make any + -- difference which of these three approaches we take, the program + -- will work correctly in any case. However, making an accurate + -- choice among these alternatives, i.e. choosing the one that + -- corresponds to what the programmer had in mind, does make a + -- significant difference in the quality of error recovery. + + Restore_Scan_State (Scan_State); -- to END + + -- First we see how good the current END entry is with respect to + -- what we expect. It is considered pretty good if the token is OK, + -- and either the label or the column matches. an END for RECORD is + -- always considered to be pretty good in the record case. This is + -- because not only does a record disallow a nested structure, but + -- also it is unlikely that such nesting could occur by accident. + + Pretty_Good := (Token_OK and (Column_OK or Label_OK)) + or else Scope.Table (Scope.Last).Etyp = E_Record; + + -- Next check, if there is a deeper entry in the stack which + -- has a very high probability of being acceptable, then insert + -- the END entry we want, leaving the higher level entry for later + + for J in reverse 1 .. Scope.Last - 1 loop + Evaluate_End_Entry (J); + + -- To even consider the deeper entry to be immediately acceptable, + -- it must be syntactically correct. Furthermore it must either + -- have a correct label, or the correct column. If the current + -- entry was a close match (Pretty_Good set), then we are even + -- more strict in accepting the outer level one: even if it has + -- the right label, it must have the right column as well. + + if Syntax_OK then + if Pretty_Good then + Outer_Match := Label_OK and Column_OK; + else + Outer_Match := Label_OK or Column_OK; + end if; + else + Outer_Match := False; + end if; + + -- If the outer entry does convincingly match the END text, then + -- back up the scan to the start of the END sequence, issue an + -- error message indicating the END we expected, and return with + -- Token pointing to the END (case 3 from above discussion). + + if Outer_Match then + Output_End_Missing; + Pop_Scope_Stack; + End_Action := Insert_And_Accept; + return; + end if; + end loop; + + -- Here we have a situation in which the current END entry is + -- syntactically incorrect, but there is no deeper entry in the + -- END stack which convincingly matches it. + + -- If the END text was judged to be a Pretty_Good match for the + -- expected token or if it appears left of the expected column, + -- then we will accept it as the one we want, scanning past it, even + -- though it is not completely right (we issue a message showing what + -- we expected it to be). This is action 2 from the discussion above. + -- There is one other special case to consider: the LOOP case. + -- Consider the example: + + -- Lbl: loop + -- null; + -- end loop; + + -- Here the column lines up with Lbl, so END LOOP is to the right, + -- but it is still acceptable. LOOP is the one case where alignment + -- practices vary substantially in practice. + + if Pretty_Good + or else End_Column <= Scope.Table (Scope.Last).Ecol + or else (End_Type = Scope.Table (Scope.Last).Etyp + and then End_Type = E_Loop) + then + Output_End_Expected (Ins => False); + Pop_Scope_Stack; + End_Action := Skip_And_Accept; + return; + + -- Here we have the case where the END is to the right of the + -- expected column and does not have a correct label to convince + -- us that it nevertheless belongs to the current scope. For this + -- we consider that it probably belongs not to the current context, + -- but to some inner context that was not properly recognized (due to + -- other syntax errors), and for which no proper scope stack entry + -- was made. The proper action in this case is to delete the END text + -- and return False to the caller as a signal to keep on looking for + -- an acceptable END. This is action 1 from the discussion above. + + else + Output_End_Deleted; + End_Action := Skip_And_Reject; + return; + end if; + end if; + end Pop_End_Context; + + ---------------- + -- Same_Label -- + ---------------- + + function Same_Label (Label1, Label2 : Node_Id) return Boolean is + begin + if Nkind (Label1) in N_Has_Chars + and then Nkind (Label2) in N_Has_Chars + then + return Chars (Label1) = Chars (Label2); + + elsif Nkind (Label1) = N_Selected_Component + and then Nkind (Label2) = N_Selected_Component + then + return Same_Label (Prefix (Label1), Prefix (Label2)) and then + Same_Label (Selector_Name (Label1), Selector_Name (Label2)); + + elsif Nkind (Label1) = N_Designator + and then Nkind (Label2) = N_Defining_Program_Unit_Name + then + return Same_Label (Name (Label1), Name (Label2)) and then + Same_Label (Identifier (Label1), Defining_Identifier (Label2)); + + else + return False; + end if; + end Same_Label; + +end Endh; diff --git a/gcc/ada/par-labl.adb b/gcc/ada/par-labl.adb new file mode 100644 index 00000000000..e43d3f3f01d --- /dev/null +++ b/gcc/ada/par-labl.adb @@ -0,0 +1,202 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P A R . L A B L -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.18 $ -- +-- -- +-- Copyright (C) 1992-1998, 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +separate (Par) +procedure Labl is + Enclosing_Body_Or_Block : Node_Id; + -- Innermost enclosing body or block statement + + Label_Decl_Node : Node_Id; + -- Implicit label declaration node + + Defining_Ident_Node : Node_Id; + -- Defining identifier node for implicit label declaration + + Next_Label_Elmt : Elmt_Id; + -- Next element on label element list + + Label_Node : Node_Id; + -- Next label node to process + + function Find_Enclosing_Body_Or_Block (N : Node_Id) return Node_Id; + -- Find the innermost body or block that encloses N. + + function Find_Enclosing_Body (N : Node_Id) return Node_Id; + -- Find the innermost body that encloses N. + + procedure Check_Distinct_Labels; + -- Checks the rule in RM-5.1(11), which requires distinct identifiers + -- for all the labels in a given body. + + --------------------------- + -- Check_Distinct_Labels -- + --------------------------- + + procedure Check_Distinct_Labels is + Label_Id : constant Node_Id := Identifier (Label_Node); + + Enclosing_Body : constant Node_Id := + Find_Enclosing_Body (Enclosing_Body_Or_Block); + -- Innermost enclosing body + + Next_Other_Label_Elmt : Elmt_Id := First_Elmt (Label_List); + -- Next element on label element list + + Other_Label : Node_Id; + -- Next label node to process + + begin + -- Loop through all the labels, and if we find some other label + -- (i.e. not Label_Node) that has the same identifier, + -- and whose innermost enclosing body is the same, + -- then we have an error. + + -- Note that in the worst case, this is quadratic in the number + -- of labels. However, labels are not all that common, and this + -- is only called for explicit labels. + -- ???Nonetheless, the efficiency could be improved. For example, + -- call Labl for each body, rather than once per compilation. + + while Present (Next_Other_Label_Elmt) loop + Other_Label := Node (Next_Other_Label_Elmt); + + exit when Label_Node = Other_Label; + + if Chars (Label_Id) = Chars (Identifier (Other_Label)) + and then Enclosing_Body = Find_Enclosing_Body (Other_Label) + then + Error_Msg_Sloc := Sloc (Other_Label); + Error_Msg_N ("& conflicts with label#", Label_Id); + exit; + end if; + + Next_Elmt (Next_Other_Label_Elmt); + end loop; + end Check_Distinct_Labels; + + ------------------------- + -- Find_Enclosing_Body -- + ------------------------- + + function Find_Enclosing_Body (N : Node_Id) return Node_Id is + Result : Node_Id := N; + + begin + -- This is the same as Find_Enclosing_Body_Or_Block, except + -- that we skip block statements and accept statements, instead + -- of stopping at them. + + while Present (Result) + and then Nkind (Result) /= N_Entry_Body + and then Nkind (Result) /= N_Task_Body + and then Nkind (Result) /= N_Package_Body + and then Nkind (Result) /= N_Subprogram_Body + loop + Result := Parent (Result); + end loop; + + return Result; + end Find_Enclosing_Body; + + ---------------------------------- + -- Find_Enclosing_Body_Or_Block -- + ---------------------------------- + + function Find_Enclosing_Body_Or_Block (N : Node_Id) return Node_Id is + Result : Node_Id := Parent (N); + + begin + -- Climb up the parent chain until we find a body or block. + + while Present (Result) + and then Nkind (Result) /= N_Accept_Statement + and then Nkind (Result) /= N_Entry_Body + and then Nkind (Result) /= N_Task_Body + and then Nkind (Result) /= N_Package_Body + and then Nkind (Result) /= N_Subprogram_Body + and then Nkind (Result) /= N_Block_Statement + loop + Result := Parent (Result); + end loop; + + return Result; + end Find_Enclosing_Body_Or_Block; + +-- Start of processing for Par.Labl + +begin + Next_Label_Elmt := First_Elmt (Label_List); + + while Present (Next_Label_Elmt) loop + Label_Node := Node (Next_Label_Elmt); + + if not Comes_From_Source (Label_Node) then + goto Next_Label; + end if; + + -- Find the innermost enclosing body or block, which is where + -- we need to implicitly declare this label + + Enclosing_Body_Or_Block := Find_Enclosing_Body_Or_Block (Label_Node); + + -- If we didn't find a parent, then the label in question never got + -- hooked into a reasonable declarative part. This happens only in + -- error situations, and we simply ignore the entry (we aren't going + -- to get into the semantics in any case given the error). + + if Present (Enclosing_Body_Or_Block) then + Check_Distinct_Labels; + + -- Now create the implicit label declaration node and its + -- corresponding defining identifier. Note that the defining + -- occurrence of a label is the implicit label declaration that + -- we are creating. The label itself is an applied occurrence. + + Label_Decl_Node := + New_Node (N_Implicit_Label_Declaration, Sloc (Label_Node)); + Defining_Ident_Node := + New_Entity (N_Defining_Identifier, Sloc (Identifier (Label_Node))); + Set_Chars (Defining_Ident_Node, Chars (Identifier (Label_Node))); + Set_Defining_Identifier (Label_Decl_Node, Defining_Ident_Node); + Set_Label_Construct (Label_Decl_Node, Label_Node); + + -- Now attach the implicit label declaration to the appropriate + -- declarative region, creating a declaration list if none exists + + if not Present (Declarations (Enclosing_Body_Or_Block)) then + Set_Declarations (Enclosing_Body_Or_Block, New_List); + end if; + + Append (Label_Decl_Node, Declarations (Enclosing_Body_Or_Block)); + end if; + + <<Next_Label>> + Next_Elmt (Next_Label_Elmt); + end loop; + +end Labl; diff --git a/gcc/ada/par-load.adb b/gcc/ada/par-load.adb new file mode 100644 index 00000000000..39934caacb0 --- /dev/null +++ b/gcc/ada/par-load.adb @@ -0,0 +1,410 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P A R . L O A D -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.60 $ +-- -- +-- Copyright (C) 1992-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +-- The Par.Load procedure loads all units that are definitely required before +-- it makes any sense at all to proceed with semantic analysis, including +-- with'ed units, corresponding specs for bodies, parents of child specs, +-- and parents of subunits. All these units are loaded and pointers installed +-- in the tree as described in the spec of package Lib. + +with Fname; use Fname; +with Fname.UF; use Fname.UF; +with Lib.Load; use Lib.Load; +with Uname; use Uname; +with Namet; use Namet; +with Casing; use Casing; +with Opt; use Opt; +with Osint; use Osint; +with Sinput.L; use Sinput.L; +with Stylesw; use Stylesw; +with Validsw; use Validsw; + +separate (Par) +procedure Load is + + File_Name : File_Name_Type; + -- Name of file for current unit, derived from unit name + + Cur_Unum : Unit_Number_Type := Current_Source_Unit; + -- Unit number of unit that we just finished parsing. Note that we need + -- to capture this, because Source_Unit will change as we parse new + -- source files in the multiple main source file case. + + Curunit : constant Node_Id := Cunit (Cur_Unum); + -- Compilation unit node for current compilation unit + + Loc : Source_Ptr := Sloc (Curunit); + -- Source location for compilation unit node + + Save_Style_Check : Boolean; + Save_Style_Checks : Style_Check_Options; + -- Save style check so it can be restored later + + Save_Validity_Check : Boolean; + Save_Validity_Checks : Validity_Check_Options; + -- Save validity check so it can be restored later + + With_Cunit : Node_Id; + -- Compilation unit node for withed unit + + Context_Node : Node_Id; + -- Next node in context items list + + With_Node : Node_Id; + -- N_With_Clause node + + Spec_Name : Unit_Name_Type; + -- Unit name of required spec + + Body_Name : Unit_Name_Type; + -- Unit name of corresponding body + + Unum : Unit_Number_Type; + -- Unit number of loaded unit + + function Same_File_Name_Except_For_Case + (Expected_File_Name : File_Name_Type; + Actual_File_Name : File_Name_Type) + return Boolean; + -- Given an actual file name and an expected file name (the latter being + -- derived from the unit name), determine if they are the same except for + -- possibly different casing of letters. + + function Same_File_Name_Except_For_Case + (Expected_File_Name : File_Name_Type; + Actual_File_Name : File_Name_Type) + return Boolean + is + begin + Get_Name_String (Actual_File_Name); + Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); + + declare + Lower_Case_Actual_File_Name : String (1 .. Name_Len); + + begin + Lower_Case_Actual_File_Name := Name_Buffer (1 .. Name_Len); + Get_Name_String (Expected_File_Name); + Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); + return Lower_Case_Actual_File_Name = Name_Buffer (1 .. Name_Len); + end; + + end Same_File_Name_Except_For_Case; + +-- Start of processing for Load + +begin + -- Don't do any loads if we already had a fatal error + + if Fatal_Error (Cur_Unum) then + return; + end if; + + Save_Style_Check_Options (Save_Style_Checks); + Save_Style_Check := Opt.Style_Check; + + Save_Validity_Check_Options (Save_Validity_Checks); + Save_Validity_Check := Opt.Validity_Checks_On; + + -- If main unit, set Main_Unit_Entity (this will get overwritten if + -- the main unit has a separate spec, that happens later on in Load) + + if Cur_Unum = Main_Unit then + Main_Unit_Entity := Cunit_Entity (Main_Unit); + end if; + + -- If we have no unit name, things are seriously messed up by previous + -- errors, and we should not try to continue compilation. + + if Unit_Name (Cur_Unum) = No_Name then + raise Unrecoverable_Error; + end if; + + -- Next step, make sure that the unit name matches the file name + -- and issue a warning message if not. We only output this for the + -- main unit, since for other units it is more serious and is + -- caught in a separate test below. + + File_Name := + Get_File_Name + (Unit_Name (Cur_Unum), + Subunit => Nkind (Unit (Cunit (Cur_Unum))) = N_Subunit); + + if Cur_Unum = Main_Unit + and then File_Name /= Unit_File_Name (Cur_Unum) + and then (File_Names_Case_Sensitive + or not Same_File_Name_Except_For_Case + (File_Name, Unit_File_Name (Cur_Unum))) + then + Error_Msg_Name_1 := File_Name; + Error_Msg + ("?file name does not match unit name, should be{", Sloc (Curunit)); + end if; + + -- For units other than the main unit, the expected unit name is set and + -- must be the same as the actual unit name, or we are in big trouble, and + -- abandon the compilation since there are situations where this really + -- gets us into bad trouble (e.g. some subunit situations). + + if Cur_Unum /= Main_Unit + and then Expected_Unit (Cur_Unum) /= Unit_Name (Cur_Unum) + then + Loc := Error_Location (Cur_Unum); + Error_Msg_Name_1 := Unit_File_Name (Cur_Unum); + Get_Name_String (Error_Msg_Name_1); + + -- Check for predefined file case + + if Name_Len > 1 + and then Name_Buffer (2) = '-' + and then (Name_Buffer (1) = 'a' + or else + Name_Buffer (1) = 's' + or else + Name_Buffer (1) = 'i' + or else + Name_Buffer (1) = 'g') + then + -- In the predefined file case, we know the user did not construct + -- their own package, but we got the wrong one. This means that the + -- name supplied by the user crunched to something we recognized, + -- but then the file did not contain the unit expected. Most likely + -- this is due to a misspelling, e.g. + + -- with Ada.Calender; + + -- This crunches to a-calend, which indeed contains the unit + -- Ada.Calendar, and we can diagnose the misspelling. This is + -- a simple heuristic, but it catches many common cases of + -- misspelling of predefined unit names without needing a full + -- list of them. + + Error_Msg_Name_1 := Expected_Unit (Cur_Unum); + Error_Msg ("% is not a predefined library unit!", Loc); + Error_Msg_Name_1 := Unit_Name (Cur_Unum); + Error_Msg ("possible misspelling of %!", Loc); + + -- Non-predefined file name case + + else + Error_Msg ("file { does not contain expected unit!", Loc); + Error_Msg_Unit_1 := Expected_Unit (Cur_Unum); + Error_Msg ("expected unit $!", Loc); + Error_Msg_Unit_1 := Unit_Name (Cur_Unum); + Error_Msg ("found unit $!", Loc); + end if; + + raise Unrecoverable_Error; + end if; + + -- If current unit is a body, load its corresponding spec + + if Nkind (Unit (Curunit)) = N_Package_Body + or else Nkind (Unit (Curunit)) = N_Subprogram_Body + then + Spec_Name := Get_Spec_Name (Unit_Name (Cur_Unum)); + Unum := + Load_Unit + (Load_Name => Spec_Name, + Required => False, + Subunit => False, + Error_Node => Curunit, + Corr_Body => Cur_Unum); + + -- If we successfully load the unit, then set the spec pointer. Once + -- again note that if the loaded unit has a fatal error, Load will + -- have set our Fatal_Error flag to propagate this condition. + + if Unum /= No_Unit then + Set_Library_Unit (Curunit, Cunit (Unum)); + + -- If this is a separate spec for the main unit, then we reset + -- Main_Unit_Entity to point to the entity for this separate spec + + if Cur_Unum = Main_Unit then + Main_Unit_Entity := Cunit_Entity (Unum); + end if; + + -- If we don't find the spec, then if we have a subprogram body, we + -- are still OK, we just have a case of a body acting as its own spec + + elsif Nkind (Unit (Curunit)) = N_Subprogram_Body then + Set_Acts_As_Spec (Curunit, True); + Set_Library_Unit (Curunit, Curunit); + + -- Otherwise we do have an error, repeat the load request for the spec + -- with Required set True to generate an appropriate error message. + + else + Unum := + Load_Unit + (Load_Name => Spec_Name, + Required => True, + Subunit => False, + Error_Node => Curunit); + return; + end if; + + -- If current unit is a child unit spec, load its parent + + elsif Nkind (Unit (Curunit)) = N_Package_Declaration + or else Nkind (Unit (Curunit)) = N_Subprogram_Declaration + or else Nkind (Unit (Curunit)) in N_Generic_Declaration + or else Nkind (Unit (Curunit)) in N_Generic_Instantiation + or else Nkind (Unit (Curunit)) in N_Renaming_Declaration + then + -- Turn style and validity checks off for parent unit + + if not GNAT_Mode then + Reset_Style_Check_Options; + Reset_Validity_Check_Options; + end if; + + Spec_Name := Get_Parent_Spec_Name (Unit_Name (Cur_Unum)); + + if Spec_Name /= No_Name then + Unum := + Load_Unit + (Load_Name => Spec_Name, + Required => True, + Subunit => False, + Error_Node => Curunit); + + if Unum /= No_Unit then + Set_Parent_Spec (Unit (Curunit), Cunit (Unum)); + end if; + end if; + + -- If current unit is a subunit, then load its parent body + + elsif Nkind (Unit (Curunit)) = N_Subunit then + Body_Name := Get_Parent_Body_Name (Unit_Name (Cur_Unum)); + Unum := + Load_Unit + (Load_Name => Body_Name, + Required => True, + Subunit => True, + Error_Node => Name (Unit (Curunit))); + + if Unum /= No_Unit then + Set_Library_Unit (Curunit, Cunit (Unum)); + end if; + + end if; + + -- Now we load with'ed units, with style/validity checks turned off + + if not GNAT_Mode then + Reset_Style_Check_Options; + Reset_Validity_Check_Options; + end if; + + -- Loop through context items + + Context_Node := First (Context_Items (Curunit)); + while Present (Context_Node) loop + + if Nkind (Context_Node) = N_With_Clause then + With_Node := Context_Node; + Spec_Name := Get_Unit_Name (With_Node); + + Unum := + Load_Unit + (Load_Name => Spec_Name, + Required => False, + Subunit => False, + Error_Node => With_Node, + Renamings => True); + + -- If we find the unit, then set spec pointer in the N_With_Clause + -- to point to the compilation unit for the spec. Remember that + -- the Load routine itself sets our Fatal_Error flag if the loaded + -- unit gets a fatal error, so we don't need to worry about that. + + if Unum /= No_Unit then + Set_Library_Unit (With_Node, Cunit (Unum)); + + -- If the spec isn't found, then try finding the corresponding + -- body, since it is possible that we have a subprogram body + -- that is acting as a spec (since no spec is present). + + else + Body_Name := Get_Body_Name (Spec_Name); + Unum := + Load_Unit + (Load_Name => Body_Name, + Required => False, + Subunit => False, + Error_Node => With_Node, + Renamings => True); + + -- If we got a subprogram body, then mark that we are using + -- the body as a spec in the file table, and set the spec + -- pointer in the N_With_Clause to point to the body entity. + + if Unum /= No_Unit + and then Nkind (Unit (Cunit (Unum))) = N_Subprogram_Body + then + With_Cunit := Cunit (Unum); + Set_Library_Unit (With_Node, With_Cunit); + Set_Acts_As_Spec (With_Cunit, True); + Set_Library_Unit (With_Cunit, With_Cunit); + + -- If we couldn't find the body, or if it wasn't a body spec + -- then we are in trouble. We make one more call to Load to + -- require the spec. We know it will fail of course, the + -- purpose is to generate the required error message (we prefer + -- that this message refer to the missing spec, not the body) + + else + Unum := + Load_Unit + (Load_Name => Spec_Name, + Required => True, + Subunit => False, + Error_Node => With_Node, + Renamings => True); + + -- Here we create a dummy package unit for the missing unit + + Unum := Create_Dummy_Package_Unit (With_Node, Spec_Name); + Set_Library_Unit (With_Node, Cunit (Unum)); + end if; + end if; + end if; + + Next (Context_Node); + end loop; + + -- Restore style/validity check mode for main unit + + Set_Style_Check_Options (Save_Style_Checks); + Opt.Style_Check := Save_Style_Check; + Set_Validity_Check_Options (Save_Validity_Checks); + Opt.Validity_Checks_On := Save_Validity_Check; +end Load; diff --git a/gcc/ada/par-prag.adb b/gcc/ada/par-prag.adb new file mode 100644 index 00000000000..bfca40e8c18 --- /dev/null +++ b/gcc/ada/par-prag.adb @@ -0,0 +1,950 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P A R . P R A G -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.149 $ +-- -- +-- Copyright (C) 1992-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +-- Generally the parser checks the basic syntax of pragmas, but does not +-- do specialized syntax checks for individual pragmas, these are deferred +-- to semantic analysis time (see unit Sem_Prag). There are some pragmas +-- which require recognition and either partial or complete processing +-- during parsing, and this unit performs this required processing. + +with Fname.UF; use Fname.UF; +with Osint; use Osint; +with Stringt; use Stringt; +with Stylesw; use Stylesw; +with Uintp; use Uintp; +with Uname; use Uname; + +separate (Par) + +function Prag (Pragma_Node : Node_Id; Semi : Source_Ptr) return Node_Id is + Pragma_Name : constant Name_Id := Chars (Pragma_Node); + Pragma_Sloc : constant Source_Ptr := Sloc (Pragma_Node); + Arg_Count : Nat; + Arg_Node : Node_Id; + + ----------------------- + -- Local Subprograms -- + ----------------------- + + function Arg1 return Node_Id; + function Arg2 return Node_Id; + function Arg3 return Node_Id; + function Arg4 return Node_Id; + -- Obtain specified Pragma_Argument_Association. It is allowable to call + -- the routine for the argument one past the last present argument, but + -- that is the only case in which a non-present argument can be referenced. + + procedure Check_Arg_Count (Required : Int); + -- Check argument count for pragma = Required. + -- If not give error and raise Error_Resync. + + procedure Check_Arg_Is_String_Literal (Arg : Node_Id); + -- Check the expression of the specified argument to make sure that it + -- is a string literal. If not give error and raise Error_Resync. + + procedure Check_Arg_Is_On_Or_Off (Arg : Node_Id); + -- Check the expression of the specified argument to make sure that it + -- is an identifier which is either ON or OFF, and if not, then issue + -- an error message and raise Error_Resync. + + procedure Check_No_Identifier (Arg : Node_Id); + -- Checks that the given argument does not have an identifier. If an + -- identifier is present, then an error message is issued, and + -- Error_Resync is raised. + + procedure Check_Optional_Identifier (Arg : Node_Id; Id : Name_Id); + -- Checks if the given argument has an identifier, and if so, requires + -- it to match the given identifier name. If there is a non-matching + -- identifier, then an error message is given and Error_Resync raised. + + procedure Check_Required_Identifier (Arg : Node_Id; Id : Name_Id); + -- Same as Check_Optional_Identifier, except that the name is required + -- to be present and to match the given Id value. + + ---------- + -- Arg1 -- + ---------- + + function Arg1 return Node_Id is + begin + return First (Pragma_Argument_Associations (Pragma_Node)); + end Arg1; + + ---------- + -- Arg2 -- + ---------- + + function Arg2 return Node_Id is + begin + return Next (Arg1); + end Arg2; + + ---------- + -- Arg3 -- + ---------- + + function Arg3 return Node_Id is + begin + return Next (Arg2); + end Arg3; + + ---------- + -- Arg4 -- + ---------- + + function Arg4 return Node_Id is + begin + return Next (Arg3); + end Arg4; + + --------------------- + -- Check_Arg_Count -- + --------------------- + + procedure Check_Arg_Count (Required : Int) is + begin + if Arg_Count /= Required then + Error_Msg ("wrong number of arguments for pragma%", Pragma_Sloc); + raise Error_Resync; + end if; + end Check_Arg_Count; + + ---------------------------- + -- Check_Arg_Is_On_Or_Off -- + ---------------------------- + + procedure Check_Arg_Is_On_Or_Off (Arg : Node_Id) is + Argx : constant Node_Id := Expression (Arg); + + begin + if Nkind (Expression (Arg)) /= N_Identifier + or else (Chars (Argx) /= Name_On + and then + Chars (Argx) /= Name_Off) + then + Error_Msg_Name_2 := Name_On; + Error_Msg_Name_3 := Name_Off; + + Error_Msg + ("argument for pragma% must be% or%", Sloc (Argx)); + raise Error_Resync; + end if; + end Check_Arg_Is_On_Or_Off; + + --------------------------------- + -- Check_Arg_Is_String_Literal -- + --------------------------------- + + procedure Check_Arg_Is_String_Literal (Arg : Node_Id) is + begin + if Nkind (Expression (Arg)) /= N_String_Literal then + Error_Msg + ("argument for pragma% must be string literal", + Sloc (Expression (Arg))); + raise Error_Resync; + end if; + end Check_Arg_Is_String_Literal; + + ------------------------- + -- Check_No_Identifier -- + ------------------------- + + procedure Check_No_Identifier (Arg : Node_Id) is + begin + if Chars (Arg) /= No_Name then + Error_Msg_N ("pragma% does not permit named arguments", Arg); + raise Error_Resync; + end if; + end Check_No_Identifier; + + ------------------------------- + -- Check_Optional_Identifier -- + ------------------------------- + + procedure Check_Optional_Identifier (Arg : Node_Id; Id : Name_Id) is + begin + if Present (Arg) and then Chars (Arg) /= No_Name then + if Chars (Arg) /= Id then + Error_Msg_Name_2 := Id; + Error_Msg_N ("pragma% argument expects identifier%", Arg); + end if; + end if; + end Check_Optional_Identifier; + + ------------------------------- + -- Check_Required_Identifier -- + ------------------------------- + + procedure Check_Required_Identifier (Arg : Node_Id; Id : Name_Id) is + begin + if Chars (Arg) /= Id then + Error_Msg_Name_2 := Id; + Error_Msg_N ("pragma% argument must have identifier%", Arg); + end if; + end Check_Required_Identifier; + + ---------- + -- Prag -- + ---------- + +begin + Error_Msg_Name_1 := Pragma_Name; + + -- Count number of arguments. This loop also checks if any of the arguments + -- are Error, indicating a syntax error as they were parsed. If so, we + -- simply return, because we get into trouble with cascaded errors if we + -- try to perform our error checks on junk arguments. + + Arg_Count := 0; + + if Present (Pragma_Argument_Associations (Pragma_Node)) then + Arg_Node := Arg1; + + while Arg_Node /= Empty loop + Arg_Count := Arg_Count + 1; + + if Expression (Arg_Node) = Error then + return Error; + end if; + + Next (Arg_Node); + end loop; + end if; + + -- Remaining processing is pragma dependent + + case Get_Pragma_Id (Pragma_Name) is + + ------------ + -- Ada_83 -- + ------------ + + -- This pragma must be processed at parse time, since we want to set + -- the Ada 83 and Ada 95 switches properly at parse time to recognize + -- Ada 83 syntax or Ada 95 syntax as appropriate. + + when Pragma_Ada_83 => + Ada_83 := True; + Ada_95 := False; + + ------------ + -- Ada_95 -- + ------------ + + -- This pragma must be processed at parse time, since we want to set + -- the Ada 83 and Ada_95 switches properly at parse time to recognize + -- Ada 83 syntax or Ada 95 syntax as appropriate. + + when Pragma_Ada_95 => + Ada_83 := False; + Ada_95 := True; + + ----------- + -- Debug -- + ----------- + + -- pragma Debug (PROCEDURE_CALL_STATEMENT); + + -- This has to be processed by the parser because of the very peculiar + -- form of the second parameter, which is syntactically from a formal + -- point of view a function call (since it must be an expression), but + -- semantically we treat it as a procedure call (which has exactly the + -- same syntactic form, so that's why we can get away with this!) + + when Pragma_Debug => + Check_Arg_Count (1); + Check_No_Identifier (Arg1); + + declare + Expr : constant Node_Id := New_Copy (Expression (Arg1)); + + begin + if Nkind (Expr) /= N_Indexed_Component + and then Nkind (Expr) /= N_Function_Call + and then Nkind (Expr) /= N_Identifier + and then Nkind (Expr) /= N_Selected_Component + then + Error_Msg + ("argument of pragma% is not procedure call", Sloc (Expr)); + raise Error_Resync; + else + Set_Debug_Statement + (Pragma_Node, P_Statement_Name (Expr)); + end if; + end; + + ------------------------------- + -- Extensions_Allowed (GNAT) -- + ------------------------------- + + -- pragma Extensions_Allowed (Off | On) + + -- The processing for pragma Extensions_Allowed must be done at + -- parse time, since extensions mode may affect what is accepted. + + when Pragma_Extensions_Allowed => + Check_Arg_Count (1); + Check_No_Identifier (Arg1); + Check_Arg_Is_On_Or_Off (Arg1); + Opt.Extensions_Allowed := (Chars (Expression (Arg1)) = Name_On); + + ---------------- + -- List (2.8) -- + ---------------- + + -- pragma List (Off | On) + + -- The processing for pragma List must be done at parse time, + -- since a listing can be generated in parse only mode. + + when Pragma_List => + Check_Arg_Count (1); + Check_No_Identifier (Arg1); + Check_Arg_Is_On_Or_Off (Arg1); + + -- We unconditionally make a List_On entry for the pragma, so that + -- in the List (Off) case, the pragma will print even in a region + -- of code with listing turned off (this is required!) + + List_Pragmas.Increment_Last; + List_Pragmas.Table (List_Pragmas.Last) := + (Ptyp => List_On, Ploc => Sloc (Pragma_Node)); + + -- Now generate the list off entry for pragma List (Off) + + if Chars (Expression (Arg1)) = Name_Off then + List_Pragmas.Increment_Last; + List_Pragmas.Table (List_Pragmas.Last) := + (Ptyp => List_Off, Ploc => Semi); + end if; + + ---------------- + -- Page (2.8) -- + ---------------- + + -- pragma Page; + + -- Processing for this pragma must be done at parse time, since a + -- listing can be generated in parse only mode with semantics off. + + when Pragma_Page => + Check_Arg_Count (0); + List_Pragmas.Increment_Last; + List_Pragmas.Table (List_Pragmas.Last) := (Page, Semi); + + ----------------------------- + -- Source_File_Name (GNAT) -- + ----------------------------- + + -- There are five forms of this pragma: + + -- pragma Source_File_Name ( + -- [UNIT_NAME =>] unit_NAME, + -- BODY_FILE_NAME => STRING_LITERAL); + + -- pragma Source_File_Name ( + -- [UNIT_NAME =>] unit_NAME, + -- SPEC_FILE_NAME => STRING_LITERAL); + + -- pragma Source_File_Name ( + -- BODY_FILE_NAME => STRING_LITERAL + -- [, DOT_REPLACEMENT => STRING_LITERAL] + -- [, CASING => CASING_SPEC]); + + -- pragma Source_File_Name ( + -- SPEC_FILE_NAME => STRING_LITERAL + -- [, DOT_REPLACEMENT => STRING_LITERAL] + -- [, CASING => CASING_SPEC]); + + -- pragma Source_File_Name ( + -- SUBUNIT_FILE_NAME => STRING_LITERAL + -- [, DOT_REPLACEMENT => STRING_LITERAL] + -- [, CASING => CASING_SPEC]); + + -- CASING_SPEC ::= Uppercase | Lowercase | Mixedcase + + -- Note: we process this during parsing, since we need to have the + -- source file names set well before the semantic analysis starts, + -- since we load the spec and with'ed packages before analysis. + + when Pragma_Source_File_Name => Source_File_Name : declare + Unam : Unit_Name_Type; + Expr1 : Node_Id; + Pat : String_Ptr; + Typ : Character; + Dot : String_Ptr; + Cas : Casing_Type; + Nast : Nat; + + function Get_Fname (Arg : Node_Id) return Name_Id; + -- Process file name from unit name form of pragma + + function Get_String_Argument (Arg : Node_Id) return String_Ptr; + -- Process string literal value from argument + + procedure Process_Casing (Arg : Node_Id); + -- Process Casing argument of pattern form of pragma + + procedure Process_Dot_Replacement (Arg : Node_Id); + -- Process Dot_Replacement argument of patterm form of pragma + + --------------- + -- Get_Fname -- + --------------- + + function Get_Fname (Arg : Node_Id) return Name_Id is + begin + String_To_Name_Buffer (Strval (Expression (Arg))); + + for J in 1 .. Name_Len loop + if Is_Directory_Separator (Name_Buffer (J)) then + Error_Msg + ("directory separator character not allowed", + Sloc (Expression (Arg)) + Source_Ptr (J)); + end if; + end loop; + + return Name_Find; + end Get_Fname; + + ------------------------- + -- Get_String_Argument -- + ------------------------- + + function Get_String_Argument (Arg : Node_Id) return String_Ptr is + Str : String_Id; + + begin + if Nkind (Expression (Arg)) /= N_String_Literal + and then + Nkind (Expression (Arg)) /= N_Operator_Symbol + then + Error_Msg_N + ("argument for pragma% must be string literal", Arg); + raise Error_Resync; + end if; + + Str := Strval (Expression (Arg)); + + -- Check string has no wide chars + + for J in 1 .. String_Length (Str) loop + if Get_String_Char (Str, J) > 255 then + Error_Msg + ("wide character not allowed in pattern for pragma%", + Sloc (Expression (Arg2)) + Text_Ptr (J) - 1); + end if; + end loop; + + -- Acquire string + + String_To_Name_Buffer (Str); + return new String'(Name_Buffer (1 .. Name_Len)); + end Get_String_Argument; + + -------------------- + -- Process_Casing -- + -------------------- + + procedure Process_Casing (Arg : Node_Id) is + Expr : constant Node_Id := Expression (Arg); + + begin + Check_Required_Identifier (Arg, Name_Casing); + + if Nkind (Expr) = N_Identifier then + if Chars (Expr) = Name_Lowercase then + Cas := All_Lower_Case; + return; + elsif Chars (Expr) = Name_Uppercase then + Cas := All_Upper_Case; + return; + elsif Chars (Expr) = Name_Mixedcase then + Cas := Mixed_Case; + return; + end if; + end if; + + Error_Msg_N + ("Casing argument for pragma% must be " & + "one of Mixedcase, Lowercase, Uppercase", + Arg); + end Process_Casing; + + ----------------------------- + -- Process_Dot_Replacement -- + ----------------------------- + + procedure Process_Dot_Replacement (Arg : Node_Id) is + begin + Check_Required_Identifier (Arg, Name_Dot_Replacement); + Dot := Get_String_Argument (Arg); + end Process_Dot_Replacement; + + -- Start of processing for Source_File_Name pragma + + begin + -- We permit from 1 to 3 arguments + + if Arg_Count not in 1 .. 3 then + Check_Arg_Count (1); + end if; + + Expr1 := Expression (Arg1); + + -- If first argument is identifier or selected component, then + -- we have the specific file case of the Source_File_Name pragma, + -- and the first argument is a unit name. + + if Nkind (Expr1) = N_Identifier + or else + (Nkind (Expr1) = N_Selected_Component + and then + Nkind (Selector_Name (Expr1)) = N_Identifier) + then + Check_Arg_Count (2); + + Check_Optional_Identifier (Arg1, Name_Unit_Name); + Unam := Get_Unit_Name (Expr1); + + Check_Arg_Is_String_Literal (Arg2); + + if Chars (Arg2) = Name_Spec_File_Name then + Set_File_Name (Get_Spec_Name (Unam), Get_Fname (Arg2)); + + elsif Chars (Arg2) = Name_Body_File_Name then + Set_File_Name (Unam, Get_Fname (Arg2)); + + else + Error_Msg_N ("pragma% argument has incorrect identifier", Arg2); + return Pragma_Node; + end if; + + -- If the first argument is not an identifier, then we must have + -- the pattern form of the pragma, and the first argument must be + -- the pattern string with an appropriate name. + + else + if Chars (Arg1) = Name_Spec_File_Name then + Typ := 's'; + + elsif Chars (Arg1) = Name_Body_File_Name then + Typ := 'b'; + + elsif Chars (Arg1) = Name_Subunit_File_Name then + Typ := 'u'; + + elsif Chars (Arg1) = Name_Unit_Name then + Error_Msg_N + ("Unit_Name parameter for pragma% must be an identifier", + Arg1); + raise Error_Resync; + + else + Error_Msg_N ("pragma% argument has incorrect identifier", Arg1); + raise Error_Resync; + end if; + + Pat := Get_String_Argument (Arg1); + + -- Check pattern has exactly one asterisk + + Nast := 0; + for J in Pat'Range loop + if Pat (J) = '*' then + Nast := Nast + 1; + end if; + end loop; + + if Nast /= 1 then + Error_Msg_N + ("file name pattern must have exactly one * character", + Arg2); + return Pragma_Node; + end if; + + -- Set defaults for Casing and Dot_Separator parameters + + Cas := All_Lower_Case; + + Dot := new String'("."); + + -- Process second and third arguments if present + + if Arg_Count > 1 then + if Chars (Arg2) = Name_Casing then + Process_Casing (Arg2); + + if Arg_Count = 3 then + Process_Dot_Replacement (Arg3); + end if; + + else + Process_Dot_Replacement (Arg2); + + if Arg_Count = 3 then + Process_Casing (Arg3); + end if; + end if; + end if; + + Set_File_Name_Pattern (Pat, Typ, Dot, Cas); + end if; + end Source_File_Name; + + ----------------------------- + -- Source_Reference (GNAT) -- + ----------------------------- + + -- pragma Source_Reference + -- (INTEGER_LITERAL [, STRING_LITERAL] ); + + -- Processing for this pragma must be done at parse time, since error + -- messages needing the proper line numbers can be generated in parse + -- only mode with semantic checking turned off, and indeed we usually + -- turn off semantic checking anyway if any parse errors are found. + + when Pragma_Source_Reference => Source_Reference : declare + Fname : Name_Id; + + begin + if Arg_Count /= 1 then + Check_Arg_Count (2); + Check_No_Identifier (Arg2); + end if; + + -- Check that this is first line of file. We skip this test if + -- we are in syntax check only mode, since we may be dealing with + -- multiple compilation units. + + if Get_Physical_Line_Number (Pragma_Sloc) /= 1 + and then Num_SRef_Pragmas (Current_Source_File) = 0 + and then Operating_Mode /= Check_Syntax + then + Error_Msg + ("first % pragma must be first line of file", Pragma_Sloc); + raise Error_Resync; + end if; + + Check_No_Identifier (Arg1); + + if Arg_Count = 1 then + if Num_SRef_Pragmas (Current_Source_File) = 0 then + Error_Msg + ("file name required for first % pragma in file", + Pragma_Sloc); + raise Error_Resync; + + else + Fname := No_Name; + end if; + + -- File name present + + else + Check_Arg_Is_String_Literal (Arg2); + String_To_Name_Buffer (Strval (Expression (Arg2))); + Fname := Name_Find; + + if Num_SRef_Pragmas (Current_Source_File) > 0 then + if Fname /= Full_Ref_Name (Current_Source_File) then + Error_Msg + ("file name must be same in all % pragmas", Pragma_Sloc); + raise Error_Resync; + end if; + end if; + end if; + + if Nkind (Expression (Arg1)) /= N_Integer_Literal then + Error_Msg + ("argument for pragma% must be integer literal", + Sloc (Expression (Arg1))); + raise Error_Resync; + + -- OK, this source reference pragma is effective, however, we + -- ignore it if it is not in the first unit in the multiple unit + -- case. This is because the only purpose in this case is to + -- provide source pragmas for subsequent use by gnatchop. + + else + if Num_Library_Units = 1 then + Register_Source_Ref_Pragma + (Fname, + Strip_Directory (Fname), + UI_To_Int (Intval (Expression (Arg1))), + Get_Physical_Line_Number (Pragma_Sloc) + 1); + end if; + end if; + end Source_Reference; + + ------------------------- + -- Style_Checks (GNAT) -- + ------------------------- + + -- pragma Style_Checks (On | Off | ALL_CHECKS | STRING_LITERAL); + + -- This is processed by the parser since some of the style + -- checks take place during source scanning and parsing. + + when Pragma_Style_Checks => Style_Checks : declare + A : Node_Id; + S : String_Id; + C : Char_Code; + OK : Boolean := True; + + begin + -- Two argument case is only for semantics + + if Arg_Count = 2 then + null; + + else + Check_Arg_Count (1); + Check_No_Identifier (Arg1); + A := Expression (Arg1); + + if Nkind (A) = N_String_Literal then + S := Strval (A); + + declare + Slen : Natural := Natural (String_Length (S)); + Options : String (1 .. Slen); + J : Natural; + Ptr : Natural; + + begin + J := 1; + loop + C := Get_String_Char (S, Int (J)); + + if not In_Character_Range (C) then + OK := False; + Ptr := J; + exit; + + else + Options (J) := Get_Character (C); + end if; + + if J = Slen then + Set_Style_Check_Options (Options, OK, Ptr); + exit; + + else + J := J + 1; + end if; + end loop; + + if not OK then + Error_Msg + ("invalid style check option", + Sloc (Expression (Arg1)) + Source_Ptr (Ptr)); + raise Error_Resync; + end if; + end; + + elsif Nkind (A) /= N_Identifier then + OK := False; + + elsif Chars (A) = Name_All_Checks then + Stylesw.Set_Default_Style_Check_Options; + + elsif Chars (A) = Name_On then + Style_Check := True; + + elsif Chars (A) = Name_Off then + Style_Check := False; + + else + OK := False; + end if; + + if not OK then + Error_Msg ("incorrect argument for pragma%", Sloc (A)); + raise Error_Resync; + end if; + end if; + end Style_Checks; + + --------------------- + -- Warnings (GNAT) -- + --------------------- + + -- pragma Warnings (On | Off, [LOCAL_NAME]) + + -- The one argument case is processed by the parser, since it may + -- control parser warnings as well as semantic warnings, and in any + -- case we want to be absolutely sure that the range in the warnings + -- table is set well before any semantic analysis is performed. + + when Pragma_Warnings => + if Arg_Count = 1 then + Check_No_Identifier (Arg1); + Check_Arg_Is_On_Or_Off (Arg1); + + if Chars (Expression (Arg1)) = Name_On then + Set_Warnings_Mode_On (Pragma_Sloc); + else + Set_Warnings_Mode_Off (Pragma_Sloc); + end if; + end if; + + ----------------------- + -- All Other Pragmas -- + ----------------------- + + -- For all other pragmas, checking and processing is handled + -- entirely in Sem_Prag, and no further checking is done by Par. + + when Pragma_Abort_Defer | + Pragma_AST_Entry | + Pragma_All_Calls_Remote | + Pragma_Annotate | + Pragma_Assert | + Pragma_Asynchronous | + Pragma_Atomic | + Pragma_Atomic_Components | + Pragma_Attach_Handler | + Pragma_CPP_Class | + Pragma_CPP_Constructor | + Pragma_CPP_Virtual | + Pragma_CPP_Vtable | + Pragma_C_Pass_By_Copy | + Pragma_Comment | + Pragma_Common_Object | + Pragma_Complex_Representation | + Pragma_Component_Alignment | + Pragma_Controlled | + Pragma_Convention | + Pragma_Discard_Names | + Pragma_Eliminate | + Pragma_Elaborate | + Pragma_Elaborate_All | + Pragma_Elaborate_Body | + Pragma_Elaboration_Checks | + Pragma_Export | + Pragma_Export_Exception | + Pragma_Export_Function | + Pragma_Export_Object | + Pragma_Export_Procedure | + Pragma_Export_Valued_Procedure | + Pragma_Extend_System | + Pragma_External_Name_Casing | + Pragma_Finalize_Storage_Only | + Pragma_Float_Representation | + Pragma_Ident | + Pragma_Import | + Pragma_Import_Exception | + Pragma_Import_Function | + Pragma_Import_Object | + Pragma_Import_Procedure | + Pragma_Import_Valued_Procedure | + Pragma_Initialize_Scalars | + Pragma_Inline | + Pragma_Inline_Always | + Pragma_Inline_Generic | + Pragma_Inspection_Point | + Pragma_Interface | + Pragma_Interface_Name | + Pragma_Interrupt_Handler | + Pragma_Interrupt_Priority | + Pragma_Java_Constructor | + Pragma_Java_Interface | + Pragma_License | + Pragma_Link_With | + Pragma_Linker_Alias | + Pragma_Linker_Options | + Pragma_Linker_Section | + Pragma_Locking_Policy | + Pragma_Long_Float | + Pragma_Machine_Attribute | + Pragma_Main | + Pragma_Main_Storage | + Pragma_Memory_Size | + Pragma_No_Return | + Pragma_No_Run_Time | + Pragma_Normalize_Scalars | + Pragma_Optimize | + Pragma_Pack | + Pragma_Passive | + Pragma_Polling | + Pragma_Preelaborate | + Pragma_Priority | + Pragma_Propagate_Exceptions | + Pragma_Psect_Object | + Pragma_Pure | + Pragma_Pure_Function | + Pragma_Queuing_Policy | + Pragma_Remote_Call_Interface | + Pragma_Remote_Types | + Pragma_Restrictions | + Pragma_Restricted_Run_Time | + Pragma_Ravenscar | + Pragma_Reviewable | + Pragma_Share_Generic | + Pragma_Shared | + Pragma_Shared_Passive | + Pragma_Storage_Size | + Pragma_Storage_Unit | + Pragma_Stream_Convert | + Pragma_Subtitle | + Pragma_Suppress | + Pragma_Suppress_All | + Pragma_Suppress_Debug_Info | + Pragma_Suppress_Initialization | + Pragma_System_Name | + Pragma_Task_Dispatching_Policy | + Pragma_Task_Info | + Pragma_Task_Name | + Pragma_Task_Storage | + Pragma_Time_Slice | + Pragma_Title | + Pragma_Unchecked_Union | + Pragma_Unimplemented_Unit | + Pragma_Unreserve_All_Interrupts | + Pragma_Unsuppress | + Pragma_Use_VADS_Size | + Pragma_Volatile | + Pragma_Volatile_Components | + Pragma_Weak_External | + Pragma_Validity_Checks => + null; + + end case; + + return Pragma_Node; + + -------------------- + -- Error Handling -- + -------------------- + +exception + when Error_Resync => + return Error; + +end Prag; diff --git a/gcc/ada/par-sync.adb b/gcc/ada/par-sync.adb new file mode 100644 index 00000000000..d1ba793d9cd --- /dev/null +++ b/gcc/ada/par-sync.adb @@ -0,0 +1,312 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P A R . S Y N C -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.19 $ +-- -- +-- Copyright (C) 1992-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +separate (Par) +package body Sync is + + procedure Resync_Init; + -- This routine is called on initiating a resynchronization action + + procedure Resync_Resume; + -- This routine is called on completing a resynchronization action + + ------------------- + -- Resync_Choice -- + ------------------- + + procedure Resync_Choice is + begin + Resync_Init; + + -- Loop till we get a token that terminates a choice. Note that EOF is + -- one such token, so we are sure to get out of this loop eventually! + + while Token not in Token_Class_Cterm loop + Scan; + end loop; + + Resync_Resume; + end Resync_Choice; + + ------------------ + -- Resync_Cunit -- + ------------------ + + procedure Resync_Cunit is + begin + Resync_Init; + + while Token not in Token_Class_Cunit + and then Token /= Tok_EOF + loop + Scan; + end loop; + + Resync_Resume; + end Resync_Cunit; + + ----------------------- + -- Resync_Expression -- + ----------------------- + + procedure Resync_Expression is + Paren_Count : Int; + + begin + Resync_Init; + Paren_Count := 0; + + loop + -- Terminating tokens are those in class Eterm and also RANGE, + -- DIGITS or DELTA if not preceded by an apostrophe (if they are + -- preceded by an apostrophe, then they are attributes). In addiion, + -- at the outer parentheses level only, we also consider a comma, + -- right parenthesis or vertical bar to terminate an expression. + + if Token in Token_Class_Eterm + + or else (Token in Token_Class_Atkwd + and then Prev_Token /= Tok_Apostrophe) + + or else (Paren_Count = 0 + and then + (Token = Tok_Comma + or else Token = Tok_Right_Paren + or else Token = Tok_Vertical_Bar)) + then + -- A special check: if we stop on the ELSE of OR ELSE or the + -- THEN of AND THEN, keep going, because this is not really an + -- expression terminator after all. Also, keep going past WITH + -- since this can be part of an extension aggregate + + if (Token = Tok_Else and then Prev_Token = Tok_Or) + or else (Token = Tok_Then and then Prev_Token = Tok_And) + or else Token = Tok_With + then + null; + else + exit; + end if; + end if; + + if Token = Tok_Left_Paren then + Paren_Count := Paren_Count + 1; + + elsif Token = Tok_Right_Paren then + Paren_Count := Paren_Count - 1; + + end if; + + Scan; -- past token to be skipped + end loop; + + Resync_Resume; + end Resync_Expression; + + ----------------- + -- Resync_Init -- + ----------------- + + procedure Resync_Init is + begin + -- The following check makes sure we do not get stuck in an infinite + -- loop resynchonizing and getting nowhere. If we are called to do a + -- resynchronize and we are exactly at the same point that we left off + -- on the last resynchronize call, then we force at least one token to + -- be skipped so that we make progress! + + if Token_Ptr = Last_Resync_Point then + Scan; -- to skip at least one token + end if; + + -- Output extra error message if debug R flag is set + + if Debug_Flag_R then + Error_Msg_SC ("resynchronizing!"); + end if; + end Resync_Init; + + --------------------------- + -- Resync_Past_Semicolon -- + --------------------------- + + procedure Resync_Past_Semicolon is + begin + Resync_Init; + + loop + -- Done if we are at a semicolon + + if Token = Tok_Semicolon then + Scan; -- past semicolon + exit; + + -- Done if we are at a token which normally appears only after + -- a semicolon. One special glitch is that the keyword private is + -- in this category only if it does NOT appear after WITH. + + elsif Token in Token_Class_After_SM + and then (Token /= Tok_Private or else Prev_Token /= Tok_With) + then + exit; + + -- Otherwise keep going + + else + Scan; + end if; + end loop; + + -- Fall out of loop with resyncrhonization complete + + Resync_Resume; + end Resync_Past_Semicolon; + + ---------------------------------------------- + -- Resync_Past_Semicolon_Or_To_Loop_Or_Then -- + ---------------------------------------------- + + procedure Resync_Past_Semicolon_Or_To_Loop_Or_Then is + begin + Resync_Init; + + loop + -- Done if at semicolon + + if Token = Tok_Semicolon then + Scan; -- past the semicolon + exit; + + -- Done if we are at a token which normally appears only after + -- a semicolon. One special glitch is that the keyword private is + -- in this category only if it does NOT appear after WITH. + + elsif (Token in Token_Class_After_SM + and then (Token /= Tok_Private + or else Prev_Token /= Tok_With)) + then + exit; + + -- Done if we are at THEN or LOOP + + elsif Token = Tok_Then or else Token = Tok_Loop then + exit; + + -- Otherwise keep going + + else + Scan; + end if; + end loop; + + -- Fall out of loop with resyncrhonization complete + + Resync_Resume; + end Resync_Past_Semicolon_Or_To_Loop_Or_Then; + + ------------------- + -- Resync_Resume -- + ------------------- + + procedure Resync_Resume is + begin + -- Save resync point (see special test in Resync_Init) + + Last_Resync_Point := Token_Ptr; + + if Debug_Flag_R then + Error_Msg_SC ("resuming here!"); + end if; + end Resync_Resume; + + -------------------- + -- Resync_To_When -- + -------------------- + + procedure Resync_To_When is + begin + Resync_Init; + + loop + -- Done if at semicolon, WHEN or IS + + if Token = Tok_Semicolon + or else Token = Tok_When + or else Token = Tok_Is + then + exit; + + -- Otherwise keep going + + else + Scan; + end if; + end loop; + + -- Fall out of loop with resyncrhonization complete + + Resync_Resume; + end Resync_To_When; + + --------------------------- + -- Resync_Semicolon_List -- + --------------------------- + + procedure Resync_Semicolon_List is + Paren_Count : Int; + + begin + Resync_Init; + Paren_Count := 0; + + loop + if Token = Tok_EOF + or else Token = Tok_Semicolon + or else Token = Tok_Is + or else Token in Token_Class_After_SM + then + exit; + + elsif Token = Tok_Left_Paren then + Paren_Count := Paren_Count + 1; + + elsif Token = Tok_Right_Paren then + if Paren_Count = 0 then + exit; + else + Paren_Count := Paren_Count - 1; + end if; + end if; + + Scan; + end loop; + + Resync_Resume; + end Resync_Semicolon_List; + +end Sync; diff --git a/gcc/ada/par-tchk.adb b/gcc/ada/par-tchk.adb new file mode 100644 index 00000000000..4d49e7af738 --- /dev/null +++ b/gcc/ada/par-tchk.adb @@ -0,0 +1,812 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P A R . T C H K -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.37 $ +-- -- +-- Copyright (C) 1992-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +-- Token scan routines. + +-- Error recovery: none of the T_xxx or TF_xxx routines raise Error_Resync + +separate (Par) +package body Tchk is + + type Position is (SC, BC, AP); + -- Specify position of error message (see Error_Msg_SC/BC/AP) + + ----------------------- + -- Local Subprograms -- + ----------------------- + + procedure Check_Token (T : Token_Type; P : Position); + pragma Inline (Check_Token); + -- Called by T_xx routines to check for reserved keyword token. P is the + -- position of the error message if the token is missing (see Wrong_Token) + + procedure Wrong_Token (T : Token_Type; P : Position); + -- Called when scanning a reserved keyword when the keyword is not + -- present. T is the token type for the keyword, and P indicates the + -- position to be used to place a message relative to the current + -- token if the keyword is not located nearby. + + ----------------- + -- Check_Token -- + ----------------- + + procedure Check_Token (T : Token_Type; P : Position) is + begin + if Token = T then + Scan; + return; + else + Wrong_Token (T, P); + end if; + end Check_Token; + + ------------- + -- T_Abort -- + ------------- + + procedure T_Abort is + begin + Check_Token (Tok_Abort, SC); + end T_Abort; + + ------------- + -- T_Arrow -- + ------------- + + procedure T_Arrow is + begin + if Token = Tok_Arrow then + Scan; + + -- A little recovery helper, accept then in place of => + + elsif Token = Tok_Then then + Error_Msg_BC ("missing ""=>"""); + Scan; -- past THEN used in place of => + + elsif Token = Tok_Colon_Equal then + Error_Msg_SC (""":="" should be ""=>"""); + Scan; -- past := used in place of => + + else + Error_Msg_AP ("missing ""=>"""); + end if; + end T_Arrow; + + ---------- + -- T_At -- + ---------- + + procedure T_At is + begin + Check_Token (Tok_At, SC); + end T_At; + + ------------ + -- T_Body -- + ------------ + + procedure T_Body is + begin + Check_Token (Tok_Body, BC); + end T_Body; + + ----------- + -- T_Box -- + ----------- + + procedure T_Box is + begin + if Token = Tok_Box then + Scan; + else + Error_Msg_AP ("missing ""<>"""); + end if; + end T_Box; + + ------------- + -- T_Colon -- + ------------- + + procedure T_Colon is + begin + if Token = Tok_Colon then + Scan; + else + Error_Msg_AP ("missing "":"""); + end if; + end T_Colon; + + ------------------- + -- T_Colon_Equal -- + ------------------- + + procedure T_Colon_Equal is + begin + if Token = Tok_Colon_Equal then + Scan; + + elsif Token = Tok_Equal then + Error_Msg_SC ("""="" should be "":="""); + Scan; + + elsif Token = Tok_Colon then + Error_Msg_SC (""":"" should be "":="""); + Scan; + + elsif Token = Tok_Is then + Error_Msg_SC ("IS should be "":="""); + Scan; + + else + Error_Msg_AP ("missing "":="""); + end if; + end T_Colon_Equal; + + ------------- + -- T_Comma -- + ------------- + + procedure T_Comma is + begin + if Token = Tok_Comma then + Scan; + + else + if Token = Tok_Pragma then + P_Pragmas_Misplaced; + end if; + + if Token = Tok_Comma then + Scan; + else + Error_Msg_AP ("missing "","""); + end if; + end if; + + if Token = Tok_Pragma then + P_Pragmas_Misplaced; + end if; + end T_Comma; + + --------------- + -- T_Dot_Dot -- + --------------- + + procedure T_Dot_Dot is + begin + if Token = Tok_Dot_Dot then + Scan; + else + Error_Msg_AP ("missing "".."""); + end if; + end T_Dot_Dot; + + ----------- + -- T_For -- + ----------- + + procedure T_For is + begin + Check_Token (Tok_For, AP); + end T_For; + + ----------------------- + -- T_Greater_Greater -- + ----------------------- + + procedure T_Greater_Greater is + begin + if Token = Tok_Greater_Greater then + Scan; + else + Error_Msg_AP ("missing "">>"""); + end if; + end T_Greater_Greater; + + ------------------ + -- T_Identifier -- + ------------------ + + procedure T_Identifier is + begin + if Token = Tok_Identifier then + Scan; + elsif Token in Token_Class_Literal then + Error_Msg_SC ("identifier expected"); + Scan; + else + Error_Msg_AP ("identifier expected"); + end if; + end T_Identifier; + + ---------- + -- T_In -- + ---------- + + procedure T_In is + begin + Check_Token (Tok_In, AP); + end T_In; + + ---------- + -- T_Is -- + ---------- + + procedure T_Is is + begin + if Token = Tok_Is then + Scan; + + Ignore (Tok_Semicolon); + + -- Allow OF, => or = to substitute for IS with complaint + + elsif Token = Tok_Arrow + or else Token = Tok_Of + or else Token = Tok_Equal + then + Error_Msg_SC ("missing IS"); + Scan; -- token used in place of IS + else + Wrong_Token (Tok_Is, AP); + end if; + + while Token = Tok_Is loop + Error_Msg_SC ("extra IS ignored"); + Scan; + end loop; + end T_Is; + + ------------------ + -- T_Left_Paren -- + ------------------ + + procedure T_Left_Paren is + begin + if Token = Tok_Left_Paren then + Scan; + else + Error_Msg_AP ("missing ""("""); + end if; + end T_Left_Paren; + + ------------ + -- T_Loop -- + ------------ + + procedure T_Loop is + begin + if Token = Tok_Do then + Error_Msg_SC ("LOOP expected"); + Scan; + else + Check_Token (Tok_Loop, AP); + end if; + end T_Loop; + + ----------- + -- T_Mod -- + ----------- + + procedure T_Mod is + begin + Check_Token (Tok_Mod, AP); + end T_Mod; + + ----------- + -- T_New -- + ----------- + + procedure T_New is + begin + Check_Token (Tok_New, AP); + end T_New; + + ---------- + -- T_Of -- + ---------- + + procedure T_Of is + begin + Check_Token (Tok_Of, AP); + end T_Of; + + ---------- + -- T_Or -- + ---------- + + procedure T_Or is + begin + Check_Token (Tok_Or, AP); + end T_Or; + + --------------- + -- T_Private -- + --------------- + + procedure T_Private is + begin + Check_Token (Tok_Private, SC); + end T_Private; + + ------------- + -- T_Range -- + ------------- + + procedure T_Range is + begin + Check_Token (Tok_Range, AP); + end T_Range; + + -------------- + -- T_Record -- + -------------- + + procedure T_Record is + begin + Check_Token (Tok_Record, AP); + end T_Record; + + ------------------- + -- T_Right_Paren -- + ------------------- + + procedure T_Right_Paren is + begin + if Token = Tok_Right_Paren then + Scan; + else + Error_Msg_AP ("missing "")"""); + end if; + end T_Right_Paren; + + ----------------- + -- T_Semicolon -- + ----------------- + + procedure T_Semicolon is + begin + + if Token = Tok_Semicolon then + Scan; + + if Token = Tok_Semicolon then + Error_Msg_SC ("extra "";"" ignored"); + Scan; + end if; + + elsif Token = Tok_Colon then + Error_Msg_SC (""":"" should be "";"""); + Scan; + + elsif Token = Tok_Comma then + Error_Msg_SC (""","" should be "";"""); + Scan; + + elsif Token = Tok_Dot then + Error_Msg_SC ("""."" should be "";"""); + Scan; + + -- An interesting little kludge here. If the previous token is a + -- semicolon, then there is no way that we can legitimately need + -- another semicolon. This could only arise in an error situation + -- where an error has already been signalled. By simply ignoring + -- the request for a semicolon in this case, we avoid some spurious + -- missing semicolon messages. + + elsif Prev_Token = Tok_Semicolon then + return; + + -- If the current token is | then this is a reasonable + -- place to suggest the possibility of a "C" confusion :-) + + elsif Token = Tok_Vertical_Bar then + Error_Msg_SC ("unexpected occurrence of ""|"", did you mean OR'?"); + Resync_Past_Semicolon; + + -- Otherwise we really do have a missing semicolon + + else + Error_Msg_AP ("missing "";"""); + return; + end if; + + end T_Semicolon; + + ------------ + -- T_Then -- + ------------ + + procedure T_Then is + begin + Check_Token (Tok_Then, AP); + end T_Then; + + ------------ + -- T_Type -- + ------------ + + procedure T_Type is + begin + Check_Token (Tok_Type, BC); + end T_Type; + + ----------- + -- T_Use -- + ----------- + + procedure T_Use is + begin + Check_Token (Tok_Use, SC); + end T_Use; + + ------------ + -- T_When -- + ------------ + + procedure T_When is + begin + Check_Token (Tok_When, SC); + end T_When; + + ------------ + -- T_With -- + ------------ + + procedure T_With is + begin + Check_Token (Tok_With, BC); + end T_With; + + -------------- + -- TF_Arrow -- + -------------- + + procedure TF_Arrow is + Scan_State : Saved_Scan_State; + + begin + if Token = Tok_Arrow then + Scan; -- skip arrow and we are done + + elsif Token = Tok_Colon_Equal then + T_Arrow; -- Let T_Arrow give the message + + else + T_Arrow; -- give missing arrow message + Save_Scan_State (Scan_State); -- at start of junk tokens + + loop + if Prev_Token_Ptr < Current_Line_Start + or else Token = Tok_Semicolon + or else Token = Tok_EOF + then + Restore_Scan_State (Scan_State); -- to where we were! + return; + end if; + + Scan; -- continue search! + + if Token = Tok_Arrow then + Scan; -- past arrow + return; + end if; + end loop; + end if; + end TF_Arrow; + + ----------- + -- TF_Is -- + ----------- + + procedure TF_Is is + Scan_State : Saved_Scan_State; + + begin + if Token = Tok_Is then + T_Is; -- past IS and we are done + + -- Allow OF or => or = in place of IS (with error message) + + elsif Token = Tok_Of + or else Token = Tok_Arrow + or else Token = Tok_Equal + then + T_Is; -- give missing IS message and skip bad token + + else + T_Is; -- give missing IS message + Save_Scan_State (Scan_State); -- at start of junk tokens + + loop + if Prev_Token_Ptr < Current_Line_Start + or else Token = Tok_Semicolon + or else Token = Tok_EOF + then + Restore_Scan_State (Scan_State); -- to where we were! + return; + end if; + + Scan; -- continue search! + + if Token = Tok_Is + or else Token = Tok_Of + or else Token = Tok_Arrow + then + Scan; -- past IS or OF or => + return; + end if; + end loop; + end if; + end TF_Is; + + ------------- + -- TF_Loop -- + ------------- + + procedure TF_Loop is + Scan_State : Saved_Scan_State; + + begin + if Token = Tok_Loop then + Scan; -- past LOOP and we are done + + -- Allow DO or THEN in place of LOOP + + elsif Token = Tok_Then or else Token = Tok_Do then + T_Loop; -- give missing LOOP message + + else + T_Loop; -- give missing LOOP message + Save_Scan_State (Scan_State); -- at start of junk tokens + + loop + if Prev_Token_Ptr < Current_Line_Start + or else Token = Tok_Semicolon + or else Token = Tok_EOF + then + Restore_Scan_State (Scan_State); -- to where we were! + return; + end if; + + Scan; -- continue search! + + if Token = Tok_Loop or else Token = Tok_Then then + Scan; -- past loop or then (message already generated) + return; + end if; + end loop; + end if; + end TF_Loop; + + -------------- + -- TF_Return-- + -------------- + + procedure TF_Return is + Scan_State : Saved_Scan_State; + + begin + if Token = Tok_Return then + Scan; -- skip RETURN and we are done + + else + Error_Msg_SC ("missing RETURN"); + Save_Scan_State (Scan_State); -- at start of junk tokens + + loop + if Prev_Token_Ptr < Current_Line_Start + or else Token = Tok_Semicolon + or else Token = Tok_EOF + then + Restore_Scan_State (Scan_State); -- to where we were! + return; + end if; + + Scan; -- continue search! + + if Token = Tok_Return then + Scan; -- past RETURN + return; + end if; + end loop; + end if; + end TF_Return; + + ------------------ + -- TF_Semicolon -- + ------------------ + + procedure TF_Semicolon is + Scan_State : Saved_Scan_State; + + begin + if Token = Tok_Semicolon then + T_Semicolon; + return; + + -- An interesting little kludge here. If the previous token is a + -- semicolon, then there is no way that we can legitimately need + -- another semicolon. This could only arise in an error situation + -- where an error has already been signalled. By simply ignoring + -- the request for a semicolon in this case, we avoid some spurious + -- missing semicolon messages. + + elsif Prev_Token = Tok_Semicolon then + return; + + else + if Token = Tok_Pragma then + P_Pragmas_Misplaced; + + if Token = Tok_Semicolon then + T_Semicolon; + return; + end if; + end if; + + T_Semicolon; -- give missing semicolon message + Save_Scan_State (Scan_State); -- at start of junk tokens + + loop + if Prev_Token_Ptr < Current_Line_Start + or else Token = Tok_EOF + then + Restore_Scan_State (Scan_State); -- to where we were + return; + end if; + + Scan; -- continue search + + if Token = Tok_Semicolon then + T_Semicolon; + return; + + elsif Token in Token_Class_After_SM then + return; + end if; + end loop; + end if; + end TF_Semicolon; + + ------------- + -- TF_Then -- + ------------- + + procedure TF_Then is + Scan_State : Saved_Scan_State; + + begin + if Token = Tok_Then then + Scan; -- past THEN and we are done + + else + T_Then; -- give missing THEN message + Save_Scan_State (Scan_State); -- at start of junk tokens + + loop + if Prev_Token_Ptr < Current_Line_Start + or else Token = Tok_Semicolon + or else Token = Tok_EOF + then + Restore_Scan_State (Scan_State); -- to where we were + return; + end if; + + Scan; -- continue search! + + if Token = Tok_Then then + Scan; -- past THEN + return; + end if; + end loop; + end if; + end TF_Then; + + ------------ + -- TF_Use -- + ------------ + + procedure TF_Use is + Scan_State : Saved_Scan_State; + + begin + if Token = Tok_Use then + Scan; -- past USE and we are done + + else + T_Use; -- give USE expected message + Save_Scan_State (Scan_State); -- at start of junk tokens + + loop + if Prev_Token_Ptr < Current_Line_Start + or else Token = Tok_Semicolon + or else Token = Tok_EOF + then + Restore_Scan_State (Scan_State); -- to where we were + return; + end if; + + Scan; -- continue search! + + if Token = Tok_Use then + Scan; -- past use + return; + end if; + end loop; + end if; + end TF_Use; + + ----------------- + -- Wrong_Token -- + ----------------- + + procedure Wrong_Token (T : Token_Type; P : Position) is + Missing : constant String := "missing "; + Image : constant String := Token_Type'Image (T); + Tok_Name : constant String := Image (5 .. Image'Length); + M : String (1 .. Missing'Length + Tok_Name'Length); + + begin + -- Set M to Missing & Tok_Name. + + M (1 .. Missing'Length) := Missing; + M (Missing'Length + 1 .. M'Last) := Tok_Name; + + if Token = Tok_Semicolon then + Scan; + + if Token = T then + Error_Msg_SP ("extra "";"" ignored"); + Scan; + else + Error_Msg_SP (M); + end if; + + elsif Token = Tok_Comma then + Scan; + + if Token = T then + Error_Msg_SP ("extra "","" ignored"); + Scan; + + else + Error_Msg_SP (M); + end if; + + else + case P is + when SC => Error_Msg_SC (M); + when BC => Error_Msg_BC (M); + when AP => Error_Msg_AP (M); + end case; + end if; + end Wrong_Token; + +end Tchk; diff --git a/gcc/ada/par-util.adb b/gcc/ada/par-util.adb new file mode 100644 index 00000000000..f8082b64ee6 --- /dev/null +++ b/gcc/ada/par-util.adb @@ -0,0 +1,638 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P A R . U T I L -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.64 $ +-- -- +-- Copyright (C) 1992-2001, 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +with Uintp; use Uintp; + +with GNAT.Spelling_Checker; use GNAT.Spelling_Checker; + +separate (Par) +package body Util is + + --------------------- + -- Bad_Spelling_Of -- + --------------------- + + function Bad_Spelling_Of (T : Token_Type) return Boolean is + Tname : constant String := Token_Type'Image (T); + -- Characters of token name + + S : String (1 .. Tname'Last - 4); + -- Characters of token name folded to lower case, omitting TOK_ at start + + M1 : String (1 .. 42) := "incorrect spelling of keyword ************"; + M2 : String (1 .. 44) := "illegal abbreviation of keyword ************"; + -- Buffers used to construct error message + + P1 : constant := 30; + P2 : constant := 32; + -- Starting subscripts in M1, M2 for keyword name + + SL : constant Natural := S'Length; + -- Length of expected token name excluding TOK_ at start + + begin + if Token /= Tok_Identifier then + return False; + end if; + + for J in S'Range loop + S (J) := Fold_Lower (Tname (Integer (J) + 4)); + end loop; + + Get_Name_String (Token_Name); + + -- A special check for case of PROGRAM used for PROCEDURE + + if T = Tok_Procedure + and then Name_Len = 7 + and then Name_Buffer (1 .. 7) = "program" + then + Error_Msg_SC ("PROCEDURE expected"); + Token := T; + return True; + + -- A special check for an illegal abbrevation + + elsif Name_Len < S'Length + and then Name_Len >= 4 + and then Name_Buffer (1 .. Name_Len) = S (1 .. Name_Len) + then + for J in 1 .. S'Last loop + M2 (P2 + J - 1) := Fold_Upper (S (J)); + end loop; + + Error_Msg_SC (M2 (1 .. P2 - 1 + S'Last)); + Token := T; + return True; + end if; + + -- Now we go into the full circuit to check for a misspelling + + -- Never consider something a misspelling if either the actual or + -- expected string is less than 3 characters (before this check we + -- used to consider i to be a misspelled if in some cases!) + + if SL < 3 or else Name_Len < 3 then + return False; + + -- Special case: prefix matches, i.e. the leading characters of the + -- token that we have exactly match the required keyword. If there + -- are at least two characters left over, assume that we have a case + -- of two keywords joined together which should not be joined. + + elsif Name_Len > SL + 1 + and then S = Name_Buffer (1 .. SL) + then + Scan_Ptr := Token_Ptr + S'Length; + Error_Msg_S ("missing space"); + Token := T; + return True; + end if; + + if Is_Bad_Spelling_Of (Name_Buffer (1 .. Name_Len), S) then + + for J in 1 .. S'Last loop + M1 (P1 + J - 1) := Fold_Upper (S (J)); + end loop; + + Error_Msg_SC (M1 (1 .. P1 - 1 + S'Last)); + Token := T; + return True; + + else + return False; + end if; + + end Bad_Spelling_Of; + + ---------------------- + -- Check_95_Keyword -- + ---------------------- + + -- On entry, the caller has checked that current token is an identifier + -- whose name matches the name of the 95 keyword New_Tok. + + procedure Check_95_Keyword (Token_95, Next : Token_Type) is + Scan_State : Saved_Scan_State; + + begin + Save_Scan_State (Scan_State); -- at identifier/keyword + Scan; -- past identifier/keyword + + if Token = Next then + Restore_Scan_State (Scan_State); -- to identifier + Error_Msg_Name_1 := Token_Name; + Error_Msg_SC ("(Ada 83) keyword* cannot be used!"); + Token := Token_95; + else + Restore_Scan_State (Scan_State); -- to identifier + end if; + end Check_95_Keyword; + + ---------------------- + -- Check_Bad_Layout -- + ---------------------- + + procedure Check_Bad_Layout is + begin + if Style.RM_Column_Check and then Token_Is_At_Start_Of_Line + and then Start_Column <= Scope.Table (Scope.Last).Ecol + then + Error_Msg_BC ("(style) incorrect layout"); + end if; + end Check_Bad_Layout; + + -------------------------- + -- Check_Misspelling_Of -- + -------------------------- + + procedure Check_Misspelling_Of (T : Token_Type) is + begin + if Bad_Spelling_Of (T) then + null; + end if; + end Check_Misspelling_Of; + + ----------------------------- + -- Check_Simple_Expression -- + ----------------------------- + + procedure Check_Simple_Expression (E : Node_Id) is + begin + if Expr_Form = EF_Non_Simple then + Error_Msg_N ("this expression must be parenthesized", E); + end if; + end Check_Simple_Expression; + + --------------------------------------- + -- Check_Simple_Expression_In_Ada_83 -- + --------------------------------------- + + procedure Check_Simple_Expression_In_Ada_83 (E : Node_Id) is + begin + if Expr_Form = EF_Non_Simple then + if Ada_83 then + Error_Msg_N ("(Ada 83) this expression must be parenthesized!", E); + end if; + end if; + end Check_Simple_Expression_In_Ada_83; + + ------------------------ + -- Check_Subtype_Mark -- + ------------------------ + + function Check_Subtype_Mark (Mark : Node_Id) return Node_Id is + begin + if Nkind (Mark) = N_Identifier + or else Nkind (Mark) = N_Selected_Component + or else (Nkind (Mark) = N_Attribute_Reference + and then Is_Type_Attribute_Name (Attribute_Name (Mark))) + or else Mark = Error + then + return Mark; + else + Error_Msg ("subtype mark expected", Sloc (Mark)); + return Error; + end if; + end Check_Subtype_Mark; + + ------------------- + -- Comma_Present -- + ------------------- + + function Comma_Present return Boolean is + Scan_State : Saved_Scan_State; + Paren_Count : Nat; + + begin + -- First check, if a comma is present, then a comma is present! + + if Token = Tok_Comma then + T_Comma; + return True; + + -- If we have a right paren, then that is taken as ending the list + -- i.e. no comma is present. + + elsif Token = Tok_Right_Paren then + return False; + + -- If pragmas, then get rid of them and make a recursive call + -- to process what follows these pragmas. + + elsif Token = Tok_Pragma then + P_Pragmas_Misplaced; + return Comma_Present; + + -- At this stage we have an error, and the goal is to decide on whether + -- or not we should diagnose an error and report a (non-existent) + -- comma as being present, or simply to report no comma is present + + -- If we are a semicolon, then the question is whether we have a missing + -- right paren, or whether the semicolon should have been a comma. To + -- guess the right answer, we scan ahead keeping track of the paren + -- level, looking for a clue that helps us make the right decision. + + -- This approach is highly accurate in the single error case, and does + -- not make bad mistakes in the multiple error case (indeed we can't + -- really make a very bad decision at this point in any case). + + elsif Token = Tok_Semicolon then + Save_Scan_State (Scan_State); + Scan; -- past semicolon + + -- Check for being followed by identifier => which almost certainly + -- means we are still in a parameter list and the comma should have + -- been a semicolon (such a sequence could not follow a semicolon) + + if Token = Tok_Identifier then + Scan; + + if Token = Tok_Arrow then + goto Assume_Comma; + end if; + end if; + + -- If that test didn't work, loop ahead looking for a comma or + -- semicolon at the same parenthesis level. Always remember that + -- we can't go badly wrong in an error situation like this! + + Paren_Count := 0; + + -- Here is the look ahead loop, Paren_Count tells us whether the + -- token we are looking at is at the same paren level as the + -- suspicious semicolon that we are trying to figure out. + + loop + + -- If we hit another semicolon or an end of file, and we have + -- not seen a right paren or another comma on the way, then + -- probably the semicolon did end the list. Indeed that is + -- certainly the only single error correction possible here. + + if Token = Tok_Semicolon or else Token = Tok_EOF then + Restore_Scan_State (Scan_State); + return False; + + -- A comma at the same paren level as the semicolon is a strong + -- indicator that the semicolon should have been a comma, indeed + -- again this is the only possible single error correction. + + elsif Token = Tok_Comma then + exit when Paren_Count = 0; + + -- A left paren just bumps the paren count + + elsif Token = Tok_Left_Paren then + Paren_Count := Paren_Count + 1; + + -- A right paren that is at the same paren level as the semicolon + -- also means that the only possible single error correction is + -- to assume that the semicolon should have been a comma. If we + -- are not at the same paren level, then adjust the paren level. + + elsif Token = Tok_Right_Paren then + exit when Paren_Count = 0; + Paren_Count := Paren_Count - 1; + end if; + + -- Keep going, we haven't made a decision yet + + Scan; + end loop; + + -- If we fall through the loop, it means that we found a terminating + -- right paren or another comma. In either case it is reasonable to + -- assume that the semicolon was really intended to be a comma. Also + -- come here for the identifier arrow case. + + <<Assume_Comma>> + Restore_Scan_State (Scan_State); + Error_Msg_SC (""";"" illegal here, replaced by "","""); + Scan; -- past the semicolon + return True; + + -- If we are not at semicolon or a right paren, then we base the + -- decision on whether or not the next token can be part of an + -- expression. If not, then decide that no comma is present (the + -- caller will eventually generate a missing right parent message) + + elsif Token in Token_Class_Eterm then + return False; + + -- Otherwise we assume a comma is present, even if none is present, + -- since the next token must be part of an expression, so if we were + -- at the end of the list, then there is more than one error present. + + else + T_Comma; -- to give error + return True; + end if; + end Comma_Present; + + ----------------------- + -- Discard_Junk_List -- + ----------------------- + + procedure Discard_Junk_List (L : List_Id) is + begin + null; + end Discard_Junk_List; + + ----------------------- + -- Discard_Junk_Node -- + ----------------------- + + procedure Discard_Junk_Node (N : Node_Id) is + begin + null; + end Discard_Junk_Node; + + ------------ + -- Ignore -- + ------------ + + procedure Ignore (T : Token_Type) is + begin + if Token = T then + if T = Tok_Comma then + Error_Msg_SC ("unexpected "","" ignored"); + + elsif T = Tok_Left_Paren then + Error_Msg_SC ("unexpected ""("" ignored"); + + elsif T = Tok_Right_Paren then + Error_Msg_SC ("unexpected "")"" ignored"); + + elsif T = Tok_Semicolon then + Error_Msg_SC ("unexpected "";"" ignored"); + + else + declare + Tname : constant String := Token_Type'Image (Token); + Msg : String := "unexpected keyword ????????????????????????"; + + begin + -- Loop to copy characters of keyword name (ignoring Tok_) + + for J in 5 .. Tname'Last loop + Msg (J + 14) := Fold_Upper (Tname (J)); + end loop; + + Msg (Tname'Last + 15 .. Tname'Last + 22) := " ignored"; + Error_Msg_SC (Msg (1 .. Tname'Last + 22)); + end; + end if; + + Scan; -- Scan past ignored token + end if; + end Ignore; + + ---------------------------- + -- Is_Reserved_Identifier -- + ---------------------------- + + function Is_Reserved_Identifier return Boolean is + begin + if not Is_Reserved_Keyword (Token) then + return False; + + else + declare + Ident_Casing : constant Casing_Type := + Identifier_Casing (Current_Source_File); + + Key_Casing : constant Casing_Type := + Keyword_Casing (Current_Source_File); + + begin + -- If the casing of identifiers and keywords is different in + -- this source file, and the casing of this token matches the + -- keyword casing, then we return False, since it is pretty + -- clearly intended to be a keyword. + + if Ident_Casing /= Unknown + and then Key_Casing /= Unknown + and then Ident_Casing /= Key_Casing + and then Determine_Token_Casing = Key_Casing + then + return False; + + -- Otherwise assume that an identifier was intended + + else + return True; + end if; + end; + end if; + end Is_Reserved_Identifier; + + ---------------------- + -- Merge_Identifier -- + ---------------------- + + procedure Merge_Identifier (Prev : Node_Id; Nxt : Token_Type) is + begin + if Token /= Tok_Identifier then + return; + end if; + + declare + S : Saved_Scan_State; + T : Token_Type; + + begin + Save_Scan_State (S); + Scan; + T := Token; + Restore_Scan_State (S); + + if T /= Nxt then + return; + end if; + end; + + -- Check exactly one space between identifiers + + if Source (Token_Ptr - 1) /= ' ' + or else Int (Token_Ptr) /= + Int (Prev_Token_Ptr) + Length_Of_Name (Chars (Prev)) + 1 + then + return; + end if; + + -- Do the merge + + Get_Name_String (Chars (Token_Node)); + + declare + Buf : String (1 .. Name_Len) := Name_Buffer (1 .. Name_Len); + + begin + Get_Name_String (Chars (Prev)); + Add_Char_To_Name_Buffer ('_'); + Add_Str_To_Name_Buffer (Buf); + Set_Chars (Prev, Name_Find); + end; + + Error_Msg_Node_1 := Prev; + Error_Msg_SC + ("unexpected identifier, possibly & was meant here"); + Scan; + end Merge_Identifier; + + ------------------- + -- No_Constraint -- + ------------------- + + procedure No_Constraint is + begin + if Token in Token_Class_Consk then + Error_Msg_SC ("constraint not allowed here"); + Discard_Junk_Node (P_Constraint_Opt); + end if; + end No_Constraint; + + -------------------- + -- No_Right_Paren -- + -------------------- + + function No_Right_Paren (Expr : Node_Id) return Node_Id is + begin + if Token = Tok_Right_Paren then + Error_Msg_SC ("unexpected right parenthesis"); + Resync_Expression; + return Error; + else + return Expr; + end if; + end No_Right_Paren; + + --------------------- + -- Pop_Scope_Stack -- + --------------------- + + procedure Pop_Scope_Stack is + begin + pragma Assert (Scope.Last > 0); + Scope.Decrement_Last; + + if Debug_Flag_P then + Error_Msg_Uint_1 := UI_From_Int (Scope.Last); + Error_Msg_SC ("decrement scope stack ptr, new value = ^!"); + end if; + end Pop_Scope_Stack; + + ---------------------- + -- Push_Scope_Stack -- + ---------------------- + + procedure Push_Scope_Stack is + begin + Scope.Increment_Last; + Scope.Table (Scope.Last).Junk := False; + Scope.Table (Scope.Last).Node := Empty; + + if Debug_Flag_P then + Error_Msg_Uint_1 := UI_From_Int (Scope.Last); + Error_Msg_SC ("increment scope stack ptr, new value = ^!"); + end if; + end Push_Scope_Stack; + + ---------------------- + -- Separate_Present -- + ---------------------- + + function Separate_Present return Boolean is + Scan_State : Saved_Scan_State; + + begin + if Token = Tok_Separate then + return True; + + elsif Token /= Tok_Identifier then + return False; + + else + Save_Scan_State (Scan_State); + Scan; -- past identifier + + if Token = Tok_Semicolon then + Restore_Scan_State (Scan_State); + return Bad_Spelling_Of (Tok_Separate); + + else + Restore_Scan_State (Scan_State); + return False; + end if; + end if; + end Separate_Present; + + -------------------------- + -- Signal_Bad_Attribute -- + -------------------------- + + procedure Signal_Bad_Attribute is + begin + Error_Msg_N ("unrecognized attribute&", Token_Node); + + -- Check for possible misspelling + + Get_Name_String (Token_Name); + + declare + AN : constant String := Name_Buffer (1 .. Name_Len); + + begin + Error_Msg_Name_1 := First_Attribute_Name; + while Error_Msg_Name_1 <= Last_Attribute_Name loop + Get_Name_String (Error_Msg_Name_1); + + if Is_Bad_Spelling_Of + (AN, Name_Buffer (1 .. Name_Len)) + then + Error_Msg_N + ("\possible misspelling of %", Token_Node); + exit; + end if; + + Error_Msg_Name_1 := Error_Msg_Name_1 + 1; + end loop; + end; + end Signal_Bad_Attribute; + + ------------------------------- + -- Token_Is_At_Start_Of_Line -- + ------------------------------- + + function Token_Is_At_Start_Of_Line return Boolean is + begin + return (Token_Ptr = First_Non_Blank_Location or else Token = Tok_EOF); + end Token_Is_At_Start_Of_Line; + +end Util; diff --git a/gcc/ada/par.adb b/gcc/ada/par.adb new file mode 100644 index 00000000000..f45a83b4390 --- /dev/null +++ b/gcc/ada/par.adb @@ -0,0 +1,1181 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P A R -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.126 $ +-- -- +-- Copyright (C) 1992-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +with Atree; use Atree; +with Casing; use Casing; +with Csets; use Csets; +with Debug; use Debug; +with Elists; use Elists; +with Errout; use Errout; +with Fname; use Fname; +with Lib; use Lib; +with Namet; use Namet; +with Nlists; use Nlists; +with Nmake; use Nmake; +with Opt; use Opt; +with Output; use Output; +with Scans; use Scans; +with Scn; use Scn; +with Sinput; use Sinput; +with Sinput.L; use Sinput.L; +with Sinfo; use Sinfo; +with Snames; use Snames; +with Style; +with Table; + +function Par (Configuration_Pragmas : Boolean) return List_Id is + + Num_Library_Units : Natural := 0; + -- Count number of units parsed (relevant only in syntax check only mode, + -- since in semantics check mode only a single unit is permitted anyway) + + Unit_Node : Node_Id; + -- Stores compilation unit node for current unit + + Save_Config_Switches : Config_Switches_Type; + -- Variable used to save values of config switches while we parse the + -- new unit, to be restored on exit for proper recursive behavior. + + Loop_Block_Count : Nat := 0; + -- Counter used for constructing loop/block names (see the routine + -- Par.Ch5.Get_Loop_Block_Name) + + -------------------- + -- Error Recovery -- + -------------------- + + -- When an error is encountered, a call is made to one of the Error_Msg + -- routines to record the error. If the syntax scan is not derailed by the + -- error (e.g. a complaint that logical operators are inconsistent in an + -- EXPRESSION), then control returns from the Error_Msg call, and the + -- parse continues unimpeded. + + -- If on the other hand, the Error_Msg represents a situation from which + -- the parser cannot recover locally, the exception Error_Resync is raised + -- immediately after the call to Error_Msg. Handlers for Error_Resync + -- are located at strategic points to resynchronize the parse. For example, + -- when an error occurs in a statement, the handler skips to the next + -- semicolon and continues the scan from there. + + -- Each parsing procedure contains a note with the heading "Error recovery" + -- which shows if it can propagate the Error_Resync exception. In order + -- not to propagate the exception, a procedure must either contain its own + -- handler for this exception, or it must not call any other routines which + -- propagate the exception. + + -- Note: the arrangement of Error_Resync handlers is such that it should + -- never be possible to transfer control through a procedure which made + -- an entry in the scope stack, invalidating the contents of the stack. + + Error_Resync : exception; + -- Exception raised on error that is not handled locally, see above. + + Last_Resync_Point : Source_Ptr; + -- The resynchronization routines in Par.Sync run a risk of getting + -- stuck in an infinite loop if they do not skip a token, and the caller + -- keeps repeating the same resync call. On the other hand, if they skip + -- a token unconditionally, some recovery opportunities are missed. The + -- variable Last_Resync_Point records the token location previously set + -- by a Resync call, and if a subsequent Resync call occurs at the same + -- location, then the Resync routine does guarantee to skip a token. + + -------------------------------------------- + -- Handling Semicolon Used in Place of IS -- + -------------------------------------------- + + -- The following global variables are used in handling the error situation + -- of using a semicolon in place of IS in a subprogram declaration as in: + + -- procedure X (Y : Integer); + -- Q : Integer; + -- begin + -- ... + -- end; + + -- The two contexts in which this can appear are at the outer level, and + -- within a declarative region. At the outer level, we know something is + -- wrong as soon as we see the Q (or begin, if there are no declarations), + -- and we can immediately decide that the semicolon should have been IS. + + -- The situation in a declarative region is more complex. The declaration + -- of Q could belong to the outer region, and we do not know that we have + -- an error until we hit the begin. It is still not clear at this point + -- from a syntactic point of view that something is wrong, because the + -- begin could belong to the enclosing subprogram or package. However, we + -- can incorporate a bit of semantic knowledge and note that the body of + -- X is missing, so we definitely DO have an error. We diagnose this error + -- as semicolon in place of IS on the subprogram line. + + -- There are two styles for this diagnostic. If the begin immediately + -- follows the semicolon, then we can place a flag (IS expected) right + -- on the semicolon. Otherwise we do not detect the error until we hit + -- the begin which refers back to the line with the semicolon. + + -- To control the process in the second case, the following global + -- variables are set to indicate that we have a subprogram declaration + -- whose body is required and has not yet been found. The prefix SIS + -- stands for "Subprogram IS" handling. + + SIS_Entry_Active : Boolean; + -- Set True to indicate that an entry is active (i.e. that a subprogram + -- declaration has been encountered, and no body for this subprogram has + -- been encountered). The remaining fields are valid only if this is True. + + SIS_Labl : Node_Id; + -- Subprogram designator + + SIS_Sloc : Source_Ptr; + -- Source location of FUNCTION/PROCEDURE keyword + + SIS_Ecol : Column_Number; + -- Column number of FUNCTION/PROCEDURE keyword + + SIS_Semicolon_Sloc : Source_Ptr; + -- Source location of semicolon at end of subprogram declaration + + SIS_Declaration_Node : Node_Id; + -- Pointer to tree node for subprogram declaration + + SIS_Missing_Semicolon_Message : Error_Msg_Id; + -- Used to save message ID of missing semicolon message (which will be + -- modified to missing IS if necessary). Set to No_Error_Msg in the + -- normal (non-error) case. + + -- Five things can happen to an active SIS entry + + -- 1. If a BEGIN is encountered with an SIS entry active, then we have + -- exactly the situation in which we know the body of the subprogram is + -- missing. After posting an error message, we change the spec to a body, + -- rechaining the declarations that intervened between the spec and BEGIN. + + -- 2. Another subprogram declaration or body is encountered. In this + -- case the entry gets overwritten with the information for the new + -- subprogram declaration. We don't catch some nested cases this way, + -- but it doesn't seem worth the effort. + + -- 3. A nested declarative region (e.g. package declaration or package + -- body) is encountered. The SIS active indication is reset at the start + -- of such a nested region. Again, like case 2, this causes us to miss + -- some nested cases, but it doesn't seen worth the effort to stack and + -- unstack the SIS information. Maybe we will reconsider this if we ever + -- get a complaint about a missed case :-) + + -- 4. We encounter a valid pragma INTERFACE or IMPORT that effectively + -- supplies the missing body. In this case we reset the entry. + + -- 5. We encounter the end of the declarative region without encoutering + -- a BEGIN first. In this situation we simply reset the entry. We know + -- that there is a missing body, but it seems more reasonable to let the + -- later semantic checking discover this. + + -------------------------------------------- + -- Handling IS Used in Place of Semicolon -- + -------------------------------------------- + + -- This is a somewhat trickier situation, and we can't catch it in all + -- cases, but we do our best to detect common situations resulting from + -- a "cut and paste" operation which forgets to change the IS to semicolon. + -- Consider the following example: + + -- package body X is + -- procedure A; + -- procedure B is + -- procedure C; + -- ... + -- procedure D is + -- begin + -- ... + -- end; + -- begin + -- ... + -- end; + + -- The trouble is that the section of text from PROCEDURE B through END; + -- consitutes a valid procedure body, and the danger is that we find out + -- far too late that something is wrong (indeed most compilers will behave + -- uncomfortably on the above example). + + -- We have two approaches to helping to control this situation. First we + -- make every attempt to avoid swallowing the last END; if we can be + -- sure that some error will result from doing so. In particular, we won't + -- accept the END; unless it is exactly correct (in particular it must not + -- have incorrect name tokens), and we won't accept it if it is immediately + -- followed by end of file, WITH or SEPARATE (all tokens that unmistakeably + -- signal the start of a compilation unit, and which therefore allow us to + -- reserve the END; for the outer level.) For more details on this aspect + -- of the handling, see package Par.Endh. + + -- If we can avoid eating up the END; then the result in the absense of + -- any additional steps would be to post a missing END referring back to + -- the subprogram with the bogus IS. Similarly, if the enclosing package + -- has no BEGIN, then the result is a missing BEGIN message, which again + -- refers back to the subprogram header. + + -- Such an error message is not too bad (it's already a big improvement + -- over what many parsers do), but it's not ideal, because the declarations + -- following the IS have been absorbed into the wrong scope. In the above + -- case, this could result for example in a bogus complaint that the body + -- of D was missing from the package. + + -- To catch at least some of these cases, we take the following additional + -- steps. First, a subprogram body is marked as having a suspicious IS if + -- the declaration line is followed by a line which starts with a symbol + -- that can start a declaration in the same column, or to the left of the + -- column in which the FUNCTION or PROCEDURE starts (normal style is to + -- indent any declarations which really belong a subprogram). If such a + -- subprogram encounters a missing BEGIN or missing END, then we decide + -- that the IS should have been a semicolon, and the subprogram body node + -- is marked (by setting the Bad_Is_Detected flag true. Note that we do + -- not do this for library level procedures, only for nested procedures, + -- since for library level procedures, we must have a body. + + -- The processing for a declarative part checks to see if the last + -- declaration scanned is marked in this way, and if it is, the tree + -- is modified to reflect the IS being interpreted as a semicolon. + + --------------------------------------------------- + -- Parser Type Definitions and Control Variables -- + --------------------------------------------------- + + -- The following variable and associated type declaration are used by the + -- expression parsing routines to return more detailed information about + -- the categorization of a parsed expression. + + type Expr_Form_Type is ( + EF_Simple_Name, -- Simple name, i.e. possibly qualified identifier + EF_Name, -- Simple expression which could also be a name + EF_Simple, -- Simple expression which is not call or name + EF_Range_Attr, -- Range attribute reference + EF_Non_Simple); -- Expression that is not a simple expression + + Expr_Form : Expr_Form_Type; + + -- The following type is used for calls to P_Subprogram, P_Package, P_Task, + -- P_Protected to indicate which of several possibilities is acceptable. + + type Pf_Rec is record + Spcn : Boolean; -- True if specification OK + Decl : Boolean; -- True if declaration OK + Gins : Boolean; -- True if generic instantiation OK + Pbod : Boolean; -- True if proper body OK + Rnam : Boolean; -- True if renaming declaration OK + Stub : Boolean; -- True if body stub OK + Fil1 : Boolean; -- Filler to fill to 8 bits + Fil2 : Boolean; -- Filler to fill to 8 bits + end record; + pragma Pack (Pf_Rec); + + function T return Boolean renames True; + function F return Boolean renames False; + + Pf_Decl_Gins_Pbod_Rnam_Stub : constant Pf_Rec := + Pf_Rec'(F, T, T, T, T, T, F, F); + Pf_Decl : constant Pf_Rec := + Pf_Rec'(F, T, F, F, F, F, F, F); + Pf_Decl_Gins_Pbod_Rnam : constant Pf_Rec := + Pf_Rec'(F, T, T, T, T, F, F, F); + Pf_Decl_Pbod : constant Pf_Rec := + Pf_Rec'(F, T, F, T, F, F, F, F); + Pf_Pbod : constant Pf_Rec := + Pf_Rec'(F, F, F, T, F, F, F, F); + Pf_Spcn : constant Pf_Rec := + Pf_Rec'(T, F, F, F, F, F, F, F); + -- The above are the only allowed values of Pf_Rec arguments + + type SS_Rec is record + Eftm : Boolean; -- ELSIF can terminate sequence + Eltm : Boolean; -- ELSE can terminate sequence + Extm : Boolean; -- EXCEPTION can terminate sequence + Ortm : Boolean; -- OR can terminate sequence + Sreq : Boolean; -- at least one statement required + Tatm : Boolean; -- THEN ABORT can terminate sequence + Whtm : Boolean; -- WHEN can terminate sequence + Unco : Boolean; -- Unconditional terminate after one statement + end record; + pragma Pack (SS_Rec); + + SS_Eftm_Eltm_Sreq : constant SS_Rec := SS_Rec'(T, T, F, F, T, F, F, F); + SS_Eltm_Ortm_Tatm : constant SS_Rec := SS_Rec'(F, T, F, T, F, T, F, F); + SS_Extm_Sreq : constant SS_Rec := SS_Rec'(F, F, T, F, T, F, F, F); + SS_None : constant SS_Rec := SS_Rec'(F, F, F, F, F, F, F, F); + SS_Ortm_Sreq : constant SS_Rec := SS_Rec'(F, F, F, T, T, F, F, F); + SS_Sreq : constant SS_Rec := SS_Rec'(F, F, F, F, T, F, F, F); + SS_Sreq_Whtm : constant SS_Rec := SS_Rec'(F, F, F, F, T, F, T, F); + SS_Whtm : constant SS_Rec := SS_Rec'(F, F, F, F, F, F, T, F); + SS_Unco : constant SS_Rec := SS_Rec'(F, F, F, F, F, F, F, T); + + Label_List : Elist_Id; + -- List of label nodes for labels appearing in the current compilation. + -- Used by Par.Labl to construct the corresponding implicit declarations. + + ----------------- + -- Scope Table -- + ----------------- + + -- The scope table, also referred to as the scope stack, is used to + -- record the current scope context. It is organized as a stack, with + -- inner nested entries corresponding to higher entries on the stack. + -- An entry is made when the parser encounters the opening of a nested + -- construct (such as a record, task, package etc.), and then package + -- Par.Endh uses this stack to deal with END lines (including properly + -- dealing with END nesting errors). + + type SS_End_Type is + -- Type of end entry required for this scope. The last two entries are + -- used only in the subprogram body case to mark the case of a suspicious + -- IS, or a bad IS (i.e. suspicions confirmed by missing BEGIN or END). + -- See separate section on dealing with IS used in place of semicolon. + -- Note that for many purposes E_Name, E_Suspicious_Is and E_Bad_Is are + -- treated the same (E_Suspicious_Is and E_Bad_Is are simply special cases + -- of E_Name). They are placed at the end of the enumeration so that a + -- test for >= E_Name catches all three cases efficiently. + + (E_Dummy, -- dummy entry at outer level + E_Case, -- END CASE; + E_If, -- END IF; + E_Loop, -- END LOOP; + E_Record, -- END RECORD; + E_Select, -- END SELECT; + E_Name, -- END [name]; + E_Suspicious_Is, -- END [name]; (case of suspicious IS) + E_Bad_Is); -- END [name]; (case of bad IS) + + -- The following describes a single entry in the scope table + + type Scope_Table_Entry is record + Etyp : SS_End_Type; + -- Type of end entry, as per above description + + Lreq : Boolean; + -- A flag indicating whether the label, if present, is required to + -- appear on the end line. It is referenced only in the case of + -- Etyp = E_Name or E_Suspicious_Is where the name may or may not be + -- required (yes for labeled block, no in other cases). Note that for + -- all cases except begin, the question of whether a label is required + -- can be determined from the other fields (for loop, it is required if + -- it is present, and for the other constructs it is never required or + -- allowed). + + Ecol : Column_Number; + -- Contains the absolute column number (with tabs expanded) of the + -- the expected column of the end assuming normal Ada indentation + -- usage. If the RM_Column_Check mode is set, this value is used for + -- generating error messages about indentation. Otherwise it is used + -- only to control heuristic error recovery actions. + + Labl : Node_Id; + -- This field is used only for the LOOP and BEGIN cases, and is the + -- Node_Id value of the label name. For all cases except child units, + -- this value is an entity whose Chars field contains the name pointer + -- that identifies the label uniquely. For the child unit case the Labl + -- field references an N_Defining_Program_Unit_Name node for the name. + -- For cases other than LOOP or BEGIN, the Label field is set to Error, + -- indicating that it is an error to have a label on the end line. + + Decl : List_Id; + -- Points to the list of declarations (i.e. the declarative part) + -- associated with this construct. It is set only in the END [name] + -- cases, and is set to No_List for all other cases which do not have a + -- declarative unit associated with them. This is used for determining + -- the proper location for implicit label declarations. + + Node : Node_Id; + -- Empty except in the case of entries for IF and CASE statements, + -- in which case it contains the N_If_Statement or N_Case_Statement + -- node. This is used for setting the End_Span field. + + Sloc : Source_Ptr; + -- Source location of the opening token of the construct. This is + -- used to refer back to this line in error messages (such as missing + -- or incorrect end lines). The Sloc field is not used, and is not set, + -- if a label is present (the Labl field provides the text name of the + -- label in this case, which is fine for error messages). + + S_Is : Source_Ptr; + -- S_Is is relevant only if Etyp is set to E_Suspicious_Is or + -- E_Bad_Is. It records the location of the IS that is considered + -- to be suspicious. + + Junk : Boolean; + -- A boolean flag that is set true if the opening entry is the dubious + -- result of some prior error, e.g. a record entry where the record + -- keyword was missing. It is used to suppress the issuing of a + -- corresponding junk complaint about the end line (we do not want + -- to complain about a missing end record when there was no record). + end record; + + -- The following declares the scope table itself. The Last field is the + -- stack pointer, so that Scope.Table (Scope.Last) is the top entry. The + -- oldest entry, at Scope_Stack (0), is a dummy entry with Etyp set to + -- E_Dummy, and the other fields undefined. This dummy entry ensures that + -- Scope_Stack (Scope_Stack_Ptr).Etyp can always be tested, and that the + -- scope stack pointer is always in range. + + package Scope is new Table.Table ( + Table_Component_Type => Scope_Table_Entry, + Table_Index_Type => Int, + Table_Low_Bound => 0, + Table_Initial => 50, + Table_Increment => 100, + Table_Name => "Scope"); + + --------------------------------- + -- Parsing Routines by Chapter -- + --------------------------------- + + -- Uncommented declarations in this section simply parse the construct + -- corresponding to their name, and return an ID value for the Node or + -- List that is created. + + package Ch2 is + function P_Identifier return Node_Id; + function P_Pragma return Node_Id; + + function P_Pragmas_Opt return List_Id; + -- This function scans for a sequence of pragmas in other than a + -- declaration sequence or statement sequence context. All pragmas + -- can appear except pragmas Assert and Debug, which are only allowed + -- in a declaration or statement sequence context. + + procedure P_Pragmas_Misplaced; + -- Skips misplaced pragmas with a complaint + + procedure P_Pragmas_Opt (List : List_Id); + -- Parses optional pragmas and appends them to the List + end Ch2; + + package Ch3 is + Missing_Begin_Msg : Error_Msg_Id; + -- This variable is set by a call to P_Declarative_Part. Normally it + -- is set to No_Error_Msg, indicating that no special processing is + -- required by the caller. The special case arises when a statement + -- is found in the sequence of declarations. In this case the Id of + -- the message issued ("declaration expected") is preserved in this + -- variable, then the caller can change it to an appropriate missing + -- begin message if indeed the BEGIN is missing. + + function P_Access_Definition return Node_Id; + function P_Access_Type_Definition return Node_Id; + function P_Array_Type_Definition return Node_Id; + function P_Basic_Declarative_Items return List_Id; + function P_Constraint_Opt return Node_Id; + function P_Declarative_Part return List_Id; + function P_Defining_Identifier return Node_Id; + function P_Discrete_Choice_List return List_Id; + function P_Discrete_Range return Node_Id; + function P_Discrete_Subtype_Definition return Node_Id; + function P_Known_Discriminant_Part_Opt return List_Id; + function P_Signed_Integer_Type_Definition return Node_Id; + function P_Range return Node_Id; + function P_Range_Or_Subtype_Mark return Node_Id; + function P_Range_Constraint return Node_Id; + function P_Record_Definition return Node_Id; + function P_Subtype_Indication return Node_Id; + function P_Subtype_Mark return Node_Id; + function P_Subtype_Mark_Resync return Node_Id; + function P_Unknown_Discriminant_Part_Opt return Boolean; + + procedure P_Component_Items (Decls : List_Id); + -- Scan out one or more component items and append them to the + -- given list. Only scans out more than one declaration in the + -- case where the source has a single declaration with multiple + -- defining identifiers. + + function Init_Expr_Opt (P : Boolean := False) return Node_Id; + -- If an initialization expression is present (:= expression), then + -- it is scanned out and returned, otherwise Empty is returned if no + -- initialization expression is present. This procedure also handles + -- certain common error cases cleanly. The parameter P indicates if + -- a right paren can follow the expression (default = no right paren + -- allowed). + + procedure Skip_Declaration (S : List_Id); + -- Used when scanning statements to skip past a mispaced declaration + -- The declaration is scanned out and appended to the given list. + -- Token is known to be a declaration token (in Token_Class_Declk) + -- on entry, so there definition is a declaration to be scanned. + + function P_Subtype_Indication (Subtype_Mark : Node_Id) return Node_Id; + -- This version of P_Subtype_Indication is called when the caller has + -- already scanned out the subtype mark which is passed as a parameter. + + function P_Subtype_Mark_Attribute (Type_Node : Node_Id) return Node_Id; + -- Parse a subtype mark attribute. The caller has already parsed the + -- subtype mark, which is passed in as the argument, and has checked + -- that the current token is apostrophe. + + end Ch3; + + package Ch4 is + function P_Aggregate return Node_Id; + function P_Expression return Node_Id; + function P_Expression_No_Right_Paren return Node_Id; + function P_Expression_Or_Range_Attribute return Node_Id; + function P_Function_Name return Node_Id; + function P_Name return Node_Id; + function P_Qualified_Simple_Name return Node_Id; + function P_Qualified_Simple_Name_Resync return Node_Id; + function P_Simple_Expression return Node_Id; + function P_Simple_Expression_Or_Range_Attribute return Node_Id; + + function P_Qualified_Expression + (Subtype_Mark : Node_Id) + return Node_Id; + -- This routine scans out a qualified expression when the caller has + -- already scanned out the name and apostrophe of the construct. + + end Ch4; + + package Ch5 is + + function P_Statement_Name (Name_Node : Node_Id) return Node_Id; + -- Given a node representing a name (which is a call), converts it + -- to the syntactically corresponding procedure call statement. + + function P_Sequence_Of_Statements (SS_Flags : SS_Rec) return List_Id; + -- The argument indicates the acceptable termination tokens. + -- See body in Par.Ch5 for details of the use of this parameter. + + procedure Parse_Decls_Begin_End (Parent : Node_Id); + -- Parses declarations and handled statement sequence, setting + -- fields of Parent node appropriately. + + end Ch5; + + package Ch6 is + function P_Designator return Node_Id; + function P_Defining_Program_Unit_Name return Node_Id; + function P_Formal_Part return List_Id; + function P_Parameter_Profile return List_Id; + function P_Return_Statement return Node_Id; + function P_Subprogram_Specification return Node_Id; + + procedure P_Mode (Node : Node_Id); + -- Sets In_Present and/or Out_Present flags in Node scanning past + -- IN, OUT or IN OUT tokens in the source. + + function P_Subprogram (Pf_Flags : Pf_Rec) return Node_Id; + -- Scans out any construct starting with either of the keywords + -- PROCEDURE or FUNCTION. The parameter indicates which possible + -- possible kinds of construct (body, spec, instantiation etc.) + -- are permissible in the current context. + + end Ch6; + + package Ch7 is + function P_Package (Pf_Flags : Pf_Rec) return Node_Id; + -- Scans out any construct starting with the keyword PACKAGE. The + -- parameter indicates which possible kinds of construct (body, spec, + -- instantiation etc.) are permissible in the current context. + end Ch7; + + package Ch8 is + function P_Use_Clause return Node_Id; + end Ch8; + + package Ch9 is + function P_Abort_Statement return Node_Id; + function P_Abortable_Part return Node_Id; + function P_Accept_Statement return Node_Id; + function P_Delay_Statement return Node_Id; + function P_Entry_Body return Node_Id; + function P_Protected return Node_Id; + function P_Requeue_Statement return Node_Id; + function P_Select_Statement return Node_Id; + function P_Task return Node_Id; + function P_Terminate_Alternative return Node_Id; + end Ch9; + + package Ch10 is + function P_Compilation_Unit return Node_Id; + -- Note: this function scans a single compilation unit, and + -- checks that an end of file follows this unit, diagnosing + -- any unexpected input as an error, and then skipping it, so + -- that Token is set to Tok_EOF on return. An exception is in + -- syntax-only mode, where multiple compilation units are + -- permitted. In this case, P_Compilation_Unit does not check + -- for end of file and there may be more compilation units to + -- scan. The caller can uniquely detect this situation by the + -- fact that Token is not set to Tok_EOF on return. + end Ch10; + + package Ch11 is + function P_Handled_Sequence_Of_Statements return Node_Id; + function P_Raise_Statement return Node_Id; + + function Parse_Exception_Handlers return List_Id; + -- Parses the partial construct EXCEPTION followed by a list of + -- exception handlers which appears in a number of productions, + -- and returns the list of exception handlers. + + end Ch11; + + package Ch12 is + function P_Generic return Node_Id; + function P_Generic_Actual_Part_Opt return List_Id; + end Ch12; + + package Ch13 is + function P_Representation_Clause return Node_Id; + + function P_Code_Statement (Subtype_Mark : Node_Id) return Node_Id; + -- Function to parse a code statement. The caller has scanned out + -- the name to be used as the subtype mark (but has not checked that + -- it is suitable for use as a subtype mark, i.e. is either an + -- identifier or a selected component). The current token is an + -- apostrophe and the following token is either a left paren or + -- RANGE (the latter being an error to be caught by P_Code_Statement. + end Ch13; + + -- Note: the parsing for annexe J features (i.e. obsolescent features) + -- is found in the logical section where these features would be if + -- they were not obsolescent. In particular: + + -- Delta constraint is parsed by P_Delta_Constraint (3.5.9) + -- At clause is parsed by P_At_Clause (13.1) + -- Mod clause is parsed by P_Mod_Clause (13.5.1) + + ------------------ + -- End Handling -- + ------------------ + + -- Routines for handling end lines, including scope recovery + + package Endh is + + function Check_End return Boolean; + -- Called when an end sequence is required. In the absence of an error + -- situation, Token contains Tok_End on entry, but in a missing end + -- case, this may not be the case. Pop_End_Context is used to determine + -- the appropriate action to be taken. The returned result is True if + -- an End sequence was encountered and False if no End sequence was + -- present. This occurs if the END keyword encountered was determined + -- to be improper and deleted (i.e. Pop_End_Context set End_Action to + -- Skip_And_Reject). Note that the END sequence includes a semicolon, + -- except in the case of END RECORD, where a semicolon follows the END + -- RECORD, but is not part of the record type definition itself. + + procedure End_Skip; + -- Skip past an end sequence. On entry Token contains Tok_End, and we + -- we know that the end sequence is syntactically incorrect, and that + -- an appropriate error message has already been posted. The mission + -- is simply to position the scan pointer to be the best guess of the + -- position after the end sequence. We do not issue any additional + -- error messages while carrying this out. + + procedure End_Statements (Parent : Node_Id := Empty); + -- Called when an end is required or expected to terminate a sequence + -- of statements. The caller has already made an appropriate entry in + -- the Scope.Table to describe the expected form of the end. This can + -- only be used in cases where the only appropriate terminator is end. + -- If Parent is non-empty, then if a correct END line is encountered, + -- the End_Label field of Parent is set appropriately. + + end Endh; + + ------------------------------------ + -- Resynchronization After Errors -- + ------------------------------------ + + -- These procedures are used to resynchronize after errors. Following an + -- error which is not immediately locally recoverable, the exception + -- Error_Resync is raised. The handler for Error_Resync typically calls + -- one of these recovery procedures to resynchronize the source position + -- to a point from which parsing can be restarted. + + -- Note: these procedures output an information message that tokens are + -- being skipped, but this message is output only if the option for + -- Multiple_Errors_Per_Line is set in Options. + + package Sync is + + procedure Resync_Choice; + -- Used if an error occurs scanning a choice. The scan pointer is + -- advanced to the next vertical bar, arrow, or semicolon, whichever + -- comes first. We also quit if we encounter an end of file. + + procedure Resync_Expression; + -- Used if an error is detected during the parsing of an expression. + -- It skips past tokens until either a token which cannot be part of + -- an expression is encountered (an expression terminator), or if a + -- comma or right parenthesis or vertical bar is encountered at the + -- current parenthesis level (a parenthesis level counter is maintained + -- to carry out this test). + + procedure Resync_Past_Semicolon; + -- Used if an error occurs while scanning a sequence of declarations. + -- The scan pointer is positioned past the next semicolon and the scan + -- resumes. The scan is also resumed on encountering a token which + -- starts a declaration (but we make sure to skip at least one token + -- in this case, to avoid getting stuck in a loop). + + procedure Resync_Past_Semicolon_Or_To_Loop_Or_Then; + -- Used if an error occurs while scanning a sequence of statements. + -- The scan pointer is positioned past the next semicolon, or to the + -- next occurrence of either then or loop, and the scan resumes. + + procedure Resync_To_When; + -- Used when an error occurs scanning an entry index specification. + -- The scan pointer is positioned to the next WHEN (or to IS or + -- semicolon if either of these appear before WHEN, indicating + -- another error has occurred). + + procedure Resync_Semicolon_List; + -- Used if an error occurs while scanning a parenthesized list of items + -- separated by semicolons. The scan pointer is advanced to the next + -- semicolon or right parenthesis at the outer parenthesis level, or + -- to the next is or RETURN keyword occurence, whichever comes first. + + procedure Resync_Cunit; + -- Synchronize to next token which could be the start of a compilation + -- unit, or to the end of file token. + + end Sync; + + ------------------------- + -- Token Scan Routines -- + ------------------------- + + -- Routines to check for expected tokens + + package Tchk is + + -- Procedures with names of the form T_xxx, where Tok_xxx is a token + -- name, check that the current token matches the required token, and + -- if so, scan past it. If not, an error is issued indicating that + -- the required token is not present (xxx expected). In most cases, the + -- scan pointer is not moved in the not-found case, but there are some + -- exceptions to this, see for example T_Id, where the scan pointer is + -- moved across a literal appearing where an identifier is expected. + + procedure T_Abort; + procedure T_Arrow; + procedure T_At; + procedure T_Body; + procedure T_Box; + procedure T_Colon; + procedure T_Colon_Equal; + procedure T_Comma; + procedure T_Dot_Dot; + procedure T_For; + procedure T_Greater_Greater; + procedure T_Identifier; + procedure T_In; + procedure T_Is; + procedure T_Left_Paren; + procedure T_Loop; + procedure T_Mod; + procedure T_New; + procedure T_Of; + procedure T_Or; + procedure T_Private; + procedure T_Range; + procedure T_Record; + procedure T_Right_Paren; + procedure T_Semicolon; + procedure T_Then; + procedure T_Type; + procedure T_Use; + procedure T_When; + procedure T_With; + + -- Procedures have names of the form TF_xxx, where Tok_xxx is a token + -- name check that the current token matches the required token, and + -- if so, scan past it. If not, an error message is issued indicating + -- that the required token is not present (xxx expected). + + -- If the missing token is at the end of the line, then control returns + -- immediately after posting the message. If there are remaining tokens + -- on the current line, a search is conducted to see if the token + -- appears later on the current line, as follows: + + -- A call to Scan_Save is issued and a forward search for the token + -- is carried out. If the token is found on the current line before a + -- semicolon, then it is scanned out and the scan continues from that + -- point. If not the scan is restored to the point where it was missing. + + procedure TF_Arrow; + procedure TF_Is; + procedure TF_Loop; + procedure TF_Return; + procedure TF_Semicolon; + procedure TF_Then; + procedure TF_Use; + + end Tchk; + + ---------------------- + -- Utility Routines -- + ---------------------- + + package Util is + + function Bad_Spelling_Of (T : Token_Type) return Boolean; + -- This function is called in an error situation. It checks if the + -- current token is an identifier whose name is a plausible bad + -- spelling of the given keyword token, and if so, issues an error + -- message, sets Token from T, and returns True. Otherwise Token is + -- unchanged, and False is returned. + + procedure Check_Bad_Layout; + -- Check for bad indentation in RM checking mode. Used for statements + -- and declarations. Checks if current token is at start of line and + -- is exdented from the current expected end column, and if so an + -- error message is generated. + + procedure Check_Misspelling_Of (T : Token_Type); + pragma Inline (Check_Misspelling_Of); + -- This is similar to the function above, except that it does not + -- return a result. It is typically used in a situation where any + -- identifier is an error, and it makes sense to simply convert it + -- to the given token if it is a plausible misspelling of it. + + procedure Check_95_Keyword (Token_95, Next : Token_Type); + -- This routine checks if the token after the current one matches the + -- Next argument. If so, the scan is backed up to the current token + -- and Token_Type is changed to Token_95 after issuing an appropriate + -- error message ("(Ada 83) keyword xx cannot be used"). If not, + -- the scan is backed up with Token_Type unchanged. This routine + -- is used to deal with an attempt to use a 95 keyword in Ada 83 + -- mode. The caller has typically checked that the current token, + -- an identifier, matches one of the 95 keywords. + + procedure Check_Simple_Expression (E : Node_Id); + -- Given an expression E, that has just been scanned, so that Expr_Form + -- is still set, outputs an error if E is a non-simple expression. E is + -- not modified by this call. + + procedure Check_Simple_Expression_In_Ada_83 (E : Node_Id); + -- Like Check_Simple_Expression, except that the error message is only + -- given when operating in Ada 83 mode, and includes "in Ada 83". + + function Check_Subtype_Mark (Mark : Node_Id) return Node_Id; + -- Called to check that a node representing a name (or call) is + -- suitable for a subtype mark, i.e, that it is an identifier or + -- a selected component. If so, or if it is already Error, then + -- it is returned unchanged. Otherwise an error message is issued + -- and Error is returned. + + function Comma_Present return Boolean; + -- Used in comma delimited lists to determine if a comma is present, or + -- can reasonably be assumed to have been present (an error message is + -- generated in the latter case). If True is returned, the scan has been + -- positioned past the comma. If False is returned, the scan position + -- is unchanged. Note that all comma-delimited lists are terminated by + -- a right paren, so the only legitimate tokens when Comma_Present is + -- called are right paren and comma. If some other token is found, then + -- Comma_Present has the job of deciding whether it is better to pretend + -- a comma was present, post a message for a missing comma and return + -- True, or return False and let the caller diagnose the missing right + -- parenthesis. + + procedure Discard_Junk_Node (N : Node_Id); + procedure Discard_Junk_List (L : List_Id); + pragma Inline (Discard_Junk_Node); + pragma Inline (Discard_Junk_List); + -- These procedures do nothing at all, their effect is simply to discard + -- the argument. A typical use is to skip by some junk that is not + -- expected in the current context. + + procedure Ignore (T : Token_Type); + -- If current token matches T, then give an error message and skip + -- past it, otherwise the call has no effect at all. T may be any + -- reserved word token, or comma, left or right paren, or semicolon. + + function Is_Reserved_Identifier return Boolean; + -- Test if current token is a reserved identifier. This test is based + -- on the token being a keyword and being spelled in typical identifier + -- style (i.e. starting with an upper case letter). + + procedure Merge_Identifier (Prev : Node_Id; Nxt : Token_Type); + -- Called when the previous token is an identifier (whose Token_Node + -- value is given by Prev) to check if current token is an identifier + -- that can be merged with the previous one adding an underscore. The + -- merge is only attempted if the following token matches Nxt. If all + -- conditions are met, an error message is issued, and the merge is + -- carried out, modifying the Chars field of Prev. + + procedure No_Constraint; + -- Called in a place where no constraint is allowed, but one might + -- appear due to a common error (e.g. after the type mark in a procedure + -- parameter. If a constraint is present, an error message is posted, + -- and the constraint is scanned and discarded. + + function No_Right_Paren (Expr : Node_Id) return Node_Id; + -- Function to check for no right paren at end of expression, returns + -- its argument if no right paren, else flags paren and returns Error. + + procedure Push_Scope_Stack; + pragma Inline (Push_Scope_Stack); + -- Push a new entry onto the scope stack. Scope.Last (the stack pointer) + -- is incremented. The Junk field is preinitialized to False. The caller + -- is expected to fill in all remaining entries of the new new top stack + -- entry at Scope.Table (Scope.Last). + + procedure Pop_Scope_Stack; + -- Pop an entry off the top of the scope stack. Scope_Last (the scope + -- table stack pointer) is decremented by one. It is a fatal error to + -- try to pop off the dummy entry at the bottom of the stack (i.e. + -- Scope.Last must be non-zero at the time of call). + + function Separate_Present return Boolean; + -- Determines if the current token is either Tok_Separate, or an + -- identifier that is a possible misspelling of "separate" followed + -- by a semicolon. True is returned if so, otherwise False. + + procedure Signal_Bad_Attribute; + -- The current token is an identifier that is supposed to be an + -- attribute identifier but is not. This routine posts appropriate + -- error messages, including a check for a near misspelling. + + function Token_Is_At_Start_Of_Line return Boolean; + pragma Inline (Token_Is_At_Start_Of_Line); + -- Determines if the current token is the first token on the line + + end Util; + + --------------------------------------- + -- Specialized Syntax Check Routines -- + --------------------------------------- + + function Prag (Pragma_Node : Node_Id; Semi : Source_Ptr) return Node_Id; + -- This function is passed a tree for a pragma that has been scanned out. + -- The pragma is syntactically well formed according to the general syntax + -- for pragmas and the pragma identifier is for one of the recognized + -- pragmas. It performs specific syntactic checks for specific pragmas. + -- The result is the input node if it is OK, or Error otherwise. The + -- reason that this is separated out is to facilitate the addition + -- of implementation defined pragmas. The second parameter records the + -- location of the semicolon following the pragma (this is needed for + -- correct processing of the List and Page pragmas). The returned value + -- is a copy of Pragma_Node, or Error if an error is found. + + ------------------------- + -- Subsidiary Routines -- + ------------------------- + + procedure Labl; + -- This procedure creates implicit label declarations for all label that + -- are declared in the current unit. Note that this could conceptually + -- be done at the point where the labels are declared, but it is tricky + -- to do it then, since the tree is not hooked up at the point where the + -- label is declared (e.g. a sequence of statements is not yet attached + -- to its containing scope at the point a label in the sequence is found) + + procedure Load; + -- This procedure loads all subsidiary units that are required by this + -- unit, including with'ed units, specs for bodies, and parents for child + -- units. It does not load bodies for inlined procedures and generics, + -- since we don't know till semantic analysis is complete what is needed. + + ----------- + -- Stubs -- + ----------- + + -- The package bodies can see all routines defined in all other subpackages + + use Ch2; + use Ch3; + use Ch4; + use Ch5; + use Ch6; + use Ch7; + use Ch8; + use Ch9; + use Ch10; + use Ch11; + use Ch12; + use Ch13; + + use Endh; + use Tchk; + use Sync; + use Util; + + package body Ch2 is separate; + package body Ch3 is separate; + package body Ch4 is separate; + package body Ch5 is separate; + package body Ch6 is separate; + package body Ch7 is separate; + package body Ch8 is separate; + package body Ch9 is separate; + package body Ch10 is separate; + package body Ch11 is separate; + package body Ch12 is separate; + package body Ch13 is separate; + + package body Endh is separate; + package body Tchk is separate; + package body Sync is separate; + package body Util is separate; + + function Prag (Pragma_Node : Node_Id; Semi : Source_Ptr) return Node_Id + is separate; + + procedure Labl is separate; + procedure Load is separate; + + --------- + -- Par -- + --------- + +-- This function is the parse routine called at the outer level. It parses +-- the current compilation unit and adds implicit label declarations. + +begin + -- Deal with configuration pragmas case first + + if Configuration_Pragmas then + declare + Ecount : constant Int := Errors_Detected; + Pragmas : List_Id := Empty_List; + P_Node : Node_Id; + + begin + loop + if Token = Tok_EOF then + return Pragmas; + + elsif Token /= Tok_Pragma then + Error_Msg_SC ("only pragmas allowed in configuration file"); + return Error_List; + + else + P_Node := P_Pragma; + + if Errors_Detected > Ecount then + return Error_List; + end if; + + if Chars (P_Node) > Last_Configuration_Pragma_Name + and then Chars (P_Node) /= Name_Source_Reference + then + Error_Msg_SC + ("only configuration pragmas allowed " & + "in configuration file"); + return Error_List; + end if; + + Append (P_Node, Pragmas); + end if; + end loop; + end; + + -- Normal case of compilation unit + + else + Save_Opt_Config_Switches (Save_Config_Switches); + + -- Special processing for language defined units. For this purpose + -- we do NOT consider the renamings in annex J as predefined. That + -- allows users to compile their own versions of these files, and + -- in particular, in the VMS implementation, the DEC versions can + -- be substituted for the standard Ada 95 versions. + + if Is_Predefined_File_Name + (Fname => File_Name (Current_Source_File), + Renamings_Included => False) + then + Set_Opt_Config_Switches + (Is_Internal_File_Name (File_Name (Current_Source_File))); + + -- If this is the main unit, disallow compilation unless the -gnatg + -- (GNAT mode) switch is set (from a user point of view, the rule is + -- that language defined units cannot be recompiled). + + -- However, an exception is s-rpc, and its children. We test this + -- by looking at the character after the minus, the rule is that + -- System.RPC and its children are the only children in System + -- whose second level name can start with the letter r. + + Get_Name_String (File_Name (Current_Source_File)); + + if (Name_Len < 3 or else Name_Buffer (1 .. 3) /= "s-r") + and then Current_Source_Unit = Main_Unit + and then not GNAT_Mode + and then Operating_Mode = Generate_Code + then + Error_Msg_SC ("language defined units may not be recompiled"); + end if; + end if; + + -- The following loop runs more than once only in syntax check mode + -- where we allow multiple compilation units in the same file. + + loop + Set_Opt_Config_Switches + (Is_Internal_File_Name (File_Name (Current_Source_File))); + + -- Initialize scope table and other parser control variables + + Compiler_State := Parsing; + Scope.Init; + Scope.Increment_Last; + Scope.Table (0).Etyp := E_Dummy; + SIS_Entry_Active := False; + Last_Resync_Point := No_Location; + + Label_List := New_Elmt_List; + Unit_Node := P_Compilation_Unit; + + -- If we are not at an end of file, then this means that we are + -- in syntax scan mode, and we can have another compilation unit, + -- otherwise we will exit from the loop. + + exit when Token = Tok_EOF; + Restore_Opt_Config_Switches (Save_Config_Switches); + Set_Comes_From_Source_Default (False); + end loop; + + -- Now that we have completely parsed the source file, we can + -- complete the source file table entry. + + Complete_Source_File_Entry; + + -- An internal error check, the scope stack should now be empty + + pragma Assert (Scope.Last = 0); + + -- Remaining steps are to create implicit label declarations and to + -- load required subsidiary sources. These steps are required only + -- if we are doing semantic checking. + + if Operating_Mode /= Check_Syntax or else Debug_Flag_F then + Par.Labl; + Par.Load; + end if; + + -- Restore settings of switches saved on entry + + Restore_Opt_Config_Switches (Save_Config_Switches); + Set_Comes_From_Source_Default (False); + return Empty_List; + end if; + +end Par; diff --git a/gcc/ada/par.ads b/gcc/ada/par.ads new file mode 100644 index 00000000000..c1110a0b135 --- /dev/null +++ b/gcc/ada/par.ads @@ -0,0 +1,44 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P A R -- +-- -- +-- S p e c -- +-- -- +-- $Revision: 1.14 $ -- +-- -- +-- Copyright (C) 1992,1993,1994,1995 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +-- The Par function and its subunits contains all the parsing routines +-- for the top down recursive descent parser that constructs the parse tree + +with Types; use Types; + +function Par (Configuration_Pragmas : Boolean) return List_Id; +-- Top level parsing routine. There are two cases: +-- +-- If Configuration_Pragmas is False, Par parses a compilation unit in the +-- current source file and sets the Cunit, Cunit_Entity and Unit_Name fields +-- of the units table entry for Current_Source_Unit. On return the parse tree +-- is complete, and decorated with any required implicit label declarations. +-- The value returned in this case is always No_List. +-- +-- If Configuration_Pragmas is True, Par parses a list of configuration +-- pragmas from the current source file, and returns the list of pragmas. diff --git a/gcc/ada/prj-attr.adb b/gcc/ada/prj-attr.adb new file mode 100644 index 00000000000..aa793025f8a --- /dev/null +++ b/gcc/ada/prj-attr.adb @@ -0,0 +1,211 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J . A T T R -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.4 $ +-- -- +-- Copyright (C) 2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +with Ada.Characters.Handling; use Ada.Characters.Handling; +with Namet; use Namet; +with Output; use Output; + +package body Prj.Attr is + + -- Names end with '#' + -- Package names are preceded by 'P' + -- Attribute names are preceded by two capital letters: + -- 'S' for Single or 'L' for list, then + -- 'V' for single variable, 'A' for associative array, or 'B' for both. + -- End is indicated by two consecutive '#'. + + Initialisation_Data : constant String := + + -- project attributes + + "SVobject_dir#" & + "LVsource_dirs#" & + "LVsource_files#" & + "SVsource_list_file#" & + "SVlibrary_dir#" & + "SVlibrary_name#" & + "SVlibrary_kind#" & + "SVlibrary_elaboration#" & + "SVlibrary_version#" & + "LVmain#" & + + -- package Naming + + "Pnaming#" & + "SVspecification_append#" & + "SVbody_append#" & + "SVseparate_append#" & + "SVcasing#" & + "SVdot_replacement#" & + "SAspecification#" & + "SAbody_part#" & + + -- package Compiler + + "Pcompiler#" & + "LBswitches#" & + "SVlocal_configuration_pragmas#" & + + -- package gnatmake + + "Pgnatmake#" & + "LBswitches#" & + "SVglobal_configuration_pragmas#" & + + -- package gnatls + + "Pgnatls#" & + "LVswitches#" & + + -- package gnatbind + + "Pgnatbind#" & + "LBswitches#" & + + -- package gnatlink + + "Pgnatlink#" & + "LBswitches#" & + + "#"; + + ---------------- + -- Initialize -- + ---------------- + + procedure Initialize is + Start : Positive := Initialisation_Data'First; + Finish : Positive := Start; + Current_Package : Package_Node_Id := Empty_Package; + Current_Attribute : Attribute_Node_Id := Empty_Attribute; + Is_An_Attribute : Boolean := False; + Kind_1 : Variable_Kind := Undefined; + Kind_2 : Attribute_Kind := Single; + Package_Name : Name_Id := No_Name; + Attribute_Name : Name_Id := No_Name; + First_Attribute : Attribute_Node_Id := Attribute_First; + begin + + -- Make sure the two tables are empty + + Attributes.Set_Last (Attributes.First); + Package_Attributes.Set_Last (Package_Attributes.First); + + while Initialisation_Data (Start) /= '#' loop + Is_An_Attribute := True; + case Initialisation_Data (Start) is + when 'P' => + -- New allowed package + Start := Start + 1; + Finish := Start; + while Initialisation_Data (Finish) /= '#' loop + Finish := Finish + 1; + end loop; + Name_Len := Finish - Start; + Name_Buffer (1 .. Name_Len) := + To_Lower (Initialisation_Data (Start .. Finish - 1)); + Package_Name := Name_Find; + for Index in Package_First .. Package_Attributes.Last loop + if Package_Name = Package_Attributes.Table (Index).Name then + Write_Line ("Duplicate package name """ & + Initialisation_Data (Start .. Finish - 1) & + """ in Prj.Attr body."); + raise Program_Error; + end if; + end loop; + + Is_An_Attribute := False; + Current_Attribute := Empty_Attribute; + Package_Attributes.Increment_Last; + Current_Package := Package_Attributes.Last; + Package_Attributes.Table (Current_Package).Name := + Package_Name; + Start := Finish + 1; + when 'S' => + Kind_1 := Single; + when 'L' => + Kind_1 := List; + when others => + raise Program_Error; + end case; + + if Is_An_Attribute then + -- New attribute + Start := Start + 1; + case Initialisation_Data (Start) is + when 'V' => + Kind_2 := Single; + when 'A' => + Kind_2 := Associative_Array; + when 'B' => + Kind_2 := Both; + when others => + raise Program_Error; + end case; + Start := Start + 1; + Finish := Start; + while Initialisation_Data (Finish) /= '#' loop + Finish := Finish + 1; + end loop; + Name_Len := Finish - Start; + Name_Buffer (1 .. Name_Len) := + To_Lower (Initialisation_Data (Start .. Finish - 1)); + Attribute_Name := Name_Find; + Attributes.Increment_Last; + if Current_Attribute = Empty_Attribute then + First_Attribute := Attributes.Last; + if Current_Package /= Empty_Package then + Package_Attributes.Table (Current_Package).First_Attribute + := Attributes.Last; + end if; + else + -- Check that there are no duplicate attributes + for Index in First_Attribute .. Attributes.Last - 1 loop + if Attribute_Name = + Attributes.Table (Index).Name then + Write_Line ("Duplicate attribute name """ & + Initialisation_Data (Start .. Finish - 1) & + """ in Prj.Attr body."); + raise Program_Error; + end if; + end loop; + Attributes.Table (Current_Attribute).Next := + Attributes.Last; + end if; + Current_Attribute := Attributes.Last; + Attributes.Table (Current_Attribute) := + (Name => Attribute_Name, + Kind_1 => Kind_1, + Kind_2 => Kind_2, + Next => Empty_Attribute); + Start := Finish + 1; + end if; + end loop; + end Initialize; + +end Prj.Attr; diff --git a/gcc/ada/prj-attr.ads b/gcc/ada/prj-attr.ads new file mode 100644 index 00000000000..ba4bb2e543b --- /dev/null +++ b/gcc/ada/prj-attr.ads @@ -0,0 +1,108 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J . A T T R -- +-- -- +-- S p e c -- +-- -- +-- $Revision: 1.1 $ +-- -- +-- Copyright (C) 2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ +-- +-- This package defines allowed packages and attributes in GNAT project +-- files. + +with Types; use Types; +with Table; + +package Prj.Attr is + + -- Define the allowed attributes + + Attributes_Initial : constant := 50; + Attributes_Increment : constant := 50; + + Attribute_Node_Low_Bound : constant := 0; + Attribute_Node_High_Bound : constant := 099_999_999; + + type Attribute_Node_Id is + range Attribute_Node_Low_Bound .. Attribute_Node_High_Bound; + + First_Attribute_Node_Id : constant Attribute_Node_Id + := Attribute_Node_Low_Bound; + + Empty_Attribute : constant Attribute_Node_Id + := Attribute_Node_Low_Bound; + + type Attribute_Kind is (Single, Associative_Array, Both); + + type Attribute_Record is record + Name : Name_Id; + Kind_1 : Variable_Kind; + Kind_2 : Attribute_Kind; + Next : Attribute_Node_Id; + end record; + + package Attributes is + new Table.Table (Table_Component_Type => Attribute_Record, + Table_Index_Type => Attribute_Node_Id, + Table_Low_Bound => First_Attribute_Node_Id, + Table_Initial => Attributes_Initial, + Table_Increment => Attributes_Increment, + Table_Name => "Prj.Attr.Attributes"); + + Attribute_First : constant Attribute_Node_Id := First_Attribute_Node_Id + 1; + + -- Define the allowed packages + + Packages_Initial : constant := 10; + Packages_Increment : constant := 10; + + Package_Node_Low_Bound : constant := 0; + Package_Node_High_Bound : constant := 099_999_999; + + type Package_Node_Id is + range Package_Node_Low_Bound .. Package_Node_High_Bound; + + First_Package_Node_Id : constant Package_Node_Id + := Package_Node_Low_Bound; + + Empty_Package : constant Package_Node_Id := Package_Node_Low_Bound; + + type Package_Record is record + Name : Name_Id; + First_Attribute : Attribute_Node_Id; + end record; + + package Package_Attributes is + new Table.Table (Table_Component_Type => Package_Record, + Table_Index_Type => Package_Node_Id, + Table_Low_Bound => First_Package_Node_Id, + Table_Initial => Packages_Initial, + Table_Increment => Packages_Increment, + Table_Name => "Prj.Attr.Packages"); + + Package_First : constant Package_Node_Id := Package_Node_Low_Bound + 1; + + procedure Initialize; + -- Initialize the two tables above (Attributes and Package_Attributes). + -- This procedure should be called by Prj.Initialize. + +end Prj.Attr; diff --git a/gcc/ada/prj-com.adb b/gcc/ada/prj-com.adb new file mode 100644 index 00000000000..3447e18f57c --- /dev/null +++ b/gcc/ada/prj-com.adb @@ -0,0 +1,49 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J . C O M -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.1 $ +-- -- +-- Copyright (C) 2000 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +with Namet; use Namet; +with Stringt; use Stringt; + +package body Prj.Com is + + ---------- + -- Hash -- + ---------- + + function Hash (Name : Name_Id) return Header_Num is + begin + return Hash (Get_Name_String (Name)); + end Hash; + + function Hash (Name : String_Id) return Header_Num is + begin + String_To_Name_Buffer (Name); + return Hash (Name_Buffer (1 .. Name_Len)); + end Hash; + +end Prj.Com; diff --git a/gcc/ada/prj-com.ads b/gcc/ada/prj-com.ads new file mode 100644 index 00000000000..ddb7d0f8ef7 --- /dev/null +++ b/gcc/ada/prj-com.ads @@ -0,0 +1,92 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J . C O M -- +-- -- +-- S p e c -- +-- -- +-- $Revision: 1.3 $ -- +-- -- +-- Copyright (C) 1992-2000 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +-- The following package declares data types for GNAT project. +-- These data types are used in the bodies of the Prj hierarchy. + +with GNAT.HTable; +with Table; +with Types; use Types; + +package Prj.Com is + + -- At one point, this package was private. + -- It cannot be private, because it is used outside of + -- the Prj hierarchy. + + Tool_Name : Name_Id := No_Name; + + Current_Verbosity : Verbosity := Default; + + type Spec_Or_Body is + (Specification, Body_Part); + + type File_Name_Data is record + Name : Name_Id := No_Name; + Path : Name_Id := No_Name; + Project : Project_Id := No_Project; + Needs_Pragma : Boolean := False; + end record; + -- File and Path name of a spec or body. + + type File_Names_Data is array (Spec_Or_Body) of File_Name_Data; + + type Unit_Id is new Nat; + No_Unit : constant Unit_Id := 0; + type Unit_Data is record + Name : Name_Id := No_Name; + File_Names : File_Names_Data; + end record; + -- File and Path names of a unit, with a reference to its + -- GNAT Project File. + + package Units is new Table.Table + (Table_Component_Type => Unit_Data, + Table_Index_Type => Unit_Id, + Table_Low_Bound => 1, + Table_Initial => 100, + Table_Increment => 100, + Table_Name => "Prj.Com.Units"); + + type Header_Num is range 0 .. 2047; + + function Hash is new GNAT.HTable.Hash (Header_Num => Header_Num); + + function Hash (Name : Name_Id) return Header_Num; + + function Hash (Name : String_Id) return Header_Num; + + package Units_Htable is new GNAT.HTable.Simple_HTable + (Header_Num => Header_Num, + Element => Unit_Id, + No_Element => No_Unit, + Key => Name_Id, + Hash => Hash, + Equal => "="); + +end Prj.Com; diff --git a/gcc/ada/prj-dect.adb b/gcc/ada/prj-dect.adb new file mode 100644 index 00000000000..65f7e43a4b6 --- /dev/null +++ b/gcc/ada/prj-dect.adb @@ -0,0 +1,942 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J . D E C T -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.5 $ +-- -- +-- Copyright (C) 2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +with Errout; use Errout; +with Prj.Strt; +with Prj.Tree; use Prj.Tree; +with Scans; use Scans; +with Sinfo; use Sinfo; +with Types; use Types; +with Prj.Attr; use Prj.Attr; + +package body Prj.Dect is + + type Zone is (In_Project, In_Package, In_Case_Construction); + + procedure Parse_Attribute_Declaration + (Attribute : out Project_Node_Id; + First_Attribute : Attribute_Node_Id; + Current_Project : Project_Node_Id; + Current_Package : Project_Node_Id); + -- Parse an attribute declaration. + + procedure Parse_Case_Construction + (Case_Construction : out Project_Node_Id; + First_Attribute : Attribute_Node_Id; + Current_Project : Project_Node_Id; + Current_Package : Project_Node_Id); + -- Parse a case construction + + procedure Parse_Declarative_Items + (Declarations : out Project_Node_Id; + In_Zone : Zone; + First_Attribute : Attribute_Node_Id; + Current_Project : Project_Node_Id; + Current_Package : Project_Node_Id); + -- Parse declarative items. Depending on In_Zone, some declarative + -- items may be forbiden. + + procedure Parse_Package_Declaration + (Package_Declaration : out Project_Node_Id; + Current_Project : Project_Node_Id); + -- Parse a package declaration + + procedure Parse_String_Type_Declaration + (String_Type : out Project_Node_Id; + Current_Project : Project_Node_Id; + First_Attribute : Attribute_Node_Id); + -- type <name> is ( <literal_string> { , <literal_string> } ) ; + + procedure Parse_Variable_Declaration + (Variable : out Project_Node_Id; + First_Attribute : Attribute_Node_Id; + Current_Project : Project_Node_Id; + Current_Package : Project_Node_Id); + -- Parse a variable assignment + -- <variable_Name> := <expression>; OR + -- <variable_Name> : <string_type_Name> := <string_expression>; + + ----------- + -- Parse -- + ----------- + + procedure Parse + (Declarations : out Project_Node_Id; + Current_Project : Project_Node_Id; + Modifying : Project_Node_Id) + is + First_Declarative_Item : Project_Node_Id := Empty_Node; + + begin + Declarations := Default_Project_Node (Of_Kind => N_Project_Declaration); + Set_Location_Of (Declarations, To => Token_Ptr); + Set_Modified_Project_Of (Declarations, To => Modifying); + Parse_Declarative_Items + (Declarations => First_Declarative_Item, + In_Zone => In_Project, + First_Attribute => Prj.Attr.Attribute_First, + Current_Project => Current_Project, + Current_Package => Empty_Node); + Set_First_Declarative_Item_Of + (Declarations, To => First_Declarative_Item); + end Parse; + + --------------------------------- + -- Parse_Attribute_Declaration -- + --------------------------------- + + procedure Parse_Attribute_Declaration + (Attribute : out Project_Node_Id; + First_Attribute : Attribute_Node_Id; + Current_Project : Project_Node_Id; + Current_Package : Project_Node_Id) + is + Current_Attribute : Attribute_Node_Id := First_Attribute; + + begin + Attribute := Default_Project_Node (Of_Kind => N_Attribute_Declaration); + Set_Location_Of (Attribute, To => Token_Ptr); + + -- Scan past "for" + + Scan; + + Expect (Tok_Identifier, "identifier"); + + if Token = Tok_Identifier then + Set_Name_Of (Attribute, To => Token_Name); + Set_Location_Of (Attribute, To => Token_Ptr); + while Current_Attribute /= Empty_Attribute + and then + Attributes.Table (Current_Attribute).Name /= Token_Name + loop + Current_Attribute := Attributes.Table (Current_Attribute).Next; + end loop; + + if Current_Attribute = Empty_Attribute then + Error_Msg ("undefined attribute", Token_Ptr); + end if; + + Scan; + end if; + + if Token = Tok_Left_Paren then + if Current_Attribute /= Empty_Attribute + and then Attributes.Table (Current_Attribute).Kind_2 = Single + then + Error_Msg ("this attribute cannot be an associative array", + Location_Of (Attribute)); + end if; + + Scan; + Expect (Tok_String_Literal, "literal string"); + + if Token = Tok_String_Literal then + Set_Associative_Array_Index_Of (Attribute, Strval (Token_Node)); + Scan; + end if; + + Expect (Tok_Right_Paren, ")"); + + if Token = Tok_Right_Paren then + Scan; + end if; + + else + if Current_Attribute /= Empty_Attribute + and then + Attributes.Table (Current_Attribute).Kind_2 = Associative_Array + then + Error_Msg ("this attribute need to be an associative array", + Location_Of (Attribute)); + end if; + end if; + + if Current_Attribute /= Empty_Attribute then + Set_Expression_Kind_Of + (Attribute, To => Attributes.Table (Current_Attribute).Kind_1); + end if; + + Expect (Tok_Use, "use"); + + if Token = Tok_Use then + Scan; + + declare + Expression_Location : constant Source_Ptr := Token_Ptr; + Expression : Project_Node_Id := Empty_Node; + + begin + Prj.Strt.Parse_Expression + (Expression => Expression, + Current_Project => Current_Project, + Current_Package => Current_Package); + Set_Expression_Of (Attribute, To => Expression); + + if Current_Attribute /= Empty_Attribute + and then Expression /= Empty_Node + and then Attributes.Table (Current_Attribute).Kind_1 /= + Expression_Kind_Of (Expression) + then + Error_Msg + ("wrong expression kind for the attribute", + Expression_Location); + end if; + end; + end if; + + end Parse_Attribute_Declaration; + + ----------------------------- + -- Parse_Case_Construction -- + ----------------------------- + + procedure Parse_Case_Construction + (Case_Construction : out Project_Node_Id; + First_Attribute : Attribute_Node_Id; + Current_Project : Project_Node_Id; + Current_Package : Project_Node_Id) + 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; + + begin + Case_Construction := + Default_Project_Node (Of_Kind => N_Case_Construction); + Set_Location_Of (Case_Construction, To => Token_Ptr); + + -- Scan past "case" + + Scan; + + -- Get the switch variable + + Expect (Tok_Identifier, "identifier"); + + if Token = Tok_Identifier then + Variable_Location := Token_Ptr; + Prj.Strt.Parse_Variable_Reference + (Variable => Case_Variable, + Current_Project => Current_Project, + Current_Package => Current_Package); + Set_Case_Variable_Reference_Of + (Case_Construction, To => Case_Variable); + + else + if Token /= Tok_Is then + Scan; + end if; + end if; + + if Case_Variable /= Empty_Node then + String_Type := String_Type_Of (Case_Variable); + + if String_Type = Empty_Node then + Error_Msg ("this variable is not typed", Variable_Location); + end if; + end if; + + Expect (Tok_Is, "is"); + + if Token = Tok_Is then + + -- Scan past "is" + + Scan; + end if; + + Prj.Strt.Start_New_Case_Construction (String_Type); + + When_Loop : + + while Token = Tok_When loop + + if First_Case_Item then + Current_Item := Default_Project_Node (Of_Kind => N_Case_Item); + Set_First_Case_Item_Of (Case_Construction, To => Current_Item); + First_Case_Item := False; + + else + Next_Item := Default_Project_Node (Of_Kind => N_Case_Item); + Set_Next_Case_Item (Current_Item, To => Next_Item); + Current_Item := Next_Item; + end if; + + Set_Location_Of (Current_Item, To => Token_Ptr); + + -- Scan past "when" + + Scan; + + if Token = Tok_Others then + + -- Scan past "others" + + Scan; + + Expect (Tok_Arrow, "=>"); + + -- Empty_Node in Field1 of a Case_Item indicates + -- the "when others =>" branch. + + Set_First_Choice_Of (Current_Item, To => Empty_Node); + + Parse_Declarative_Items + (Declarations => First_Declarative_Item, + In_Zone => In_Case_Construction, + First_Attribute => First_Attribute, + Current_Project => Current_Project, + Current_Package => Current_Package); + + -- "when others =>" must be the last branch, so save the + -- Case_Item and exit + + Set_First_Declarative_Item_Of + (Current_Item, To => First_Declarative_Item); + exit When_Loop; + + else + Prj.Strt.Parse_Choice_List (First_Choice => First_Choice); + Set_First_Choice_Of (Current_Item, To => First_Choice); + + Expect (Tok_Arrow, "=>"); + + Parse_Declarative_Items + (Declarations => First_Declarative_Item, + In_Zone => In_Case_Construction, + First_Attribute => First_Attribute, + Current_Project => Current_Project, + Current_Package => Current_Package); + + Set_First_Declarative_Item_Of + (Current_Item, To => First_Declarative_Item); + + end if; + end loop When_Loop; + + Prj.Strt.End_Case_Construction; + + Expect (Tok_End, "end case"); + + if Token = Tok_End then + + -- Scan past "end" + + Scan; + + Expect (Tok_Case, "case"); + + end if; + + -- Scan past "case" + + Scan; + + Expect (Tok_Semicolon, ";"); + + end Parse_Case_Construction; + + ----------------------------- + -- Parse_Declarative_Items -- + ----------------------------- + + procedure Parse_Declarative_Items + (Declarations : out Project_Node_Id; + In_Zone : Zone; + First_Attribute : Attribute_Node_Id; + Current_Project : Project_Node_Id; + Current_Package : Project_Node_Id) + 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; + + Item_Location := Token_Ptr; + + case Token is + when Tok_Identifier => + + if In_Zone = In_Case_Construction then + Error_Msg ("a variable cannot be declared here", + Token_Ptr); + end if; + + Parse_Variable_Declaration + (Current_Declaration, + First_Attribute => First_Attribute, + Current_Project => Current_Project, + Current_Package => Current_Package); + + when Tok_For => + + Parse_Attribute_Declaration + (Attribute => Current_Declaration, + First_Attribute => First_Attribute, + Current_Project => Current_Project, + Current_Package => Current_Package); + + when Tok_Package => + + -- Package declaration + + if In_Zone /= In_Project then + Error_Msg ("a package cannot be declared here", Token_Ptr); + end if; + + Parse_Package_Declaration + (Package_Declaration => Current_Declaration, + Current_Project => Current_Project); + + when Tok_Type => + + -- Type String Declaration + + if In_Zone /= In_Project then + Error_Msg ("a string type cannot be declared here", + Token_Ptr); + end if; + + Parse_String_Type_Declaration + (String_Type => Current_Declaration, + Current_Project => Current_Project, + First_Attribute => First_Attribute); + + when Tok_Case => + + -- Case construction + + Parse_Case_Construction + (Case_Construction => Current_Declaration, + First_Attribute => First_Attribute, + Current_Project => Current_Project, + Current_Package => Current_Package); + + when others => + exit; + + -- We are leaving Parse_Declarative_Items positionned + -- 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"); + + if Current_Declarative_Item = Empty_Node then + Current_Declarative_Item := + Default_Project_Node (Of_Kind => N_Declarative_Item); + Declarations := Current_Declarative_Item; + + else + Next_Declarative_Item := + Default_Project_Node (Of_Kind => N_Declarative_Item); + Set_Next_Declarative_Item + (Current_Declarative_Item, To => Next_Declarative_Item); + Current_Declarative_Item := Next_Declarative_Item; + end if; + + Set_Current_Item_Node + (Current_Declarative_Item, To => Current_Declaration); + Set_Location_Of (Current_Declarative_Item, To => Item_Location); + + end loop; + + end Parse_Declarative_Items; + + ------------------------------- + -- Parse_Package_Declaration -- + ------------------------------- + + procedure Parse_Package_Declaration + (Package_Declaration : out Project_Node_Id; + Current_Project : Project_Node_Id) + is + First_Attribute : Attribute_Node_Id := Empty_Attribute; + Current_Package : Package_Node_Id := Empty_Package; + First_Declarative_Item : Project_Node_Id := Empty_Node; + + begin + Package_Declaration := + Default_Project_Node (Of_Kind => N_Package_Declaration); + Set_Location_Of (Package_Declaration, To => Token_Ptr); + + -- Scan past "package" + + Scan; + + Expect (Tok_Identifier, "identifier"); + + if Token = Tok_Identifier then + + Set_Name_Of (Package_Declaration, To => Token_Name); + + for Index in Package_Attributes.First .. Package_Attributes.Last loop + if Token_Name = Package_Attributes.Table (Index).Name then + First_Attribute := + Package_Attributes.Table (Index).First_Attribute; + Current_Package := Index; + exit; + end if; + end loop; + + if Current_Package = Empty_Package then + Error_Msg ("not an allowed package name", Token_Ptr); + + else + Set_Package_Id_Of (Package_Declaration, To => Current_Package); + + declare + Current : Project_Node_Id := First_Package_Of (Current_Project); + + begin + while Current /= Empty_Node + and then Name_Of (Current) /= Token_Name + loop + Current := Next_Package_In_Project (Current); + end loop; + + if Current /= Empty_Node then + Error_Msg + ("package declared twice in the same project", Token_Ptr); + + else + -- Add the package to the project list + + Set_Next_Package_In_Project + (Package_Declaration, + To => First_Package_Of (Current_Project)); + Set_First_Package_Of + (Current_Project, To => Package_Declaration); + end if; + end; + end if; + + -- Scan past the package name + + Scan; + + end if; + + if Token = Tok_Renames then + -- Scan past "renames" + Scan; + + Expect (Tok_Identifier, "identifier"); + + if Token = Tok_Identifier then + declare + Project_Name : Name_Id := Token_Name; + Clause : Project_Node_Id := + First_With_Clause_Of (Current_Project); + The_Project : Project_Node_Id := Empty_Node; + + begin + while Clause /= Empty_Node loop + The_Project := Project_Node_Of (Clause); + exit when Name_Of (The_Project) = Project_Name; + Clause := Next_With_Clause_Of (Clause); + end loop; + + if Clause = Empty_Node then + Error_Msg ("not an imported project", Token_Ptr); + else + Set_Project_Of_Renamed_Package_Of + (Package_Declaration, To => The_Project); + end if; + end; + + Scan; + Expect (Tok_Dot, "."); + + if Token = Tok_Dot then + Scan; + Expect (Tok_Identifier, "identifier"); + + if Token = Tok_Identifier then + if Name_Of (Package_Declaration) /= Token_Name then + Error_Msg ("not the same package name", Token_Ptr); + elsif + Project_Of_Renamed_Package_Of (Package_Declaration) + /= Empty_Node + then + declare + Current : Project_Node_Id := + First_Package_Of + (Project_Of_Renamed_Package_Of + (Package_Declaration)); + + begin + while Current /= Empty_Node + and then Name_Of (Current) /= Token_Name + loop + Current := Next_Package_In_Project (Current); + end loop; + + if Current = Empty_Node then + Error_Msg + ("not a package declared by the project", + Token_Ptr); + end if; + end; + end if; + + Scan; + end if; + end if; + end if; + + Expect (Tok_Semicolon, ";"); + + elsif Token = Tok_Is then + + Parse_Declarative_Items + (Declarations => First_Declarative_Item, + In_Zone => In_Package, + First_Attribute => First_Attribute, + Current_Project => Current_Project, + Current_Package => Package_Declaration); + + Set_First_Declarative_Item_Of + (Package_Declaration, To => First_Declarative_Item); + + Expect (Tok_End, "end"); + + if Token = Tok_End then + + -- Scan past "end" + + Scan; + 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) /= No_Name + and then Token_Name /= Name_Of (Package_Declaration) + then + Error_Msg_Name_1 := Name_Of (Package_Declaration); + Error_Msg ("expected {", Token_Ptr); + end if; + + if Token /= Tok_Semicolon then + + -- Scan past the package name + + Scan; + end if; + + Expect (Tok_Semicolon, ";"); + + else + Error_Msg ("expected ""is"" or ""renames""", Token_Ptr); + end if; + + end Parse_Package_Declaration; + + ----------------------------------- + -- Parse_String_Type_Declaration -- + ----------------------------------- + + procedure Parse_String_Type_Declaration + (String_Type : out Project_Node_Id; + Current_Project : Project_Node_Id; + First_Attribute : Attribute_Node_Id) + 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); + + Set_Location_Of (String_Type, To => Token_Ptr); + + -- Scan past "type" + + Scan; + + Expect (Tok_Identifier, "identifier"); + + if Token = Tok_Identifier then + Set_Name_Of (String_Type, To => Token_Name); + + Current := First_String_Type_Of (Current_Project); + while Current /= Empty_Node + and then + Name_Of (Current) /= Token_Name + loop + Current := Next_String_Type (Current); + end loop; + + if Current /= Empty_Node then + Error_Msg ("duplicate string type name", Token_Ptr); + else + Current := First_Variable_Of (Current_Project); + while Current /= Empty_Node + and then Name_Of (Current) /= Token_Name + loop + Current := Next_Variable (Current); + end loop; + + if Current /= Empty_Node then + Error_Msg ("already a variable name", Token_Ptr); + else + Set_Next_String_Type + (String_Type, To => First_String_Type_Of (Current_Project)); + Set_First_String_Type_Of (Current_Project, To => String_Type); + end if; + end if; + + -- Scan past the name + + Scan; + end if; + + Expect (Tok_Is, "is"); + + if Token = Tok_Is then + Scan; + end if; + + Expect (Tok_Left_Paren, "("); + + if Token = Tok_Left_Paren then + Scan; + end if; + + Prj.Strt.Parse_String_Type_List (First_String => First_String); + Set_First_Literal_String (String_Type, To => First_String); + + Expect (Tok_Right_Paren, ")"); + + if Token = Tok_Right_Paren then + Scan; + end if; + + end Parse_String_Type_Declaration; + + -------------------------------- + -- Parse_Variable_Declaration -- + -------------------------------- + + procedure Parse_Variable_Declaration + (Variable : out Project_Node_Id; + First_Attribute : Attribute_Node_Id; + Current_Project : Project_Node_Id; + Current_Package : Project_Node_Id) + 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; + + begin + Variable := + Default_Project_Node (Of_Kind => N_Variable_Declaration); + Set_Name_Of (Variable, To => Variable_Name); + Set_Location_Of (Variable, To => Token_Ptr); + + -- Scan past the variable name + + Scan; + + if Token = Tok_Colon then + + -- Typed string variable declaration + + Scan; + Set_Kind_Of (Variable, N_Typed_Variable_Declaration); + Expect (Tok_Identifier, "identifier"); + + if Token = Tok_Identifier then + String_Type_Name := Token_Name; + Type_Location := Token_Ptr; + Scan; + + if Token = Tok_Dot then + Project_String_Type_Name := String_Type_Name; + Project_Location := Type_Location; + + -- Scan past the dot + + Scan; + Expect (Tok_Identifier, "identifier"); + + if Token = Tok_Identifier then + String_Type_Name := Token_Name; + Type_Location := Token_Ptr; + Scan; + else + String_Type_Name := No_Name; + end if; + end if; + + if String_Type_Name /= No_Name then + declare + Current : Project_Node_Id := + First_String_Type_Of (Current_Project); + + 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 + (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 ("unknown project", Project_Location); + Current := Empty_Node; + else + Current := + First_String_Type_Of + (The_Project_Name_And_Node.Node); + end if; + end; + end if; + + while Current /= Empty_Node + and then Name_Of (Current) /= String_Type_Name + loop + Current := Next_String_Type (Current); + end loop; + + if Current = Empty_Node then + Error_Msg ("unknown string type", Type_Location); + else + Set_String_Type_Of + (Variable, To => Current); + end if; + end; + end if; + end if; + end if; + + Expect (Tok_Colon_Equal, ":="); + + if Token = Tok_Colon_Equal then + Scan; + end if; + + -- Get the single string or string list value + + Expression_Location := Token_Ptr; + + Prj.Strt.Parse_Expression + (Expression => Expression, + Current_Project => Current_Project, + Current_Package => Current_Package); + Set_Expression_Of (Variable, To => Expression); + + if Expression /= Empty_Node then + Set_Expression_Kind_Of + (Variable, To => Expression_Kind_Of (Expression)); + end if; + + declare + The_Variable : Project_Node_Id := Empty_Node; + + begin + if Current_Package /= Empty_Node then + The_Variable := First_Variable_Of (Current_Package); + elsif Current_Project /= Empty_Node then + The_Variable := First_Variable_Of (Current_Project); + end if; + + while The_Variable /= Empty_Node + and then Name_Of (The_Variable) /= Variable_Name + loop + The_Variable := Next_Variable (The_Variable); + end loop; + + if The_Variable = Empty_Node then + if Current_Package /= Empty_Node then + Set_Next_Variable + (Variable, To => First_Variable_Of (Current_Package)); + Set_First_Variable_Of (Current_Package, To => Variable); + + elsif Current_Project /= Empty_Node then + Set_Next_Variable + (Variable, To => First_Variable_Of (Current_Project)); + Set_First_Variable_Of (Current_Project, To => Variable); + end if; + + else + if Expression_Kind_Of (Variable) /= Undefined then + if Expression_Kind_Of (The_Variable) = Undefined then + Set_Expression_Kind_Of + (The_Variable, To => Expression_Kind_Of (Variable)); + + else + if Expression_Kind_Of (The_Variable) /= + Expression_Kind_Of (Variable) + then + Error_Msg ("wrong expression kind for the variable", + Expression_Location); + end if; + end if; + end if; + end if; + end; + + end Parse_Variable_Declaration; + +end Prj.Dect; diff --git a/gcc/ada/prj-dect.ads b/gcc/ada/prj-dect.ads new file mode 100644 index 00000000000..3072c573b62 --- /dev/null +++ b/gcc/ada/prj-dect.ads @@ -0,0 +1,41 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J . D E C T -- +-- -- +-- S p e c -- +-- -- +-- $Revision: 1.2 $ +-- -- +-- Copyright (C) 2000 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ +-- +-- Parse a list of declarative items in a project file. + +with Prj.Tree; + +private package Prj.Dect is + + procedure Parse + (Declarations : out Prj.Tree.Project_Node_Id; + Current_Project : Prj.Tree.Project_Node_Id; + Modifying : Prj.Tree.Project_Node_Id); + -- Parse project declarative items. + +end Prj.Dect; diff --git a/gcc/ada/prj-env.adb b/gcc/ada/prj-env.adb new file mode 100644 index 00000000000..171a2d03c1a --- /dev/null +++ b/gcc/ada/prj-env.adb @@ -0,0 +1,1471 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J . E N V -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.17 $ +-- -- +-- Copyright (C) 2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +with GNAT.OS_Lib; use GNAT.OS_Lib; +with Namet; use Namet; +with Opt; +with Osint; use Osint; +with Output; use Output; +with Prj.Com; use Prj.Com; +with Prj.Util; +with Snames; use Snames; +with Stringt; use Stringt; +with Table; + +package body Prj.Env is + + type Naming_Id is new Nat; + No_Naming : constant Naming_Id := 0; + + Ada_Path_Buffer : String_Access := new String (1 .. 1_000); + -- A buffer where values for ADA_INCLUDE_PATH + -- and ADA_OBJECTS_PATH are stored. + + Ada_Path_Length : Natural := 0; + -- Index of the last valid character in Ada_Path_Buffer. + + package Namings is new Table.Table ( + Table_Component_Type => Naming_Data, + Table_Index_Type => Naming_Id, + Table_Low_Bound => 1, + Table_Initial => 5, + Table_Increment => 100, + Table_Name => "Prj.Env.Namings"); + + Default_Naming : constant Naming_Id := Namings.First; + + Global_Configuration_Pragmas : Name_Id; + Local_Configuration_Pragmas : Name_Id; + + ----------------------- + -- Local Subprograms -- + ----------------------- + + function Body_Path_Name_Of (Unit : Unit_Id) return String; + -- Returns the path name of the body of a unit. + -- Compute it first, if necessary. + + function Spec_Path_Name_Of (Unit : Unit_Id) return String; + -- Returns the path name of the spec of a unit. + -- Compute it first, if necessary. + + procedure Add_To_Path (Path : String); + -- Add Path to global variable Ada_Path_Buffer + -- Increment Ada_Path_Length + + ---------------------- + -- Ada_Include_Path -- + ---------------------- + + function Ada_Include_Path (Project : Project_Id) return String_Access is + + procedure Add (Project : Project_Id); + -- Add all the source directories of a project to the path, + -- only if this project has not been visited. + -- Call itself recursively for projects being modified, + -- and imported projects. + -- Add the project to the list Seen if this is the first time + -- we call Add for this project. + + --------- + -- Add -- + --------- + + procedure Add (Project : Project_Id) is + begin + -- If Seen is empty, then the project cannot have been + -- visited. + + if not Projects.Table (Project).Seen then + Projects.Table (Project).Seen := True; + + declare + Data : Project_Data := Projects.Table (Project); + List : Project_List := Data.Imported_Projects; + + Current : String_List_Id := Data.Source_Dirs; + Source_Dir : String_Element; + + begin + -- Add to path all source directories of this project + + while Current /= Nil_String loop + if Ada_Path_Length > 0 then + Add_To_Path (Path => (1 => Path_Separator)); + end if; + + Source_Dir := String_Elements.Table (Current); + String_To_Name_Buffer (Source_Dir.Value); + + declare + New_Path : constant String := + Name_Buffer (1 .. Name_Len); + begin + Add_To_Path (New_Path); + end; + + Current := Source_Dir.Next; + end loop; + + -- Call Add to the project being modified, if any + + if Data.Modifies /= No_Project then + Add (Data.Modifies); + end if; + + -- Call Add for each imported project, if any + + while List /= Empty_Project_List loop + Add (Project_Lists.Table (List).Project); + List := Project_Lists.Table (List).Next; + end loop; + end; + end if; + + end Add; + + -- Start of processing for Ada_Include_Path + + begin + -- If it is the first time we call this function for + -- this project, compute the source path + + if Projects.Table (Project).Include_Path = null then + Ada_Path_Length := 0; + + for Index in 1 .. Projects.Last loop + Projects.Table (Index).Seen := False; + end loop; + + Add (Project); + Projects.Table (Project).Include_Path := + new String'(Ada_Path_Buffer (1 .. Ada_Path_Length)); + end if; + + return Projects.Table (Project).Include_Path; + end Ada_Include_Path; + + ---------------------- + -- Ada_Objects_Path -- + ---------------------- + + function Ada_Objects_Path + (Project : Project_Id; + Including_Libraries : Boolean := True) + return String_Access is + + procedure Add (Project : Project_Id); + -- Add all the object directory of a project to the path, + -- only if this project has not been visited. + -- Call itself recursively for projects being modified, + -- and imported projects. + -- Add the project to the list Seen if this is the first time + -- we call Add for this project. + + --------- + -- Add -- + --------- + + procedure Add (Project : Project_Id) is + begin + + -- If this project has not been seen yet + + if not Projects.Table (Project).Seen then + Projects.Table (Project).Seen := True; + + declare + Data : Project_Data := Projects.Table (Project); + List : Project_List := Data.Imported_Projects; + + begin + -- Add to path the object directory of this project + -- except if we don't include library project and + -- this is a library project. + + if (Data.Library and then Including_Libraries) + or else + (Data.Object_Directory /= No_Name + and then + (not Including_Libraries or else not Data.Library)) + then + if Ada_Path_Length > 0 then + Add_To_Path (Path => (1 => Path_Separator)); + end if; + + -- For a library project, att the library directory + + if Data.Library then + declare + New_Path : constant String := + Get_Name_String (Data.Library_Dir); + begin + Add_To_Path (New_Path); + end; + else + + -- For a non library project, add the object directory + declare + New_Path : constant String := + Get_Name_String (Data.Object_Directory); + begin + Add_To_Path (New_Path); + end; + end if; + end if; + + -- Call Add to the project being modified, if any + + if Data.Modifies /= No_Project then + Add (Data.Modifies); + end if; + + -- Call Add for each imported project, if any + + while List /= Empty_Project_List loop + Add (Project_Lists.Table (List).Project); + List := Project_Lists.Table (List).Next; + end loop; + end; + + end if; + end Add; + + -- Start of processing for Ada_Objects_Path + + begin + -- If it is the first time we call this function for + -- this project, compute the objects path + + if Projects.Table (Project).Objects_Path = null then + Ada_Path_Length := 0; + + for Index in 1 .. Projects.Last loop + Projects.Table (Index).Seen := False; + end loop; + + Add (Project); + Projects.Table (Project).Objects_Path := + new String'(Ada_Path_Buffer (1 .. Ada_Path_Length)); + end if; + + return Projects.Table (Project).Objects_Path; + end Ada_Objects_Path; + + ----------------- + -- Add_To_Path -- + ----------------- + + procedure Add_To_Path (Path : String) is + begin + -- If Ada_Path_Buffer is too small, double it + + if Ada_Path_Length + Path'Length > Ada_Path_Buffer'Last then + declare + New_Ada_Path_Buffer : constant String_Access := + new String + (1 .. Ada_Path_Buffer'Last + + Ada_Path_Buffer'Last); + + begin + New_Ada_Path_Buffer (1 .. Ada_Path_Length) := + Ada_Path_Buffer (1 .. Ada_Path_Length); + Ada_Path_Buffer := New_Ada_Path_Buffer; + end; + end if; + + Ada_Path_Buffer + (Ada_Path_Length + 1 .. Ada_Path_Length + Path'Length) := Path; + Ada_Path_Length := Ada_Path_Length + Path'Length; + end Add_To_Path; + + ----------------------- + -- Body_Path_Name_Of -- + ----------------------- + + function Body_Path_Name_Of (Unit : Unit_Id) return String is + Data : Unit_Data := Units.Table (Unit); + + begin + -- If we don't know the path name of the body of this unit, + -- we compute it, and we store it. + + if Data.File_Names (Body_Part).Path = No_Name then + declare + Current_Source : String_List_Id := + Projects.Table (Data.File_Names (Body_Part).Project).Sources; + Path : GNAT.OS_Lib.String_Access; + + begin + -- By default, put the file name + + Data.File_Names (Body_Part).Path := + Data.File_Names (Body_Part).Name; + + -- For each source directory + + while Current_Source /= Nil_String loop + String_To_Name_Buffer + (String_Elements.Table (Current_Source).Value); + Path := + Locate_Regular_File + (Namet.Get_Name_String + (Data.File_Names (Body_Part).Name), + Name_Buffer (1 .. Name_Len)); + + -- If the file is in this directory, + -- then we store the path, and we are done. + + if Path /= null then + Name_Len := Path'Length; + Name_Buffer (1 .. Name_Len) := Path.all; + Data.File_Names (Body_Part).Path := Name_Enter; + exit; + + else + Current_Source := + String_Elements.Table (Current_Source).Next; + end if; + end loop; + + Units.Table (Unit) := Data; + end; + end if; + + -- Returned the value stored + + return Namet.Get_Name_String (Data.File_Names (Body_Part).Path); + end Body_Path_Name_Of; + + -------------------------------- + -- Create_Config_Pragmas_File -- + -------------------------------- + + procedure Create_Config_Pragmas_File + (For_Project : Project_Id; + Main_Project : Project_Id) + is + File_Name : Temp_File_Name; + File : File_Descriptor := Invalid_FD; + + The_Packages : Package_Id; + Gnatmake : Prj.Package_Id; + Compiler : Prj.Package_Id; + + Current_Unit : Unit_Id := Units.First; + + First_Project : Project_List := Empty_Project_List; + + Current_Project : Project_List; + Current_Naming : Naming_Id; + + Global_Attribute : Variable_Value := Nil_Variable_Value; + Local_Attribute : Variable_Value := Nil_Variable_Value; + + Global_Attribute_Present : Boolean := False; + Local_Attribute_Present : Boolean := False; + + procedure Check (Project : Project_Id); + + procedure Check_Temp_File; + -- Check that a temporary file has been opened. + -- If not, create one, and put its name in the project data, + -- with the indication that it is a temporary file. + + procedure Copy_File (Name : String_Id); + -- Copy a configuration pragmas file into the temp file. + + procedure Put + (Unit_Name : Name_Id; + File_Name : Name_Id; + Unit_Kind : Spec_Or_Body); + -- Put an SFN pragma in the temporary file. + + procedure Put (File : File_Descriptor; S : String); + + procedure Put_Line (File : File_Descriptor; S : String); + + ----------- + -- Check -- + ----------- + + procedure Check (Project : Project_Id) is + Data : constant Project_Data := Projects.Table (Project); + + begin + if Current_Verbosity = High then + Write_Str ("Checking project file """); + Write_Str (Namet.Get_Name_String (Data.Name)); + Write_Str ("""."); + Write_Eol; + end if; + + -- Is this project in the list of the visited project? + + Current_Project := First_Project; + while Current_Project /= Empty_Project_List + and then Project_Lists.Table (Current_Project).Project /= Project + loop + Current_Project := Project_Lists.Table (Current_Project).Next; + end loop; + + -- If it is not, put it in the list, and visit it + + if Current_Project = Empty_Project_List then + Project_Lists.Increment_Last; + Project_Lists.Table (Project_Lists.Last) := + (Project => Project, Next => First_Project); + First_Project := Project_Lists.Last; + + -- Is the naming scheme of this project one that we know? + + Current_Naming := Default_Naming; + while Current_Naming <= Namings.Last and then + not Same_Naming_Scheme + (Left => Namings.Table (Current_Naming), + Right => Data.Naming) loop + Current_Naming := Current_Naming + 1; + end loop; + + -- If we don't know it, add it + + if Current_Naming > Namings.Last then + Namings.Increment_Last; + Namings.Table (Namings.Last) := Data.Naming; + + -- We need a temporary file to be created + + Check_Temp_File; + + -- Put the SFN pragmas for the naming scheme + + -- Spec + + Put_Line + (File, "pragma Source_File_Name"); + Put_Line + (File, " (Spec_File_Name => ""*" & + Namet.Get_Name_String (Data.Naming.Specification_Append) & + ""","); + Put_Line + (File, " Casing => " & + Image (Data.Naming.Casing) & ","); + Put_Line + (File, " Dot_Replacement => """ & + Namet.Get_Name_String (Data.Naming.Dot_Replacement) & + """);"); + + -- and body + + Put_Line + (File, "pragma Source_File_Name"); + Put_Line + (File, " (Body_File_Name => ""*" & + Namet.Get_Name_String (Data.Naming.Body_Append) & + ""","); + Put_Line + (File, " Casing => " & + Image (Data.Naming.Casing) & ","); + Put_Line + (File, " Dot_Replacement => """ & + Namet.Get_Name_String (Data.Naming.Dot_Replacement) & + """);"); + + -- and maybe separate + + if Data.Naming.Body_Append /= Data.Naming.Separate_Append then + Put_Line + (File, "pragma Source_File_Name"); + Put_Line + (File, " (Subunit_File_Name => ""*" & + Namet.Get_Name_String (Data.Naming.Separate_Append) & + ""","); + Put_Line + (File, " Casing => " & + Image (Data.Naming.Casing) & + ","); + Put_Line + (File, " Dot_Replacement => """ & + Namet.Get_Name_String (Data.Naming.Dot_Replacement) & + """);"); + end if; + end if; + + if Data.Modifies /= No_Project then + Check (Data.Modifies); + end if; + + declare + Current : Project_List := Data.Imported_Projects; + + begin + while Current /= Empty_Project_List loop + Check (Project_Lists.Table (Current).Project); + Current := Project_Lists.Table (Current).Next; + end loop; + end; + end if; + end Check; + + --------------------- + -- Check_Temp_File -- + --------------------- + + procedure Check_Temp_File is + begin + if File = Invalid_FD then + GNAT.OS_Lib.Create_Temp_File (File, Name => File_Name); + if File = Invalid_FD then + Osint.Fail + ("unable to create temporary configuration pragmas file"); + elsif Opt.Verbose_Mode then + Write_Str ("Creating temp file """); + Write_Str (File_Name); + Write_Line (""""); + end if; + end if; + end Check_Temp_File; + + --------------- + -- Copy_File -- + --------------- + + procedure Copy_File (Name : in String_Id) is + Input : File_Descriptor; + Buffer : String (1 .. 1_000); + Input_Length : Integer; + Output_Length : Integer; + + begin + Check_Temp_File; + String_To_Name_Buffer (Name); + + if Opt.Verbose_Mode then + Write_Str ("Copying config pragmas file """); + Write_Str (Name_Buffer (1 .. Name_Len)); + Write_Line (""" into temp file"); + end if; + + declare + Name : constant String := + Name_Buffer (1 .. Name_Len) & ASCII.NUL; + begin + Input := Open_Read (Name'Address, Binary); + end; + + if Input = Invalid_FD then + Osint.Fail + ("cannot open configuration pragmas file " & + Name_Buffer (1 .. Name_Len)); + end if; + + loop + Input_Length := Read (Input, Buffer'Address, Buffer'Length); + Output_Length := Write (File, Buffer'Address, Input_Length); + + if Output_Length /= Input_Length then + Osint.Fail ("disk full"); + end if; + + exit when Input_Length < Buffer'Length; + end loop; + + Close (Input); + + end Copy_File; + + --------- + -- Put -- + --------- + + procedure Put + (Unit_Name : Name_Id; + File_Name : Name_Id; + Unit_Kind : Spec_Or_Body) + is + begin + -- A temporary file needs to be open + + Check_Temp_File; + + -- Put the pragma SFN for the unit kind (spec or body) + + Put (File, "pragma Source_File_Name ("); + Put (File, Namet.Get_Name_String (Unit_Name)); + + if Unit_Kind = Specification then + Put (File, ", Spec_File_Name => """); + else + Put (File, ", Body_File_Name => """); + end if; + + Put (File, Namet.Get_Name_String (File_Name)); + Put_Line (File, """);"); + end Put; + + procedure Put (File : File_Descriptor; S : String) is + Last : Natural; + + begin + Last := Write (File, S (S'First)'Address, S'Length); + + if Last /= S'Length then + Osint.Fail ("Disk full"); + end if; + + if Current_Verbosity = High then + Write_Str (S); + end if; + end Put; + + -------------- + -- Put_Line -- + -------------- + + procedure Put_Line (File : File_Descriptor; S : String) is + S0 : String (1 .. S'Length + 1); + Last : Natural; + + begin + -- Add an ASCII.LF to the string. As this gnat.adc + -- is supposed to be used only by the compiler, we don't + -- care about the characters for the end of line. + -- The truth is we could have put a space, but it is + -- more convenient to be able to read gnat.adc during + -- development. And the development was done under UNIX. + -- Hence the ASCII.LF. + + S0 (1 .. S'Length) := S; + S0 (S0'Last) := ASCII.LF; + Last := Write (File, S0'Address, S0'Length); + + if Last /= S'Length + 1 then + Osint.Fail ("Disk full"); + end if; + + if Current_Verbosity = High then + Write_Line (S); + end if; + end Put_Line; + + -- Start of processing for Create_Config_Pragmas_File + + begin + + if not Projects.Table (For_Project).Config_Checked then + + -- Remove any memory of processed naming schemes, if any + + Namings.Set_Last (Default_Naming); + + -- Check the naming schemes + + Check (For_Project); + + -- Visit all the units and process those that need an SFN pragma + + while Current_Unit <= Units.Last loop + declare + Unit : constant Unit_Data := + Units.Table (Current_Unit); + + begin + if Unit.File_Names (Specification).Needs_Pragma then + Put (Unit.Name, + Unit.File_Names (Specification).Name, + Specification); + end if; + + if Unit.File_Names (Body_Part).Needs_Pragma then + Put (Unit.Name, + Unit.File_Names (Body_Part).Name, + Body_Part); + end if; + + Current_Unit := Current_Unit + 1; + end; + end loop; + + The_Packages := Projects.Table (Main_Project).Decl.Packages; + Gnatmake := + Prj.Util.Value_Of + (Name => Name_Gnatmake, + In_Packages => The_Packages); + + if Gnatmake /= No_Package then + Global_Attribute := Prj.Util.Value_Of + (Variable_Name => Global_Configuration_Pragmas, + In_Variables => Packages.Table (Gnatmake).Decl.Attributes); + Global_Attribute_Present := + Global_Attribute /= Nil_Variable_Value + and then String_Length (Global_Attribute.Value) > 0; + end if; + + The_Packages := Projects.Table (For_Project).Decl.Packages; + Compiler := + Prj.Util.Value_Of + (Name => Name_Compiler, + In_Packages => The_Packages); + + if Compiler /= No_Package then + Local_Attribute := Prj.Util.Value_Of + (Variable_Name => Local_Configuration_Pragmas, + In_Variables => Packages.Table (Compiler).Decl.Attributes); + Local_Attribute_Present := + Local_Attribute /= Nil_Variable_Value + and then String_Length (Local_Attribute.Value) > 0; + end if; + + if Global_Attribute_Present then + + if File /= Invalid_FD + or else Local_Attribute_Present + then + Copy_File (Global_Attribute.Value); + else + String_To_Name_Buffer (Global_Attribute.Value); + Projects.Table (For_Project).Config_File_Name := Name_Find; + end if; + end if; + + if Local_Attribute_Present then + + if File /= Invalid_FD then + Copy_File (Local_Attribute.Value); + + else + String_To_Name_Buffer (Local_Attribute.Value); + Projects.Table (For_Project).Config_File_Name := Name_Find; + end if; + + end if; + + if File /= Invalid_FD then + GNAT.OS_Lib.Close (File); + + if Opt.Verbose_Mode then + Write_Str ("Closing configuration file """); + Write_Str (File_Name); + Write_Line (""""); + end if; + + Name_Len := File_Name'Length; + Name_Buffer (1 .. Name_Len) := File_Name; + Projects.Table (For_Project).Config_File_Name := Name_Find; + Projects.Table (For_Project).Config_File_Temp := True; + end if; + + Projects.Table (For_Project).Config_Checked := True; + + end if; + + end Create_Config_Pragmas_File; + + ------------------------------------ + -- File_Name_Of_Library_Unit_Body -- + ------------------------------------ + + function File_Name_Of_Library_Unit_Body + (Name : String; + Project : Project_Id) + return String + is + Data : constant Project_Data := Projects.Table (Project); + Original_Name : String := Name; + + Extended_Spec_Name : String := + Name & Namet.Get_Name_String + (Data.Naming.Specification_Append); + Extended_Body_Name : String := + Name & Namet.Get_Name_String + (Data.Naming.Body_Append); + + Unit : Unit_Data; + + The_Original_Name : Name_Id; + The_Spec_Name : Name_Id; + The_Body_Name : Name_Id; + + begin + Canonical_Case_File_Name (Original_Name); + Name_Len := Original_Name'Length; + Name_Buffer (1 .. Name_Len) := Original_Name; + The_Original_Name := Name_Find; + + Canonical_Case_File_Name (Extended_Spec_Name); + Name_Len := Extended_Spec_Name'Length; + Name_Buffer (1 .. Name_Len) := Extended_Spec_Name; + The_Spec_Name := Name_Find; + + Canonical_Case_File_Name (Extended_Body_Name); + Name_Len := Extended_Body_Name'Length; + Name_Buffer (1 .. Name_Len) := Extended_Body_Name; + The_Body_Name := Name_Find; + + if Current_Verbosity = High then + Write_Str ("Looking for file name of """); + Write_Str (Name); + Write_Char ('"'); + Write_Eol; + Write_Str (" Extended Spec Name = """); + Write_Str (Extended_Spec_Name); + Write_Char ('"'); + Write_Eol; + Write_Str (" Extended Body Name = """); + Write_Str (Extended_Body_Name); + Write_Char ('"'); + Write_Eol; + end if; + + -- For every unit + + for Current in reverse Units.First .. Units.Last loop + Unit := Units.Table (Current); + + -- If it is a unit of the same project + + if Unit.File_Names (Body_Part).Project = Project then + declare + Current_Name : constant Name_Id := + Unit.File_Names (Body_Part).Name; + + begin + -- If there is a body + + if Current_Name /= No_Name then + if Current_Verbosity = High then + Write_Str (" Comparing with """); + Write_Str (Get_Name_String (Current_Name)); + Write_Char ('"'); + Write_Eol; + end if; + + -- If it has the name of the original name, + -- return the original name + + if Unit.Name = The_Original_Name + or else Current_Name = The_Original_Name + then + if Current_Verbosity = High then + Write_Line (" OK"); + end if; + + return Get_Name_String (Current_Name); + + -- If it has the name of the extended body name, + -- return the extended body name + + elsif Current_Name = The_Body_Name then + if Current_Verbosity = High then + Write_Line (" OK"); + end if; + + return Extended_Body_Name; + + else + if Current_Verbosity = High then + Write_Line (" not good"); + end if; + end if; + end if; + end; + end if; + + -- If it is a unit of the same project + + if Units.Table (Current).File_Names (Specification).Project = + Project + then + declare + Current_Name : constant Name_Id := + Unit.File_Names (Specification).Name; + + begin + -- If there is a spec + + if Current_Name /= No_Name then + if Current_Verbosity = High then + Write_Str (" Comparing with """); + Write_Str (Get_Name_String (Current_Name)); + Write_Char ('"'); + Write_Eol; + end if; + + -- If it has the same name as the original name, + -- return the original name + + if Unit.Name = The_Original_Name + or else Current_Name = The_Original_Name + then + if Current_Verbosity = High then + Write_Line (" OK"); + end if; + + return Get_Name_String (Current_Name); + + -- If it has the same name as the extended spec name, + -- return the extended spec name + + elsif Current_Name = The_Spec_Name then + if Current_Verbosity = High then + Write_Line (" OK"); + end if; + + return Extended_Spec_Name; + + else + if Current_Verbosity = High then + Write_Line (" not good"); + end if; + end if; + end if; + end; + end if; + + end loop; + + -- We don't know this file name, return an empty string + + return ""; + end File_Name_Of_Library_Unit_Body; + + ------------------------- + -- For_All_Object_Dirs -- + ------------------------- + + procedure For_All_Object_Dirs (Project : Project_Id) is + Seen : Project_List := Empty_Project_List; + + procedure Add (Project : Project_Id); + -- Process a project. Remember the processes visited to avoid + -- processing a project twice. Recursively process an eventual + -- modified project, and all imported projects. + + --------- + -- Add -- + --------- + + procedure Add (Project : Project_Id) is + Data : constant Project_Data := Projects.Table (Project); + List : Project_List := Data.Imported_Projects; + + begin + -- If the list of visited project is empty, then + -- for sure we never visited this project. + + if Seen = Empty_Project_List then + Project_Lists.Increment_Last; + Seen := Project_Lists.Last; + Project_Lists.Table (Seen) := + (Project => Project, Next => Empty_Project_List); + + else + -- Check if the project is in the list + + declare + Current : Project_List := Seen; + + begin + loop + -- If it is, then there is nothing else to do + + if Project_Lists.Table (Current).Project = Project then + return; + end if; + + exit when Project_Lists.Table (Current).Next = + Empty_Project_List; + Current := Project_Lists.Table (Current).Next; + end loop; + + -- This project has never been visited, add it + -- to the list. + + Project_Lists.Increment_Last; + Project_Lists.Table (Current).Next := Project_Lists.Last; + Project_Lists.Table (Project_Lists.Last) := + (Project => Project, Next => Empty_Project_List); + end; + end if; + + -- If there is an object directory, call Action + -- with its name + + if Data.Object_Directory /= No_Name then + Get_Name_String (Data.Object_Directory); + Action (Name_Buffer (1 .. Name_Len)); + end if; + + -- If we are modifying a project, visit it + + if Data.Modifies /= No_Project then + Add (Data.Modifies); + end if; + + -- And visit all imported projects + + while List /= Empty_Project_List loop + Add (Project_Lists.Table (List).Project); + List := Project_Lists.Table (List).Next; + end loop; + end Add; + + -- Start of processing for For_All_Object_Dirs + + begin + -- Visit this project, and its imported projects, + -- recursively + + Add (Project); + end For_All_Object_Dirs; + + ------------------------- + -- For_All_Source_Dirs -- + ------------------------- + + procedure For_All_Source_Dirs (Project : Project_Id) is + Seen : Project_List := Empty_Project_List; + + procedure Add (Project : Project_Id); + -- Process a project. Remember the processes visited to avoid + -- processing a project twice. Recursively process an eventual + -- modified project, and all imported projects. + + --------- + -- Add -- + --------- + + procedure Add (Project : Project_Id) is + Data : constant Project_Data := Projects.Table (Project); + List : Project_List := Data.Imported_Projects; + + begin + -- If the list of visited project is empty, then + -- for sure we never visited this project. + + if Seen = Empty_Project_List then + Project_Lists.Increment_Last; + Seen := Project_Lists.Last; + Project_Lists.Table (Seen) := + (Project => Project, Next => Empty_Project_List); + + else + -- Check if the project is in the list + + declare + Current : Project_List := Seen; + + begin + loop + -- If it is, then there is nothing else to do + + if Project_Lists.Table (Current).Project = Project then + return; + end if; + + exit when Project_Lists.Table (Current).Next = + Empty_Project_List; + Current := Project_Lists.Table (Current).Next; + end loop; + + -- This project has never been visited, add it + -- to the list. + + Project_Lists.Increment_Last; + Project_Lists.Table (Current).Next := Project_Lists.Last; + Project_Lists.Table (Project_Lists.Last) := + (Project => Project, Next => Empty_Project_List); + end; + end if; + + declare + Current : String_List_Id := Data.Source_Dirs; + The_String : String_Element; + + begin + -- Call action with the name of every source directorie + + while Current /= Nil_String loop + The_String := String_Elements.Table (Current); + String_To_Name_Buffer (The_String.Value); + Action (Name_Buffer (1 .. Name_Len)); + Current := The_String.Next; + end loop; + end; + + -- If we are modifying a project, visit it + + if Data.Modifies /= No_Project then + Add (Data.Modifies); + end if; + + -- And visit all imported projects + + while List /= Empty_Project_List loop + Add (Project_Lists.Table (List).Project); + List := Project_Lists.Table (List).Next; + end loop; + end Add; + + -- Start of processing for For_All_Source_Dirs + + begin + -- Visit this project, and its imported projects recursively + + Add (Project); + end For_All_Source_Dirs; + + ------------------- + -- Get_Reference -- + ------------------- + + procedure Get_Reference + (Source_File_Name : String; + Project : out Project_Id; + Path : out Name_Id) + is + begin + if Current_Verbosity > Default then + Write_Str ("Getting Reference_Of ("""); + Write_Str (Source_File_Name); + Write_Str (""") ... "); + end if; + + declare + Original_Name : String := Source_File_Name; + Unit : Unit_Data; + + begin + Canonical_Case_File_Name (Original_Name); + + for Id in Units.First .. Units.Last loop + Unit := Units.Table (Id); + + if (Unit.File_Names (Specification).Name /= No_Name + and then + Namet.Get_Name_String + (Unit.File_Names (Specification).Name) = Original_Name) + or else (Unit.File_Names (Specification).Path /= No_Name + and then + Namet.Get_Name_String + (Unit.File_Names (Specification).Path) = + Original_Name) + then + Project := Unit.File_Names (Specification).Project; + Path := Unit.File_Names (Specification).Path; + + if Current_Verbosity > Default then + Write_Str ("Done: Specification."); + Write_Eol; + end if; + + return; + + elsif (Unit.File_Names (Body_Part).Name /= No_Name + and then + Namet.Get_Name_String + (Unit.File_Names (Body_Part).Name) = Original_Name) + or else (Unit.File_Names (Body_Part).Path /= No_Name + and then Namet.Get_Name_String + (Unit.File_Names (Body_Part).Path) = + Original_Name) + then + Project := Unit.File_Names (Body_Part).Project; + Path := Unit.File_Names (Body_Part).Path; + + if Current_Verbosity > Default then + Write_Str ("Done: Body."); + Write_Eol; + end if; + + return; + end if; + + end loop; + end; + + Project := No_Project; + Path := No_Name; + + if Current_Verbosity > Default then + Write_Str ("Cannot be found."); + Write_Eol; + end if; + end Get_Reference; + + ---------------- + -- Initialize -- + ---------------- + + procedure Initialize is + Global : constant String := "global_configuration_pragmas"; + Local : constant String := "local_configuration_pragmas"; + begin + -- Put the standard GNAT naming scheme in the Namings table + + Namings.Increment_Last; + Namings.Table (Namings.Last) := Standard_Naming_Data; + Name_Len := Global'Length; + Name_Buffer (1 .. Name_Len) := Global; + Global_Configuration_Pragmas := Name_Find; + Name_Len := Local'Length; + Name_Buffer (1 .. Name_Len) := Local; + Local_Configuration_Pragmas := Name_Find; + end Initialize; + + ------------------------------------ + -- Path_Name_Of_Library_Unit_Body -- + ------------------------------------ + + function Path_Name_Of_Library_Unit_Body + (Name : String; + Project : Project_Id) + return String + is + Data : constant Project_Data := Projects.Table (Project); + Original_Name : String := Name; + + Extended_Spec_Name : String := + Name & Namet.Get_Name_String + (Data.Naming.Specification_Append); + Extended_Body_Name : String := + Name & Namet.Get_Name_String + (Data.Naming.Body_Append); + + First : Unit_Id := Units.First; + Current : Unit_Id; + Unit : Unit_Data; + + begin + Canonical_Case_File_Name (Original_Name); + Canonical_Case_File_Name (Extended_Spec_Name); + Canonical_Case_File_Name (Extended_Spec_Name); + + if Current_Verbosity = High then + Write_Str ("Looking for path name of """); + Write_Str (Name); + Write_Char ('"'); + Write_Eol; + Write_Str (" Extended Spec Name = """); + Write_Str (Extended_Spec_Name); + Write_Char ('"'); + Write_Eol; + Write_Str (" Extended Body Name = """); + Write_Str (Extended_Body_Name); + Write_Char ('"'); + Write_Eol; + end if; + + while First <= Units.Last + and then Units.Table (First).File_Names (Body_Part).Project /= Project + loop + First := First + 1; + end loop; + + Current := First; + while Current <= Units.Last loop + Unit := Units.Table (Current); + + if Unit.File_Names (Body_Part).Project = Project + and then Unit.File_Names (Body_Part).Name /= No_Name + then + declare + Current_Name : constant String := + Namet.Get_Name_String (Unit.File_Names (Body_Part).Name); + begin + if Current_Verbosity = High then + Write_Str (" Comparing with """); + Write_Str (Current_Name); + Write_Char ('"'); + Write_Eol; + end if; + + if Current_Name = Original_Name then + if Current_Verbosity = High then + Write_Line (" OK"); + end if; + + return Body_Path_Name_Of (Current); + + elsif Current_Name = Extended_Body_Name then + if Current_Verbosity = High then + Write_Line (" OK"); + end if; + + return Body_Path_Name_Of (Current); + + else + if Current_Verbosity = High then + Write_Line (" not good"); + end if; + end if; + end; + + elsif Unit.File_Names (Specification).Name /= No_Name then + declare + Current_Name : constant String := + Namet.Get_Name_String + (Unit.File_Names (Specification).Name); + + begin + if Current_Verbosity = High then + Write_Str (" Comparing with """); + Write_Str (Current_Name); + Write_Char ('"'); + Write_Eol; + end if; + + if Current_Name = Original_Name then + if Current_Verbosity = High then + Write_Line (" OK"); + end if; + + return Spec_Path_Name_Of (Current); + + elsif Current_Name = Extended_Spec_Name then + + if Current_Verbosity = High then + Write_Line (" OK"); + end if; + + return Spec_Path_Name_Of (Current); + + else + if Current_Verbosity = High then + Write_Line (" not good"); + end if; + end if; + end; + end if; + Current := Current + 1; + end loop; + + return ""; + end Path_Name_Of_Library_Unit_Body; + + ------------------- + -- Print_Sources -- + ------------------- + + procedure Print_Sources is + Unit : Unit_Data; + + begin + Write_Line ("List of Sources:"); + + for Id in Units.First .. Units.Last loop + Unit := Units.Table (Id); + Write_Str (" "); + Write_Line (Namet.Get_Name_String (Unit.Name)); + + if Unit.File_Names (Specification).Name /= No_Name then + if Unit.File_Names (Specification).Project = No_Project then + Write_Line (" No project"); + + else + Write_Str (" Project: "); + Get_Name_String + (Projects.Table + (Unit.File_Names (Specification).Project).Path_Name); + Write_Line (Name_Buffer (1 .. Name_Len)); + end if; + + Write_Str (" spec: "); + Write_Line + (Namet.Get_Name_String + (Unit.File_Names (Specification).Name)); + end if; + + if Unit.File_Names (Body_Part).Name /= No_Name then + if Unit.File_Names (Body_Part).Project = No_Project then + Write_Line (" No project"); + + else + Write_Str (" Project: "); + Get_Name_String + (Projects.Table + (Unit.File_Names (Body_Part).Project).Path_Name); + Write_Line (Name_Buffer (1 .. Name_Len)); + end if; + + Write_Str (" body: "); + Write_Line + (Namet.Get_Name_String + (Unit.File_Names (Body_Part).Name)); + end if; + + end loop; + + Write_Line ("end of List of Sources."); + end Print_Sources; + + ----------------------- + -- Spec_Path_Name_Of -- + ----------------------- + + function Spec_Path_Name_Of (Unit : Unit_Id) return String is + Data : Unit_Data := Units.Table (Unit); + + begin + if Data.File_Names (Specification).Path = No_Name then + declare + Current_Source : String_List_Id := + Projects.Table (Data.File_Names (Specification).Project).Sources; + Path : GNAT.OS_Lib.String_Access; + + begin + Data.File_Names (Specification).Path := + Data.File_Names (Specification).Name; + + while Current_Source /= Nil_String loop + String_To_Name_Buffer + (String_Elements.Table (Current_Source).Value); + Path := Locate_Regular_File + (Namet.Get_Name_String + (Data.File_Names (Specification).Name), + Name_Buffer (1 .. Name_Len)); + + if Path /= null then + Name_Len := Path'Length; + Name_Buffer (1 .. Name_Len) := Path.all; + Data.File_Names (Specification).Path := Name_Enter; + exit; + else + Current_Source := + String_Elements.Table (Current_Source).Next; + end if; + end loop; + + Units.Table (Unit) := Data; + end; + end if; + + return Namet.Get_Name_String (Data.File_Names (Specification).Path); + end Spec_Path_Name_Of; + +end Prj.Env; diff --git a/gcc/ada/prj-env.ads b/gcc/ada/prj-env.ads new file mode 100644 index 00000000000..272c559282a --- /dev/null +++ b/gcc/ada/prj-env.ads @@ -0,0 +1,99 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J . E N V -- +-- -- +-- S p e c -- +-- -- +-- $Revision: 1.10 $ +-- -- +-- Copyright (C) 2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +-- This package implements services for Project-aware tools, related +-- to the environment (gnat.adc, ADA_INCLUDE_PATH, ADA_OBJECTS_PATH) + +with GNAT.OS_Lib; use GNAT.OS_Lib; + +package Prj.Env is + + procedure Initialize; + -- Put Standard_Naming_Data into Namings table (called by Prj.Initialize) + + procedure Print_Sources; + -- Output the list of sources, after Project files have been scanned + + procedure Create_Config_Pragmas_File + (For_Project : Project_Id; + Main_Project : Project_Id); + -- If there needs to have SFN pragmas, either for non standard naming + -- schemes or for individual units, or if Global_Configuration_Pragmas + -- has been specified in package gnatmake of the main project, or if + -- Local_Configuration_Pragmas has been specified in package Compiler + -- of the main project, build (if needed) a temporary file that contains + -- all configuration pragmas, and specify the configuration pragmas file + -- in the project data. + + function Ada_Include_Path (Project : Project_Id) return String_Access; + -- Get the ADA_INCLUDE_PATH of a Project file. For the first call, compute + -- it and cache it. + + function Ada_Objects_Path + (Project : Project_Id; + Including_Libraries : Boolean := True) + return String_Access; + -- Get the ADA_OBJECTS_PATH of a Project file. For the first call, compute + -- it and cache it. When Including_Libraries is False, do not include the + -- object directories of the library projects, and do not cache the result. + + function Path_Name_Of_Library_Unit_Body + (Name : String; + Project : Project_Id) + return String; + -- Returns the Path of a library unit. + + function File_Name_Of_Library_Unit_Body + (Name : String; + Project : Project_Id) + return String; + -- Returns the file name of a library unit, in canonical case. Name may or + -- may not have an extension (corresponding to the naming scheme of the + -- project). If there is no body with this name, but there is a spec, the + -- name of the spec is returned. If neither a body or a spec can be found, + -- return an empty string. + + procedure Get_Reference + (Source_File_Name : String; + Project : out Project_Id; + Path : out Name_Id); + -- Returns the project of a source. + + generic + with procedure Action (Path : String); + procedure For_All_Source_Dirs (Project : Project_Id); + -- Iterate through all the source directories of a project, + -- including those of imported or modified projects. + + generic + with procedure Action (Path : String); + procedure For_All_Object_Dirs (Project : Project_Id); + -- Iterate through all the object directories of a project, + -- including those of imported or modified projects. + +end Prj.Env; diff --git a/gcc/ada/prj-ext.adb b/gcc/ada/prj-ext.adb new file mode 100644 index 00000000000..b6f6ab8bb14 --- /dev/null +++ b/gcc/ada/prj-ext.adb @@ -0,0 +1,130 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J . E X T -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.5 $ +-- -- +-- Copyright (C) 2000 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +with GNAT.HTable; +with GNAT.OS_Lib; use GNAT.OS_Lib; +with Namet; use Namet; +with Prj.Com; use Prj.Com; +with Stringt; use Stringt; +with Types; use Types; + +package body Prj.Ext is + + package Htable is new GNAT.HTable.Simple_HTable + (Header_Num => Header_Num, + Element => String_Id, + No_Element => No_String, + Key => Name_Id, + Hash => Hash, + Equal => "="); + + --------- + -- Add -- + --------- + + procedure Add + (External_Name : String; + Value : String) + is + The_Key : Name_Id; + The_Value : String_Id; + + begin + Start_String; + Store_String_Chars (Value); + The_Value := End_String; + Name_Len := External_Name'Length; + Name_Buffer (1 .. Name_Len) := External_Name; + The_Key := Name_Find; + Htable.Set (The_Key, The_Value); + end Add; + + ----------- + -- Check -- + ----------- + + function Check (Declaration : String) return Boolean is + begin + for Equal_Pos in Declaration'Range loop + + if Declaration (Equal_Pos) = '=' then + exit when Equal_Pos = Declaration'First; + exit when Equal_Pos = Declaration'Last; + Add + (External_Name => + Declaration (Declaration'First .. Equal_Pos - 1), + Value => + Declaration (Equal_Pos + 1 .. Declaration'Last)); + return True; + end if; + + end loop; + + return False; + end Check; + + -------------- + -- Value_Of -- + -------------- + + function Value_Of + (External_Name : Name_Id; + With_Default : String_Id := No_String) + return String_Id + is + The_Value : String_Id; + + begin + The_Value := Htable.Get (External_Name); + + if The_Value /= No_String then + return The_Value; + end if; + + -- Find if it is an environment. + -- If it is, put the value in the hash table. + + declare + Env_Value : constant String_Access := + Getenv (Get_Name_String (External_Name)); + + begin + if Env_Value /= null and then Env_Value'Length > 0 then + Start_String; + Store_String_Chars (Env_Value.all); + The_Value := End_String; + Htable.Set (External_Name, The_Value); + return The_Value; + + else + return With_Default; + end if; + end; + end Value_Of; + +end Prj.Ext; diff --git a/gcc/ada/prj-ext.ads b/gcc/ada/prj-ext.ads new file mode 100644 index 00000000000..4c12b786bcf --- /dev/null +++ b/gcc/ada/prj-ext.ads @@ -0,0 +1,51 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J . E X T -- +-- -- +-- S p e c -- +-- -- +-- $Revision: 1.3 $ +-- -- +-- Copyright (C) 2000 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +-- Set, Get and cache External reference, to be used as External functions +-- in project files. + +with Types; use Types; + +package Prj.Ext is + + procedure Add + (External_Name : String; + Value : String); + -- Add an external reference (or modify an existing one). + + function Value_Of + (External_Name : Name_Id; + With_Default : String_Id := No_String) + return String_Id; + -- Get the value of an external reference, and cache it for future uses. + + function Check (Declaration : String) return Boolean; + -- Check that an external declaration <external>=<value> is correct. + -- If it is correct, the external reference is Added. + +end Prj.Ext; diff --git a/gcc/ada/prj-nmsc.adb b/gcc/ada/prj-nmsc.adb new file mode 100644 index 00000000000..66031878d2b --- /dev/null +++ b/gcc/ada/prj-nmsc.adb @@ -0,0 +1,2236 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J . N M S C -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.25 $ +-- -- +-- Copyright (C) 2000-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +with Ada.Characters.Handling; use Ada.Characters.Handling; +with Ada.Strings; use Ada.Strings; +with Ada.Strings.Fixed; use Ada.Strings.Fixed; +with Ada.Strings.Maps.Constants; use Ada.Strings.Maps.Constants; +with Errout; use Errout; +with GNAT.Directory_Operations; use GNAT.Directory_Operations; +with GNAT.OS_Lib; use GNAT.OS_Lib; +with Namet; use Namet; +with Osint; use Osint; +with Output; use Output; +with Prj.Com; use Prj.Com; +with Prj.Util; use Prj.Util; +with Snames; use Snames; +with Stringt; use Stringt; +with Types; use Types; + +package body Prj.Nmsc is + + Dir_Sep : Character renames GNAT.OS_Lib.Directory_Separator; + + Error_Report : Put_Line_Access := null; + + procedure Check_Naming_Scheme (Naming : Naming_Data); + -- Check that the package Naming is correct. + + procedure Check_Naming_Scheme + (Name : Name_Id; + Unit : out Name_Id); + -- Check that a name is a valid unit name. + + procedure Error_Msg (Msg : String; Flag_Location : Source_Ptr); + -- Output an error message. + -- If Error_Report is null, simply call Errout.Error_Msg. + -- Otherwise, disregard Flag_Location and use Error_Report. + + function Get_Name_String (S : String_Id) return String; + -- Get the string from a String_Id + + procedure Get_Unit + (File_Name : Name_Id; + Naming : Naming_Data; + Unit_Name : out Name_Id; + Unit_Kind : out Spec_Or_Body; + Needs_Pragma : out Boolean); + -- Find out, from a file name, the unit name, the unit kind + -- and if a specific SFN pragma is needed. + -- If the file name corresponds to no unit, then Unit_Name + -- will be No_Name. + + function Is_Illegal_Append (This : String) return Boolean; + -- Returns True if the string This cannot be used as + -- a Specification_Append, a Body_Append or a Separate_Append. + + procedure Record_Source + (File_Name : Name_Id; + Path_Name : Name_Id; + Project : Project_Id; + Data : in out Project_Data; + Error_If_Invalid : Boolean; + Location : Source_Ptr; + Current_Source : in out String_List_Id); + -- Put a unit in the list of units of a project, if the file name + -- corresponds to a valid unit name. + -- If it does not correspond to a valid unit name, report an error + -- only if Error_If_Invalid is true. + + procedure Show_Source_Dirs (Project : Project_Id); + -- List all the source directories of a project. + + function Locate_Directory + (Name : Name_Id; + Parent : Name_Id) + return Name_Id; + -- Locate a directory. + -- Returns No_Name if directory does not exist. + + function Path_Name_Of + (File_Name : String_Id; + Directory : Name_Id) + return String; + -- Returns the path name of a (non project) file. + -- Returns an empty string if file cannot be found. + + function Path_Name_Of + (File_Name : String_Id; + Directory : String_Id) + return String; + -- Same as above except that Directory is a String_Id instead + -- of a Name_Id. + + ------------------------- + -- Check_Naming_Scheme -- + ------------------------- + + procedure Check_Naming_Scheme (Naming : Naming_Data) is + begin + -- Only check if we are not using the standard naming scheme + + if Naming /= Standard_Naming_Data then + declare + Dot_Replacement : constant String := + Get_Name_String + (Naming.Dot_Replacement); + Specification_Append : constant String := + Get_Name_String + (Naming.Specification_Append); + Body_Append : constant String := + Get_Name_String + (Naming.Body_Append); + Separate_Append : constant String := + Get_Name_String + (Naming.Separate_Append); + + begin + -- Dot_Replacement cannot + -- - be empty + -- - start or end with an alphanumeric + -- - be a single '_' + -- - start with an '_' followed by an alphanumeric + -- - contain a '.' except if it is "." + + if Dot_Replacement'Length = 0 + or else Is_Alphanumeric + (Dot_Replacement (Dot_Replacement'First)) + or else Is_Alphanumeric + (Dot_Replacement (Dot_Replacement'Last)) + or else (Dot_Replacement (Dot_Replacement'First) = '_' + and then + (Dot_Replacement'Length = 1 + or else + Is_Alphanumeric + (Dot_Replacement (Dot_Replacement'First + 1)))) + or else (Dot_Replacement'Length > 1 + and then + Index (Source => Dot_Replacement, + Pattern => ".") /= 0) + then + Error_Msg + ('"' & Dot_Replacement & + """ is illegal for Dot_Replacement.", + Naming.Dot_Repl_Loc); + end if; + + -- Appends cannot + -- - be empty + -- - start with an alphanumeric + -- - start with an '_' followed by an alphanumeric + + if Is_Illegal_Append (Specification_Append) then + Error_Msg + ('"' & Specification_Append & + """ is illegal for Specification_Append.", + Naming.Spec_Append_Loc); + end if; + + if Is_Illegal_Append (Body_Append) then + Error_Msg + ('"' & Body_Append & + """ is illegal for Body_Append.", + Naming.Body_Append_Loc); + end if; + + if Body_Append /= Separate_Append then + if Is_Illegal_Append (Separate_Append) then + Error_Msg + ('"' & Separate_Append & + """ is illegal for Separate_Append.", + Naming.Sep_Append_Loc); + end if; + end if; + + -- Specification_Append cannot have the same termination as + -- Body_Append or Separate_Append + + if Specification_Append'Length >= Body_Append'Length + and then + Body_Append (Body_Append'Last - + Specification_Append'Length + 1 .. + Body_Append'Last) = Specification_Append + then + Error_Msg + ("Body_Append (""" & + Body_Append & + """) cannot end with" & + " Specification_Append (""" & + Specification_Append & """).", + Naming.Body_Append_Loc); + end if; + + if Specification_Append'Length >= Separate_Append'Length + and then + Separate_Append + (Separate_Append'Last - Specification_Append'Length + 1 + .. + Separate_Append'Last) = Specification_Append + then + Error_Msg + ("Separate_Append (""" & + Separate_Append & + """) cannot end with" & + " Specification_Append (""" & + Specification_Append & """).", + Naming.Sep_Append_Loc); + end if; + end; + end if; + end Check_Naming_Scheme; + + procedure Check_Naming_Scheme + (Name : Name_Id; + Unit : out Name_Id) + is + The_Name : String := Get_Name_String (Name); + Need_Letter : Boolean := True; + Last_Underscore : Boolean := False; + OK : Boolean := The_Name'Length > 0; + + begin + for Index in The_Name'Range loop + if Need_Letter then + + -- We need a letter (at the beginning, and following a dot), + -- but we don't have one. + + if Is_Letter (The_Name (Index)) then + Need_Letter := False; + + else + OK := False; + + if Current_Verbosity = High then + Write_Int (Types.Int (Index)); + Write_Str (": '"); + Write_Char (The_Name (Index)); + Write_Line ("' is not a letter."); + end if; + + exit; + end if; + + elsif Last_Underscore + and then (The_Name (Index) = '_' or else The_Name (Index) = '.') + then + -- Two underscores are illegal, and a dot cannot follow + -- an underscore. + + OK := False; + + if Current_Verbosity = High then + Write_Int (Types.Int (Index)); + Write_Str (": '"); + Write_Char (The_Name (Index)); + Write_Line ("' is illegal here."); + end if; + + exit; + + elsif The_Name (Index) = '.' then + + -- We need a letter after a dot + + Need_Letter := True; + + elsif The_Name (Index) = '_' then + Last_Underscore := True; + + else + -- We need an letter or a digit + + Last_Underscore := False; + + if not Is_Alphanumeric (The_Name (Index)) then + OK := False; + + if Current_Verbosity = High then + Write_Int (Types.Int (Index)); + Write_Str (": '"); + Write_Char (The_Name (Index)); + Write_Line ("' is not alphanumeric."); + end if; + + exit; + end if; + end if; + end loop; + + -- We cannot end with an underscore or a dot + + OK := OK and then not Need_Letter and then not Last_Underscore; + + if OK then + Unit := Name; + else + -- We signal a problem with No_Name + + Unit := No_Name; + end if; + end Check_Naming_Scheme; + + procedure Check_Naming_Scheme + (Project : Project_Id; + Report_Error : Put_Line_Access) + is + Last_Source_Dir : String_List_Id := Nil_String; + Data : Project_Data := Projects.Table (Project); + + procedure Check_Unit_Names (List : Array_Element_Id); + -- Check that a list of unit names contains only valid names. + + procedure Find_Source_Dirs (From : String_Id; Location : Source_Ptr); + -- Find one or several source directories, and add them + -- to the list of source directories of the project. + + procedure Find_Sources; + -- Find all the sources in all of the source directories + -- of a project. + + procedure Get_Path_Name_And_Record_Source + (File_Name : String; + Location : Source_Ptr; + Current_Source : in out String_List_Id); + -- Find the path name of a source in the source directories and + -- record the source, if found. + + procedure Get_Sources_From_File + (Path : String; + Location : Source_Ptr); + -- Get the sources of a project from a text file + + ---------------------- + -- Check_Unit_Names -- + ---------------------- + + procedure Check_Unit_Names (List : Array_Element_Id) is + Current : Array_Element_Id := List; + Element : Array_Element; + Unit_Name : Name_Id; + + begin + -- Loop through elements of the string list + + while Current /= No_Array_Element loop + Element := Array_Elements.Table (Current); + + -- Check that it contains a valid unit name + + Check_Naming_Scheme (Element.Index, Unit_Name); + + if Unit_Name = No_Name then + Error_Msg_Name_1 := Element.Index; + Error_Msg + ("{ is not a valid unit name.", + Element.Value.Location); + + else + + if Current_Verbosity = High then + Write_Str (" Body_Part ("""); + Write_Str (Get_Name_String (Unit_Name)); + Write_Line (""")"); + end if; + + Element.Index := Unit_Name; + Array_Elements.Table (Current) := Element; + end if; + + Current := Element.Next; + end loop; + end Check_Unit_Names; + + ---------------------- + -- Find_Source_Dirs -- + ---------------------- + + procedure Find_Source_Dirs (From : String_Id; Location : Source_Ptr) is + + Directory : String (1 .. Integer (String_Length (From))); + Directory_Id : Name_Id; + Element : String_Element; + + procedure Recursive_Find_Dirs (Path : String_Id); + -- Find all the subdirectories (recursively) of Path + -- and add them to the list of source directories + -- of the project. + + ------------------------- + -- Recursive_Find_Dirs -- + ------------------------- + + procedure Recursive_Find_Dirs (Path : String_Id) is + Dir : Dir_Type; + Name : String (1 .. 250); + Last : Natural; + The_Path : String := Get_Name_String (Path) & Dir_Sep; + + The_Path_Last : Positive := The_Path'Last; + + begin + if The_Path'Length > 1 + and then + (The_Path (The_Path_Last - 1) = Dir_Sep + or else The_Path (The_Path_Last - 1) = '/') + then + The_Path_Last := The_Path_Last - 1; + end if; + + if Current_Verbosity = High then + Write_Str (" "); + Write_Line (The_Path (The_Path'First .. The_Path_Last)); + end if; + + String_Elements.Increment_Last; + Element := + (Value => Path, + Location => No_Location, + Next => Nil_String); + + -- Case of first source directory + + if Last_Source_Dir = Nil_String then + Data.Source_Dirs := String_Elements.Last; + + -- Here we already have source directories. + + else + -- Link the previous last to the new one + + String_Elements.Table (Last_Source_Dir).Next := + String_Elements.Last; + end if; + + -- And register this source directory as the new last + + Last_Source_Dir := String_Elements.Last; + String_Elements.Table (Last_Source_Dir) := Element; + + -- Now look for subdirectories + + Open (Dir, The_Path (The_Path'First .. The_Path_Last)); + + loop + Read (Dir, Name, Last); + exit when Last = 0; + + if Current_Verbosity = High then + Write_Str (" Checking "); + Write_Line (Name (1 .. Last)); + end if; + + if Name (1 .. Last) /= "." + and then Name (1 .. Last) /= ".." + then + -- Avoid . and .. + + declare + Path_Name : constant String := + The_Path (The_Path'First .. The_Path_Last) & + Name (1 .. Last); + + begin + if Is_Directory (Path_Name) then + + -- We have found a new subdirectory, + -- register it and find its own subdirectories. + + Start_String; + Store_String_Chars (Path_Name); + Recursive_Find_Dirs (End_String); + end if; + end; + end if; + end loop; + + Close (Dir); + + exception + when Directory_Error => + null; + end Recursive_Find_Dirs; + + -- Start of processing for Find_Source_Dirs + + begin + if Current_Verbosity = High then + Write_Str ("Find_Source_Dirs ("""); + end if; + + String_To_Name_Buffer (From); + Directory := Name_Buffer (1 .. Name_Len); + Directory_Id := Name_Find; + + if Current_Verbosity = High then + Write_Str (Directory); + Write_Line (""")"); + end if; + + -- First, check if we are looking for a directory tree, + -- indicated by "/**" at the end. + + if Directory'Length >= 3 + and then Directory (Directory'Last - 1 .. Directory'Last) = "**" + and then (Directory (Directory'Last - 2) = '/' + or else + Directory (Directory'Last - 2) = Dir_Sep) + then + Name_Len := Directory'Length - 3; + + if Name_Len = 0 then + -- This is the case of "/**": all directories + -- in the file system. + + Name_Len := 1; + Name_Buffer (1) := Directory (Directory'First); + + else + Name_Buffer (1 .. Name_Len) := + Directory (Directory'First .. Directory'Last - 3); + end if; + + if Current_Verbosity = High then + Write_Str ("Looking for all subdirectories of """); + Write_Str (Name_Buffer (1 .. Name_Len)); + Write_Line (""""); + end if; + + declare + Base_Dir : constant Name_Id := Name_Find; + Root : constant Name_Id := + Locate_Directory (Base_Dir, Data.Directory); + + begin + if Root = No_Name then + Error_Msg_Name_1 := Base_Dir; + if Location = No_Location then + Error_Msg ("{ is not a valid directory.", Data.Location); + else + Error_Msg ("{ is not a valid directory.", Location); + end if; + + else + -- We have an existing directory, + -- we register it and all of its subdirectories. + + if Current_Verbosity = High then + Write_Line ("Looking for source directories:"); + end if; + + Start_String; + Store_String_Chars (Get_Name_String (Root)); + Recursive_Find_Dirs (End_String); + + if Current_Verbosity = High then + Write_Line ("End of looking for source directories."); + end if; + end if; + end; + + -- We have a single directory + + else + declare + Path_Name : constant Name_Id := + Locate_Directory (Directory_Id, Data.Directory); + + begin + if Path_Name = No_Name then + Error_Msg_Name_1 := Directory_Id; + if Location = No_Location then + Error_Msg ("{ is not a valid directory", Data.Location); + else + Error_Msg ("{ is not a valid directory", Location); + end if; + else + + -- As it is an existing directory, we add it to + -- the list of directories. + + String_Elements.Increment_Last; + Start_String; + Store_String_Chars (Get_Name_String (Path_Name)); + Element.Value := End_String; + + if Last_Source_Dir = Nil_String then + + -- This is the first source directory + + Data.Source_Dirs := String_Elements.Last; + + else + -- We already have source directories, + -- link the previous last to the new one. + + String_Elements.Table (Last_Source_Dir).Next := + String_Elements.Last; + end if; + + -- And register this source directory as the new last + + Last_Source_Dir := String_Elements.Last; + String_Elements.Table (Last_Source_Dir) := Element; + end if; + end; + end if; + end Find_Source_Dirs; + + ------------------ + -- Find_Sources -- + ------------------ + + procedure Find_Sources is + Source_Dir : String_List_Id := Data.Source_Dirs; + Element : String_Element; + Dir : Dir_Type; + Current_Source : String_List_Id := Nil_String; + + begin + if Current_Verbosity = High then + Write_Line ("Looking for sources:"); + end if; + + -- For each subdirectory + + while Source_Dir /= Nil_String loop + begin + Element := String_Elements.Table (Source_Dir); + if Element.Value /= No_String then + declare + Source_Directory : String + (1 .. Integer (String_Length (Element.Value))); + begin + String_To_Name_Buffer (Element.Value); + Source_Directory := Name_Buffer (1 .. Name_Len); + if Current_Verbosity = High then + Write_Str ("Source_Dir = "); + Write_Line (Source_Directory); + end if; + + -- We look to every entry in the source directory + + Open (Dir, Source_Directory); + + loop + Read (Dir, Name_Buffer, Name_Len); + + if Current_Verbosity = High then + Write_Str (" Checking "); + Write_Line (Name_Buffer (1 .. Name_Len)); + end if; + + exit when Name_Len = 0; + + declare + Path_Access : constant GNAT.OS_Lib.String_Access := + Locate_Regular_File + (Name_Buffer (1 .. Name_Len), + Source_Directory); + + File_Name : Name_Id; + Path_Name : Name_Id; + + begin + -- If it is a regular file + + if Path_Access /= null then + File_Name := Name_Find; + Name_Len := Path_Access'Length; + Name_Buffer (1 .. Name_Len) := Path_Access.all; + Path_Name := Name_Find; + + -- We attempt to register it as a source. + -- However, there is no error if the file + -- does not contain a valid source (as + -- indicated by Error_If_Invalid => False). + -- But there is an error if we have a + -- duplicate unit name. + + Record_Source + (File_Name => File_Name, + Path_Name => Path_Name, + Project => Project, + Data => Data, + Error_If_Invalid => False, + Location => No_Location, + Current_Source => Current_Source); + + else + if Current_Verbosity = High then + Write_Line + (" Not a regular file."); + end if; + end if; + end; + end loop; + + Close (Dir); + end; + end if; + + exception + when Directory_Error => + null; + end; + + Source_Dir := Element.Next; + end loop; + + if Current_Verbosity = High then + Write_Line ("end Looking for sources."); + end if; + + -- If we have looked for sources and found none, then + -- it is an error. If a project is not supposed to contain + -- any source, then we never call Find_Sources. + + if Current_Source = Nil_String then + Error_Msg ("there are no sources in this project", + Data.Location); + end if; + end Find_Sources; + + ------------------------------------- + -- Get_Path_Name_And_Record_Source -- + ------------------------------------- + + procedure Get_Path_Name_And_Record_Source + (File_Name : String; + Location : Source_Ptr; + Current_Source : in out String_List_Id) + is + Source_Dir : String_List_Id := Data.Source_Dirs; + Element : String_Element; + Path_Name : GNAT.OS_Lib.String_Access; + Found : Boolean := False; + File : Name_Id; + + begin + if Current_Verbosity = High then + Write_Str (" Checking """); + Write_Str (File_Name); + Write_Line ("""."); + end if; + + -- We look in all source directories for this file name + + while Source_Dir /= Nil_String loop + Element := String_Elements.Table (Source_Dir); + + if Current_Verbosity = High then + Write_Str (" """); + Write_Str (Get_Name_String (Element.Value)); + Write_Str (""": "); + end if; + + Path_Name := + Locate_Regular_File + (File_Name, + Get_Name_String (Element.Value)); + + if Path_Name /= null then + if Current_Verbosity = High then + Write_Line ("OK"); + end if; + + Name_Len := File_Name'Length; + Name_Buffer (1 .. Name_Len) := File_Name; + File := Name_Find; + Name_Len := Path_Name'Length; + Name_Buffer (1 .. Name_Len) := Path_Name.all; + + -- We register the source. + -- We report an error if the file does not + -- correspond to a source. + + Record_Source + (File_Name => File, + Path_Name => Name_Find, + Project => Project, + Data => Data, + Error_If_Invalid => True, + Location => Location, + Current_Source => Current_Source); + Found := True; + exit; + + else + if Current_Verbosity = High then + Write_Line ("No"); + end if; + + Source_Dir := Element.Next; + end if; + end loop; + + if not Found then + Name_Len := File_Name'Length; + Name_Buffer (1 .. Name_Len) := File_Name; + Error_Msg_Name_1 := Name_Find; + Error_Msg + ("cannot find source {", Location); + end if; + end Get_Path_Name_And_Record_Source; + + --------------------------- + -- Get_Sources_From_File -- + --------------------------- + + procedure Get_Sources_From_File + (Path : String; + Location : Source_Ptr) + is + File : Prj.Util.Text_File; + Line : String (1 .. 250); + Last : Natural; + Current_Source : String_List_Id := Nil_String; + + Nmb_Errors : constant Nat := Errors_Detected; + + begin + if Current_Verbosity = High then + Write_Str ("Opening """); + Write_Str (Path); + Write_Line ("""."); + end if; + + -- We open the file + + Prj.Util.Open (File, Path); + + if not Prj.Util.Is_Valid (File) then + Error_Msg ("file does not exist", Location); + else + while not Prj.Util.End_Of_File (File) loop + Prj.Util.Get_Line (File, Line, Last); + + -- If the line is not empty and does not start with "--", + -- then it must contains a file name. + + if Last /= 0 + and then (Last = 1 or else Line (1 .. 2) /= "--") + then + Get_Path_Name_And_Record_Source + (File_Name => Line (1 .. Last), + Location => Location, + Current_Source => Current_Source); + exit when Nmb_Errors /= Errors_Detected; + end if; + end loop; + + Prj.Util.Close (File); + + end if; + + -- We should have found at least one source. + -- If not, report an error. + + if Current_Source = Nil_String then + Error_Msg ("this project has no source", Location); + end if; + end Get_Sources_From_File; + + -- Start of processing for Check_Naming_Scheme + + begin + + Error_Report := Report_Error; + + if Current_Verbosity = High then + Write_Line ("Starting to look for directories"); + end if; + + -- Let's check the object directory + + declare + Object_Dir : Variable_Value := + Util.Value_Of (Name_Object_Dir, Data.Decl.Attributes); + + begin + pragma Assert (Object_Dir.Kind = Single, + "Object_Dir is not a single string"); + + -- We set the object directory to its default + + Data.Object_Directory := Data.Directory; + + if not String_Equal (Object_Dir.Value, Empty_String) then + + String_To_Name_Buffer (Object_Dir.Value); + + if Name_Len = 0 then + Error_Msg ("Object_Dir cannot be empty", + Object_Dir.Location); + + else + -- We check that the specified object directory + -- does exist. + + Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); + + declare + Dir_Id : constant Name_Id := Name_Find; + + begin + Data.Object_Directory := + Locate_Directory (Dir_Id, Data.Directory); + + if Data.Object_Directory = No_Name then + Error_Msg_Name_1 := Dir_Id; + Error_Msg + ("the object directory { cannot be found", + Data.Location); + end if; + end; + end if; + end if; + end; + + if Current_Verbosity = High then + if Data.Object_Directory = No_Name then + Write_Line ("No object directory"); + else + Write_Str ("Object directory: """); + Write_Str (Get_Name_String (Data.Object_Directory)); + Write_Line (""""); + end if; + end if; + + -- Let's check the source directories + + declare + Source_Dirs : Variable_Value := + Util.Value_Of (Name_Source_Dirs, Data.Decl.Attributes); + + begin + + if Current_Verbosity = High then + Write_Line ("Starting to look for source directories"); + end if; + + pragma Assert (Source_Dirs.Kind = List, + "Source_Dirs is not a list"); + + if Source_Dirs.Default then + + -- No Source_Dirs specified: the single source directory + -- is the one containing the project file + + String_Elements.Increment_Last; + Data.Source_Dirs := String_Elements.Last; + Start_String; + Store_String_Chars (Get_Name_String (Data.Directory)); + String_Elements.Table (Data.Source_Dirs) := + (Value => End_String, + Location => No_Location, + Next => Nil_String); + + if Current_Verbosity = High then + Write_Line ("(Undefined) Single object directory:"); + Write_Str (" """); + Write_Str (Get_Name_String (Data.Directory)); + Write_Line (""""); + end if; + + elsif Source_Dirs.Values = Nil_String then + + -- If Source_Dirs is an empty string list, this means + -- that this project contains no source. + + if Data.Object_Directory = Data.Directory then + Data.Object_Directory := No_Name; + end if; + + Data.Source_Dirs := Nil_String; + + else + declare + Source_Dir : String_List_Id := Source_Dirs.Values; + Element : String_Element; + + begin + -- We will find the source directories for each + -- element of the list + + while Source_Dir /= Nil_String loop + Element := String_Elements.Table (Source_Dir); + Find_Source_Dirs (Element.Value, Element.Location); + Source_Dir := Element.Next; + end loop; + end; + end if; + + if Current_Verbosity = High then + Write_Line ("Puting source directories in canonical cases"); + end if; + + declare + Current : String_List_Id := Data.Source_Dirs; + Element : String_Element; + + begin + while Current /= Nil_String loop + Element := String_Elements.Table (Current); + if Element.Value /= No_String then + String_To_Name_Buffer (Element.Value); + Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); + Start_String; + Store_String_Chars (Name_Buffer (1 .. Name_Len)); + Element.Value := End_String; + String_Elements.Table (Current) := Element; + end if; + + Current := Element.Next; + end loop; + end; + end; + + -- Library Dir, Name, Version and Kind + + declare + Attributes : constant Prj.Variable_Id := Data.Decl.Attributes; + + Lib_Dir : Prj.Variable_Value := + Prj.Util.Value_Of (Snames.Name_Library_Dir, Attributes); + + Lib_Name : Prj.Variable_Value := + Prj.Util.Value_Of (Snames.Name_Library_Name, Attributes); + + Lib_Version : Prj.Variable_Value := + Prj.Util.Value_Of + (Snames.Name_Library_Version, Attributes); + + The_Lib_Kind : Prj.Variable_Value := + Prj.Util.Value_Of + (Snames.Name_Library_Kind, Attributes); + + begin + pragma Assert (Lib_Dir.Kind = Single); + + if Lib_Dir.Value = Empty_String then + + if Current_Verbosity = High then + Write_Line ("No library directory"); + end if; + + else + -- Find path name, check that it is a directory + + Stringt.String_To_Name_Buffer (Lib_Dir.Value); + + declare + Dir_Id : constant Name_Id := Name_Find; + + begin + Data.Library_Dir := + Locate_Directory (Dir_Id, Data.Directory); + + if Data.Library_Dir = No_Name then + Error_Msg ("not an existing directory", + Lib_Dir.Location); + + elsif Data.Library_Dir = Data.Object_Directory then + Error_Msg + ("library directory cannot be the same " & + "as object directory", + Lib_Dir.Location); + Data.Library_Dir := No_Name; + + else + if Current_Verbosity = High then + Write_Str ("Library directory ="""); + Write_Str (Get_Name_String (Data.Library_Dir)); + Write_Line (""""); + end if; + end if; + end; + end if; + + pragma Assert (Lib_Name.Kind = Single); + + if Lib_Name.Value = Empty_String then + if Current_Verbosity = High then + Write_Line ("No library name"); + end if; + + else + Stringt.String_To_Name_Buffer (Lib_Name.Value); + + if not Is_Letter (Name_Buffer (1)) then + Error_Msg ("must start with a letter", + Lib_Name.Location); + + else + Data.Library_Name := Name_Find; + + for Index in 2 .. Name_Len loop + if not Is_Alphanumeric (Name_Buffer (Index)) then + Data.Library_Name := No_Name; + Error_Msg ("only letters and digits are allowed", + Lib_Name.Location); + exit; + end if; + end loop; + + if Data.Library_Name /= No_Name + and then Current_Verbosity = High then + Write_Str ("Library name = """); + Write_Str (Get_Name_String (Data.Library_Name)); + Write_Line (""""); + end if; + end if; + end if; + + Data.Library := + Data.Library_Dir /= No_Name + and then + Data.Library_Name /= No_Name; + + if Data.Library then + if Current_Verbosity = High then + Write_Line ("This is a library project file"); + end if; + + pragma Assert (Lib_Version.Kind = Single); + + if Lib_Version.Value = Empty_String then + if Current_Verbosity = High then + Write_Line ("No library version specified"); + end if; + + else + Stringt.String_To_Name_Buffer (Lib_Version.Value); + Data.Lib_Internal_Name := Name_Find; + end if; + + pragma Assert (The_Lib_Kind.Kind = Single); + + if The_Lib_Kind.Value = Empty_String then + if Current_Verbosity = High then + Write_Line ("No library kind specified"); + end if; + + else + Stringt.String_To_Name_Buffer (The_Lib_Kind.Value); + + declare + Kind_Name : constant String := + Ada.Characters.Handling.To_Lower + (Name_Buffer (1 .. Name_Len)); + + OK : Boolean := True; + + begin + if Kind_Name = "static" then + Data.Library_Kind := Static; + + elsif Kind_Name = "dynamic" then + Data.Library_Kind := Dynamic; + + elsif Kind_Name = "relocatable" then + Data.Library_Kind := Relocatable; + + else + Error_Msg + ("illegal value for Library_Kind", + The_Lib_Kind.Location); + OK := False; + end if; + + if Current_Verbosity = High and then OK then + Write_Str ("Library kind = "); + Write_Line (Kind_Name); + end if; + end; + end if; + end if; + end; + + if Current_Verbosity = High then + Show_Source_Dirs (Project); + end if; + + declare + Naming_Id : constant Package_Id := + Util.Value_Of (Name_Naming, Data.Decl.Packages); + + Naming : Package_Element; + + begin + -- If there is a package Naming, we will put in Data.Naming + -- what is in this package Naming. + + if Naming_Id /= No_Package then + Naming := Packages.Table (Naming_Id); + + if Current_Verbosity = High then + Write_Line ("Checking ""Naming""."); + end if; + + declare + Bodies : constant Array_Element_Id := + Util.Value_Of (Name_Body_Part, Naming.Decl.Arrays); + + Specifications : constant Array_Element_Id := + Util.Value_Of + (Name_Specification, Naming.Decl.Arrays); + + begin + if Bodies /= No_Array_Element then + + -- We have elements in the array Body_Part + + if Current_Verbosity = High then + Write_Line ("Found Bodies."); + end if; + + Data.Naming.Bodies := Bodies; + Check_Unit_Names (Bodies); + + else + if Current_Verbosity = High then + Write_Line ("No Bodies."); + end if; + end if; + + if Specifications /= No_Array_Element then + + -- We have elements in the array Specification + + if Current_Verbosity = High then + Write_Line ("Found Specifications."); + end if; + + Data.Naming.Specifications := Specifications; + Check_Unit_Names (Specifications); + + else + if Current_Verbosity = High then + Write_Line ("No Specifications."); + end if; + end if; + end; + + -- We are now checking if variables Dot_Replacement, Casing, + -- Specification_Append, Body_Append and/or Separate_Append + -- exist. + -- For each variable, if it does not exist, we do nothing, + -- because we already have the default. + + -- Let's check Dot_Replacement + + declare + Dot_Replacement : constant Variable_Value := + Util.Value_Of + (Name_Dot_Replacement, + Naming.Decl.Attributes); + + begin + pragma Assert (Dot_Replacement.Kind = Single, + "Dot_Replacement is not a single string"); + + if not Dot_Replacement.Default then + + String_To_Name_Buffer (Dot_Replacement.Value); + + if Name_Len = 0 then + Error_Msg ("Dot_Replacement cannot be empty", + Dot_Replacement.Location); + + else + Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); + Data.Naming.Dot_Replacement := Name_Find; + Data.Naming.Dot_Repl_Loc := Dot_Replacement.Location; + end if; + + end if; + + end; + + if Current_Verbosity = High then + Write_Str (" Dot_Replacement = """); + Write_Str (Get_Name_String (Data.Naming.Dot_Replacement)); + Write_Char ('"'); + Write_Eol; + end if; + + -- Check Casing + + declare + Casing_String : constant Variable_Value := + Util.Value_Of (Name_Casing, Naming.Decl.Attributes); + + begin + pragma Assert (Casing_String.Kind = Single, + "Dot_Replacement is not a single string"); + + if not Casing_String.Default then + declare + Casing_Image : constant String := + Get_Name_String (Casing_String.Value); + + begin + declare + Casing : constant Casing_Type := + Value (Casing_Image); + + begin + Data.Naming.Casing := Casing; + end; + + exception + when Constraint_Error => + if Casing_Image'Length = 0 then + Error_Msg ("Casing cannot be an empty string", + Casing_String.Location); + + else + Name_Len := Casing_Image'Length; + Name_Buffer (1 .. Name_Len) := Casing_Image; + Error_Msg_Name_1 := Name_Find; + Error_Msg + ("{ is not a correct Casing", + Casing_String.Location); + end if; + end; + end if; + end; + + if Current_Verbosity = High then + Write_Str (" Casing = "); + Write_Str (Image (Data.Naming.Casing)); + Write_Char ('.'); + Write_Eol; + end if; + + -- Let's check Specification_Append + + declare + Specification_Append : constant Variable_Value := + Util.Value_Of + (Name_Specification_Append, + Naming.Decl.Attributes); + + begin + pragma Assert (Specification_Append.Kind = Single, + "Specification_Append is not a single string"); + + if not Specification_Append.Default then + String_To_Name_Buffer (Specification_Append.Value); + + if Name_Len = 0 then + Error_Msg ("Specification_Append cannot be empty", + Specification_Append.Location); + + else + Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); + Data.Naming.Specification_Append := Name_Find; + Data.Naming.Spec_Append_Loc := + Specification_Append.Location; + end if; + end if; + end; + + if Current_Verbosity = High then + Write_Str (" Specification_Append = """); + Write_Str (Get_Name_String (Data.Naming.Specification_Append)); + Write_Line ("""."); + end if; + + -- Check Body_Append + + declare + Body_Append : constant Variable_Value := + Util.Value_Of + (Name_Body_Append, Naming.Decl.Attributes); + + begin + pragma Assert (Body_Append.Kind = Single, + "Body_Append is not a single string"); + + if not Body_Append.Default then + + String_To_Name_Buffer (Body_Append.Value); + + if Name_Len = 0 then + Error_Msg ("Body_Append cannot be empty", + Body_Append.Location); + + else + Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); + Data.Naming.Body_Append := Name_Find; + Data.Naming.Body_Append_Loc := Body_Append.Location; + + -- As we have a new Body_Append, we set Separate_Append + -- to the same value. + + Data.Naming.Separate_Append := Data.Naming.Body_Append; + Data.Naming.Sep_Append_Loc := Data.Naming.Body_Append_Loc; + end if; + end if; + end; + + if Current_Verbosity = High then + Write_Str (" Body_Append = """); + Write_Str (Get_Name_String (Data.Naming.Body_Append)); + Write_Line ("""."); + end if; + + -- Check Separate_Append + + declare + Separate_Append : constant Variable_Value := + Util.Value_Of + (Name_Separate_Append, + Naming.Decl.Attributes); + + begin + pragma Assert (Separate_Append.Kind = Single, + "Separate_Append is not a single string"); + + if not Separate_Append.Default then + String_To_Name_Buffer (Separate_Append.Value); + + if Name_Len = 0 then + Error_Msg ("Separate_Append cannot be empty", + Separate_Append.Location); + + else + Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); + Data.Naming.Separate_Append := Name_Find; + Data.Naming.Sep_Append_Loc := Separate_Append.Location; + end if; + end if; + end; + + if Current_Verbosity = High then + Write_Str (" Separate_Append = """); + Write_Str (Get_Name_String (Data.Naming.Separate_Append)); + Write_Line ("""."); + Write_Line ("end Naming."); + end if; + + -- Now, we check if Data.Naming is valid + + Check_Naming_Scheme (Data.Naming); + end if; + end; + + -- If we have source directories, then let's find the sources. + + if Data.Source_Dirs /= Nil_String then + declare + Sources : constant Variable_Value := + Util.Value_Of + (Name_Source_Files, + Data.Decl.Attributes); + + Source_List_File : constant Variable_Value := + Util.Value_Of + (Name_Source_List_File, + Data.Decl.Attributes); + + begin + pragma Assert + (Sources.Kind = List, + "Source_Files is not a list"); + pragma Assert + (Source_List_File.Kind = Single, + "Source_List_File is not a single string"); + + if not Sources.Default then + if not Source_List_File.Default then + Error_Msg + ("?both variables source_files and " & + "source_list_file are present", + Source_List_File.Location); + end if; + + -- Sources is a list of file names + + declare + Current_Source : String_List_Id := Nil_String; + Current : String_List_Id := Sources.Values; + Element : String_Element; + + begin + while Current /= Nil_String loop + Element := String_Elements.Table (Current); + String_To_Name_Buffer (Element.Value); + + declare + File_Name : constant String := + Name_Buffer (1 .. Name_Len); + + begin + Get_Path_Name_And_Record_Source + (File_Name => File_Name, + Location => Element.Location, + Current_Source => Current_Source); + Current := Element.Next; + end; + end loop; + end; + + -- No source_files specified. + -- We check Source_List_File has been specified. + + elsif not Source_List_File.Default then + + -- Source_List_File is the name of the file + -- that contains the source file names + + declare + Source_File_Path_Name : constant String := + Path_Name_Of + (Source_List_File.Value, + Data.Directory); + + begin + if Source_File_Path_Name'Length = 0 then + String_To_Name_Buffer (Source_List_File.Value); + Error_Msg_Name_1 := Name_Find; + Error_Msg + ("file with sources { does not exist", + Source_List_File.Location); + + else + Get_Sources_From_File + (Source_File_Path_Name, + Source_List_File.Location); + end if; + end; + + else + -- Neither Source_Files nor Source_List_File has been + -- specified. + -- Find all the files that satisfy + -- the naming scheme in all the source directories. + + Find_Sources; + end if; + end; + end if; + + Projects.Table (Project) := Data; + end Check_Naming_Scheme; + + --------------- + -- Error_Msg -- + --------------- + + procedure Error_Msg (Msg : String; Flag_Location : Source_Ptr) is + begin + if Error_Report = null then + Errout.Error_Msg (Msg, Flag_Location); + + else + declare + Error_Buffer : String (1 .. 5_000); + Error_Last : Natural := 0; + Msg_Name : Natural := 0; + First : Positive := Msg'First; + + procedure Add (C : Character); + -- Add a character to the buffer + + procedure Add (S : String); + -- Add a string to the buffer + + procedure Add (Id : Name_Id); + -- Add a name to the buffer + + --------- + -- Add -- + --------- + + procedure Add (C : Character) is + begin + Error_Last := Error_Last + 1; + Error_Buffer (Error_Last) := C; + end Add; + + procedure Add (S : String) is + begin + Error_Buffer (Error_Last + 1 .. Error_Last + S'Length) := S; + Error_Last := Error_Last + S'Length; + end Add; + + procedure Add (Id : Name_Id) is + begin + Get_Name_String (Id); + Add (Name_Buffer (1 .. Name_Len)); + end Add; + + begin + if Msg (First) = '\' then + -- Continuation character, ignore. + First := First + 1; + + elsif Msg (First) = '?' then + -- Warning character. It is always the first one, + -- in this package. + First := First + 1; + Add ("Warning: "); + end if; + + for Index in First .. Msg'Last loop + if Msg (Index) = '{' or else Msg (Index) = '%' then + -- Include a name between double quotes. + Msg_Name := Msg_Name + 1; + Add ('"'); + + case Msg_Name is + when 1 => Add (Error_Msg_Name_1); + + when 2 => Add (Error_Msg_Name_2); + + when 3 => Add (Error_Msg_Name_3); + + when others => null; + end case; + + Add ('"'); + + else + Add (Msg (Index)); + end if; + + end loop; + + Error_Report (Error_Buffer (1 .. Error_Last)); + end; + end if; + end Error_Msg; + + --------------------- + -- Get_Name_String -- + --------------------- + + function Get_Name_String (S : String_Id) return String is + begin + if S = No_String then + return ""; + else + String_To_Name_Buffer (S); + return Name_Buffer (1 .. Name_Len); + end if; + end Get_Name_String; + + -------------- + -- Get_Unit -- + -------------- + + procedure Get_Unit + (File_Name : Name_Id; + Naming : Naming_Data; + Unit_Name : out Name_Id; + Unit_Kind : out Spec_Or_Body; + Needs_Pragma : out Boolean) + is + Canonical_Case_Name : Name_Id; + + begin + Needs_Pragma := False; + Get_Name_String (File_Name); + Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); + Canonical_Case_Name := Name_Find; + + if Naming.Bodies /= No_Array_Element then + + -- There are some specified file names for some bodies + -- of this project. Find out if File_Name is one of these bodies. + + declare + Current : Array_Element_Id := Naming.Bodies; + Element : Array_Element; + + begin + while Current /= No_Array_Element loop + Element := Array_Elements.Table (Current); + + if Element.Index /= No_Name then + String_To_Name_Buffer (Element.Value.Value); + Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); + + if Canonical_Case_Name = Name_Find then + + -- File_Name corresponds to one body. + -- So, we know it is a body, and we know the unit name. + + Unit_Kind := Body_Part; + Unit_Name := Element.Index; + Needs_Pragma := True; + return; + end if; + end if; + + Current := Element.Next; + end loop; + end; + end if; + + if Naming.Specifications /= No_Array_Element then + + -- There are some specified file names for some bodiesspecifications + -- of this project. Find out if File_Name is one of these + -- specifications. + + declare + Current : Array_Element_Id := Naming.Specifications; + Element : Array_Element; + + begin + while Current /= No_Array_Element loop + Element := Array_Elements.Table (Current); + + if Element.Index /= No_Name then + String_To_Name_Buffer (Element.Value.Value); + Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); + + if Canonical_Case_Name = Name_Find then + + -- File_Name corresponds to one specification. + -- So, we know it is a spec, and we know the unit name. + + Unit_Kind := Specification; + Unit_Name := Element.Index; + Needs_Pragma := True; + return; + end if; + + end if; + + Current := Element.Next; + end loop; + end; + end if; + + declare + File : String := Get_Name_String (Canonical_Case_Name); + First : Positive := File'First; + Last : Natural := File'Last; + + begin + -- Check if the end of the file name is Specification_Append + + Get_Name_String (Naming.Specification_Append); + + if File'Length > Name_Len + and then File (Last - Name_Len + 1 .. Last) = + Name_Buffer (1 .. Name_Len) + then + -- We have a spec + + Unit_Kind := Specification; + Last := Last - Name_Len; + + if Current_Verbosity = High then + Write_Str (" Specification: "); + Write_Line (File (First .. Last)); + end if; + + else + Get_Name_String (Naming.Body_Append); + + -- Check if the end of the file name is Body_Append + + if File'Length > Name_Len + and then File (Last - Name_Len + 1 .. Last) = + Name_Buffer (1 .. Name_Len) + then + -- We have a body + + Unit_Kind := Body_Part; + Last := Last - Name_Len; + + if Current_Verbosity = High then + Write_Str (" Body: "); + Write_Line (File (First .. Last)); + end if; + + elsif Naming.Separate_Append /= Naming.Body_Append then + Get_Name_String (Naming.Separate_Append); + + -- Check if the end of the file name is Separate_Append + + if File'Length > Name_Len + and then File (Last - Name_Len + 1 .. Last) = + Name_Buffer (1 .. Name_Len) + then + -- We have a separate (a body) + + Unit_Kind := Body_Part; + Last := Last - Name_Len; + + if Current_Verbosity = High then + Write_Str (" Separate: "); + Write_Line (File (First .. Last)); + end if; + + else + Last := 0; + end if; + + else + Last := 0; + end if; + end if; + + if Last = 0 then + + -- This is not a source file + + Unit_Name := No_Name; + Unit_Kind := Specification; + + if Current_Verbosity = High then + Write_Line (" Not a valid file name."); + end if; + + return; + end if; + + Get_Name_String (Naming.Dot_Replacement); + + if Name_Buffer (1 .. Name_Len) /= "." then + + -- If Dot_Replacement is not a single dot, + -- then there should not be any dot in the name. + + for Index in First .. Last loop + if File (Index) = '.' then + if Current_Verbosity = High then + Write_Line + (" Not a valid file name (some dot not replaced)."); + end if; + + Unit_Name := No_Name; + return; + + end if; + end loop; + + -- Replace the substring Dot_Replacement with dots + + declare + Index : Positive := First; + + begin + while Index <= Last - Name_Len + 1 loop + + if File (Index .. Index + Name_Len - 1) = + Name_Buffer (1 .. Name_Len) + then + File (Index) := '.'; + + if Name_Len > 1 and then Index < Last then + File (Index + 1 .. Last - Name_Len + 1) := + File (Index + Name_Len .. Last); + end if; + + Last := Last - Name_Len + 1; + end if; + + Index := Index + 1; + end loop; + end; + end if; + + -- Check if the casing is right + + declare + Src : String := File (First .. Last); + + begin + case Naming.Casing is + when All_Lower_Case => + Fixed.Translate + (Source => Src, + Mapping => Lower_Case_Map); + + when All_Upper_Case => + Fixed.Translate + (Source => Src, + Mapping => Upper_Case_Map); + + when Mixed_Case | Unknown => + null; + end case; + + if Src /= File (First .. Last) then + if Current_Verbosity = High then + Write_Line (" Not a valid file name (casing)."); + end if; + + Unit_Name := No_Name; + return; + end if; + + -- We put the name in lower case + + Fixed.Translate + (Source => Src, + Mapping => Lower_Case_Map); + + if Current_Verbosity = High then + Write_Str (" "); + Write_Line (Src); + end if; + + Name_Len := Src'Length; + Name_Buffer (1 .. Name_Len) := Src; + + -- Now, we check if this name is a valid unit name + + Check_Naming_Scheme (Name => Name_Find, Unit => Unit_Name); + end; + + end; + + end Get_Unit; + + ----------------------- + -- Is_Illegal_Append -- + ----------------------- + + function Is_Illegal_Append (This : String) return Boolean is + begin + return This'Length = 0 + or else Is_Alphanumeric (This (This'First)) + or else (This'Length >= 2 + and then This (This'First) = '_' + and then Is_Alphanumeric (This (This'First + 1))); + end Is_Illegal_Append; + + ---------------------- + -- Locate_Directory -- + ---------------------- + + function Locate_Directory + (Name : Name_Id; + Parent : Name_Id) + return Name_Id + is + The_Name : constant String := Get_Name_String (Name); + The_Parent : constant String := + Get_Name_String (Parent) & Dir_Sep; + + The_Parent_Last : Positive := The_Parent'Last; + + begin + if The_Parent'Length > 1 + and then (The_Parent (The_Parent_Last - 1) = Dir_Sep + or else The_Parent (The_Parent_Last - 1) = '/') + then + The_Parent_Last := The_Parent_Last - 1; + end if; + + if Current_Verbosity = High then + Write_Str ("Locate_Directory ("""); + Write_Str (The_Name); + Write_Str (""", """); + Write_Str (The_Parent); + Write_Line (""")"); + end if; + + if Is_Absolute_Path (The_Name) then + if Is_Directory (The_Name) then + return Name; + end if; + + else + declare + Full_Path : constant String := + The_Parent (The_Parent'First .. The_Parent_Last) & + The_Name; + + begin + if Is_Directory (Full_Path) then + Name_Len := Full_Path'Length; + Name_Buffer (1 .. Name_Len) := Full_Path; + return Name_Find; + end if; + end; + + end if; + + return No_Name; + end Locate_Directory; + + ------------------ + -- Path_Name_Of -- + ------------------ + + function Path_Name_Of + (File_Name : String_Id; + Directory : String_Id) + return String + is + Result : String_Access; + + begin + String_To_Name_Buffer (File_Name); + + declare + The_File_Name : constant String := Name_Buffer (1 .. Name_Len); + + begin + String_To_Name_Buffer (Directory); + Result := Locate_Regular_File + (File_Name => The_File_Name, + Path => Name_Buffer (1 .. Name_Len)); + end; + + if Result = null then + return ""; + else + Canonical_Case_File_Name (Result.all); + return Result.all; + end if; + end Path_Name_Of; + + function Path_Name_Of + (File_Name : String_Id; + Directory : Name_Id) + return String + is + Result : String_Access; + The_Directory : constant String := Get_Name_String (Directory); + + begin + String_To_Name_Buffer (File_Name); + Result := Locate_Regular_File + (File_Name => Name_Buffer (1 .. Name_Len), + Path => The_Directory); + + if Result = null then + return ""; + else + Canonical_Case_File_Name (Result.all); + return Result.all; + end if; + end Path_Name_Of; + + ------------------- + -- Record_Source -- + ------------------- + + procedure Record_Source + (File_Name : Name_Id; + Path_Name : Name_Id; + Project : Project_Id; + Data : in out Project_Data; + Error_If_Invalid : Boolean; + Location : Source_Ptr; + Current_Source : in out String_List_Id) + is + Unit_Name : Name_Id; + Unit_Kind : Spec_Or_Body; + Needs_Pragma : Boolean; + The_Location : Source_Ptr := Location; + + begin + -- Find out the unit name, the unit kind and if it needs + -- a specific SFN pragma. + + Get_Unit + (File_Name => File_Name, + Naming => Data.Naming, + Unit_Name => Unit_Name, + Unit_Kind => Unit_Kind, + Needs_Pragma => Needs_Pragma); + + -- If it is not a source file, report an error only if + -- Error_If_Invalid is true. + + if Unit_Name = No_Name then + if Error_If_Invalid then + Error_Msg_Name_1 := File_Name; + Error_Msg + ("{ is not a valid source file name", + Location); + + else + if Current_Verbosity = High then + Write_Str (" """); + Write_Str (Get_Name_String (File_Name)); + Write_Line (""" is not a valid source file name (ignored)."); + end if; + end if; + + else + -- Put the file name in the list of sources of the project + + String_Elements.Increment_Last; + Get_Name_String (File_Name); + Start_String; + Store_String_Chars (Name_Buffer (1 .. Name_Len)); + String_Elements.Table (String_Elements.Last) := + (Value => End_String, + Location => No_Location, + Next => Nil_String); + + if Current_Source = Nil_String then + Data.Sources := String_Elements.Last; + + else + String_Elements.Table (Current_Source).Next := + String_Elements.Last; + end if; + + Current_Source := String_Elements.Last; + + -- Put the unit in unit list + + declare + The_Unit : Unit_Id := Units_Htable.Get (Unit_Name); + The_Unit_Data : Unit_Data; + + begin + if Current_Verbosity = High then + Write_Str ("Putting "); + Write_Str (Get_Name_String (Unit_Name)); + Write_Line (" in the unit list."); + end if; + + -- The unit is already in the list, but may be it is + -- only the other unit kind (spec or body), or what is + -- in the unit list is a unit of a project we are modifying. + + if The_Unit /= Prj.Com.No_Unit then + The_Unit_Data := Units.Table (The_Unit); + + if The_Unit_Data.File_Names (Unit_Kind).Name = No_Name + or else (Data.Modifies /= No_Project + and then + The_Unit_Data.File_Names (Unit_Kind).Project = + Data.Modifies) + then + The_Unit_Data.File_Names (Unit_Kind) := + (Name => File_Name, + Path => Path_Name, + Project => Project, + Needs_Pragma => Needs_Pragma); + Units.Table (The_Unit) := The_Unit_Data; + + else + -- It is an error to have two units with the same name + -- and the same kind (spec or body). + + if The_Location = No_Location then + The_Location := Projects.Table (Project).Location; + end if; + + Error_Msg_Name_1 := Unit_Name; + Error_Msg ("duplicate source {", The_Location); + + Error_Msg_Name_1 := + Projects.Table + (The_Unit_Data.File_Names (Unit_Kind).Project).Name; + Error_Msg_Name_2 := + The_Unit_Data.File_Names (Unit_Kind).Path; + Error_Msg ("\ project file {, {", The_Location); + + Error_Msg_Name_1 := Projects.Table (Project).Name; + Error_Msg_Name_2 := Path_Name; + Error_Msg ("\ project file {, {", The_Location); + + end if; + + -- It is a new unit, create a new record + + else + Units.Increment_Last; + The_Unit := Units.Last; + Units_Htable.Set (Unit_Name, The_Unit); + The_Unit_Data.Name := Unit_Name; + The_Unit_Data.File_Names (Unit_Kind) := + (Name => File_Name, + Path => Path_Name, + Project => Project, + Needs_Pragma => Needs_Pragma); + Units.Table (The_Unit) := The_Unit_Data; + end if; + end; + end if; + end Record_Source; + + ---------------------- + -- Show_Source_Dirs -- + ---------------------- + + procedure Show_Source_Dirs (Project : Project_Id) is + Current : String_List_Id := Projects.Table (Project).Source_Dirs; + Element : String_Element; + + begin + Write_Line ("Source_Dirs:"); + + while Current /= Nil_String loop + Element := String_Elements.Table (Current); + Write_Str (" "); + Write_Line (Get_Name_String (Element.Value)); + Current := Element.Next; + end loop; + + Write_Line ("end Source_Dirs."); + end Show_Source_Dirs; + +end Prj.Nmsc; diff --git a/gcc/ada/prj-nmsc.ads b/gcc/ada/prj-nmsc.ads new file mode 100644 index 00000000000..5fcc00538da --- /dev/null +++ b/gcc/ada/prj-nmsc.ads @@ -0,0 +1,43 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J . N M S C -- +-- -- +-- S p e c -- +-- -- +-- $Revision: 1.3 $ +-- -- +-- Copyright (C) 2000-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ +-- +-- Check the Naming Scheme of a project file, find the directories +-- and the source files. + +private package Prj.Nmsc is + + procedure Check_Naming_Scheme + (Project : Project_Id; + Report_Error : Put_Line_Access); + -- Check that the Naming Scheme of a project is legal. Find the + -- object directory, the source directories, and the source files. + -- Check the source files against the Naming Scheme. + -- If Report_Error is null , use the standard error reporting mechanism + -- (Errout). Otherwise, report errors using Report_Error. + +end Prj.Nmsc; diff --git a/gcc/ada/prj-pars.adb b/gcc/ada/prj-pars.adb new file mode 100644 index 00000000000..620d2e113a9 --- /dev/null +++ b/gcc/ada/prj-pars.adb @@ -0,0 +1,92 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J . P A R S -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.19 $ +-- -- +-- Copyright (C) 2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +with Ada.Exceptions; use Ada.Exceptions; + +with Errout; use Errout; +with Output; use Output; +with Prj.Com; use Prj.Com; +with Prj.Part; +with Prj.Proc; +with Prj.Tree; use Prj.Tree; + +package body Prj.Pars is + + ----------- + -- Parse -- + ----------- + + procedure Parse + (Project : out Project_Id; + Project_File_Name : String) + is + Project_Tree : Project_Node_Id := Empty_Node; + The_Project : Project_Id := No_Project; + + begin + -- Parse the main project file into a tree + + Prj.Part.Parse + (Project => Project_Tree, + Project_File_Name => Project_File_Name, + Always_Errout_Finalize => False); + + -- If there were no error, process the tree + + if Project_Tree /= Empty_Node then + Prj.Proc.Process + (Project => The_Project, + From_Project_Node => Project_Tree, + Report_Error => null); + Errout.Finalize; + end if; + + Project := The_Project; + + exception + when X : others => + + -- Internal error + + Write_Line (Exception_Information (X)); + Write_Str ("Exception "); + Write_Str (Exception_Name (X)); + Write_Line (" raised, while processing project file"); + Project := No_Project; + end Parse; + + ------------------- + -- Set_Verbosity -- + ------------------- + + procedure Set_Verbosity (To : in Verbosity) is + begin + Current_Verbosity := To; + end Set_Verbosity; + +end Prj.Pars; diff --git a/gcc/ada/prj-pars.ads b/gcc/ada/prj-pars.ads new file mode 100644 index 00000000000..0adaf72f4c2 --- /dev/null +++ b/gcc/ada/prj-pars.ads @@ -0,0 +1,44 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J . P A R S -- +-- -- +-- S p e c -- +-- -- +-- $Revision: 1.8 $ +-- -- +-- Copyright (C) 2000-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ +-- +-- Implements the parsing of project files. + +package Prj.Pars is + + procedure Set_Verbosity (To : Verbosity); + -- Set the verbosity when parsing the project files. + + procedure Parse + (Project : out Project_Id; + Project_File_Name : String); + -- Parse a project files and all its imported project files. + -- If parsing is successful, Project_Id is the project ID + -- of the main project file; otherwise, Project_Id is set + -- to No_Project. + +end Prj.Pars; diff --git a/gcc/ada/prj-part.adb b/gcc/ada/prj-part.adb new file mode 100644 index 00000000000..8100ad49e95 --- /dev/null +++ b/gcc/ada/prj-part.adb @@ -0,0 +1,871 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J . P A R T -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.10 $ +-- -- +-- Copyright (C) 2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +with Ada.Characters.Handling; use Ada.Characters.Handling; +with Ada.Exceptions; use Ada.Exceptions; +with Errout; use Errout; +with GNAT.Directory_Operations; use GNAT.Directory_Operations; +with GNAT.OS_Lib; use GNAT.OS_Lib; +with Namet; use Namet; +with Osint; use Osint; +with Output; use Output; +with Prj.Com; use Prj.Com; +with Prj.Dect; +with Scans; use Scans; +with Scn; use Scn; +with Sinfo; use Sinfo; +with Sinput; use Sinput; +with Sinput.P; use Sinput.P; +with Stringt; use Stringt; +with Table; +with Types; use Types; + +pragma Elaborate_All (GNAT.OS_Lib); + +package body Prj.Part is + + Dir_Sep : Character renames GNAT.OS_Lib.Directory_Separator; + + Project_File_Extension : String := ".gpr"; + + Project_Path : String_Access; + -- The project path; initialized during package elaboration. + + Ada_Project_Path : constant String := "ADA_PROJECT_PATH"; + Prj_Path : constant String_Access := Getenv (Ada_Project_Path); + + ------------------------------------ + -- Local Packages and Subprograms -- + ------------------------------------ + + package Project_Stack is new Table.Table + (Table_Component_Type => Name_Id, + Table_Index_Type => Nat, + Table_Low_Bound => 1, + Table_Initial => 10, + Table_Increment => 10, + Table_Name => "Prj.Part.Project_Stack"); + -- This table is used to detect circular dependencies + -- for imported and modified projects. + + procedure Parse_Context_Clause + (Context_Clause : out Project_Node_Id; + Project_Directory : Name_Id); + -- Parse the context clause of a project + -- Does nothing if there is b\no context clause (if the current + -- token is not "with"). + + procedure Parse_Single_Project + (Project : out Project_Node_Id; + Path_Name : String; + Modified : Boolean); + -- Parse a project file. + -- Recursive procedure: it calls itself for imported and + -- modified projects. + + function Path_Name_Of + (File_Name : String; + Directory : String) + return String; + -- Returns the path name of a (non project) file. + -- Returns an empty string if file cannot be found. + + function Project_Path_Name_Of + (Project_File_Name : String; + Directory : String) + return String; + -- Returns the path name of a project file. + -- Returns an empty string if project file cannot be found. + + function Immediate_Directory_Of (Path_Name : Name_Id) return Name_Id; + -- Get the directory of the file with the specified path name. + -- This includes the directory separator as the last character. + -- Returns "./" if Path_Name contains no directory separator. + + function Simple_File_Name_Of (Path_Name : Name_Id) return Name_Id; + -- Returns the name of a file with the specified path name + -- with no directory information. + + function Project_Name_From (Path_Name : String) return Name_Id; + -- Returns the name of the project that corresponds to its path name. + -- Returns No_Name if the path name is invalid, because the corresponding + -- project name does not have the syntax of an ada identifier. + + ---------------------------- + -- Immediate_Directory_Of -- + ---------------------------- + + function Immediate_Directory_Of (Path_Name : Name_Id) return Name_Id is + begin + Get_Name_String (Path_Name); + + for Index in reverse 1 .. Name_Len loop + if Name_Buffer (Index) = '/' + or else Name_Buffer (Index) = Dir_Sep + then + -- Remove from name all characters after the last + -- directory separator. + + Name_Len := Index; + return Name_Find; + end if; + end loop; + + -- There is no directory separator in name. Return "./" or ".\". + Name_Len := 2; + Name_Buffer (1) := '.'; + Name_Buffer (2) := Dir_Sep; + return Name_Find; + end Immediate_Directory_Of; + + ----------- + -- Parse -- + ----------- + + procedure Parse + (Project : out Project_Node_Id; + Project_File_Name : String; + Always_Errout_Finalize : Boolean) + is + Current_Directory : constant String := Get_Current_Dir; + + begin + Project := Empty_Node; + + if Current_Verbosity >= Medium then + Write_Str ("ADA_PROJECT_PATH="""); + Write_Str (Project_Path.all); + Write_Line (""""); + end if; + + declare + Path_Name : constant String := + Project_Path_Name_Of (Project_File_Name, + Directory => Current_Directory); + + begin + -- Initialize the tables + + Tree_Private_Part.Project_Nodes.Set_Last (Empty_Node); + Tree_Private_Part.Projects_Htable.Reset; + + Errout.Initialize; + + -- And parse the main project file + + if Path_Name = "" then + Fail ("project file """ & Project_File_Name & """ not found"); + end if; + + Parse_Single_Project + (Project => Project, + Path_Name => Path_Name, + Modified => False); + + if Errout.Errors_Detected > 0 then + Project := Empty_Node; + end if; + + if Project = Empty_Node or else Always_Errout_Finalize then + Errout.Finalize; + end if; + end; + + exception + when X : others => + + -- Internal error + + Write_Line (Exception_Information (X)); + Write_Str ("Exception "); + Write_Str (Exception_Name (X)); + Write_Line (" raised, while processing project file"); + Project := Empty_Node; + end Parse; + + -------------------------- + -- Parse_Context_Clause -- + -------------------------- + + procedure Parse_Context_Clause + (Context_Clause : out Project_Node_Id; + Project_Directory : Name_Id) + is + Project_Directory_Path : constant String := + Get_Name_String (Project_Directory); + Current_With_Clause : Project_Node_Id := Empty_Node; + Next_With_Clause : Project_Node_Id := Empty_Node; + + begin + -- Assume no context clause + + Context_Clause := Empty_Node; + With_Loop : + + -- If Token is not "with", there is no context clause, + -- or we have exhausted the with clauses. + + while Token = Tok_With loop + Comma_Loop : + loop + -- Scan past "with" or "," + + Scan; + Expect (Tok_String_Literal, "literal string"); + + if Token /= Tok_String_Literal then + return; + end if; + + -- New with clause + + if Current_With_Clause = Empty_Node then + + -- First with clause of the context clause + + Current_With_Clause := Default_Project_Node + (Of_Kind => N_With_Clause); + Context_Clause := Current_With_Clause; + + else + Next_With_Clause := Default_Project_Node + (Of_Kind => N_With_Clause); + Set_Next_With_Clause_Of (Current_With_Clause, Next_With_Clause); + Current_With_Clause := Next_With_Clause; + end if; + + Set_String_Value_Of (Current_With_Clause, Strval (Token_Node)); + Set_Location_Of (Current_With_Clause, Token_Ptr); + String_To_Name_Buffer (String_Value_Of (Current_With_Clause)); + + declare + Original_Path : constant String := + Name_Buffer (1 .. Name_Len); + + Imported_Path_Name : constant String := + Project_Path_Name_Of + (Original_Path, + Project_Directory_Path); + + Withed_Project : Project_Node_Id := Empty_Node; + + begin + if Imported_Path_Name = "" then + + -- The project file cannot be found + + Name_Len := Original_Path'Length; + Name_Buffer (1 .. Name_Len) := Original_Path; + Error_Msg_Name_1 := Name_Find; + + Error_Msg ("unknown project file: {", Token_Ptr); + + else + -- Parse the imported project + + Parse_Single_Project + (Project => Withed_Project, + Path_Name => Imported_Path_Name, + Modified => False); + + if Withed_Project /= Empty_Node then + + -- If parsing was successful, record project name + -- and path name in with clause + + Set_Project_Node_Of (Current_With_Clause, Withed_Project); + Set_Name_Of (Current_With_Clause, + Name_Of (Withed_Project)); + Name_Len := Imported_Path_Name'Length; + Name_Buffer (1 .. Name_Len) := Imported_Path_Name; + Set_Path_Name_Of (Current_With_Clause, Name_Find); + end if; + end if; + end; + + Scan; + if Token = Tok_Semicolon then + + -- End of (possibly multiple) with clause; + -- Scan past the semicolon. + + Scan; + exit Comma_Loop; + + elsif Token /= Tok_Comma then + Error_Msg ("expected comma or semi colon", Token_Ptr); + exit Comma_Loop; + end if; + end loop Comma_Loop; + end loop With_Loop; + + end Parse_Context_Clause; + + -------------------------- + -- Parse_Single_Project -- + -------------------------- + + procedure Parse_Single_Project + (Project : out Project_Node_Id; + Path_Name : String; + Modified : Boolean) + is + Canonical_Path_Name : Name_Id; + Project_Directory : Name_Id; + Project_Scan_State : Saved_Project_Scan_State; + Source_Index : Source_File_Index; + + Modified_Project : Project_Node_Id := Empty_Node; + + A_Project_Name_And_Node : Tree_Private_Part.Project_Name_And_Node := + Tree_Private_Part.Projects_Htable.Get_First; + + Name_From_Path : constant Name_Id := Project_Name_From (Path_Name); + + use Tree_Private_Part; + + begin + Name_Len := Path_Name'Length; + Name_Buffer (1 .. Name_Len) := Path_Name; + Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); + Canonical_Path_Name := Name_Find; + + -- Check for a circular dependency + + for Index in 1 .. Project_Stack.Last loop + if Canonical_Path_Name = Project_Stack.Table (Index) then + Error_Msg ("circular dependency detected", Token_Ptr); + Error_Msg_Name_1 := Canonical_Path_Name; + Error_Msg ("\ { is imported by", Token_Ptr); + + for Current in reverse 1 .. Project_Stack.Last loop + Error_Msg_Name_1 := Project_Stack.Table (Current); + + if Error_Msg_Name_1 /= Canonical_Path_Name then + Error_Msg + ("\ { which itself is imported by", Token_Ptr); + + else + Error_Msg ("\ {", Token_Ptr); + exit; + end if; + end loop; + + Project := Empty_Node; + return; + end if; + end loop; + + Project_Stack.Increment_Last; + Project_Stack.Table (Project_Stack.Last) := Canonical_Path_Name; + + -- Check if the project file has already been parsed. + + while + A_Project_Name_And_Node /= Tree_Private_Part.No_Project_Name_And_Node + loop + if + Path_Name_Of (A_Project_Name_And_Node.Node) = Canonical_Path_Name + then + if Modified then + + if A_Project_Name_And_Node.Modified then + Error_Msg + ("cannot modify several times the same project file", + Token_Ptr); + + else + Error_Msg + ("cannot modify an imported project file", + Token_Ptr); + end if; + + elsif A_Project_Name_And_Node.Modified then + Error_Msg + ("cannot imported a modified project file", + Token_Ptr); + end if; + + Project := A_Project_Name_And_Node.Node; + Project_Stack.Decrement_Last; + return; + end if; + + A_Project_Name_And_Node := Tree_Private_Part.Projects_Htable.Get_Next; + end loop; + + -- We never encountered this project file + -- Save the scan state, load the project file and start to scan it. + + Save_Project_Scan_State (Project_Scan_State); + Source_Index := Load_Project_File (Path_Name); + + -- if we cannot find it, we stop + + if Source_Index = No_Source_File then + Project := Empty_Node; + Project_Stack.Decrement_Last; + return; + end if; + + Initialize_Scanner (Types.No_Unit, Source_Index); + + if Name_From_Path = No_Name then + + -- The project file name is not correct (no or bad extension, + -- or not following Ada identifier's syntax). + + Error_Msg_Name_1 := Canonical_Path_Name; + Error_Msg ("?{ is not a valid path name for a project file", + Token_Ptr); + end if; + + if Current_Verbosity >= Medium then + Write_Str ("Parsing """); + Write_Str (Path_Name); + Write_Char ('"'); + Write_Eol; + end if; + + Project_Directory := Immediate_Directory_Of (Canonical_Path_Name); + Project := Default_Project_Node (Of_Kind => N_Project); + Set_Directory_Of (Project, Project_Directory); + Set_Name_Of (Project, Simple_File_Name_Of (Canonical_Path_Name)); + Set_Path_Name_Of (Project, Canonical_Path_Name); + Set_Location_Of (Project, Token_Ptr); + + -- Is there any imported project? + + declare + First_With_Clause : Project_Node_Id := Empty_Node; + + begin + Parse_Context_Clause (Context_Clause => First_With_Clause, + Project_Directory => Project_Directory); + Set_First_With_Clause_Of (Project, First_With_Clause); + end; + + Expect (Tok_Project, "project"); + + -- Scan past "project" + + if Token = Tok_Project then + Set_Location_Of (Project, Token_Ptr); + Scan; + end if; + + Expect (Tok_Identifier, "identifier"); + + if Token = Tok_Identifier then + Set_Name_Of (Project, Token_Name); + + Get_Name_String (Token_Name); + Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); + + declare + Expected_Name : constant Name_Id := Name_Find; + + begin + if Name_From_Path /= No_Name + and then Expected_Name /= Name_From_Path + then + -- The project name is not the one that was expected from + -- the file name. Report a warning. + + Error_Msg_Name_1 := Expected_Name; + Error_Msg ("?file name does not match unit name, " & + "should be `{" & Project_File_Extension & "`", + Token_Ptr); + end if; + end; + + declare + Project_Name : Name_Id := + Tree_Private_Part.Projects_Htable.Get_First.Name; + + begin + -- Check if we already have a project with this name + + while Project_Name /= No_Name + and then Project_Name /= Token_Name + loop + Project_Name := Tree_Private_Part.Projects_Htable.Get_Next.Name; + end loop; + + if Project_Name /= No_Name then + Error_Msg ("duplicate project name", Token_Ptr); + + else + Tree_Private_Part.Projects_Htable.Set + (K => Token_Name, + E => (Name => Token_Name, + Node => Project, + Modified => Modified)); + end if; + end; + + -- Scan past the project name + + Scan; + + end if; + + if Token = Tok_Modifying then + + -- We are modifying another project + + -- Scan past "modifying" + + Scan; + + Expect (Tok_String_Literal, "literal string"); + + if Token = Tok_String_Literal then + Set_Modified_Project_Path_Of (Project, Strval (Token_Node)); + String_To_Name_Buffer (Modified_Project_Path_Of (Project)); + + declare + Original_Path_Name : constant String := + Name_Buffer (1 .. Name_Len); + + Modified_Project_Path_Name : constant String := + Project_Path_Name_Of + (Original_Path_Name, + Get_Name_String + (Project_Directory)); + + begin + if Modified_Project_Path_Name = "" then + + -- We could not find the project file to modify + + Name_Len := Original_Path_Name'Length; + Name_Buffer (1 .. Name_Len) := Original_Path_Name; + Error_Msg_Name_1 := Name_Find; + + Error_Msg ("unknown project file: {", Token_Ptr); + + else + Parse_Single_Project + (Project => Modified_Project, + Path_Name => Modified_Project_Path_Name, + Modified => True); + end if; + end; + + -- Scan past the modified project path + + Scan; + end if; + end if; + + Expect (Tok_Is, "is"); + + declare + Project_Declaration : Project_Node_Id := Empty_Node; + + begin + -- No need to Scan past "is", Prj.Dect.Parse will do it. + + Prj.Dect.Parse + (Declarations => Project_Declaration, + Current_Project => Project, + Modifying => Modified_Project); + Set_Project_Declaration_Of (Project, Project_Declaration); + end; + + Expect (Tok_End, "end"); + + -- Scan past "end" + + if Token = Tok_End then + Scan; + end if; + + Expect (Tok_Identifier, "identifier"); + + if Token = Tok_Identifier then + + -- We check if this is the project name + + if To_Lower (Get_Name_String (Token_Name)) /= + Get_Name_String (Name_Of (Project)) + then + Error_Msg ("Expected """ & + Get_Name_String (Name_Of (Project)) & """", + Token_Ptr); + end if; + end if; + + if Token /= Tok_Semicolon then + Scan; + end if; + + Expect (Tok_Semicolon, ";"); + + -- Restore the scan state, in case we are not the main project + + Restore_Project_Scan_State (Project_Scan_State); + + Project_Stack.Decrement_Last; + end Parse_Single_Project; + + ------------------ + -- Path_Name_Of -- + ------------------ + + function Path_Name_Of + (File_Name : String; + Directory : String) + return String + is + Result : String_Access; + + begin + Result := Locate_Regular_File (File_Name => File_Name, + Path => Directory); + + if Result = null then + return ""; + + else + Canonical_Case_File_Name (Result.all); + return Result.all; + end if; + end Path_Name_Of; + + ----------------------- + -- Project_Name_From -- + ----------------------- + + function Project_Name_From (Path_Name : String) return Name_Id is + Canonical : String (1 .. Path_Name'Length) := Path_Name; + First : Natural := Canonical'Last; + Last : Positive := First; + + begin + if First = 0 then + return No_Name; + end if; + + Canonical_Case_File_Name (Canonical); + + while First > 0 + and then + Canonical (First) /= '.' + loop + First := First - 1; + end loop; + + if Canonical (First) = '.' then + if Canonical (First .. Last) = Project_File_Extension + and then First /= 1 + then + First := First - 1; + Last := First; + + while First > 0 + and then Canonical (First) /= '/' + and then Canonical (First) /= Dir_Sep + loop + First := First - 1; + end loop; + + else + return No_Name; + end if; + + else + return No_Name; + end if; + + if Canonical (First) = '/' + or else Canonical (First) = Dir_Sep + then + First := First + 1; + end if; + + Name_Len := Last - First + 1; + Name_Buffer (1 .. Name_Len) := To_Lower (Canonical (First .. Last)); + + if not Is_Letter (Name_Buffer (1)) then + return No_Name; + + else + for Index in 2 .. Name_Len - 1 loop + if Name_Buffer (Index) = '_' then + if Name_Buffer (Index + 1) = '_' then + return No_Name; + end if; + + elsif not Is_Alphanumeric (Name_Buffer (Index)) then + return No_Name; + end if; + + end loop; + + if not Is_Alphanumeric (Name_Buffer (Name_Len)) then + return No_Name; + + else + return Name_Find; + end if; + + end if; + end Project_Name_From; + + -------------------------- + -- Project_Path_Name_Of -- + -------------------------- + + function Project_Path_Name_Of + (Project_File_Name : String; + Directory : String) + return String + is + Result : String_Access; + + begin + -- First we try <file_name>.<extension> + + if Current_Verbosity = High then + Write_Str ("Project_Path_Name_Of ("""); + Write_Str (Project_File_Name); + Write_Str (""", """); + Write_Str (Directory); + Write_Line (""");"); + Write_Str (" Trying "); + Write_Str (Project_File_Name); + Write_Line (Project_File_Extension); + end if; + + Result := + Locate_Regular_File + (File_Name => Project_File_Name & Project_File_Extension, + Path => Project_Path.all); + + -- Then we try <file_name> + + if Result = null then + if Current_Verbosity = High then + Write_Str (" Trying "); + Write_Line (Project_File_Name); + end if; + + Result := + Locate_Regular_File + (File_Name => Project_File_Name, + Path => Project_Path.all); + + -- The we try <directory>/<file_name>.<extension> + + if Result = null then + if Current_Verbosity = High then + Write_Str (" Trying "); + Write_Str (Directory); + Write_Str (Project_File_Name); + Write_Line (Project_File_Extension); + end if; + + Result := + Locate_Regular_File + (File_Name => Directory & Project_File_Name & + Project_File_Extension, + Path => Project_Path.all); + + -- Then we try <directory>/<file_name> + + if Result = null then + if Current_Verbosity = High then + Write_Str (" Trying "); + Write_Str (Directory); + Write_Line (Project_File_Name); + end if; + + Result := + Locate_Regular_File + (File_Name => Directory & Project_File_Name, + Path => Project_Path.all); + end if; + end if; + end if; + + -- If we cannot find the project file, we return an empty string + + if Result = null then + return ""; + + else + declare + Final_Result : String + := GNAT.OS_Lib.Normalize_Pathname (Result.all); + begin + Free (Result); + Canonical_Case_File_Name (Final_Result); + return Final_Result; + end; + + end if; + + end Project_Path_Name_Of; + + ------------------------- + -- Simple_File_Name_Of -- + ------------------------- + + function Simple_File_Name_Of (Path_Name : Name_Id) return Name_Id is + begin + Get_Name_String (Path_Name); + + for Index in reverse 1 .. Name_Len loop + if Name_Buffer (Index) = '/' + or else Name_Buffer (Index) = Dir_Sep + then + exit when Index = Name_Len; + Name_Buffer (1 .. Name_Len - Index) := + Name_Buffer (Index + 1 .. Name_Len); + Name_Len := Name_Len - Index; + return Name_Find; + end if; + end loop; + + return No_Name; + + end Simple_File_Name_Of; + +begin + Canonical_Case_File_Name (Project_File_Extension); + + if Prj_Path.all = "" then + Project_Path := new String'("."); + + else + Project_Path := new String'("." & Path_Separator & Prj_Path.all); + end if; + +end Prj.Part; diff --git a/gcc/ada/prj-part.ads b/gcc/ada/prj-part.ads new file mode 100644 index 00000000000..d960b732b35 --- /dev/null +++ b/gcc/ada/prj-part.ads @@ -0,0 +1,46 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J . P A R T -- +-- -- +-- S p e c -- +-- -- +-- $Revision: 1.3 $ +-- -- +-- Copyright (C) 2000-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ +-- +-- Implements the parsing of project files into a tree. + +with Prj.Tree; use Prj.Tree; + +package Prj.Part is + + procedure Parse + (Project : out Project_Node_Id; + Project_File_Name : String; + Always_Errout_Finalize : Boolean); + -- Parse a project file and all its imported project files + -- and create a tree. + -- Return the node for the project (or Empty_Node if parsing failed). + -- If Always_Errout_Finalize is True, Errout.Finalize is called + -- in all cases; otherwise, Errout.Finalize is only called if there are + -- errors (but not if there are only warnings). + +end Prj.Part; diff --git a/gcc/ada/prj-proc.adb b/gcc/ada/prj-proc.adb new file mode 100644 index 00000000000..4822596f964 --- /dev/null +++ b/gcc/ada/prj-proc.adb @@ -0,0 +1,1371 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J . P R O C -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.16 $ +-- -- +-- Copyright (C) 2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +with Errout; use Errout; +with Namet; use Namet; +with Opt; +with Output; use Output; +with Prj.Attr; use Prj.Attr; +with Prj.Com; use Prj.Com; +with Prj.Ext; use Prj.Ext; +with Prj.Nmsc; use Prj.Nmsc; +with Stringt; use Stringt; + +with GNAT.HTable; + +package body Prj.Proc is + + Error_Report : Put_Line_Access := null; + + package Processed_Projects is new GNAT.HTable.Simple_HTable + (Header_Num => Header_Num, + Element => Project_Id, + No_Element => No_Project, + Key => Name_Id, + Hash => Hash, + Equal => "="); + -- This hash table contains all processed projects + + procedure Add (To_Exp : in out String_Id; Str : String_Id); + -- Concatenate two strings and returns another string if both + -- arguments are not null string. + + procedure Add_Attributes + (Decl : in out Declarations; + First : Attribute_Node_Id); + -- Add all attributes, starting with First, with their default + -- values to the package or project with declarations Decl. + + function Expression + (Project : Project_Id; + From_Project_Node : Project_Node_Id; + Pkg : Package_Id; + First_Term : Project_Node_Id; + Kind : Variable_Kind) + return Variable_Value; + -- From N_Expression project node From_Project_Node, compute the value + -- of an expression and return it as a Variable_Value. + + function Imported_Or_Modified_Project_From + (Project : Project_Id; + With_Name : Name_Id) + return Project_Id; + -- Find an imported or modified project of Project whose name is With_Name. + + function Package_From + (Project : Project_Id; + With_Name : Name_Id) + return Package_Id; + -- Find the package of Project whose name is With_Name. + + procedure Process_Declarative_Items + (Project : Project_Id; + From_Project_Node : Project_Node_Id; + Pkg : Package_Id; + Item : Project_Node_Id); + -- Process declarative items starting with From_Project_Node, and put them + -- in declarations Decl. This is a recursive procedure; it calls itself for + -- a package declaration or a case construction. + + procedure Recursive_Process + (Project : out Project_Id; + From_Project_Node : Project_Node_Id; + Modified_By : Project_Id); + -- Process project with node From_Project_Node in the tree. + -- Do nothing if From_Project_Node is Empty_Node. + -- If project has already been processed, simply return its project id. + -- Otherwise create a new project id, mark it as processed, call itself + -- recursively for all imported projects and a modified project, if any. + -- Then process the declarative items of the project. + + procedure Check (Project : in out Project_Id); + -- Set all projects to not checked, then call Recursive_Check for + -- the main project Project. + -- Project is set to No_Project if errors occurred. + + procedure Recursive_Check (Project : Project_Id); + -- If Project is marked as not checked, mark it as checked, + -- call Check_Naming_Scheme for the project, then call itself + -- for a possible modified project and all the imported projects + -- of Project. + + --------- + -- Add -- + --------- + + procedure Add (To_Exp : in out String_Id; Str : String_Id) is + begin + if To_Exp = Types.No_String or else String_Length (To_Exp) = 0 then + + -- To_Exp is nil or empty. The result is Str. + + To_Exp := Str; + + -- If Str is nil, then do not change To_Ext + + elsif Str /= No_String then + Start_String (To_Exp); + Store_String_Chars (Str); + To_Exp := End_String; + end if; + end Add; + + -------------------- + -- Add_Attributes -- + -------------------- + + procedure Add_Attributes + (Decl : in out Declarations; + First : Attribute_Node_Id) is + The_Attribute : Attribute_Node_Id := First; + Attribute_Data : Attribute_Record; + + begin + while The_Attribute /= Empty_Attribute loop + Attribute_Data := Attributes.Table (The_Attribute); + + if Attribute_Data.Kind_2 /= Associative_Array then + declare + New_Attribute : Variable_Value; + + begin + case Attribute_Data.Kind_1 is + + -- Undefined should not happen + + when Undefined => + pragma Assert + (False, "attribute with an undefined kind"); + raise Program_Error; + + -- Single attributes have a default value of empty string + + when Single => + New_Attribute := + (Kind => Single, + Location => No_Location, + Default => True, + Value => Empty_String); + + -- List attributes have a default value of nil list + + when List => + New_Attribute := + (Kind => List, + Location => No_Location, + Default => True, + Values => Nil_String); + + end case; + + Variable_Elements.Increment_Last; + Variable_Elements.Table (Variable_Elements.Last) := + (Next => Decl.Attributes, + Name => Attribute_Data.Name, + Value => New_Attribute); + Decl.Attributes := Variable_Elements.Last; + end; + end if; + + The_Attribute := Attributes.Table (The_Attribute).Next; + end loop; + + end Add_Attributes; + + ----------- + -- Check -- + ----------- + + procedure Check (Project : in out Project_Id) is + begin + -- Make sure that all projects are marked as not checked. + + for Index in 1 .. Projects.Last loop + Projects.Table (Index).Checked := False; + end loop; + + Recursive_Check (Project); + + if Errout.Errors_Detected > 0 then + Project := No_Project; + end if; + + end Check; + + ---------------- + -- Expression -- + ---------------- + + function Expression + (Project : Project_Id; + From_Project_Node : Project_Node_Id; + Pkg : Package_Id; + First_Term : Project_Node_Id; + Kind : Variable_Kind) + return Variable_Value + is + The_Term : Project_Node_Id := First_Term; + -- The term in the expression list + + The_Current_Term : Project_Node_Id := Empty_Node; + -- The current term node id + + Term_Kind : Variable_Kind; + -- The kind of the current term + + Result : Variable_Value (Kind => Kind); + -- The returned result + + Last : String_List_Id := Nil_String; + -- Reference to the last string elements in Result, when Kind is List. + + begin + Result.Location := Location_Of (From_Project_Node); + + -- Process each term of the expression, starting with First_Term + + while The_Term /= Empty_Node loop + + -- We get the term data and kind ... + + Term_Kind := Expression_Kind_Of (The_Term); + + The_Current_Term := Current_Term (The_Term); + + case Kind_Of (The_Current_Term) is + + when N_Literal_String => + + case Kind is + + when Undefined => + + -- Should never happen + + pragma Assert (False, "Undefined expression kind"); + raise Program_Error; + + when Single => + Add (Result.Value, String_Value_Of (The_Current_Term)); + + when List => + + String_Elements.Increment_Last; + + if Last = Nil_String then + + -- This can happen in an expression such as + -- () & "toto" + + Result.Values := String_Elements.Last; + + else + String_Elements.Table (Last).Next := + String_Elements.Last; + end if; + + Last := String_Elements.Last; + String_Elements.Table (Last) := + (Value => String_Value_Of (The_Current_Term), + Location => Location_Of (The_Current_Term), + Next => Nil_String); + + end case; + + when N_Literal_String_List => + + declare + String_Node : Project_Node_Id := + First_Expression_In_List (The_Current_Term); + + Value : Variable_Value; + + begin + if String_Node /= Empty_Node then + + -- If String_Node is nil, it is an empty list, + -- there is nothing to do + + Value := Expression + (Project => Project, + From_Project_Node => From_Project_Node, + Pkg => Pkg, + First_Term => Tree.First_Term (String_Node), + Kind => Single); + String_Elements.Increment_Last; + + if Result.Values = Nil_String then + + -- This literal string list is the first term + -- in a string list expression + + Result.Values := String_Elements.Last; + + else + String_Elements.Table (Last).Next := + String_Elements.Last; + end if; + + Last := String_Elements.Last; + String_Elements.Table (Last) := + (Value => Value.Value, + Location => Value.Location, + Next => Nil_String); + + loop + -- Add the other element of the literal string list + -- one after the other + + String_Node := + Next_Expression_In_List (String_Node); + + exit when String_Node = Empty_Node; + + Value := + Expression + (Project => Project, + From_Project_Node => From_Project_Node, + Pkg => Pkg, + First_Term => Tree.First_Term (String_Node), + Kind => Single); + + String_Elements.Increment_Last; + String_Elements.Table (Last).Next := + String_Elements.Last; + Last := String_Elements.Last; + String_Elements.Table (Last) := + (Value => Value.Value, + Location => Value.Location, + Next => Nil_String); + end loop; + + end if; + + end; + + when N_Variable_Reference | N_Attribute_Reference => + + declare + The_Project : Project_Id := Project; + The_Package : Package_Id := Pkg; + The_Name : Name_Id := No_Name; + The_Variable_Id : Variable_Id := No_Variable; + The_Variable : Variable; + Term_Project : constant Project_Node_Id := + Project_Node_Of (The_Current_Term); + Term_Package : constant Project_Node_Id := + Package_Node_Of (The_Current_Term); + + begin + if Term_Project /= Empty_Node and then + Term_Project /= From_Project_Node + then + -- This variable or attribute comes from another project + + The_Name := Name_Of (Term_Project); + The_Project := Imported_Or_Modified_Project_From + (Project => Project, With_Name => The_Name); + end if; + + if Term_Package /= Empty_Node then + + -- This is an attribute of a package + + The_Name := Name_Of (Term_Package); + The_Package := Projects.Table (The_Project).Decl.Packages; + + while The_Package /= No_Package + and then Packages.Table (The_Package).Name /= The_Name + loop + The_Package := Packages.Table (The_Package).Next; + end loop; + + pragma Assert + (The_Package /= No_Package, + "package not found."); + + elsif Kind_Of (The_Current_Term) = N_Attribute_Reference then + The_Package := No_Package; + end if; + + The_Name := Name_Of (The_Current_Term); + + if The_Package /= No_Package then + + -- First, if there is a package, look into the package + + if Kind_Of (The_Current_Term) = N_Variable_Reference then + The_Variable_Id := + Packages.Table (The_Package).Decl.Variables; + + else + The_Variable_Id := + Packages.Table (The_Package).Decl.Attributes; + end if; + + while The_Variable_Id /= No_Variable + and then + Variable_Elements.Table (The_Variable_Id).Name /= + The_Name + loop + The_Variable_Id := + Variable_Elements.Table (The_Variable_Id).Next; + end loop; + + end if; + + if The_Variable_Id = No_Variable then + + -- If we have not found it, look into the project + + if Kind_Of (The_Current_Term) = N_Variable_Reference then + The_Variable_Id := + Projects.Table (The_Project).Decl.Variables; + + else + The_Variable_Id := + Projects.Table (The_Project).Decl.Attributes; + end if; + + while The_Variable_Id /= No_Variable + and then + Variable_Elements.Table (The_Variable_Id).Name /= + The_Name + loop + The_Variable_Id := + Variable_Elements.Table (The_Variable_Id).Next; + end loop; + + end if; + + pragma Assert (The_Variable_Id /= No_Variable, + "variable or attribute not found"); + + The_Variable := Variable_Elements.Table (The_Variable_Id); + + case Kind is + + when Undefined => + + -- Should never happen + + pragma Assert (False, "undefined expression kind"); + null; + + when Single => + + case The_Variable.Value.Kind is + + when Undefined => + null; + + when Single => + Add (Result.Value, The_Variable.Value.Value); + + when List => + + -- Should never happen + + pragma Assert + (False, + "list cannot appear in single " & + "string expression"); + null; + + end case; + + when List => + case The_Variable.Value.Kind is + + when Undefined => + null; + + when Single => + String_Elements.Increment_Last; + + if Last = Nil_String then + + -- This can happen in an expression such as + -- () & Var + + Result.Values := String_Elements.Last; + + else + String_Elements.Table (Last).Next := + String_Elements.Last; + end if; + + Last := String_Elements.Last; + String_Elements.Table (Last) := + (Value => The_Variable.Value.Value, + Location => Location_Of (The_Current_Term), + Next => Nil_String); + + when List => + + declare + The_List : String_List_Id := + The_Variable.Value.Values; + + begin + while The_List /= Nil_String loop + String_Elements.Increment_Last; + + if Last = Nil_String then + Result.Values := String_Elements.Last; + + else + String_Elements.Table (Last).Next := + String_Elements.Last; + + end if; + + Last := String_Elements.Last; + String_Elements.Table (Last) := + (Value => + String_Elements.Table + (The_List).Value, + Location => Location_Of + (The_Current_Term), + Next => Nil_String); + The_List := + String_Elements.Table (The_List).Next; + + end loop; + end; + end case; + end case; + end; + + when N_External_Value => + String_To_Name_Buffer + (String_Value_Of (External_Reference_Of (The_Current_Term))); + + declare + Name : constant Name_Id := Name_Find; + Default : String_Id := No_String; + Value : String_Id := No_String; + + Default_Node : constant Project_Node_Id := + External_Default_Of (The_Current_Term); + + begin + if Default_Node /= Empty_Node then + Default := String_Value_Of (Default_Node); + end if; + + Value := Prj.Ext.Value_Of (Name, Default); + + if Value = No_String then + if Error_Report = null then + Error_Msg + ("undefined external reference", + Location_Of (The_Current_Term)); + + else + Error_Report + ("""" & Get_Name_String (Name) & + """ is an undefined external reference"); + end if; + + Value := Empty_String; + + end if; + + case Kind is + + when Undefined => + null; + + when Single => + Add (Result.Value, Value); + + when List => + String_Elements.Increment_Last; + + if Last = Nil_String then + Result.Values := String_Elements.Last; + + else + String_Elements.Table (Last).Next := + String_Elements.Last; + end if; + + Last := String_Elements.Last; + String_Elements.Table (Last) := + (Value => Value, + Location => Location_Of (The_Current_Term), + Next => Nil_String); + + end case; + + end; + + when others => + + -- Should never happen + + pragma Assert + (False, + "illegal node kind in an expression"); + raise Program_Error; + + end case; + + The_Term := Next_Term (The_Term); + + end loop; + return Result; + end Expression; + + --------------------------------------- + -- Imported_Or_Modified_Project_From -- + --------------------------------------- + + function Imported_Or_Modified_Project_From + (Project : Project_Id; + With_Name : Name_Id) + return Project_Id + is + Data : constant Project_Data := Projects.Table (Project); + List : Project_List := Data.Imported_Projects; + + begin + -- First check if it is the name of a modified project + + if Data.Modifies /= No_Project + and then Projects.Table (Data.Modifies).Name = With_Name + then + return Data.Modifies; + + else + -- Then check the name of each imported project + + while List /= Empty_Project_List + and then + Projects.Table + (Project_Lists.Table (List).Project).Name /= With_Name + + loop + List := Project_Lists.Table (List).Next; + end loop; + + pragma Assert + (List /= Empty_Project_List, + "project not found"); + + return Project_Lists.Table (List).Project; + end if; + + end Imported_Or_Modified_Project_From; + + ------------------ + -- Package_From -- + ------------------ + + function Package_From + (Project : Project_Id; + With_Name : Name_Id) + return Package_Id + is + Data : constant Project_Data := Projects.Table (Project); + Result : Package_Id := Data.Decl.Packages; + + begin + -- Check the name of each existing package of Project + + while Result /= No_Package + and then + Packages.Table (Result).Name /= With_Name + loop + Result := Packages.Table (Result).Next; + end loop; + + if Result = No_Package then + -- Should never happen + Write_Line ("package """ & Get_Name_String (With_Name) & + """ not found"); + raise Program_Error; + + else + return Result; + end if; + end Package_From; + + ------------- + -- Process -- + ------------- + + procedure Process + (Project : out Project_Id; + From_Project_Node : Project_Node_Id; + Report_Error : Put_Line_Access) + is + begin + Error_Report := Report_Error; + + -- Make sure there is no projects in the data structure + + Projects.Set_Last (No_Project); + Processed_Projects.Reset; + + -- And process the main project and all of the projects it depends on, + -- recursively + + Recursive_Process + (Project => Project, + From_Project_Node => From_Project_Node, + Modified_By => No_Project); + + if Errout.Errors_Detected > 0 then + Project := No_Project; + end if; + + if Project /= No_Project then + Check (Project); + end if; + + end Process; + + ------------------------------- + -- Process_Declarative_Items -- + ------------------------------- + + procedure Process_Declarative_Items + (Project : Project_Id; + From_Project_Node : Project_Node_Id; + Pkg : Package_Id; + Item : Project_Node_Id) is + + Current_Declarative_Item : Project_Node_Id := Item; + + Current_Item : Project_Node_Id := Empty_Node; + + begin + -- For each declarative item + + while Current_Declarative_Item /= Empty_Node loop + + -- Get its data + + Current_Item := Current_Item_Node (Current_Declarative_Item); + + -- And set Current_Declarative_Item to the next declarative item + -- ready for the next iteration + + Current_Declarative_Item := Next_Declarative_Item + (Current_Declarative_Item); + + case Kind_Of (Current_Item) is + + when N_Package_Declaration => + Packages.Increment_Last; + + declare + New_Pkg : constant Package_Id := Packages.Last; + The_New_Package : Package_Element; + + Project_Of_Renamed_Package : constant Project_Node_Id := + Project_Of_Renamed_Package_Of + (Current_Item); + + begin + The_New_Package.Name := Name_Of (Current_Item); + + if Pkg /= No_Package then + The_New_Package.Next := + Packages.Table (Pkg).Decl.Packages; + Packages.Table (Pkg).Decl.Packages := New_Pkg; + else + The_New_Package.Next := + Projects.Table (Project).Decl.Packages; + Projects.Table (Project).Decl.Packages := New_Pkg; + end if; + + Packages.Table (New_Pkg) := The_New_Package; + + if Project_Of_Renamed_Package /= Empty_Node then + + -- Renamed package + + declare + Project_Name : constant Name_Id := + Name_Of + (Project_Of_Renamed_Package); + + Renamed_Project : constant Project_Id := + Imported_Or_Modified_Project_From + (Project, Project_Name); + + Renamed_Package : constant Package_Id := + Package_From + (Renamed_Project, + Name_Of (Current_Item)); + + begin + Packages.Table (New_Pkg).Decl := + Packages.Table (Renamed_Package).Decl; + end; + + else + -- Set the default values of the attributes + + Add_Attributes + (Packages.Table (New_Pkg).Decl, + Package_Attributes.Table + (Package_Id_Of (Current_Item)).First_Attribute); + + Process_Declarative_Items + (Project => Project, + From_Project_Node => From_Project_Node, + Pkg => New_Pkg, + Item => First_Declarative_Item_Of + (Current_Item)); + end if; + + end; + + when N_String_Type_Declaration => + + -- There is nothing to process + + null; + + when N_Attribute_Declaration | + N_Typed_Variable_Declaration | + N_Variable_Declaration => + + pragma Assert (Expression_Of (Current_Item) /= Empty_Node, + "no expression for an object declaration"); + + declare + New_Value : constant Variable_Value := + Expression + (Project => Project, + From_Project_Node => From_Project_Node, + Pkg => Pkg, + First_Term => + Tree.First_Term (Expression_Of + (Current_Item)), + Kind => + Expression_Kind_Of (Current_Item)); + + The_Variable : Variable_Id := No_Variable; + + Current_Item_Name : constant Name_Id := + Name_Of (Current_Item); + + begin + if Kind_Of (Current_Item) = N_Typed_Variable_Declaration then + + if String_Equal (New_Value.Value, Empty_String) then + Error_Msg_Name_1 := Name_Of (Current_Item); + + if Error_Report = null then + Error_Msg + ("no value defined for %", + Location_Of (Current_Item)); + + else + Error_Report + ("no value defined for " & + Get_Name_String (Error_Msg_Name_1)); + end if; + + else + declare + Current_String : Project_Node_Id := + First_Literal_String + (String_Type_Of + (Current_Item)); + + begin + while Current_String /= Empty_Node + and then not String_Equal + (String_Value_Of (Current_String), + New_Value.Value) + loop + Current_String := + Next_Literal_String (Current_String); + end loop; + + if Current_String = Empty_Node then + String_To_Name_Buffer (New_Value.Value); + Error_Msg_Name_1 := Name_Find; + Error_Msg_Name_2 := Name_Of (Current_Item); + + if Error_Report = null then + Error_Msg + ("value { is illegal for typed string %", + Location_Of (Current_Item)); + + else + Error_Report + ("value """ & + Get_Name_String (Error_Msg_Name_1) & + """ is illegal for typed string """ & + Get_Name_String (Error_Msg_Name_2) & + """"); + end if; + end if; + end; + end if; + end if; + + if Kind_Of (Current_Item) /= N_Attribute_Declaration + or else + Associative_Array_Index_Of (Current_Item) = No_String + then + -- Usual case + + -- Code below really needs more comments ??? + + if Kind_Of (Current_Item) = N_Attribute_Declaration then + if Pkg /= No_Package then + The_Variable := + Packages.Table (Pkg).Decl.Attributes; + + else + The_Variable := + Projects.Table (Project).Decl.Attributes; + end if; + + else + if Pkg /= No_Package then + The_Variable := + Packages.Table (Pkg).Decl.Variables; + + else + The_Variable := + Projects.Table (Project).Decl.Variables; + end if; + + end if; + + while + The_Variable /= No_Variable + and then + Variable_Elements.Table (The_Variable).Name /= + Current_Item_Name + loop + The_Variable := + Variable_Elements.Table (The_Variable).Next; + end loop; + + if The_Variable = No_Variable then + pragma Assert + (Kind_Of (Current_Item) /= N_Attribute_Declaration, + "illegal attribute declaration"); + + Variable_Elements.Increment_Last; + The_Variable := Variable_Elements.Last; + + if Pkg /= No_Package then + Variable_Elements.Table (The_Variable) := + (Next => + Packages.Table (Pkg).Decl.Variables, + Name => Current_Item_Name, + Value => New_Value); + Packages.Table (Pkg).Decl.Variables := The_Variable; + + else + Variable_Elements.Table (The_Variable) := + (Next => + Projects.Table (Project).Decl.Variables, + Name => Current_Item_Name, + Value => New_Value); + Projects.Table (Project).Decl.Variables := + The_Variable; + end if; + + else + Variable_Elements.Table (The_Variable).Value := + New_Value; + + end if; + + else + -- Associative array attribute + + String_To_Name_Buffer + (Associative_Array_Index_Of (Current_Item)); + + declare + The_Array : Array_Id; + + The_Array_Element : Array_Element_Id := + No_Array_Element; + + Index_Name : constant Name_Id := Name_Find; + + begin + + if Pkg /= No_Package then + The_Array := Packages.Table (Pkg).Decl.Arrays; + + else + The_Array := Projects.Table (Project).Decl.Arrays; + end if; + + while + The_Array /= No_Array + and then Arrays.Table (The_Array).Name /= + Current_Item_Name + loop + The_Array := Arrays.Table (The_Array).Next; + end loop; + + if The_Array = No_Array then + Arrays.Increment_Last; + The_Array := Arrays.Last; + + if Pkg /= No_Package then + Arrays.Table (The_Array) := + (Name => Current_Item_Name, + Value => No_Array_Element, + Next => Packages.Table (Pkg).Decl.Arrays); + Packages.Table (Pkg).Decl.Arrays := The_Array; + + else + Arrays.Table (The_Array) := + (Name => Current_Item_Name, + Value => No_Array_Element, + Next => + Projects.Table (Project).Decl.Arrays); + Projects.Table (Project).Decl.Arrays := + The_Array; + end if; + + else + The_Array_Element := Arrays.Table (The_Array).Value; + end if; + + while The_Array_Element /= No_Array_Element + and then + Array_Elements.Table (The_Array_Element).Index /= + Index_Name + loop + The_Array_Element := + Array_Elements.Table (The_Array_Element).Next; + end loop; + + if The_Array_Element = No_Array_Element then + Array_Elements.Increment_Last; + The_Array_Element := Array_Elements.Last; + Array_Elements.Table (The_Array_Element) := + (Index => Index_Name, + Value => New_Value, + Next => Arrays.Table (The_Array).Value); + Arrays.Table (The_Array).Value := The_Array_Element; + + else + Array_Elements.Table (The_Array_Element).Value := + New_Value; + end if; + end; + end if; + end; + + when N_Case_Construction => + declare + The_Project : Project_Id := Project; + The_Package : Package_Id := Pkg; + The_Variable : Variable_Value := Nil_Variable_Value; + Case_Value : String_Id := No_String; + Case_Item : Project_Node_Id := Empty_Node; + Choice_String : Project_Node_Id := Empty_Node; + Decl_Item : Project_Node_Id := Empty_Node; + + begin + declare + Variable_Node : constant Project_Node_Id := + Case_Variable_Reference_Of + (Current_Item); + + Var_Id : Variable_Id := No_Variable; + Name : Name_Id := No_Name; + + begin + if Project_Node_Of (Variable_Node) /= Empty_Node then + Name := Name_Of (Project_Node_Of (Variable_Node)); + The_Project := + Imported_Or_Modified_Project_From (Project, Name); + end if; + + if Package_Node_Of (Variable_Node) /= Empty_Node then + Name := Name_Of (Package_Node_Of (Variable_Node)); + The_Package := Package_From (The_Project, Name); + end if; + + Name := Name_Of (Variable_Node); + + if The_Package /= No_Package then + Var_Id := Packages.Table (The_Package).Decl.Variables; + Name := Name_Of (Variable_Node); + while Var_Id /= No_Variable + and then + Variable_Elements.Table (Var_Id).Name /= Name + loop + Var_Id := Variable_Elements.Table (Var_Id).Next; + end loop; + end if; + + if Var_Id = No_Variable + and then Package_Node_Of (Variable_Node) = Empty_Node + then + Var_Id := Projects.Table (The_Project).Decl.Variables; + while Var_Id /= No_Variable + and then + Variable_Elements.Table (Var_Id).Name /= Name + loop + Var_Id := Variable_Elements.Table (Var_Id).Next; + end loop; + end if; + + if Var_Id = No_Variable then + + -- Should never happen + + Write_Line ("variable """ & + Get_Name_String (Name) & + """ not found"); + raise Program_Error; + end if; + + The_Variable := Variable_Elements.Table (Var_Id).Value; + + if The_Variable.Kind /= Single then + + -- Should never happen + + Write_Line ("variable""" & + Get_Name_String (Name) & + """ is not a single string variable"); + raise Program_Error; + end if; + + Case_Value := The_Variable.Value; + end; + + Case_Item := First_Case_Item_Of (Current_Item); + Case_Item_Loop : + while Case_Item /= Empty_Node loop + Choice_String := First_Choice_Of (Case_Item); + + if Choice_String = Empty_Node then + Decl_Item := First_Declarative_Item_Of (Case_Item); + exit Case_Item_Loop; + end if; + + Choice_Loop : + while Choice_String /= Empty_Node loop + if String_Equal (Case_Value, + String_Value_Of (Choice_String)) + then + Decl_Item := + First_Declarative_Item_Of (Case_Item); + exit Case_Item_Loop; + end if; + + Choice_String := + Next_Literal_String (Choice_String); + end loop Choice_Loop; + Case_Item := Next_Case_Item (Case_Item); + end loop Case_Item_Loop; + + if Decl_Item /= Empty_Node then + Process_Declarative_Items + (Project => Project, + From_Project_Node => From_Project_Node, + Pkg => Pkg, + Item => Decl_Item); + end if; + end; + + when others => + + -- Should never happen + + Write_Line ("Illegal declarative item: " & + Project_Node_Kind'Image (Kind_Of (Current_Item))); + raise Program_Error; + end case; + end loop; + end Process_Declarative_Items; + + --------------------- + -- Recursive_Check -- + --------------------- + + procedure Recursive_Check (Project : Project_Id) is + Data : Project_Data; + Imported_Project_List : Project_List := Empty_Project_List; + + begin + -- Do nothing if Project is No_Project, or Project has already + -- been marked as checked. + + if Project /= No_Project + and then not Projects.Table (Project).Checked + then + Data := Projects.Table (Project); + + -- Call itself for a possible modified project. + -- (if there is no modified project, then nothing happens). + + Recursive_Check (Data.Modifies); + + -- Call itself for all imported projects + + Imported_Project_List := Data.Imported_Projects; + while Imported_Project_List /= Empty_Project_List loop + Recursive_Check + (Project_Lists.Table (Imported_Project_List).Project); + Imported_Project_List := + Project_Lists.Table (Imported_Project_List).Next; + end loop; + + -- Mark project as checked + + Projects.Table (Project).Checked := True; + + if Opt.Verbose_Mode then + Write_Str ("Checking project file """); + Write_Str (Get_Name_String (Data.Name)); + Write_Line (""""); + end if; + + Prj.Nmsc.Check_Naming_Scheme (Project, Error_Report); + end if; + + end Recursive_Check; + + ----------------------- + -- Recursive_Process -- + ----------------------- + + procedure Recursive_Process + (Project : out Project_Id; + From_Project_Node : Project_Node_Id; + Modified_By : Project_Id) + is + With_Clause : Project_Node_Id; + + begin + if From_Project_Node = Empty_Node then + Project := No_Project; + + else + declare + Processed_Data : Project_Data := Empty_Project; + Imported : Project_List := Empty_Project_List; + Declaration_Node : Project_Node_Id := Empty_Node; + Name : constant Name_Id := + Name_Of (From_Project_Node); + + begin + Project := Processed_Projects.Get (Name); + + if Project /= No_Project then + return; + end if; + + Projects.Increment_Last; + Project := Projects.Last; + Processed_Projects.Set (Name, Project); + Processed_Data.Name := Name; + Processed_Data.Path_Name := Path_Name_Of (From_Project_Node); + Processed_Data.Location := Location_Of (From_Project_Node); + Processed_Data.Directory := Directory_Of (From_Project_Node); + Processed_Data.Modified_By := Modified_By; + Add_Attributes (Processed_Data.Decl, Attribute_First); + With_Clause := First_With_Clause_Of (From_Project_Node); + + while With_Clause /= Empty_Node loop + declare + New_Project : Project_Id; + New_Data : Project_Data; + + begin + Recursive_Process + (Project => New_Project, + From_Project_Node => Project_Node_Of (With_Clause), + Modified_By => No_Project); + New_Data := Projects.Table (New_Project); + + -- If we were the first project to import it, + -- set First_Referred_By to us. + + if New_Data.First_Referred_By = No_Project then + New_Data.First_Referred_By := Project; + Projects.Table (New_Project) := New_Data; + end if; + + -- Add this project to our list of imported projects + + Project_Lists.Increment_Last; + Project_Lists.Table (Project_Lists.Last) := + (Project => New_Project, Next => Empty_Project_List); + + -- Imported is the id of the last imported project. + -- If it is nil, then this imported project is our first. + + if Imported = Empty_Project_List then + Processed_Data.Imported_Projects := Project_Lists.Last; + + else + Project_Lists.Table (Imported).Next := Project_Lists.Last; + end if; + + Imported := Project_Lists.Last; + + With_Clause := Next_With_Clause_Of (With_Clause); + end; + end loop; + + Declaration_Node := Project_Declaration_Of (From_Project_Node); + + Recursive_Process + (Project => Processed_Data.Modifies, + From_Project_Node => Modified_Project_Of (Declaration_Node), + Modified_By => Project); + + Projects.Table (Project) := Processed_Data; + + Process_Declarative_Items + (Project => Project, + From_Project_Node => From_Project_Node, + Pkg => No_Package, + Item => First_Declarative_Item_Of + (Declaration_Node)); + + end; + end if; + end Recursive_Process; + +end Prj.Proc; diff --git a/gcc/ada/prj-proc.ads b/gcc/ada/prj-proc.ads new file mode 100644 index 00000000000..63259a42699 --- /dev/null +++ b/gcc/ada/prj-proc.ads @@ -0,0 +1,45 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J . P R O C -- +-- -- +-- S p e c -- +-- -- +-- $Revision: 1.2 $ +-- -- +-- Copyright (C) 2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ +-- +-- This package is used to convert a project file tree (see prj-tree.ads) to +-- project file data structures (see prj.ads), taking into account +-- the environment (external references). + +with Prj.Tree; use Prj.Tree; + +package Prj.Proc is + + procedure Process + (Project : out Project_Id; + From_Project_Node : Project_Node_Id; + Report_Error : Put_Line_Access); + -- Process a project file tree into project file data structures. + -- If Report_Error is null, use the standard error reporting mechanism + -- (Errout). Otherwise, report errors using Report_Error. + +end Prj.Proc; diff --git a/gcc/ada/prj-strt.adb b/gcc/ada/prj-strt.adb new file mode 100644 index 00000000000..790c632c2cf --- /dev/null +++ b/gcc/ada/prj-strt.adb @@ -0,0 +1,943 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J . S T R T -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.12 $ +-- -- +-- Copyright (C) 2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +with Errout; use Errout; +with Prj.Attr; use Prj.Attr; +with Prj.Tree; use Prj.Tree; +with Scans; use Scans; +with Sinfo; use Sinfo; +with Stringt; use Stringt; +with Table; +with Types; use Types; + +package body Prj.Strt is + + Initial_Size : constant := 8; + + type Name_Location is record + Name : Name_Id := No_Name; + Location : Source_Ptr := No_Location; + end record; + -- Store the identifier and the location of a simple name + + type Name_Range is range 0 .. 3; + subtype Name_Index is Name_Range range 1 .. Name_Range'Last; + -- A Name may contain up to 3 simple names + + type Names is array (Name_Index) of Name_Location; + -- Used to store 1 to 3 simple_names. 2 simple names are for + -- <project>.<package>, <project>.<variable> or <package>.<variable>. + -- 3 simple names are for <project>.<package>.<variable>. + + type Choice_String is record + The_String : String_Id; + Already_Used : Boolean := False; + end record; + -- The string of a case label, and an indication that it has already + -- been used (to avoid duplicate case labels). + + Choices_Initial : constant := 10; + Choices_Increment : constant := 10; + + Choice_Node_Low_Bound : constant := 0; + Choice_Node_High_Bound : constant := 099_999_999; -- In practice, infinite + + type Choice_Node_Id is + range Choice_Node_Low_Bound .. Choice_Node_High_Bound; + + First_Choice_Node_Id : constant Choice_Node_Id := + Choice_Node_Low_Bound; + + Empty_Choice : constant Choice_Node_Id := + Choice_Node_Low_Bound; + + First_Choice_Id : constant Choice_Node_Id := First_Choice_Node_Id + 1; + + package Choices is + new Table.Table (Table_Component_Type => Choice_String, + Table_Index_Type => Choice_Node_Id, + Table_Low_Bound => First_Choice_Node_Id, + Table_Initial => Choices_Initial, + Table_Increment => Choices_Increment, + Table_Name => "Prj.Strt.Choices"); + -- Used to store the case labels and check that there is no duplicate. + + package Choice_Lasts is + new Table.Table (Table_Component_Type => Choice_Node_Id, + Table_Index_Type => Nat, + Table_Low_Bound => 1, + Table_Initial => 3, + Table_Increment => 3, + Table_Name => "Prj.Strt.Choice_Lasts"); + -- Used to store the indices of the choices in table Choices, + -- to distinguish nested case constructions. + + Choice_First : Choice_Node_Id := 0; + -- Index in table Choices of the first case label of the current + -- case construction. + -- 0 means no current case construction. + + procedure Add (This_String : String_Id); + -- Add a string to the case label list, indicating that it has not + -- yet been used. + + procedure External_Reference (External_Value : out Project_Node_Id); + -- Parse an external reference. Current token is "external". + + procedure Attribute_Reference + (Reference : out Project_Node_Id; + First_Attribute : Attribute_Node_Id; + Current_Project : Project_Node_Id; + Current_Package : Project_Node_Id); + -- Parse an attribute reference. Current token is an apostrophe. + + procedure Terms + (Term : out Project_Node_Id; + Expr_Kind : in out Variable_Kind; + Current_Project : Project_Node_Id; + Current_Package : Project_Node_Id); + -- Recursive procedure to parse one term or several terms concatenated + -- using "&". + + --------- + -- Add -- + --------- + + procedure Add (This_String : String_Id) is + begin + Choices.Increment_Last; + Choices.Table (Choices.Last) := + (The_String => This_String, + Already_Used => False); + end Add; + + ------------------------- + -- Attribute_Reference -- + ------------------------- + + procedure Attribute_Reference + (Reference : out Project_Node_Id; + First_Attribute : Attribute_Node_Id; + Current_Project : Project_Node_Id; + Current_Package : Project_Node_Id) + is + Current_Attribute : Attribute_Node_Id := First_Attribute; + + begin + Reference := Default_Project_Node (Of_Kind => N_Attribute_Reference); + Set_Location_Of (Reference, To => Token_Ptr); + Scan; -- past apostrophe + Expect (Tok_Identifier, "Identifier"); + + if Token = Tok_Identifier then + Set_Name_Of (Reference, To => Token_Name); + + while Current_Attribute /= Empty_Attribute + and then + Attributes.Table (Current_Attribute).Name /= Token_Name + loop + Current_Attribute := Attributes.Table (Current_Attribute).Next; + end loop; + + if Current_Attribute = Empty_Attribute then + Error_Msg ("unknown attribute", Token_Ptr); + Reference := Empty_Node; + + elsif + Attributes.Table (Current_Attribute).Kind_2 = Associative_Array + then + Error_Msg + ("associative array attribute cannot be referenced", + Token_Ptr); + Reference := Empty_Node; + + else + Set_Project_Node_Of (Reference, To => Current_Project); + Set_Package_Node_Of (Reference, To => Current_Package); + Set_Expression_Kind_Of + (Reference, To => Attributes.Table (Current_Attribute).Kind_1); + Scan; + end if; + end if; + end Attribute_Reference; + + --------------------------- + -- End_Case_Construction -- + --------------------------- + + procedure End_Case_Construction is + begin + if Choice_Lasts.Last = 1 then + Choice_Lasts.Set_Last (0); + Choices.Set_Last (First_Choice_Node_Id); + Choice_First := 0; + + elsif Choice_Lasts.Last = 2 then + Choice_Lasts.Set_Last (1); + Choices.Set_Last (Choice_Lasts.Table (1)); + Choice_First := 1; + + else + Choice_Lasts.Decrement_Last; + Choices.Set_Last (Choice_Lasts.Table (Choice_Lasts.Last)); + Choice_First := Choice_Lasts.Table (Choice_Lasts.Last - 1) + 1; + end if; + end End_Case_Construction; + + ------------------------ + -- External_Reference -- + ------------------------ + + procedure External_Reference (External_Value : out Project_Node_Id) is + Field_Id : Project_Node_Id := Empty_Node; + + begin + External_Value := + Default_Project_Node (Of_Kind => N_External_Value, + And_Expr_Kind => Single); + Set_Location_Of (External_Value, To => Token_Ptr); + + -- The current token is External + + -- Get the left parenthesis + + Scan; + Expect (Tok_Left_Paren, "("); + + -- Scan past the left parenthesis + + if Token = Tok_Left_Paren then + Scan; + end if; + + -- Get the name of the external reference + + Expect (Tok_String_Literal, "literal string"); + + if Token = Tok_String_Literal then + Field_Id := + Default_Project_Node (Of_Kind => N_Literal_String, + And_Expr_Kind => Single); + Set_String_Value_Of (Field_Id, To => Strval (Token_Node)); + Set_External_Reference_Of (External_Value, To => Field_Id); + + -- Scan past the first argument + + Scan; + + case Token is + + when Tok_Right_Paren => + + -- Scan past the right parenthesis + Scan; + + when Tok_Comma => + + -- Scan past the comma + + Scan; + + Expect (Tok_String_Literal, "literal string"); + + -- Get the default + + if Token = Tok_String_Literal then + Field_Id := + Default_Project_Node (Of_Kind => N_Literal_String, + And_Expr_Kind => Single); + Set_String_Value_Of (Field_Id, To => Strval (Token_Node)); + Set_External_Default_Of (External_Value, To => Field_Id); + Scan; + Expect (Tok_Right_Paren, ")"); + end if; + + -- Scan past the right parenthesis + if Token = Tok_Right_Paren then + Scan; + end if; + + when others => + Error_Msg ("',' or ')' expected", Token_Ptr); + end case; + end if; + end External_Reference; + + ----------------------- + -- Parse_Choice_List -- + ----------------------- + + procedure Parse_Choice_List (First_Choice : out Project_Node_Id) is + Current_Choice : Project_Node_Id := Empty_Node; + Next_Choice : Project_Node_Id := Empty_Node; + Choice_String : String_Id := No_String; + Found : Boolean := False; + + begin + First_Choice := + Default_Project_Node (Of_Kind => N_Literal_String, + And_Expr_Kind => Single); + Current_Choice := First_Choice; + + loop + Expect (Tok_String_Literal, "literal string"); + exit when Token /= Tok_String_Literal; + Set_Location_Of (Current_Choice, To => Token_Ptr); + Choice_String := Strval (Token_Node); + Set_String_Value_Of (Current_Choice, To => Choice_String); + + Found := False; + for Choice in Choice_First .. Choices.Last loop + if String_Equal (Choices.Table (Choice).The_String, + Choice_String) + then + Found := True; + + if Choices.Table (Choice).Already_Used then + Error_Msg ("duplicate case label", Token_Ptr); + else + Choices.Table (Choice).Already_Used := True; + end if; + + exit; + end if; + end loop; + + if not Found then + Error_Msg ("illegal case label", Token_Ptr); + end if; + + Scan; + + if Token = Tok_Vertical_Bar then + Next_Choice := + Default_Project_Node (Of_Kind => N_Literal_String, + And_Expr_Kind => Single); + Set_Next_Literal_String (Current_Choice, To => Next_Choice); + Current_Choice := Next_Choice; + Scan; + else + exit; + end if; + end loop; + end Parse_Choice_List; + + ---------------------- + -- Parse_Expression -- + ---------------------- + + procedure Parse_Expression + (Expression : out Project_Node_Id; + Current_Project : Project_Node_Id; + Current_Package : Project_Node_Id) + is + First_Term : Project_Node_Id := Empty_Node; + Expression_Kind : Variable_Kind := Undefined; + + begin + Expression := Default_Project_Node (Of_Kind => N_Expression); + Set_Location_Of (Expression, To => Token_Ptr); + Terms (Term => First_Term, + Expr_Kind => Expression_Kind, + Current_Project => Current_Project, + Current_Package => Current_Package); + Set_First_Term (Expression, To => First_Term); + Set_Expression_Kind_Of (Expression, To => Expression_Kind); + end Parse_Expression; + + ---------------------------- + -- Parse_String_Type_List -- + ---------------------------- + + procedure Parse_String_Type_List (First_String : out Project_Node_Id) is + Last_String : Project_Node_Id := Empty_Node; + Next_String : Project_Node_Id := Empty_Node; + String_Value : String_Id := No_String; + + begin + First_String := + Default_Project_Node (Of_Kind => N_Literal_String, + And_Expr_Kind => Single); + Last_String := First_String; + + loop + Expect (Tok_String_Literal, "literal string"); + exit when Token /= Tok_String_Literal; + String_Value := Strval (Token_Node); + Set_String_Value_Of (Last_String, To => String_Value); + Set_Location_Of (Last_String, To => Token_Ptr); + + declare + Current : Project_Node_Id := First_String; + + begin + while Current /= Last_String loop + if String_Equal (String_Value_Of (Current), String_Value) then + Error_Msg ("duplicate value in type", Token_Ptr); + exit; + end if; + + Current := Next_Literal_String (Current); + end loop; + end; + + Scan; + + if Token /= Tok_Comma then + exit; + + else + Next_String := + Default_Project_Node (Of_Kind => N_Literal_String, + And_Expr_Kind => Single); + Set_Next_Literal_String (Last_String, To => Next_String); + Last_String := Next_String; + Scan; + end if; + end loop; + end Parse_String_Type_List; + + ------------------------------ + -- Parse_Variable_Reference -- + ------------------------------ + + procedure Parse_Variable_Reference + (Variable : out Project_Node_Id; + Current_Project : Project_Node_Id; + Current_Package : Project_Node_Id) + is + The_Names : Names; + Last_Name : Name_Range := 0; + Current_Variable : Project_Node_Id := Empty_Node; + + The_Package : Project_Node_Id := Current_Package; + The_Project : Project_Node_Id := Current_Project; + + Specified_Project : Project_Node_Id := Empty_Node; + Specified_Package : Project_Node_Id := Empty_Node; + Look_For_Variable : Boolean := True; + First_Attribute : Attribute_Node_Id := Empty_Attribute; + Variable_Name : Name_Id; + + begin + for Index in The_Names'Range loop + Expect (Tok_Identifier, "identifier"); + + if Token /= Tok_Identifier then + Look_For_Variable := False; + exit; + end if; + + Last_Name := Last_Name + 1; + The_Names (Last_Name) := + (Name => Token_Name, + Location => Token_Ptr); + Scan; + exit when Token /= Tok_Dot; + Scan; + end loop; + + if Look_For_Variable then + if Token = Tok_Apostrophe then + + -- Attribute reference + + case Last_Name is + when 0 => + + -- Cannot happen + + null; + + when 1 => + for Index in Package_First .. Package_Attributes.Last loop + if Package_Attributes.Table (Index).Name = + The_Names (1).Name + then + First_Attribute := + Package_Attributes.Table (Index).First_Attribute; + exit; + end if; + end loop; + + if First_Attribute /= Empty_Attribute then + The_Package := First_Package_Of (Current_Project); + while The_Package /= Empty_Node + and then Name_Of (The_Package) /= The_Names (1).Name + loop + The_Package := Next_Package_In_Project (The_Package); + end loop; + + if The_Package = Empty_Node then + Error_Msg ("package not yet defined", + The_Names (1).Location); + end if; + + else + First_Attribute := Attribute_First; + The_Package := Empty_Node; + + declare + The_Project_Name_And_Node : + constant Tree_Private_Part.Project_Name_And_Node := + Tree_Private_Part.Projects_Htable.Get + (The_Names (1).Name); + + use Tree_Private_Part; + + begin + if The_Project_Name_And_Node = + Tree_Private_Part.No_Project_Name_And_Node + then + Error_Msg ("unknown project", + The_Names (1).Location); + else + The_Project := The_Project_Name_And_Node.Node; + end if; + end; + end if; + + when 2 => + declare + With_Clause : Project_Node_Id := + First_With_Clause_Of (Current_Project); + + begin + while With_Clause /= Empty_Node loop + The_Project := Project_Node_Of (With_Clause); + exit when Name_Of (The_Project) = The_Names (1).Name; + With_Clause := Next_With_Clause_Of (With_Clause); + end loop; + + if With_Clause = Empty_Node then + Error_Msg ("unknown project", + The_Names (1).Location); + The_Project := Empty_Node; + The_Package := Empty_Node; + First_Attribute := Attribute_First; + + else + The_Package := First_Package_Of (The_Project); + while The_Package /= Empty_Node + and then Name_Of (The_Package) /= The_Names (2).Name + loop + The_Package := + Next_Package_In_Project (The_Package); + end loop; + + if The_Package = Empty_Node then + Error_Msg ("package not declared in project", + The_Names (2).Location); + First_Attribute := Attribute_First; + + else + First_Attribute := + Package_Attributes.Table + (Package_Id_Of (The_Package)).First_Attribute; + end if; + end if; + end; + + when 3 => + Error_Msg + ("too many single names for an attribute reference", + The_Names (1).Location); + Scan; + Variable := Empty_Node; + return; + end case; + + Attribute_Reference + (Variable, + Current_Project => The_Project, + Current_Package => The_Package, + First_Attribute => First_Attribute); + return; + end if; + end if; + + Variable := + Default_Project_Node (Of_Kind => N_Variable_Reference); + + if Look_For_Variable then + case Last_Name is + when 0 => + + -- Cannot happen + + null; + + when 1 => + Set_Name_Of (Variable, To => The_Names (1).Name); + + -- Header comment needed ??? + + when 2 => + Set_Name_Of (Variable, To => The_Names (2).Name); + The_Package := First_Package_Of (Current_Project); + + while The_Package /= Empty_Node + and then Name_Of (The_Package) /= The_Names (1).Name + loop + The_Package := Next_Package_In_Project (The_Package); + end loop; + + if The_Package /= Empty_Node then + Specified_Package := The_Package; + The_Project := Empty_Node; + + else + declare + With_Clause : Project_Node_Id := + First_With_Clause_Of (Current_Project); + + begin + while With_Clause /= Empty_Node loop + The_Project := Project_Node_Of (With_Clause); + exit when Name_Of (The_Project) = The_Names (1).Name; + With_Clause := Next_With_Clause_Of (With_Clause); + end loop; + + if With_Clause = Empty_Node then + The_Project := + Modified_Project_Of + (Project_Declaration_Of (Current_Project)); + + if The_Project /= Empty_Node + and then + Name_Of (The_Project) /= The_Names (1).Name + then + The_Project := Empty_Node; + end if; + end if; + + if The_Project = Empty_Node then + Error_Msg ("unknown package or project", + The_Names (1).Location); + Look_For_Variable := False; + else + Specified_Project := The_Project; + end if; + end; + end if; + + -- Header comment needed ??? + + when 3 => + Set_Name_Of (Variable, To => The_Names (3).Name); + + declare + With_Clause : Project_Node_Id := + First_With_Clause_Of (Current_Project); + + begin + while With_Clause /= Empty_Node loop + The_Project := Project_Node_Of (With_Clause); + exit when Name_Of (The_Project) = The_Names (1).Name; + With_Clause := Next_With_Clause_Of (With_Clause); + end loop; + + if With_Clause = Empty_Node then + The_Project := + Modified_Project_Of + (Project_Declaration_Of (Current_Project)); + + if The_Project /= Empty_Node + and then Name_Of (The_Project) /= The_Names (1).Name + then + The_Project := Empty_Node; + end if; + end if; + + if The_Project = Empty_Node then + Error_Msg ("unknown package or project", + The_Names (1).Location); + Look_For_Variable := False; + + else + Specified_Project := The_Project; + The_Package := First_Package_Of (The_Project); + + while The_Package /= Empty_Node + and then Name_Of (The_Package) /= The_Names (2).Name + loop + The_Package := Next_Package_In_Project (The_Package); + end loop; + + if The_Package = Empty_Node then + Error_Msg ("unknown package", + The_Names (2).Location); + Look_For_Variable := False; + + else + Specified_Package := The_Package; + The_Project := Empty_Node; + end if; + end if; + end; + + end case; + end if; + + if Look_For_Variable then + Variable_Name := Name_Of (Variable); + Set_Project_Node_Of (Variable, To => Specified_Project); + Set_Package_Node_Of (Variable, To => Specified_Package); + + if The_Package /= Empty_Node then + Current_Variable := First_Variable_Of (The_Package); + + while Current_Variable /= Empty_Node + and then + Name_Of (Current_Variable) /= Variable_Name + loop + Current_Variable := Next_Variable (Current_Variable); + end loop; + end if; + + if Current_Variable = Empty_Node + and then The_Project /= Empty_Node + then + Current_Variable := First_Variable_Of (The_Project); + while Current_Variable /= Empty_Node + and then Name_Of (Current_Variable) /= Variable_Name + loop + Current_Variable := Next_Variable (Current_Variable); + end loop; + end if; + + if Current_Variable = Empty_Node then + Error_Msg ("unknown variable", The_Names (Last_Name).Location); + end if; + end if; + + if Current_Variable /= Empty_Node then + Set_Expression_Kind_Of + (Variable, To => Expression_Kind_Of (Current_Variable)); + + if Kind_Of (Current_Variable) = N_Typed_Variable_Declaration then + Set_String_Type_Of + (Variable, To => String_Type_Of (Current_Variable)); + end if; + end if; + end Parse_Variable_Reference; + + --------------------------------- + -- Start_New_Case_Construction -- + --------------------------------- + + procedure Start_New_Case_Construction (String_Type : Project_Node_Id) is + Current_String : Project_Node_Id; + + begin + if Choice_First = 0 then + Choice_First := 1; + Choices.Set_Last (First_Choice_Node_Id); + else + Choice_First := Choices.Last + 1; + end if; + + if String_Type /= Empty_Node then + Current_String := First_Literal_String (String_Type); + + while Current_String /= Empty_Node loop + Add (This_String => String_Value_Of (Current_String)); + Current_String := Next_Literal_String (Current_String); + end loop; + end if; + + Choice_Lasts.Increment_Last; + Choice_Lasts.Table (Choice_Lasts.Last) := Choices.Last; + + end Start_New_Case_Construction; + + ----------- + -- Terms -- + ----------- + + procedure Terms (Term : out Project_Node_Id; + Expr_Kind : in out Variable_Kind; + Current_Project : Project_Node_Id; + Current_Package : Project_Node_Id) + is + Next_Term : Project_Node_Id := Empty_Node; + Term_Id : Project_Node_Id := Empty_Node; + Current_Expression : Project_Node_Id := Empty_Node; + Next_Expression : Project_Node_Id := Empty_Node; + Current_Location : Source_Ptr := No_Location; + Reference : Project_Node_Id := Empty_Node; + + begin + Term := Default_Project_Node (Of_Kind => N_Term); + Set_Location_Of (Term, To => Token_Ptr); + + case Token is + + when Tok_Left_Paren => + case Expr_Kind is + when Undefined => + Expr_Kind := List; + when List => + null; + when Single => + Expr_Kind := List; + Error_Msg + ("literal string list cannot appear in a string", + Token_Ptr); + end case; + + Term_Id := Default_Project_Node + (Of_Kind => N_Literal_String_List, + And_Expr_Kind => List); + Set_Current_Term (Term, To => Term_Id); + Set_Location_Of (Term, To => Token_Ptr); + + Scan; + if Token = Tok_Right_Paren then + Scan; + + else + loop + Current_Location := Token_Ptr; + Parse_Expression (Expression => Next_Expression, + Current_Project => Current_Project, + Current_Package => Current_Package); + + if Expression_Kind_Of (Next_Expression) = List then + Error_Msg ("single expression expected", + Current_Location); + end if; + + if Current_Expression = Empty_Node then + Set_First_Expression_In_List + (Term_Id, To => Next_Expression); + else + Set_Next_Expression_In_List + (Current_Expression, To => Next_Expression); + end if; + + Current_Expression := Next_Expression; + exit when Token /= Tok_Comma; + Scan; -- past the comma + end loop; + + Expect (Tok_Right_Paren, "("); + + if Token = Tok_Right_Paren then + Scan; + end if; + end if; + + when Tok_String_Literal => + if Expr_Kind = Undefined then + Expr_Kind := Single; + end if; + + Term_Id := Default_Project_Node (Of_Kind => N_Literal_String); + Set_Current_Term (Term, To => Term_Id); + Set_String_Value_Of (Term_Id, To => Strval (Token_Node)); + + Scan; + + when Tok_Identifier => + Current_Location := Token_Ptr; + Parse_Variable_Reference + (Variable => Reference, + Current_Project => Current_Project, + Current_Package => Current_Package); + Set_Current_Term (Term, To => Reference); + + if Reference /= Empty_Node then + if Expr_Kind = Undefined then + Expr_Kind := Expression_Kind_Of (Reference); + + elsif Expr_Kind = Single + and then Expression_Kind_Of (Reference) = List + then + Expr_Kind := List; + Error_Msg + ("list variable cannot appear in single string expression", + Current_Location); + end if; + end if; + + when Tok_Project => + Current_Location := Token_Ptr; + Scan; + Expect (Tok_Apostrophe, "'"); + + if Token = Tok_Apostrophe then + Attribute_Reference + (Reference => Reference, + First_Attribute => Prj.Attr.Attribute_First, + Current_Project => Current_Project, + Current_Package => Empty_Node); + Set_Current_Term (Term, To => Reference); + end if; + + if Reference /= Empty_Node then + if Expr_Kind = Undefined then + Expr_Kind := Expression_Kind_Of (Reference); + + elsif Expr_Kind = Single + and then Expression_Kind_Of (Reference) = List + then + Error_Msg + ("lists cannot appear in single string expression", + Current_Location); + end if; + end if; + + when Tok_External => + if Expr_Kind = Undefined then + Expr_Kind := Single; + end if; + + External_Reference (External_Value => Reference); + Set_Current_Term (Term, To => Reference); + + when others => + Error_Msg ("cannot be part of an expression", Token_Ptr); + Term := Empty_Node; + return; + end case; + + if Token = Tok_Ampersand then + Scan; + + Terms (Term => Next_Term, + Expr_Kind => Expr_Kind, + Current_Project => Current_Project, + Current_Package => Current_Package); + Set_Next_Term (Term, To => Next_Term); + + end if; + + end Terms; + +end Prj.Strt; diff --git a/gcc/ada/prj-strt.ads b/gcc/ada/prj-strt.ads new file mode 100644 index 00000000000..9bbdbeb8832 --- /dev/null +++ b/gcc/ada/prj-strt.ads @@ -0,0 +1,96 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J . S T R T -- +-- -- +-- S p e c -- +-- -- +-- $Revision: 1.4 $ +-- -- +-- Copyright (C) 2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ +-- +-- This package implements parsing of string expressions in project files. + +with Prj.Tree; use Prj.Tree; + +private package Prj.Strt is + + procedure Parse_String_Type_List (First_String : out Project_Node_Id); + -- Get the list of literal strings that are allowed for a typed string. + -- On entry, the current token is the first literal string following + -- a left parenthesis in a string type declaration such as: + -- type Toto is ("string_1", "string_2", "string_3"); + -- On exit, the current token is the right parenthesis. + -- The parameter First_String is a node that contained the first + -- literal string of the string type, linked with the following + -- literal strings. + -- + -- Report an error if + -- - a literal string is not found at the beginning of the list + -- or after a comma + -- - two literal strings in the list are equal + + procedure Start_New_Case_Construction (String_Type : Project_Node_Id); + -- This procedure is called at the beginning of a case construction + -- The parameter String_Type is the node for the string type + -- of the case label variable. + -- The different literal strings of the string type are stored + -- into a table to be checked against the case labels of the + -- case construction. + + procedure End_Case_Construction; + -- This procedure is called at the end of a case construction + -- to remove the case labels and to restore the previous state. + -- In particular, in the case of nested case constructions, + -- the case labels of the enclosing case construction are restored. + + procedure Parse_Choice_List + (First_Choice : out Project_Node_Id); + -- Get the label for a choice list. + -- Report an error if + -- - a case label is not a literal string + -- - a case label is not in the typed string list + -- - the same case label is repeated in the same case construction + + procedure Parse_Expression + (Expression : out Project_Node_Id; + Current_Project : Project_Node_Id; + Current_Package : Project_Node_Id); + -- Parse a simple string expression or a string list expression. + -- Current_Project is the node of the project file being parsed. + -- Current_Package is the node of the package being parsed, + -- or Empty_Node when we are at the project level (not in a package). + -- On exit, Expression is the node of the expression that has + -- been parsed. + + procedure Parse_Variable_Reference + (Variable : out Project_Node_Id; + Current_Project : Project_Node_Id; + Current_Package : Project_Node_Id); + -- Parse a variable or attribute reference. + -- Used internally (in expressions) and for case variables (in Prj.Dect). + -- Current_Package is the node of the package being parsed, + -- or Empty_Node when we are at the project level (not in a package). + -- On exit, Variable is the node of the variable or attribute reference. + -- A variable reference is made of one to three simple names. + -- An attribute reference is made of one or two simple names, + -- followed by an apostroph, followed by the attribute simple name. + +end Prj.Strt; diff --git a/gcc/ada/prj-tree.adb b/gcc/ada/prj-tree.adb new file mode 100644 index 00000000000..322e4aae39f --- /dev/null +++ b/gcc/ada/prj-tree.adb @@ -0,0 +1,1478 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J . T R E E -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.7 $ +-- -- +-- Copyright (C) 2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +with Stringt; use Stringt; + +package body Prj.Tree is + + use Tree_Private_Part; + + -------------------------------- + -- Associative_Array_Index_Of -- + -------------------------------- + + function Associative_Array_Index_Of + (Node : Project_Node_Id) + return String_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + (Project_Nodes.Table (Node).Kind = N_Attribute_Declaration)); + return Project_Nodes.Table (Node).Value; + end Associative_Array_Index_Of; + + -------------------------------- + -- Case_Variable_Reference_Of -- + -------------------------------- + + function Case_Variable_Reference_Of + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Case_Construction); + return Project_Nodes.Table (Node).Field1; + end Case_Variable_Reference_Of; + + ----------------------- + -- Current_Item_Node -- + ----------------------- + + function Current_Item_Node + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Declarative_Item); + return Project_Nodes.Table (Node).Field1; + end Current_Item_Node; + + ------------------ + -- Current_Term -- + ------------------ + + function Current_Term + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Term); + return Project_Nodes.Table (Node).Field1; + end Current_Term; + + -------------------------- + -- Default_Project_Node -- + -------------------------- + + function Default_Project_Node + (Of_Kind : Project_Node_Kind; + And_Expr_Kind : Variable_Kind := Undefined) + return Project_Node_Id + is + begin + Project_Nodes.Increment_Last; + Project_Nodes.Table (Project_Nodes.Last) := + (Kind => Of_Kind, + Location => No_Location, + Directory => No_Name, + Expr_Kind => And_Expr_Kind, + Variables => Empty_Node, + Packages => Empty_Node, + Pkg_Id => Empty_Package, + Name => No_Name, + Path_Name => No_Name, + Value => No_String, + Field1 => Empty_Node, + Field2 => Empty_Node, + Field3 => Empty_Node); + return Project_Nodes.Last; + end Default_Project_Node; + + ------------------ + -- Directory_Of -- + ------------------ + + function Directory_Of (Node : Project_Node_Id) return Name_Id is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Project); + return Project_Nodes.Table (Node).Directory; + end Directory_Of; + + ------------------------ + -- Expression_Kind_Of -- + ------------------------ + + function Expression_Kind_Of (Node : Project_Node_Id) return Variable_Kind is + begin + pragma Assert + (Node /= Empty_Node + and then + (Project_Nodes.Table (Node).Kind = N_Literal_String + or else + Project_Nodes.Table (Node).Kind = N_Attribute_Declaration + or else + Project_Nodes.Table (Node).Kind = N_Variable_Declaration + or else + Project_Nodes.Table (Node).Kind = N_Typed_Variable_Declaration + or else + Project_Nodes.Table (Node).Kind = N_Expression + or else + Project_Nodes.Table (Node).Kind = N_Term + or else + Project_Nodes.Table (Node).Kind = N_Variable_Reference + or else + Project_Nodes.Table (Node).Kind = N_Attribute_Reference)); + + return Project_Nodes.Table (Node).Expr_Kind; + end Expression_Kind_Of; + + ------------------- + -- Expression_Of -- + ------------------- + + function Expression_Of + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + (Project_Nodes.Table (Node).Kind = N_Attribute_Declaration + or else + Project_Nodes.Table (Node).Kind = N_Typed_Variable_Declaration + or else + Project_Nodes.Table (Node).Kind = N_Variable_Declaration)); + + return Project_Nodes.Table (Node).Field1; + end Expression_Of; + + --------------------------- + -- External_Reference_Of -- + --------------------------- + + function External_Reference_Of + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_External_Value); + return Project_Nodes.Table (Node).Field1; + end External_Reference_Of; + + ------------------------- + -- External_Default_Of -- + ------------------------- + + function External_Default_Of + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_External_Value); + return Project_Nodes.Table (Node).Field2; + end External_Default_Of; + + ------------------------ + -- First_Case_Item_Of -- + ------------------------ + + function First_Case_Item_Of + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Case_Construction); + return Project_Nodes.Table (Node).Field2; + end First_Case_Item_Of; + + --------------------- + -- First_Choice_Of -- + --------------------- + + function First_Choice_Of + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Case_Item); + return Project_Nodes.Table (Node).Field1; + end First_Choice_Of; + + ------------------------------- + -- First_Declarative_Item_Of -- + ------------------------------- + + function First_Declarative_Item_Of + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + (Project_Nodes.Table (Node).Kind = N_Project_Declaration + or else + Project_Nodes.Table (Node).Kind = N_Case_Item + or else + Project_Nodes.Table (Node).Kind = N_Package_Declaration)); + + if Project_Nodes.Table (Node).Kind = N_Project_Declaration then + return Project_Nodes.Table (Node).Field1; + else + return Project_Nodes.Table (Node).Field2; + end if; + end First_Declarative_Item_Of; + + ------------------------------ + -- First_Expression_In_List -- + ------------------------------ + + function First_Expression_In_List + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Literal_String_List); + return Project_Nodes.Table (Node).Field1; + end First_Expression_In_List; + + -------------------------- + -- First_Literal_String -- + -------------------------- + + function First_Literal_String + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_String_Type_Declaration); + return Project_Nodes.Table (Node).Field1; + end First_Literal_String; + + ---------------------- + -- First_Package_Of -- + ---------------------- + + function First_Package_Of + (Node : Project_Node_Id) + return Package_Declaration_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Project); + return Project_Nodes.Table (Node).Packages; + end First_Package_Of; + + -------------------------- + -- First_String_Type_Of -- + -------------------------- + + function First_String_Type_Of + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Project); + return Project_Nodes.Table (Node).Field3; + end First_String_Type_Of; + + ---------------- + -- First_Term -- + ---------------- + + function First_Term + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Expression); + return Project_Nodes.Table (Node).Field1; + end First_Term; + + ----------------------- + -- First_Variable_Of -- + ----------------------- + + function First_Variable_Of + (Node : Project_Node_Id) + return Variable_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + (Project_Nodes.Table (Node).Kind = N_Project + or else + Project_Nodes.Table (Node).Kind = N_Package_Declaration)); + + return Project_Nodes.Table (Node).Variables; + end First_Variable_Of; + + -------------------------- + -- First_With_Clause_Of -- + -------------------------- + + function First_With_Clause_Of + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Project); + return Project_Nodes.Table (Node).Field1; + end First_With_Clause_Of; + + ---------------- + -- Initialize -- + ---------------- + + procedure Initialize is + begin + Project_Nodes.Set_Last (Empty_Node); + Projects_Htable.Reset; + end Initialize; + + ------------- + -- Kind_Of -- + ------------- + + function Kind_Of (Node : Project_Node_Id) return Project_Node_Kind is + begin + pragma Assert (Node /= Empty_Node); + return Project_Nodes.Table (Node).Kind; + end Kind_Of; + + ----------------- + -- Location_Of -- + ----------------- + + function Location_Of (Node : Project_Node_Id) return Source_Ptr is + begin + pragma Assert (Node /= Empty_Node); + return Project_Nodes.Table (Node).Location; + end Location_Of; + + ------------------------- + -- Modified_Project_Of -- + ------------------------- + + function Modified_Project_Of + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Project_Declaration); + return Project_Nodes.Table (Node).Field2; + end Modified_Project_Of; + + ------------------------------ + -- Modified_Project_Path_Of -- + ------------------------------ + + function Modified_Project_Path_Of + (Node : Project_Node_Id) + return String_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Project); + return Project_Nodes.Table (Node).Value; + end Modified_Project_Path_Of; + + ------------- + -- Name_Of -- + ------------- + + function Name_Of (Node : Project_Node_Id) return Name_Id is + begin + pragma Assert (Node /= Empty_Node); + return Project_Nodes.Table (Node).Name; + end Name_Of; + + -------------------- + -- Next_Case_Item -- + -------------------- + + function Next_Case_Item + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Case_Item); + return Project_Nodes.Table (Node).Field3; + end Next_Case_Item; + + --------------------------- + -- Next_Declarative_Item -- + --------------------------- + + function Next_Declarative_Item + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Declarative_Item); + return Project_Nodes.Table (Node).Field2; + end Next_Declarative_Item; + + ----------------------------- + -- Next_Expression_In_List -- + ----------------------------- + + function Next_Expression_In_List + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Expression); + return Project_Nodes.Table (Node).Field2; + end Next_Expression_In_List; + + ------------------------- + -- Next_Literal_String -- + ------------------------- + + function Next_Literal_String + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Literal_String); + return Project_Nodes.Table (Node).Field1; + end Next_Literal_String; + + ----------------------------- + -- Next_Package_In_Project -- + ----------------------------- + + function Next_Package_In_Project + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Package_Declaration); + return Project_Nodes.Table (Node).Field3; + end Next_Package_In_Project; + + ---------------------- + -- Next_String_Type -- + ---------------------- + + function Next_String_Type + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_String_Type_Declaration); + return Project_Nodes.Table (Node).Field2; + end Next_String_Type; + + --------------- + -- Next_Term -- + --------------- + + function Next_Term + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Term); + return Project_Nodes.Table (Node).Field2; + end Next_Term; + + ------------------- + -- Next_Variable -- + ------------------- + + function Next_Variable + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + (Project_Nodes.Table (Node).Kind = N_Typed_Variable_Declaration + or else + Project_Nodes.Table (Node).Kind = N_Variable_Declaration)); + + return Project_Nodes.Table (Node).Field3; + end Next_Variable; + + ------------------------- + -- Next_With_Clause_Of -- + ------------------------- + + function Next_With_Clause_Of + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_With_Clause); + return Project_Nodes.Table (Node).Field2; + end Next_With_Clause_Of; + + ------------------- + -- Package_Id_Of -- + ------------------- + + function Package_Id_Of (Node : Project_Node_Id) return Package_Node_Id is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Package_Declaration); + return Project_Nodes.Table (Node).Pkg_Id; + end Package_Id_Of; + + --------------------- + -- Package_Node_Of -- + --------------------- + + function Package_Node_Of + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + (Project_Nodes.Table (Node).Kind = N_Variable_Reference + or else + Project_Nodes.Table (Node).Kind = N_Attribute_Reference)); + return Project_Nodes.Table (Node).Field2; + end Package_Node_Of; + + ------------------ + -- Path_Name_Of -- + ------------------ + + function Path_Name_Of (Node : Project_Node_Id) return Name_Id is + begin + pragma Assert + (Node /= Empty_Node + and then + (Project_Nodes.Table (Node).Kind = N_Project + or else + Project_Nodes.Table (Node).Kind = N_With_Clause)); + return Project_Nodes.Table (Node).Path_Name; + end Path_Name_Of; + + ---------------------------- + -- Project_Declaration_Of -- + ---------------------------- + + function Project_Declaration_Of + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Project); + return Project_Nodes.Table (Node).Field2; + end Project_Declaration_Of; + + --------------------- + -- Project_Node_Of -- + --------------------- + + function Project_Node_Of + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + (Project_Nodes.Table (Node).Kind = N_With_Clause + or else + Project_Nodes.Table (Node).Kind = N_Variable_Reference + or else + Project_Nodes.Table (Node).Kind = N_Attribute_Reference)); + return Project_Nodes.Table (Node).Field1; + end Project_Node_Of; + + ----------------------------------- + -- Project_Of_Renamed_Package_Of -- + ----------------------------------- + + function Project_Of_Renamed_Package_Of + (Node : Project_Node_Id) + return Project_Node_Id + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Package_Declaration); + return Project_Nodes.Table (Node).Field1; + end Project_Of_Renamed_Package_Of; + + ------------------------------------ + -- Set_Associative_Array_Index_Of -- + ------------------------------------ + + procedure Set_Associative_Array_Index_Of + (Node : Project_Node_Id; + To : String_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Attribute_Declaration); + Project_Nodes.Table (Node).Value := To; + end Set_Associative_Array_Index_Of; + + ------------------------------------ + -- Set_Case_Variable_Reference_Of -- + ------------------------------------ + + procedure Set_Case_Variable_Reference_Of + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Case_Construction); + Project_Nodes.Table (Node).Field1 := To; + end Set_Case_Variable_Reference_Of; + + --------------------------- + -- Set_Current_Item_Node -- + --------------------------- + + procedure Set_Current_Item_Node + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Declarative_Item); + Project_Nodes.Table (Node).Field1 := To; + end Set_Current_Item_Node; + + ---------------------- + -- Set_Current_Term -- + ---------------------- + + procedure Set_Current_Term + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Term); + Project_Nodes.Table (Node).Field1 := To; + end Set_Current_Term; + + ---------------------- + -- Set_Directory_Of -- + ---------------------- + + procedure Set_Directory_Of + (Node : Project_Node_Id; + To : Name_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Project); + Project_Nodes.Table (Node).Directory := To; + end Set_Directory_Of; + + ---------------------------- + -- Set_Expression_Kind_Of -- + ---------------------------- + + procedure Set_Expression_Kind_Of + (Node : Project_Node_Id; + To : Variable_Kind) + is + begin + pragma Assert + (Node /= Empty_Node + and then + (Project_Nodes.Table (Node).Kind = N_Literal_String + or else + Project_Nodes.Table (Node).Kind = N_Attribute_Declaration + or else + Project_Nodes.Table (Node).Kind = N_Variable_Declaration + or else + Project_Nodes.Table (Node).Kind = N_Typed_Variable_Declaration + or else + Project_Nodes.Table (Node).Kind = N_Expression + or else + Project_Nodes.Table (Node).Kind = N_Term + or else + Project_Nodes.Table (Node).Kind = N_Variable_Reference + or else + Project_Nodes.Table (Node).Kind = N_Attribute_Reference)); + Project_Nodes.Table (Node).Expr_Kind := To; + end Set_Expression_Kind_Of; + + ----------------------- + -- Set_Expression_Of -- + ----------------------- + + procedure Set_Expression_Of + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + (Project_Nodes.Table (Node).Kind = N_Attribute_Declaration + or else + Project_Nodes.Table (Node).Kind = N_Typed_Variable_Declaration + or else + Project_Nodes.Table (Node).Kind = N_Variable_Declaration)); + Project_Nodes.Table (Node).Field1 := To; + end Set_Expression_Of; + + ------------------------------- + -- Set_External_Reference_Of -- + ------------------------------- + + procedure Set_External_Reference_Of + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_External_Value); + Project_Nodes.Table (Node).Field1 := To; + end Set_External_Reference_Of; + + ----------------------------- + -- Set_External_Default_Of -- + ----------------------------- + + procedure Set_External_Default_Of + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_External_Value); + Project_Nodes.Table (Node).Field2 := To; + end Set_External_Default_Of; + + ---------------------------- + -- Set_First_Case_Item_Of -- + ---------------------------- + + procedure Set_First_Case_Item_Of + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Case_Construction); + Project_Nodes.Table (Node).Field2 := To; + end Set_First_Case_Item_Of; + + ------------------------- + -- Set_First_Choice_Of -- + ------------------------- + + procedure Set_First_Choice_Of + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Case_Item); + Project_Nodes.Table (Node).Field1 := To; + end Set_First_Choice_Of; + + ------------------------ + -- Set_Next_Case_Item -- + ------------------------ + + procedure Set_Next_Case_Item + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Case_Item); + Project_Nodes.Table (Node).Field3 := To; + end Set_Next_Case_Item; + + ----------------------------------- + -- Set_First_Declarative_Item_Of -- + ----------------------------------- + + procedure Set_First_Declarative_Item_Of + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + (Project_Nodes.Table (Node).Kind = N_Project_Declaration + or else + Project_Nodes.Table (Node).Kind = N_Case_Item + or else + Project_Nodes.Table (Node).Kind = N_Package_Declaration)); + + if Project_Nodes.Table (Node).Kind = N_Project_Declaration then + Project_Nodes.Table (Node).Field1 := To; + else + Project_Nodes.Table (Node).Field2 := To; + end if; + end Set_First_Declarative_Item_Of; + + ---------------------------------- + -- Set_First_Expression_In_List -- + ---------------------------------- + + procedure Set_First_Expression_In_List + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Literal_String_List); + Project_Nodes.Table (Node).Field1 := To; + end Set_First_Expression_In_List; + + ------------------------------ + -- Set_First_Literal_String -- + ------------------------------ + + procedure Set_First_Literal_String + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_String_Type_Declaration); + Project_Nodes.Table (Node).Field1 := To; + end Set_First_Literal_String; + + -------------------------- + -- Set_First_Package_Of -- + -------------------------- + + procedure Set_First_Package_Of + (Node : Project_Node_Id; + To : Package_Declaration_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Project); + Project_Nodes.Table (Node).Packages := To; + end Set_First_Package_Of; + + ------------------------------ + -- Set_First_String_Type_Of -- + ------------------------------ + + procedure Set_First_String_Type_Of + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Project); + Project_Nodes.Table (Node).Field3 := To; + end Set_First_String_Type_Of; + + -------------------- + -- Set_First_Term -- + -------------------- + + procedure Set_First_Term + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Expression); + Project_Nodes.Table (Node).Field1 := To; + end Set_First_Term; + + --------------------------- + -- Set_First_Variable_Of -- + --------------------------- + + procedure Set_First_Variable_Of + (Node : Project_Node_Id; + To : Variable_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + (Project_Nodes.Table (Node).Kind = N_Project + or else + Project_Nodes.Table (Node).Kind = N_Package_Declaration)); + Project_Nodes.Table (Node).Variables := To; + end Set_First_Variable_Of; + + ------------------------------ + -- Set_First_With_Clause_Of -- + ------------------------------ + + procedure Set_First_With_Clause_Of + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Project); + Project_Nodes.Table (Node).Field1 := To; + end Set_First_With_Clause_Of; + + ----------------- + -- Set_Kind_Of -- + ----------------- + + procedure Set_Kind_Of + (Node : Project_Node_Id; + To : Project_Node_Kind) + is + begin + pragma Assert (Node /= Empty_Node); + Project_Nodes.Table (Node).Kind := To; + end Set_Kind_Of; + + --------------------- + -- Set_Location_Of -- + --------------------- + + procedure Set_Location_Of + (Node : Project_Node_Id; + To : Source_Ptr) + is + begin + pragma Assert (Node /= Empty_Node); + Project_Nodes.Table (Node).Location := To; + end Set_Location_Of; + + ----------------------------- + -- Set_Modified_Project_Of -- + ----------------------------- + + procedure Set_Modified_Project_Of + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Project_Declaration); + Project_Nodes.Table (Node).Field2 := To; + end Set_Modified_Project_Of; + + ---------------------------------- + -- Set_Modified_Project_Path_Of -- + ---------------------------------- + + procedure Set_Modified_Project_Path_Of + (Node : Project_Node_Id; + To : String_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Project); + Project_Nodes.Table (Node).Value := To; + end Set_Modified_Project_Path_Of; + + ----------------- + -- Set_Name_Of -- + ----------------- + + procedure Set_Name_Of + (Node : Project_Node_Id; + To : Name_Id) + is + begin + pragma Assert (Node /= Empty_Node); + Project_Nodes.Table (Node).Name := To; + end Set_Name_Of; + + ------------------------------- + -- Set_Next_Declarative_Item -- + ------------------------------- + + procedure Set_Next_Declarative_Item + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Declarative_Item); + Project_Nodes.Table (Node).Field2 := To; + end Set_Next_Declarative_Item; + + --------------------------------- + -- Set_Next_Expression_In_List -- + --------------------------------- + + procedure Set_Next_Expression_In_List + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Expression); + Project_Nodes.Table (Node).Field2 := To; + end Set_Next_Expression_In_List; + + ----------------------------- + -- Set_Next_Literal_String -- + ----------------------------- + + procedure Set_Next_Literal_String + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Literal_String); + Project_Nodes.Table (Node).Field1 := To; + end Set_Next_Literal_String; + + --------------------------------- + -- Set_Next_Package_In_Project -- + --------------------------------- + + procedure Set_Next_Package_In_Project + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Package_Declaration); + Project_Nodes.Table (Node).Field3 := To; + end Set_Next_Package_In_Project; + + -------------------------- + -- Set_Next_String_Type -- + -------------------------- + + procedure Set_Next_String_Type + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_String_Type_Declaration); + Project_Nodes.Table (Node).Field2 := To; + end Set_Next_String_Type; + + ------------------- + -- Set_Next_Term -- + ------------------- + + procedure Set_Next_Term + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Term); + Project_Nodes.Table (Node).Field2 := To; + end Set_Next_Term; + + ----------------------- + -- Set_Next_Variable -- + ----------------------- + + procedure Set_Next_Variable + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + (Project_Nodes.Table (Node).Kind = N_Typed_Variable_Declaration + or else + Project_Nodes.Table (Node).Kind = N_Variable_Declaration)); + Project_Nodes.Table (Node).Field3 := To; + end Set_Next_Variable; + + ----------------------------- + -- Set_Next_With_Clause_Of -- + ----------------------------- + + procedure Set_Next_With_Clause_Of + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_With_Clause); + Project_Nodes.Table (Node).Field2 := To; + end Set_Next_With_Clause_Of; + + ----------------------- + -- Set_Package_Id_Of -- + ----------------------- + + procedure Set_Package_Id_Of + (Node : Project_Node_Id; + To : Package_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Package_Declaration); + Project_Nodes.Table (Node).Pkg_Id := To; + end Set_Package_Id_Of; + + ------------------------- + -- Set_Package_Node_Of -- + ------------------------- + + procedure Set_Package_Node_Of + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + (Project_Nodes.Table (Node).Kind = N_Variable_Reference + or else + Project_Nodes.Table (Node).Kind = N_Attribute_Reference)); + Project_Nodes.Table (Node).Field2 := To; + end Set_Package_Node_Of; + + ---------------------- + -- Set_Path_Name_Of -- + ---------------------- + + procedure Set_Path_Name_Of + (Node : Project_Node_Id; + To : Name_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + (Project_Nodes.Table (Node).Kind = N_Project + or else + Project_Nodes.Table (Node).Kind = N_With_Clause)); + Project_Nodes.Table (Node).Path_Name := To; + end Set_Path_Name_Of; + + -------------------------------- + -- Set_Project_Declaration_Of -- + -------------------------------- + + procedure Set_Project_Declaration_Of + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Project); + Project_Nodes.Table (Node).Field2 := To; + end Set_Project_Declaration_Of; + + ------------------------- + -- Set_Project_Node_Of -- + ------------------------- + + procedure Set_Project_Node_Of + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + (Project_Nodes.Table (Node).Kind = N_With_Clause + or else + Project_Nodes.Table (Node).Kind = N_Variable_Reference + or else + Project_Nodes.Table (Node).Kind = N_Attribute_Reference)); + Project_Nodes.Table (Node).Field1 := To; + end Set_Project_Node_Of; + + --------------------------------------- + -- Set_Project_Of_Renamed_Package_Of -- + --------------------------------------- + + procedure Set_Project_Of_Renamed_Package_Of + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + Project_Nodes.Table (Node).Kind = N_Package_Declaration); + Project_Nodes.Table (Node).Field1 := To; + end Set_Project_Of_Renamed_Package_Of; + + ------------------------ + -- Set_String_Type_Of -- + ------------------------ + + procedure Set_String_Type_Of + (Node : Project_Node_Id; + To : Project_Node_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + (Project_Nodes.Table (Node).Kind = N_Variable_Reference + or else + Project_Nodes.Table (Node).Kind = N_Typed_Variable_Declaration) + and then + Project_Nodes.Table (To).Kind = N_String_Type_Declaration); + + if Project_Nodes.Table (Node).Kind = N_Variable_Reference then + Project_Nodes.Table (Node).Field3 := To; + else + Project_Nodes.Table (Node).Field2 := To; + end if; + end Set_String_Type_Of; + + ------------------------- + -- Set_String_Value_Of -- + ------------------------- + + procedure Set_String_Value_Of + (Node : Project_Node_Id; + To : String_Id) + is + begin + pragma Assert + (Node /= Empty_Node + and then + (Project_Nodes.Table (Node).Kind = N_With_Clause + or else + Project_Nodes.Table (Node).Kind = N_Literal_String)); + Project_Nodes.Table (Node).Value := To; + end Set_String_Value_Of; + + -------------------- + -- String_Type_Of -- + -------------------- + + function String_Type_Of (Node : Project_Node_Id) + return Project_Node_Id is + begin + pragma Assert + (Node /= Empty_Node + and then + (Project_Nodes.Table (Node).Kind = N_Variable_Reference + or else + Project_Nodes.Table (Node).Kind = N_Typed_Variable_Declaration)); + + if Project_Nodes.Table (Node).Kind = N_Variable_Reference then + return Project_Nodes.Table (Node).Field3; + else + return Project_Nodes.Table (Node).Field2; + end if; + end String_Type_Of; + + --------------------- + -- String_Value_Of -- + --------------------- + + function String_Value_Of (Node : Project_Node_Id) return String_Id is + begin + pragma Assert + (Node /= Empty_Node + and then + (Project_Nodes.Table (Node).Kind = N_With_Clause + or else + Project_Nodes.Table (Node).Kind = N_Literal_String)); + return Project_Nodes.Table (Node).Value; + end String_Value_Of; + + -------------------- + -- Value_Is_Valid -- + -------------------- + + function Value_Is_Valid + (For_Typed_Variable : Project_Node_Id; + Value : String_Id) + return Boolean + is + begin + pragma Assert + (For_Typed_Variable /= Empty_Node + and then + (Project_Nodes.Table (For_Typed_Variable).Kind = + N_Typed_Variable_Declaration)); + + declare + Current_String : Project_Node_Id := + First_Literal_String + (String_Type_Of (For_Typed_Variable)); + + begin + while Current_String /= Empty_Node + and then + not String_Equal (String_Value_Of (Current_String), Value) + loop + Current_String := + Next_Literal_String (Current_String); + end loop; + + return Current_String /= Empty_Node; + end; + + end Value_Is_Valid; + +end Prj.Tree; diff --git a/gcc/ada/prj-tree.ads b/gcc/ada/prj-tree.ads new file mode 100644 index 00000000000..d32fcb19808 --- /dev/null +++ b/gcc/ada/prj-tree.ads @@ -0,0 +1,742 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J . T R E E -- +-- -- +-- S p e c -- +-- -- +-- $Revision: 1.9 $ +-- -- +-- Copyright (C) 2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +-- This package defines the structure of the Project File tree. + +with GNAT.HTable; + +with Prj.Attr; use Prj.Attr; +with Prj.Com; use Prj.Com; +with Types; use Types; +with Table; + +package Prj.Tree is + + Project_Nodes_Initial : constant := 1_000; + -- Initial number of nodes in table Tree_Private_Part.Project_Nodes + Project_Nodes_Increment : constant := 100; + + Project_Node_Low_Bound : constant := 0; + Project_Node_High_Bound : constant := 099_999_999; -- In practice, infinite + + type Project_Node_Id is range + Project_Node_Low_Bound .. Project_Node_High_Bound; + -- The index of table Tree_Private_Part.Project_Nodes + + Empty_Node : constant Project_Node_Id := Project_Node_Low_Bound; + -- Designates no node in table Project_Nodes + First_Node_Id : constant Project_Node_Id := Project_Node_Low_Bound; + + subtype Variable_Node_Id is Project_Node_Id; + -- Used to designate a node whose expected kind is + -- N_Typed_Variable_Declaration, N_Variable_Declaration or + -- N_Variable_Reference. + subtype Package_Declaration_Id is Project_Node_Id; + -- Used to designate a node whose expected kind is + -- N_Project_Declaration. + + type Project_Node_Kind is + (N_Project, + N_With_Clause, + N_Project_Declaration, + N_Declarative_Item, + N_Package_Declaration, + N_String_Type_Declaration, + N_Literal_String, + N_Attribute_Declaration, + N_Typed_Variable_Declaration, + N_Variable_Declaration, + N_Expression, + N_Term, + N_Literal_String_List, + N_Variable_Reference, + N_External_Value, + N_Attribute_Reference, + N_Case_Construction, + N_Case_Item); + -- Each node in the tree is of a Project_Node_Kind + -- For the signification of the fields in each node of a + -- Project_Node_Kind, look at package Tree_Private_Part. + + procedure Initialize; + -- Initialize the Project File tree: empty the Project_Nodes table + -- and reset the Projects_Htable. + + function Default_Project_Node + (Of_Kind : Project_Node_Kind; + And_Expr_Kind : Variable_Kind := Undefined) + return Project_Node_Id; + -- Returns a Project_Node_Record with the specified Kind and + -- Expr_Kind; all the other components have default nil values. + + ---------------------- + -- Access Functions -- + ---------------------- + + -- The following query functions are part of the abstract interface + -- of the Project File tree + + function Name_Of (Node : Project_Node_Id) return Name_Id; + -- Valid for all non empty nodes. May return No_Name for nodes that have + -- no names. + + function Kind_Of (Node : Project_Node_Id) return Project_Node_Kind; + -- Valid for all non empty nodes + + function Location_Of (Node : Project_Node_Id) return Source_Ptr; + -- Valid for all non empty nodes + + function Directory_Of (Node : Project_Node_Id) return Name_Id; + -- Only valid for N_Project nodes. + + function Expression_Kind_Of (Node : Project_Node_Id) return Variable_Kind; + -- Only valid for N_Literal_String, N_Attribute_Declaration, + -- N_Variable_Declaration, N_Typed_Variable_Declaration, N_Expression, + -- N_Term, N_Variable_Reference or N_Attribute_Reference nodes. + + function First_Variable_Of + (Node : Project_Node_Id) + return Variable_Node_Id; + -- Only valid for N_Project or N_Package_Declaration nodes + + function First_Package_Of + (Node : Project_Node_Id) + return Package_Declaration_Id; + -- Only valid for N_Project nodes + + function Package_Id_Of (Node : Project_Node_Id) return Package_Node_Id; + -- Only valid for N_Package_Declaration nodes + + function Path_Name_Of (Node : Project_Node_Id) return Name_Id; + -- Only valid for N_Project and N_With_Clause nodes. + + function String_Value_Of (Node : Project_Node_Id) return String_Id; + -- Only valid for N_With_Clause or N_Literal_String nodes. + + function First_With_Clause_Of + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_Project nodes + + function Project_Declaration_Of + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_Project nodes + + function First_String_Type_Of + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_Project nodes + + function Modified_Project_Path_Of + (Node : Project_Node_Id) + return String_Id; + -- Only valid for N_With_Clause nodes + + function Project_Node_Of + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_Project nodes + + function Next_With_Clause_Of + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_With_Clause nodes + + function First_Declarative_Item_Of + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_With_Clause nodes + + function Modified_Project_Of + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_With_Clause nodes + + function Current_Item_Node + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_Declarative_Item nodes + + function Next_Declarative_Item + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_Declarative_Item node + + function Project_Of_Renamed_Package_Of + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_Package_Declaration nodes. + -- May return Empty_Node. + + function Next_Package_In_Project + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_Package_Declaration nodes + + function First_Literal_String + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_String_Type_Declaration nodes + + function Next_String_Type + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_String_Type_Declaration nodes + + function Next_Literal_String + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_Literal_String nodes + + function Expression_Of + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_Attribute_Declaration, N_Typed_Variable_Declaration + -- or N_Variable_Declaration nodes + + function Value_Is_Valid + (For_Typed_Variable : Project_Node_Id; + Value : String_Id) + return Boolean; + -- Only valid for N_Typed_Variable_Declaration. Returns True if Value is + -- in the list of allowed strings for For_Typed_Variable. False otherwise. + + function Associative_Array_Index_Of + (Node : Project_Node_Id) + return String_Id; + -- Only valid for N_Attribute_Declaration. + -- Returns No_String for non associative array attributes. + + function Next_Variable + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_Typed_Variable_Declaration or N_Variable_Declaration + -- nodes. + + function First_Term + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_Expression nodes + + function Next_Expression_In_List + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_Expression nodes + + function Current_Term + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_Term nodes + + function Next_Term + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_Term nodes + + function First_Expression_In_List + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_Literal_String_List nodes + + function Package_Node_Of + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_Variable_Reference or N_Attribute_Reference nodes. + -- May return Empty_Node. + + function String_Type_Of + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_Variable_Reference or N_Typed_Variable_Declaration + -- nodes. + + function External_Reference_Of + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_External_Value nodes + + function External_Default_Of + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_External_Value nodes + + function Case_Variable_Reference_Of + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_Case_Construction nodes + + function First_Case_Item_Of + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_Case_Construction nodes + + function First_Choice_Of + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_Case_Item nodes + + function Next_Case_Item + (Node : Project_Node_Id) + return Project_Node_Id; + -- Only valid for N_Case_Item nodes + + -------------------- + -- Set Procedures -- + -------------------- + + -- The following procedures are part of the abstract interface of + -- the Project File tree. + + -- Each Set_* procedure is valid only for the same Project_Node_Kind + -- nodes as the corresponding query function above. + + procedure Set_Name_Of + (Node : Project_Node_Id; + To : Name_Id); + + procedure Set_Kind_Of + (Node : Project_Node_Id; + To : Project_Node_Kind); + + procedure Set_Location_Of + (Node : Project_Node_Id; + To : Source_Ptr); + + procedure Set_Directory_Of + (Node : Project_Node_Id; + To : Name_Id); + + procedure Set_Expression_Kind_Of + (Node : Project_Node_Id; + To : Variable_Kind); + + procedure Set_First_Variable_Of + (Node : Project_Node_Id; + To : Variable_Node_Id); + + procedure Set_First_Package_Of + (Node : Project_Node_Id; + To : Package_Declaration_Id); + + procedure Set_Package_Id_Of + (Node : Project_Node_Id; + To : Package_Node_Id); + + procedure Set_Path_Name_Of + (Node : Project_Node_Id; + To : Name_Id); + + procedure Set_String_Value_Of + (Node : Project_Node_Id; + To : String_Id); + + procedure Set_First_With_Clause_Of + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_Project_Declaration_Of + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_First_String_Type_Of + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_Modified_Project_Path_Of + (Node : Project_Node_Id; + To : String_Id); + + procedure Set_Project_Node_Of + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_Next_With_Clause_Of + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_First_Declarative_Item_Of + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_Modified_Project_Of + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_Current_Item_Node + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_Next_Declarative_Item + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_Project_Of_Renamed_Package_Of + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_Next_Package_In_Project + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_First_Literal_String + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_Next_String_Type + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_Next_Literal_String + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_Expression_Of + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_Associative_Array_Index_Of + (Node : Project_Node_Id; + To : String_Id); + + procedure Set_Next_Variable + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_First_Term + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_Next_Expression_In_List + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_Current_Term + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_Next_Term + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_First_Expression_In_List + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_Package_Node_Of + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_String_Type_Of + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_External_Reference_Of + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_External_Default_Of + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_Case_Variable_Reference_Of + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_First_Case_Item_Of + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_First_Choice_Of + (Node : Project_Node_Id; + To : Project_Node_Id); + + procedure Set_Next_Case_Item + (Node : Project_Node_Id; + To : Project_Node_Id); + + ------------------------------- + -- Restricted Access Section -- + ------------------------------- + + package Tree_Private_Part is + + -- This is conceptually in the private part. + -- However, for efficiency, some packages are accessing it directly. + + type Project_Node_Record is record + + Kind : Project_Node_Kind; + + Location : Source_Ptr := No_Location; + + Directory : Name_Id := No_Name; + -- Only for N_Project + + Expr_Kind : Variable_Kind := Undefined; + -- See below for what Project_Node_Kind it is used + + Variables : Variable_Node_Id := Empty_Node; + -- First variable in a project or a package + + Packages : Package_Declaration_Id := Empty_Node; + -- First package declaration in a project + + Pkg_Id : Package_Node_Id := Empty_Package; + -- Only use in Package_Declaration + + Name : Name_Id := No_Name; + -- See below for what Project_Node_Kind it is used + + Path_Name : Name_Id := No_Name; + -- See below for what Project_Node_Kind it is used + + Value : String_Id := No_String; + -- See below for what Project_Node_Kind it is used + + Field1 : Project_Node_Id := Empty_Node; + -- See below the meaning for each Project_Node_Kind + + Field2 : Project_Node_Id := Empty_Node; + -- See below the meaning for each Project_Node_Kind + + Field3 : Project_Node_Id := Empty_Node; + -- See below the meaning for each Project_Node_Kind + + end record; + + -- type Project_Node_Kind is + + -- (N_Project, + -- -- Name: project name + -- -- Path_Name: project path name + -- -- Expr_Kind: Undefined + -- -- Field1: first with clause + -- -- Field2: project declaration + -- -- Field3: first string type + -- -- Value: modified project path name (if any) + + -- N_With_Clause, + -- -- Name: imported project name + -- -- Path_Name: imported project path name + -- -- Expr_Kind: Undefined + -- -- Field1: project node + -- -- Field2: next with clause + -- -- Field3: not used + -- -- Value: literal string withed + + -- N_Project_Declaration, + -- -- Name: not used + -- -- Path_Name: not used + -- -- Expr_Kind: Undefined + -- -- Field1: first declarative item + -- -- Field2: modified project + -- -- Field3: not used + -- -- Value: not used + + -- N_Declarative_Item, + -- -- Name: not used + -- -- Path_Name: not used + -- -- Expr_Kind: Undefined + -- -- Field1: current item node + -- -- Field2: next declarative item + -- -- Field3: not used + -- -- Value: not used + + -- N_Package_Declaration, + -- -- Name: package name + -- -- Path_Name: not used + -- -- Expr_Kind: Undefined + -- -- Field1: project of renamed package (if any) + -- -- Field2: first declarative item + -- -- Field3: next package in project + -- -- Value: not used + + -- N_String_Type_Declaration, + -- -- Name: type name + -- -- Path_Name: not used + -- -- Expr_Kind: Undefined + -- -- Field1: first literal string + -- -- Field2: next string type + -- -- Field3: not used + -- -- Value: not used + + -- N_Literal_String, + -- -- Name: not used + -- -- Path_Name: not used + -- -- Expr_Kind: Single + -- -- Field1: next literal string + -- -- Field2: not used + -- -- Field3: not used + -- -- Value: string value + + -- N_Attribute_Declaration, + -- -- Name: attribute name + -- -- Path_Name: not used + -- -- Expr_Kind: attribute kind + -- -- Field1: expression + -- -- Field2: not used + -- -- Field3: not used + -- -- Value: associative array index + -- -- (if an associative array element) + + -- N_Typed_Variable_Declaration, + -- -- Name: variable name + -- -- Path_Name: not used + -- -- Expr_Kind: Single + -- -- Field1: expression + -- -- Field2: type of variable (N_String_Type_Declaration) + -- -- Field3: next variable + -- -- Value: not used + + -- N_Variable_Declaration, + -- -- Name: variable name + -- -- Path_Name: not used + -- -- Expr_Kind: variable kind + -- -- Field1: expression + -- -- Field2: not used + -- -- Field3 is used for next variable, instead of Field2, + -- -- so that it is the same field for + -- -- N_Variable_Declaration and + -- -- N_Typed_Variable_Declaration + -- -- Field3: next variable + -- -- Value: not used + + -- N_Expression, + -- -- Name: not used + -- -- Path_Name: not used + -- -- Expr_Kind: expression kind + -- -- Field1: first term + -- -- Field2: next expression in list + -- -- Field3: not used + -- -- Value: not used + + -- N_Term, + -- -- Name: not used + -- -- Path_Name: not used + -- -- Expr_Kind: term kind + -- -- Field1: current term + -- -- Field2: next term in the expression + -- -- Field3: not used + -- -- Value: not used + + -- N_Literal_String_List, + -- -- Designates a list of string expressions between brackets + -- -- separated by commas. The string expressions are not necessarily + -- -- literal strings. + -- -- Name: not used + -- -- Path_Name: not used + -- -- Expr_Kind: List + -- -- Field1: first expression + -- -- Field2: not used + -- -- Field3: not used + -- -- Value: not used + + -- N_Variable_Reference, + -- -- Name: variable name + -- -- Path_Name: not used + -- -- Expr_Kind: variable kind + -- -- Field1: project (if specified) + -- -- Field2: package (if specified) + -- -- Field3: type of variable (N_String_Type_Declaration), if any + -- -- Value: not used + + -- N_External_Value, + -- -- Name: not used + -- -- Path_Name: not used + -- -- Expr_Kind: Single + -- -- Field1: Name of the external reference (literal string) + -- -- Field2: Default (literal string) + -- -- Field3: not used + -- -- Value: not used + + -- N_Attribute_Reference, + -- -- Name: attribute name + -- -- Path_Name: not used + -- -- Expr_Kind: attribute kind + -- -- Field1: project + -- -- Field2: package (if attribute of a package) + -- -- Field3: not used + -- -- Value: not used + + -- N_Case_Construction, + -- -- Name: not used + -- -- Path_Name: not used + -- -- Expr_Kind: Undefined + -- -- Field1: case variable reference + -- -- Field2: first case item + -- -- Field3: not used + -- -- Value: not used + + -- N_Case_Item); + -- -- Name: not used + -- -- Path_Name: not used + -- -- Expr_Kind: not used + -- -- Field1: first choice (literal string) + -- -- Field2: first declarative item + -- -- Field3: next case item + -- -- Value: not used + + package Project_Nodes is + new Table.Table (Table_Component_Type => Project_Node_Record, + Table_Index_Type => Project_Node_Id, + Table_Low_Bound => First_Node_Id, + Table_Initial => Project_Nodes_Initial, + Table_Increment => Project_Nodes_Increment, + Table_Name => "Project_Nodes"); + -- This table contains the syntactic tree of project data + -- from project files. + + type Project_Name_And_Node is record + Name : Name_Id; + -- Name of the project + Node : Project_Node_Id; + -- Node of the project in table Project_Nodes + Modified : Boolean; + -- True when the project is being modified by another project + end record; + + No_Project_Name_And_Node : constant Project_Name_And_Node := + (Name => No_Name, Node => Empty_Node, Modified => True); + + package Projects_Htable is new GNAT.HTable.Simple_HTable + (Header_Num => Header_Num, + Element => Project_Name_And_Node, + No_Element => No_Project_Name_And_Node, + Key => Name_Id, + Hash => Hash, + Equal => "="); + -- This hash table contains a mapping of project names to project nodes. + -- Note that this hash table contains only the nodes whose Kind is + -- N_Project. It is used to find the node of a project from its + -- name, and to verify if a project has already been parsed, knowing + -- its name. + + end Tree_Private_Part; + +end Prj.Tree; diff --git a/gcc/ada/prj-util.adb b/gcc/ada/prj-util.adb new file mode 100644 index 00000000000..6a94a0cfc4c --- /dev/null +++ b/gcc/ada/prj-util.adb @@ -0,0 +1,415 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J . U T I L -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.8 $ -- +-- -- +-- Copyright (C) 2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +with Ada.Unchecked_Deallocation; + +with Namet; use Namet; +with Osint; +with Output; use Output; +with Stringt; use Stringt; + +package body Prj.Util is + + procedure Free is new Ada.Unchecked_Deallocation + (Text_File_Data, Text_File); + + ----------- + -- Close -- + ----------- + + procedure Close (File : in out Text_File) is + begin + if File = null then + Osint.Fail ("Close attempted on an invalid Text_File"); + end if; + + Close (File.FD); + Free (File); + end Close; + + ----------------- + -- End_Of_File -- + ----------------- + + function End_Of_File (File : Text_File) return Boolean is + begin + if File = null then + Osint.Fail ("End_Of_File attempted on an invalid Text_File"); + end if; + + return File.End_Of_File_Reached; + end End_Of_File; + + -------------- + -- Get_Line -- + -------------- + + procedure Get_Line + (File : Text_File; + Line : out String; + Last : out Natural) + is + C : Character; + + procedure Advance; + + ------------- + -- Advance -- + ------------- + + procedure Advance is + begin + if File.Cursor = File.Buffer_Len then + File.Buffer_Len := + Read + (FD => File.FD, + A => File.Buffer'Address, + N => File.Buffer'Length); + + if File.Buffer_Len = 0 then + File.End_Of_File_Reached := True; + return; + else + File.Cursor := 1; + end if; + + else + File.Cursor := File.Cursor + 1; + end if; + end Advance; + + -- Start of processing for Get_Line + + begin + if File = null then + Osint.Fail ("Get_Line attempted on an invalid Text_File"); + end if; + + Last := Line'First - 1; + + if not File.End_Of_File_Reached then + loop + C := File.Buffer (File.Cursor); + exit when C = ASCII.CR or else C = ASCII.LF; + Last := Last + 1; + Line (Last) := C; + Advance; + + if File.End_Of_File_Reached then + return; + end if; + + exit when Last = Line'Last; + end loop; + + if C = ASCII.CR or else C = ASCII.LF then + Advance; + + if File.End_Of_File_Reached then + return; + end if; + end if; + + if C = ASCII.CR + and then File.Buffer (File.Cursor) = ASCII.LF + then + Advance; + end if; + end if; + end Get_Line; + + -------------- + -- Is_Valid -- + -------------- + + function Is_Valid (File : Text_File) return Boolean is + begin + return File /= null; + end Is_Valid; + + ---------- + -- Open -- + ---------- + + procedure Open (File : out Text_File; Name : in String) is + FD : File_Descriptor; + File_Name : String (1 .. Name'Length + 1); + + begin + File_Name (1 .. Name'Length) := Name; + File_Name (File_Name'Last) := ASCII.NUL; + FD := Open_Read (Name => File_Name'Address, + Fmode => GNAT.OS_Lib.Text); + if FD = Invalid_FD then + File := null; + else + File := new Text_File_Data; + File.FD := FD; + File.Buffer_Len := + Read (FD => FD, + A => File.Buffer'Address, + N => File.Buffer'Length); + + if File.Buffer_Len = 0 then + File.End_Of_File_Reached := True; + else + File.Cursor := 1; + end if; + end if; + end Open; + + -------------- + -- Value_Of -- + -------------- + + function Value_Of + (Index : Name_Id; + In_Array : Array_Element_Id) + return Name_Id + is + Current : Array_Element_Id := In_Array; + Element : Array_Element; + + begin + while Current /= No_Array_Element loop + Element := Array_Elements.Table (Current); + + if Index = Element.Index then + exit when Element.Value.Kind /= Single; + exit when String_Length (Element.Value.Value) = 0; + String_To_Name_Buffer (Element.Value.Value); + return Name_Find; + else + Current := Element.Next; + end if; + end loop; + + return No_Name; + end Value_Of; + + function Value_Of + (Index : Name_Id; + In_Array : Array_Element_Id) + return Variable_Value + is + Current : Array_Element_Id := In_Array; + Element : Array_Element; + + begin + while Current /= No_Array_Element loop + Element := Array_Elements.Table (Current); + + if Index = Element.Index then + return Element.Value; + else + Current := Element.Next; + end if; + end loop; + + return Nil_Variable_Value; + end Value_Of; + + function Value_Of + (Name : Name_Id; + Attribute_Or_Array_Name : Name_Id; + In_Package : Package_Id) + return Variable_Value + is + The_Array : Array_Element_Id; + The_Attribute : Variable_Value := Nil_Variable_Value; + + begin + if In_Package /= No_Package then + + -- First, look if there is an array element that fits + + The_Array := + Value_Of + (Name => Attribute_Or_Array_Name, + In_Arrays => Packages.Table (In_Package).Decl.Arrays); + The_Attribute := + Value_Of + (Index => Name, + In_Array => The_Array); + + -- If there is no array element, look for a variable + + if The_Attribute = Nil_Variable_Value then + The_Attribute := + Value_Of + (Variable_Name => Attribute_Or_Array_Name, + In_Variables => Packages.Table (In_Package).Decl.Attributes); + end if; + end if; + + return The_Attribute; + end Value_Of; + + function Value_Of + (Index : Name_Id; + In_Array : Name_Id; + In_Arrays : Array_Id) + return Name_Id + is + Current : Array_Id := In_Arrays; + The_Array : Array_Data; + + begin + while Current /= No_Array loop + The_Array := Arrays.Table (Current); + if The_Array.Name = In_Array then + return Value_Of (Index, In_Array => The_Array.Value); + else + Current := The_Array.Next; + end if; + end loop; + + return No_Name; + end Value_Of; + + function Value_Of + (Name : Name_Id; + In_Arrays : Array_Id) + return Array_Element_Id + is + Current : Array_Id := In_Arrays; + The_Array : Array_Data; + + begin + while Current /= No_Array loop + The_Array := Arrays.Table (Current); + if The_Array.Name = Name then + return The_Array.Value; + else + Current := The_Array.Next; + end if; + end loop; + + return No_Array_Element; + end Value_Of; + + function Value_Of + (Name : Name_Id; + In_Packages : Package_Id) + return Package_Id + is + Current : Package_Id := In_Packages; + The_Package : Package_Element; + + begin + while Current /= No_Package loop + The_Package := Packages.Table (Current); + exit when The_Package.Name /= No_Name and then + The_Package.Name = Name; + Current := The_Package.Next; + end loop; + + return Current; + end Value_Of; + + function Value_Of + (Variable_Name : Name_Id; + In_Variables : Variable_Id) + return Variable_Value + is + Current : Variable_Id := In_Variables; + The_Variable : Variable; + + begin + while Current /= No_Variable loop + The_Variable := Variable_Elements.Table (Current); + + if Variable_Name = The_Variable.Name then + return The_Variable.Value; + else + Current := The_Variable.Next; + end if; + end loop; + + return Nil_Variable_Value; + end Value_Of; + + --------------- + -- Write_Str -- + --------------- + + procedure Write_Str + (S : String; + Max_Length : Positive; + Separator : Character) + is + First : Positive := S'First; + Last : Natural := S'Last; + + begin + -- Nothing to do for empty strings + + if S'Length > 0 then + -- Start on a new line if current line is already longer than + -- Max_Length. + + if Positive (Column) >= Max_Length then + Write_Eol; + end if; + + -- If length of remainder is longer than Max_Length, we need to + -- cut the remainder in several lines. + + while Positive (Column) + S'Last - First > Max_Length loop + -- Try the maximum length possible + + Last := First + Max_Length - Positive (Column); + + -- Look for last Separator in the line + + while Last >= First and then S (Last) /= Separator loop + Last := Last - 1; + end loop; + + -- If we do not find a separator, we output the maximum length + -- possible. + if Last < First then + Last := First + Max_Length - Positive (Column); + end if; + + Write_Line (S (First .. Last)); + + -- Set the beginning of the new remainder + + First := Last + 1; + + end loop; + + -- What is left goes to the buffer, without EOL + + Write_Str (S (First .. S'Last)); + + end if; + end Write_Str; + +end Prj.Util; diff --git a/gcc/ada/prj-util.ads b/gcc/ada/prj-util.ads new file mode 100644 index 00000000000..baef0404f0e --- /dev/null +++ b/gcc/ada/prj-util.ads @@ -0,0 +1,148 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J . U T I L -- +-- -- +-- S p e c -- +-- -- +-- $Revision: 1.6 $ +-- -- +-- Copyright (C) 2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ +-- +-- Utilities when using project files. + +with GNAT.OS_Lib; use GNAT.OS_Lib; +with Types; use Types; + +package Prj.Util is + + function Value_Of + (Index : Name_Id; + In_Array : Array_Element_Id) + return Name_Id; + -- Get a single string array component. + -- Returns No_Name if there is no component Index (case sensitive), + -- if In_Array is null, or if the component is a String list. + + function Value_Of + (Index : Name_Id; + In_Array : Array_Element_Id) + return Variable_Value; + -- Get a string array component (single String or String list). + -- Returns Nil_Variable_Value if there is no component Index + -- (case sensitive), or if In_Array is null. + + function Value_Of + (Name : Name_Id; + Attribute_Or_Array_Name : Name_Id; + In_Package : Package_Id) + return Variable_Value; + -- In a specific package, + -- - if there exists an array Variable_Or_Array_Name with an index + -- Name, returns the corresponding component, + -- - otherwise if there is a attribute Attribute_Or_Array_Name, + -- returns this attribute, + -- - otherwise, returns Nil_Variable_Value. + -- If In_Package is null, returns Nil_Variable_Value. + + function Value_Of + (Index : Name_Id; + In_Array : Name_Id; + In_Arrays : Array_Id) + return Name_Id; + -- Get a string array component in an array of an array list. + -- Returns No_Name if there is no component Index (case sensitive), + -- if In_Arrays is null, if In_Array is not found in In_Arrays, + -- or if the component is a String list. + + function Value_Of + (Name : Name_Id; + In_Arrays : Array_Id) + return Array_Element_Id; + -- Returns a specified array in an array list. + -- Returns No_Array_Element if In_Arrays is null or if Name is not the + -- name of an array in In_Arrays. + -- Assumption: Name is in lower case. + + function Value_Of + (Name : Name_Id; + In_Packages : Package_Id) + return Package_Id; + -- Returns a specified package in a package list. + -- Returns No_Package if In_Packages is null or if Name is not the + -- name of a package in Package_List. + -- Assumption: Name is in lower case. + + function Value_Of + (Variable_Name : Name_Id; + In_Variables : Variable_Id) + return Variable_Value; + -- Returns a specified variable in a variable list. + -- Returns null if In_Variables is null or if Variable_Name + -- is not the name of a variable in In_Variables. + -- Assumption: Variable_Name is in lower case. + + procedure Write_Str + (S : String; + Max_Length : Positive; + Separator : Character); + -- Output string S using Output.Write_Str. + -- If S is too long to fit in one line of Max_Length, cut it in + -- several lines, using Separator as the last character of each line, + -- if possible. + + type Text_File is limited private; + -- Represents a text file. + -- Default is invalid text file. + + function Is_Valid (File : Text_File) return Boolean; + -- Returns True if File designates an open text file that + -- has not yet been closed. + + procedure Open (File : out Text_File; Name : String); + -- Open a text file. If this procedure fails, File is invalid. + + function End_Of_File (File : Text_File) return Boolean; + -- Returns True if the end of the text file File has been + -- reached. Fails if File is invalid. + + procedure Get_Line + (File : Text_File; + Line : out String; + Last : out Natural); + -- Reads a line from an open text file. Fails if File is invalid. + + procedure Close (File : in out Text_File); + -- Close an open text file. File becomes invalid. + -- Fails if File is already invalid. + +private + + type Text_File_Data is record + FD : File_Descriptor := Invalid_FD; + Buffer : String (1 .. 1_000); + Buffer_Len : Natural; + Cursor : Natural := 0; + End_Of_File_Reached : Boolean := False; + end record; + + type Text_File is access Text_File_Data; + +end Prj.Util; diff --git a/gcc/ada/prj.adb b/gcc/ada/prj.adb new file mode 100644 index 00000000000..8e302117917 --- /dev/null +++ b/gcc/ada/prj.adb @@ -0,0 +1,286 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.16 $ +-- -- +-- Copyright (C) 2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +with Ada.Characters.Handling; use Ada.Characters.Handling; +with Errout; use Errout; +with GNAT.OS_Lib; use GNAT.OS_Lib; +with Namet; use Namet; +with Osint; use Osint; +with Prj.Attr; +with Prj.Com; +with Prj.Env; +with Scans; use Scans; +with Scn; +with Stringt; use Stringt; +with Sinfo.CN; +with Snames; use Snames; + +package body Prj is + + The_Empty_String : String_Id; + + subtype Known_Casing is Casing_Type range All_Upper_Case .. Mixed_Case; + + The_Casing_Images : array (Known_Casing) of String_Access := + (All_Lower_Case => new String'("lowercase"), + All_Upper_Case => new String'("UPPERCASE"), + Mixed_Case => new String'("MixedCase")); + + Initialized : Boolean := False; + + Standard_Dot_Replacement : constant Name_Id := + First_Name_Id + Character'Pos ('-'); + Standard_Specification_Append : Name_Id; + Standard_Body_Append : Name_Id; + + Std_Naming_Data : Naming_Data := + (Dot_Replacement => Standard_Dot_Replacement, + Dot_Repl_Loc => No_Location, + Casing => All_Lower_Case, + Specification_Append => No_Name, + Spec_Append_Loc => No_Location, + Body_Append => No_Name, + Body_Append_Loc => No_Location, + Separate_Append => No_Name, + Sep_Append_Loc => No_Location, + Specifications => No_Array_Element, + Bodies => No_Array_Element); + + Project_Empty : Project_Data := + (First_Referred_By => No_Project, + Name => No_Name, + Path_Name => No_Name, + Location => No_Location, + Directory => No_Name, + File_Name => No_Name, + Library => False, + Library_Dir => No_Name, + Library_Name => No_Name, + Library_Kind => Static, + Lib_Internal_Name => No_Name, + Lib_Elaboration => False, + Sources => Nil_String, + Source_Dirs => Nil_String, + Object_Directory => No_Name, + Modifies => No_Project, + Modified_By => No_Project, + Naming => Std_Naming_Data, + Decl => No_Declarations, + Imported_Projects => Empty_Project_List, + Include_Path => null, + Objects_Path => null, + Config_File_Name => No_Name, + Config_File_Temp => False, + Config_Checked => False, + Checked => False, + Seen => False, + Flag1 => False, + Flag2 => False); + + ------------------- + -- Empty_Project -- + ------------------- + + function Empty_Project return Project_Data is + begin + Initialize; + return Project_Empty; + end Empty_Project; + + ------------------ + -- Empty_String -- + ------------------ + + function Empty_String return String_Id is + begin + return The_Empty_String; + end Empty_String; + + ------------ + -- Expect -- + ------------ + + procedure Expect (The_Token : Token_Type; Token_Image : String) is + begin + if Token /= The_Token then + Error_Msg ("""" & Token_Image & """ expected", Token_Ptr); + end if; + end Expect; + + -------------------------------- + -- For_Every_Project_Imported -- + -------------------------------- + + procedure For_Every_Project_Imported + (By : Project_Id; + With_State : in out State) + is + + procedure Check (Project : Project_Id); + -- Check if a project has already been seen. + -- If not seen, mark it as seen, call Action, + -- and check all its imported projects. + + procedure Check (Project : Project_Id) is + List : Project_List; + + begin + if not Projects.Table (Project).Seen then + Projects.Table (Project).Seen := False; + Action (Project, With_State); + + List := Projects.Table (Project).Imported_Projects; + while List /= Empty_Project_List loop + Check (Project_Lists.Table (List).Project); + List := Project_Lists.Table (List).Next; + end loop; + end if; + end Check; + + begin + for Project in Projects.First .. Projects.Last loop + Projects.Table (Project).Seen := False; + end loop; + + Check (Project => By); + end For_Every_Project_Imported; + + ----------- + -- Image -- + ----------- + + function Image (Casing : Casing_Type) return String is + begin + return The_Casing_Images (Casing).all; + end Image; + + ---------------- + -- Initialize -- + ---------------- + + procedure Initialize is + begin + if not Initialized then + Initialized := True; + Stringt.Initialize; + Start_String; + The_Empty_String := End_String; + Name_Len := 4; + Name_Buffer (1 .. 4) := ".ads"; + Canonical_Case_File_Name (Name_Buffer (1 .. 4)); + Standard_Specification_Append := Name_Find; + Name_Buffer (4) := 'b'; + Canonical_Case_File_Name (Name_Buffer (1 .. 4)); + Standard_Body_Append := Name_Find; + Std_Naming_Data.Specification_Append := Standard_Specification_Append; + Std_Naming_Data.Body_Append := Standard_Body_Append; + Std_Naming_Data.Separate_Append := Standard_Body_Append; + Project_Empty.Naming := Std_Naming_Data; + Prj.Env.Initialize; + Prj.Attr.Initialize; + Set_Name_Table_Byte (Name_Project, Token_Type'Pos (Tok_Project)); + Set_Name_Table_Byte (Name_Modifying, Token_Type'Pos (Tok_Modifying)); + Set_Name_Table_Byte (Name_External, Token_Type'Pos (Tok_External)); + end if; + end Initialize; + + ------------ + -- Reset -- + ------------ + + procedure Reset is + begin + Projects.Init; + Project_Lists.Init; + Packages.Init; + Arrays.Init; + Variable_Elements.Init; + String_Elements.Init; + Prj.Com.Units.Init; + Prj.Com.Units_Htable.Reset; + end Reset; + + ------------------------ + -- Same_Naming_Scheme -- + ------------------------ + + function Same_Naming_Scheme + (Left, Right : Naming_Data) + return Boolean + is + begin + return Left.Dot_Replacement = Right.Dot_Replacement + and then Left.Casing = Right.Casing + and then Left.Specification_Append = Right.Specification_Append + and then Left.Body_Append = Right.Body_Append + and then Left.Separate_Append = Right.Separate_Append; + end Same_Naming_Scheme; + + ---------- + -- Scan -- + ---------- + + procedure Scan is + begin + Scn.Scan; + + -- Change operator symbol to literal strings, since that's the way + -- we treat all strings in a project file. + + if Token = Tok_Operator_Symbol then + Sinfo.CN.Change_Operator_Symbol_To_String_Literal (Token_Node); + Token := Tok_String_Literal; + end if; + end Scan; + + -------------------------- + -- Standard_Naming_Data -- + -------------------------- + + function Standard_Naming_Data return Naming_Data is + begin + Initialize; + return Std_Naming_Data; + end Standard_Naming_Data; + + ----------- + -- Value -- + ----------- + + function Value (Image : String) return Casing_Type is + begin + for Casing in The_Casing_Images'Range loop + if To_Lower (Image) = To_Lower (The_Casing_Images (Casing).all) then + return Casing; + end if; + end loop; + + raise Constraint_Error; + end Value; + +end Prj; diff --git a/gcc/ada/prj.ads b/gcc/ada/prj.ads new file mode 100644 index 00000000000..409a0717223 --- /dev/null +++ b/gcc/ada/prj.ads @@ -0,0 +1,416 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- P R J -- +-- -- +-- S p e c -- +-- -- +-- $Revision: 1.18 $ +-- -- +-- Copyright (C) 2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +-- The following package declares the data types for GNAT project. +-- These data types may be used by GNAT Project-aware tools. + +-- Children of these package implements various services on these data types. +-- See in particular Prj.Pars and Prj.Env. + +with Casing; use Casing; +with GNAT.OS_Lib; use GNAT.OS_Lib; +with Scans; use Scans; +with Table; +with Types; use Types; + +package Prj is + + type Put_Line_Access is access procedure (Line : String); + -- Use to customize error reporting in Prj.Proc and Prj.Nmsc. + + type Verbosity is (Default, Medium, High); + -- Verbosity when parsing GNAT Project Files. + -- Default is default (very quiet, if no errors). + -- Medium is more verbose. + -- High is extremely verbose. + + type Lib_Kind is (Static, Dynamic, Relocatable); + + function Empty_String return String_Id; + + type String_List_Id is new Nat; + Nil_String : constant String_List_Id := 0; + type String_Element is record + Value : String_Id := No_String; + Location : Source_Ptr := No_Location; + Next : String_List_Id := Nil_String; + end record; + -- To hold values for string list variables and array elements. + + package String_Elements is new Table.Table + (Table_Component_Type => String_Element, + Table_Index_Type => String_List_Id, + Table_Low_Bound => 1, + Table_Initial => 200, + Table_Increment => 100, + Table_Name => "Prj.String_Elements"); + -- The table for string elements in string lists. + + type Variable_Kind is (Undefined, List, Single); + -- Different kinds of variables + + type Variable_Value (Kind : Variable_Kind := Undefined) is record + Location : Source_Ptr := No_Location; + Default : Boolean := False; + case Kind is + when Undefined => + null; + when List => + Values : String_List_Id := Nil_String; + when Single => + Value : String_Id := No_String; + end case; + end record; + -- Values for variables and array elements + + Nil_Variable_Value : constant Variable_Value := + (Kind => Undefined, + Location => No_Location, + Default => False); + -- Value of a non existing variable or array element. + + type Variable_Id is new Nat; + No_Variable : constant Variable_Id := 0; + type Variable is record + Next : Variable_Id := No_Variable; + Name : Name_Id; + Value : Variable_Value; + end record; + -- To hold the list of variables in a project file and in packages. + + package Variable_Elements is new Table.Table + (Table_Component_Type => Variable, + Table_Index_Type => Variable_Id, + Table_Low_Bound => 1, + Table_Initial => 200, + Table_Increment => 100, + Table_Name => "Prj.Variable_Elements"); + -- The table of variable in list of variables. + + type Array_Element_Id is new Nat; + No_Array_Element : constant Array_Element_Id := 0; + type Array_Element is record + Index : Name_Id; + Value : Variable_Value; + Next : Array_Element_Id := No_Array_Element; + end record; + -- Each Array_Element represents an array element. + -- Each Array_Element is linked (Next) to the next array element, + -- if any, in the array. + + package Array_Elements is new Table.Table + (Table_Component_Type => Array_Element, + Table_Index_Type => Array_Element_Id, + Table_Low_Bound => 1, + Table_Initial => 200, + Table_Increment => 100, + Table_Name => "Prj.Array_Elements"); + -- The table that contains all array elements + + type Array_Id is new Nat; + No_Array : constant Array_Id := 0; + type Array_Data is record + Name : Name_Id := No_Name; + Value : Array_Element_Id := No_Array_Element; + Next : Array_Id := No_Array; + end record; + -- Each Array_Data represents an array. + -- Value is the id of the first element. + -- Next is the id of the next array in the project file or package. + + package Arrays is new Table.Table + (Table_Component_Type => Array_Data, + Table_Index_Type => Array_Id, + Table_Low_Bound => 1, + Table_Initial => 200, + Table_Increment => 100, + Table_Name => "Prj.Arrays"); + -- The table that contains all arrays + + type Package_Id is new Nat; + No_Package : constant Package_Id := 0; + type Declarations is record + Variables : Variable_Id := No_Variable; + Attributes : Variable_Id := No_Variable; + Arrays : Array_Id := No_Array; + Packages : Package_Id := No_Package; + end record; + + No_Declarations : constant Declarations := + (Variables => No_Variable, + Attributes => No_Variable, + Arrays => No_Array, + Packages => No_Package); + -- Declarations. Used in project structures and packages. + + type Package_Element is record + Name : Name_Id := No_Name; + Decl : Declarations := No_Declarations; + Parent : Package_Id := No_Package; + Next : Package_Id := No_Package; + end record; + -- A package. Includes declarations that may include + -- other packages. + + package Packages is new Table.Table + (Table_Component_Type => Package_Element, + Table_Index_Type => Package_Id, + Table_Low_Bound => 1, + Table_Initial => 100, + Table_Increment => 100, + Table_Name => "Prj.Packages"); + -- The table that contains all packages. + + function Image (Casing : Casing_Type) return String; + -- Similar to 'Image + + function Value (Image : String) return Casing_Type; + -- Similar to 'Value + -- This is to avoid s-valenu in the closure of the tools + -- Raises Constraint_Error if not a Casing_Type image. + + type Naming_Data is record + Dot_Replacement : Name_Id := No_Name; + -- The string to replace '.' in the source file name. + + Dot_Repl_Loc : Source_Ptr := No_Location; + -- The position in the project file source where + -- Dot_Replacement is defined. + + Casing : Casing_Type := All_Lower_Case; + -- The casing of the source file name. + + Specification_Append : Name_Id := No_Name; + -- The string to append to the unit name for the + -- source file name of a specification. + + Spec_Append_Loc : Source_Ptr := No_Location; + -- The position in the project file source where + -- Specification_Append is defined. + + Body_Append : Name_Id := No_Name; + -- The string to append to the unit name for the + -- source file name of a body. + + Body_Append_Loc : Source_Ptr := No_Location; + -- The position in the project file source where + -- Body_Append is defined. + + Separate_Append : Name_Id := No_Name; + -- The string to append to the unit name for the + -- source file name of a subunit. + + Sep_Append_Loc : Source_Ptr := No_Location; + -- The position in the project file source where + -- Separate_Append is defined. + + Specifications : Array_Element_Id := No_Array_Element; + -- An associative array mapping individual specifications + -- to source file names. + + Bodies : Array_Element_Id := No_Array_Element; + -- An associative array mapping individual bodies + -- to source file names. + + end record; + -- A naming scheme. + + function Standard_Naming_Data return Naming_Data; + pragma Inline (Standard_Naming_Data); + -- The standard GNAT naming scheme. + + function Same_Naming_Scheme + (Left, Right : Naming_Data) + return Boolean; + -- Returns True if Left and Right are the same naming scheme + -- not considering Specifications and Bodies. + + type Project_Id is new Nat; + No_Project : constant Project_Id := 0; + -- Id of a Project File + + type Project_List is new Nat; + Empty_Project_List : constant Project_List := 0; + -- A list of project files. + + type Project_Element is record + Project : Project_Id := No_Project; + Next : Project_List := Empty_Project_List; + end record; + -- Element in a list of project file. + -- Next is the id of the next project file in the list. + + package Project_Lists is new Table.Table + (Table_Component_Type => Project_Element, + Table_Index_Type => Project_List, + Table_Low_Bound => 1, + Table_Initial => 100, + Table_Increment => 100, + Table_Name => "Prj.Project_Lists"); + -- The table that contains the lists of project files. + + type Project_Data is record + First_Referred_By : Project_Id := No_Project; + -- The project, if any, that was the first to be known + -- as importing or modifying this project. + + Name : Name_Id := No_Name; + -- The name of the project. + + Path_Name : Name_Id := No_Name; + -- The path name of the project file. + + Location : Source_Ptr := No_Location; + -- The location in the project file source of the + -- reserved word project. + + Directory : Name_Id := No_Name; + -- The directory where the project file resides. + + File_Name : Name_Id := No_Name; + -- The file name of the project file. + + Library : Boolean := False; + -- True if this is a library project + + Library_Dir : Name_Id := No_Name; + -- If a library project, directory where resides the library + + Library_Name : Name_Id := No_Name; + -- If a library project, name of the library + + Library_Kind : Lib_Kind := Static; + -- If a library project, kind of library + + Lib_Internal_Name : Name_Id := No_Name; + -- If a library project, internal name store inside the library + + Lib_Elaboration : Boolean := False; + -- If a library project, indicate if <lib>init and <lib>final + -- procedures need to be defined. + + Sources : String_List_Id := Nil_String; + -- The list of all the source file names. + + Source_Dirs : String_List_Id := Nil_String; + -- The list of all the source directories. + + Object_Directory : Name_Id := No_Name; + -- The object directory of this project file. + + Modifies : Project_Id := No_Project; + -- The reference of the project file, if any, that this + -- project file modifies. + + Modified_By : Project_Id := No_Project; + -- The reference of the project file, if any, that + -- modifies this project file. + + Naming : Naming_Data := Standard_Naming_Data; + -- The naming scheme of this project file. + + Decl : Declarations := No_Declarations; + -- The declarations (variables, attributes and packages) + -- of this project file. + + Imported_Projects : Project_List := Empty_Project_List; + -- The list of all directly imported projects, if any. + + Include_Path : String_Access := null; + -- The cached value of ADA_INCLUDE_PATH for this project file. + + Objects_Path : String_Access := null; + -- The cached value of ADA_OBJECTS_PATH for this project file. + + Config_File_Name : Name_Id := No_Name; + -- The name of the configuration pragmas file, if any. + + Config_File_Temp : Boolean := False; + -- An indication that the configuration pragmas file is + -- a temporary file that must be deleted at the end. + + Config_Checked : Boolean := False; + -- A flag to avoid checking repetively the configuration pragmas file. + + Checked : Boolean := False; + -- A flag to avoid checking repetively the naming scheme of + -- this project file. + + -- Various flags that are used in an ad hoc manner + + Seen : Boolean := False; + Flag1 : Boolean := False; + Flag2 : Boolean := False; + + end record; + -- Project File representation. + + function Empty_Project return Project_Data; + -- Return the representation of an empty project. + + package Projects is new Table.Table ( + Table_Component_Type => Project_Data, + Table_Index_Type => Project_Id, + Table_Low_Bound => 1, + Table_Initial => 100, + Table_Increment => 100, + Table_Name => "Prj.Projects"); + -- The set of all project files. + + procedure Expect (The_Token : Token_Type; Token_Image : String); + -- Check that the current token is The_Token. If it is not, then + -- output an error message. + + procedure Initialize; + -- This procedure must be called before using any services from the Prj + -- hierarchy. Namet.Initialize must be called before Prj.Initialize. + + procedure Reset; + -- This procedure resets all the tables that are used when processing a + -- project file tree. Initialize must be called before the call to Reset. + + generic + type State is limited private; + with procedure Action + (Project : Project_Id; + With_State : in out State); + procedure For_Every_Project_Imported + (By : Project_Id; + With_State : in out State); + -- Call Action for each project imported directly or indirectly by project + -- By.-- Action is called according to the order of importation: if A + -- imports B, directly or indirectly, Action will be called for A before + -- it is called for B. With_State may be used by Action to choose a + -- behavior or to report some global result. + +private + + procedure Scan; + -- Calls Scn.Scan and change any Operator_Symbol to String_Literal + +end Prj; diff --git a/gcc/ada/raise.c b/gcc/ada/raise.c new file mode 100644 index 00000000000..43d630795a8 --- /dev/null +++ b/gcc/ada/raise.c @@ -0,0 +1,86 @@ +/**************************************************************************** + * * + * GNAT COMPILER COMPONENTS * + * * + * R A I S E * + * * + * C Implementation File * + * * + * $Revision: 1.1 $ + * * + * Copyright (C) 1992-2001, 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 2, 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 COPYING. If not, write * + * to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, * + * MA 02111-1307, USA. * + * * + * As a special exception, if you link this file with other files to * + * produce an executable, this file does not by itself cause the resulting * + * executable to be covered by the GNU General Public License. This except- * + * ion does not however invalidate any other reasons why the executable * + * file might be covered by the GNU Public License. * + * * + * GNAT was originally developed by the GNAT team at New York University. * + * It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). * + * * + ****************************************************************************/ + +/* Routines to support runtime exception handling */ + +#ifdef IN_RTS +#include "tconfig.h" +#include "tsystem.h" +#include <sys/stat.h> +#else +#include "config.h" +#include "system.h" +#endif + +#include "adaint.h" +#include "raise.h" + +/* We have not yet figured out how to import this directly */ + +void +_gnat_builtin_longjmp (ptr, flag) + void *ptr; + int flag ATTRIBUTE_UNUSED; +{ + __builtin_longjmp (ptr, 1); +} + +/* When an exception is raised for which no handler exists, the procedure + Ada.Exceptions.Unhandled_Exception is called, which performs the call to + adafinal to complete finalization, and then prints out the error messages + for the unhandled exception. The final step is to call this routine, which + performs any system dependent cleanup required. */ + +void +__gnat_unhandled_terminate () +{ + /* Special termination handling for VMS */ + +#ifdef VMS + { + long prvhnd; + + /* Remove the exception vector so it won't intercept any errors + in the call to exit, and go into and endless loop */ + + SYS$SETEXV (1, 0, 3, &prvhnd); + __gnat_os_exit (1); + } + +/* Termination handling for all other systems. */ + +#elif !defined (__RT__) + __gnat_os_exit (1); +#endif +} diff --git a/gcc/ada/raise.h b/gcc/ada/raise.h new file mode 100644 index 00000000000..8db83f4a2b8 --- /dev/null +++ b/gcc/ada/raise.h @@ -0,0 +1,71 @@ +/**************************************************************************** + * * + * GNAT COMPILER COMPONENTS * + * * + * R A I S E * + * * + * C Header File * + * * + * $Revision: 1.1 $ + * * + * Copyright (C) 1992-2001, 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 2, 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 COPYING. If not, write * + * to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, * + * MA 02111-1307, USA. * + * * + * As a special exception, if you link this file with other files to * + * produce an executable, this file does not by itself cause the resulting * + * executable to be covered by the GNU General Public License. This except- * + * ion does not however invalidate any other reasons why the executable * + * file might be covered by the GNU Public License. * + * * + * GNAT was originally developed by the GNAT team at New York University. * + * It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). * + * * + ****************************************************************************/ + +struct Exception_Data +{ + char Handled_By_Others; + char Lang; + int Name_Length; + char *Full_Name, Htable_Ptr; + int Import_Code; +}; + +typedef struct Exception_Data *Exception_Id; + +struct Exception_Occurrence +{ + int Max_Length; + Exception_Id Id; + int Msg_Length; + char Msg [0]; +}; + +typedef struct Exception_Occurrence *Exception_Occurrence_Access; + +extern void _gnat_builtin_longjmp PARAMS ((void *, int)); +extern void __gnat_unhandled_terminate PARAMS ((void)); +extern void *__gnat_malloc PARAMS ((__SIZE_TYPE__)); +extern void __gnat_free PARAMS ((void *)); +extern void *__gnat_realloc PARAMS ((void *, __SIZE_TYPE__)); +extern void __gnat_finalize PARAMS ((void)); +extern void set_gnat_exit_status PARAMS ((int)); +extern void __gnat_set_globals PARAMS ((int, int, int, int, int, int, + void (*) PARAMS ((void)), + int, int)); +extern void __gnat_initialize PARAMS ((void)); +extern void __gnat_init_float PARAMS ((void)); +extern void __gnat_install_handler PARAMS ((void)); + +extern int gnat_exit_status; + diff --git a/gcc/ada/repinfo.adb b/gcc/ada/repinfo.adb new file mode 100644 index 00000000000..9e711527e5b --- /dev/null +++ b/gcc/ada/repinfo.adb @@ -0,0 +1,1024 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- R E P I N F O -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.36 $ +-- -- +-- Copyright (C) 1999-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- As a special exception, if other files instantiate generics from this -- +-- unit, or you link this unit with other files to produce an executable, -- +-- this unit does not by itself cause the resulting executable to be -- +-- covered by the GNU General Public License. This exception does not -- +-- however invalidate any other reasons why the executable file might be -- +-- covered by the GNU Public License. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +with Alloc; use Alloc; +with Atree; use Atree; +with Casing; use Casing; +with Debug; use Debug; +with Einfo; use Einfo; +with Lib; use Lib; +with Namet; use Namet; +with Opt; use Opt; +with Output; use Output; +with Sinfo; use Sinfo; +with Sinput; use Sinput; +with Table; use Table; +with Uname; use Uname; +with Urealp; use Urealp; + +package body Repinfo is + + SSU : constant := 8; + -- Value for Storage_Unit, we do not want to get this from TTypes, since + -- this introduces problematic dependencies in ASIS, and in any case this + -- value is assumed to be 8 for the implementation of the DDA. + -- This is wrong for AAMP??? + + --------------------------------------- + -- Representation of gcc Expressions -- + --------------------------------------- + + -- This table is used only if Frontend_Layout_On_Target is False, + -- so that gigi lays out dynamic size/offset fields using encoded + -- gcc expressions. + + -- A table internal to this unit is used to hold the values of + -- back annotated expressions. This table is written out by -gnatt + -- and read back in for ASIS processing. + + -- Node values are stored as Uint values which are the negative of + -- the node index in this table. Constants appear as non-negative + -- Uint values. + + type Exp_Node is record + Expr : TCode; + Op1 : Node_Ref_Or_Val; + Op2 : Node_Ref_Or_Val; + Op3 : Node_Ref_Or_Val; + end record; + + package Rep_Table is new Table.Table ( + Table_Component_Type => Exp_Node, + Table_Index_Type => Nat, + Table_Low_Bound => 1, + Table_Initial => Alloc.Rep_Table_Initial, + Table_Increment => Alloc.Rep_Table_Increment, + Table_Name => "BE_Rep_Table"); + + -------------------------------------------------------------- + -- Representation of Front-End Dynamic Size/Offset Entities -- + -------------------------------------------------------------- + + package Dynamic_SO_Entity_Table is new Table.Table ( + Table_Component_Type => Entity_Id, + Table_Index_Type => Nat, + Table_Low_Bound => 1, + Table_Initial => Alloc.Rep_Table_Initial, + Table_Increment => Alloc.Rep_Table_Increment, + Table_Name => "FE_Rep_Table"); + + ----------------------- + -- Local Subprograms -- + ----------------------- + + Unit_Casing : Casing_Type; + -- Indentifier casing for current unit + + procedure Spaces (N : Natural); + -- Output given number of spaces + + function Back_End_Layout return Boolean; + -- Test for layout mode, True = back end, False = front end. This + -- function is used rather than checking the configuration parameter + -- because we do not want Repinfo to depend on Targparm (for ASIS) + + procedure List_Entities (Ent : Entity_Id); + -- This procedure lists the entities associated with the entity E, + -- starting with the First_Entity and using the Next_Entity link. + -- If a nested package is found, entities within the package are + -- recursively processed. + + procedure List_Name (Ent : Entity_Id); + -- List name of entity Ent in appropriate case. The name is listed with + -- full qualification up to but not including the compilation unit name. + + procedure List_Array_Info (Ent : Entity_Id); + -- List representation info for array type Ent + + procedure List_Object_Info (Ent : Entity_Id); + -- List representation info for object Ent + + procedure List_Record_Info (Ent : Entity_Id); + -- List representation info for record type Ent + + procedure List_Type_Info (Ent : Entity_Id); + -- List type info for type Ent + + function Rep_Not_Constant (Val : Node_Ref_Or_Val) return Boolean; + -- Returns True if Val represents a variable value, and False if it + -- represents a value that is fixed at compile time. + + procedure Write_Val (Val : Node_Ref_Or_Val; Paren : Boolean := False); + -- Given a representation value, write it out. No_Uint values or values + -- dependent on discriminants are written as two question marks. If the + -- flag Paren is set, then the output is surrounded in parentheses if + -- it is other than a simple value. + + --------------------- + -- Back_End_Layout -- + --------------------- + + function Back_End_Layout return Boolean is + begin + -- We have back end layout if the back end has made any entries in + -- the table of GCC expressions, otherwise we have front end layout. + + return Rep_Table.Last > 0; + end Back_End_Layout; + + ------------------------ + -- Create_Discrim_Ref -- + ------------------------ + + function Create_Discrim_Ref + (Discr : Entity_Id) + return Node_Ref + is + N : constant Uint := Discriminant_Number (Discr); + T : Nat; + + begin + Rep_Table.Increment_Last; + T := Rep_Table.Last; + Rep_Table.Table (T).Expr := Discrim_Val; + Rep_Table.Table (T).Op1 := N; + Rep_Table.Table (T).Op2 := No_Uint; + Rep_Table.Table (T).Op3 := No_Uint; + return UI_From_Int (-T); + end Create_Discrim_Ref; + + --------------------------- + -- Create_Dynamic_SO_Ref -- + --------------------------- + + function Create_Dynamic_SO_Ref + (E : Entity_Id) + return Dynamic_SO_Ref + is + T : Nat; + + begin + Dynamic_SO_Entity_Table.Increment_Last; + T := Dynamic_SO_Entity_Table.Last; + Dynamic_SO_Entity_Table.Table (T) := E; + return UI_From_Int (-T); + end Create_Dynamic_SO_Ref; + + ----------------- + -- Create_Node -- + ----------------- + + function Create_Node + (Expr : TCode; + Op1 : Node_Ref_Or_Val; + Op2 : Node_Ref_Or_Val := No_Uint; + Op3 : Node_Ref_Or_Val := No_Uint) + return Node_Ref + is + T : Nat; + + begin + Rep_Table.Increment_Last; + T := Rep_Table.Last; + Rep_Table.Table (T).Expr := Expr; + Rep_Table.Table (T).Op1 := Op1; + Rep_Table.Table (T).Op2 := Op2; + Rep_Table.Table (T).Op3 := Op3; + + return UI_From_Int (-T); + end Create_Node; + + --------------------------- + -- Get_Dynamic_SO_Entity -- + --------------------------- + + function Get_Dynamic_SO_Entity + (U : Dynamic_SO_Ref) + return Entity_Id + is + begin + return Dynamic_SO_Entity_Table.Table (-UI_To_Int (U)); + end Get_Dynamic_SO_Entity; + + ----------------------- + -- Is_Dynamic_SO_Ref -- + ----------------------- + + function Is_Dynamic_SO_Ref (U : SO_Ref) return Boolean is + begin + return U < Uint_0; + end Is_Dynamic_SO_Ref; + + ---------------------- + -- Is_Static_SO_Ref -- + ---------------------- + + function Is_Static_SO_Ref (U : SO_Ref) return Boolean is + begin + return U >= Uint_0; + end Is_Static_SO_Ref; + + --------- + -- lgx -- + --------- + + procedure lgx (U : Node_Ref_Or_Val) is + begin + List_GCC_Expression (U); + Write_Eol; + end lgx; + + ---------------------- + -- List_Array_Info -- + ---------------------- + + procedure List_Array_Info (Ent : Entity_Id) is + begin + List_Type_Info (Ent); + + Write_Str ("for "); + List_Name (Ent); + Write_Str ("'Component_Size use "); + Write_Val (Component_Size (Ent)); + Write_Line (";"); + end List_Array_Info; + + ------------------- + -- List_Entities -- + ------------------- + + procedure List_Entities (Ent : Entity_Id) is + E : Entity_Id; + + begin + if Present (Ent) then + E := First_Entity (Ent); + while Present (E) loop + if Comes_From_Source (E) or else Debug_Flag_AA then + + if Is_Record_Type (E) then + List_Record_Info (E); + + elsif Is_Array_Type (E) then + List_Array_Info (E); + + elsif List_Representation_Info >= 2 then + + if Is_Type (E) then + List_Type_Info (E); + + elsif Ekind (E) = E_Variable + or else + Ekind (E) = E_Constant + or else + Ekind (E) = E_Loop_Parameter + or else + Is_Formal (E) + then + List_Object_Info (E); + end if; + end if; + + -- Recurse over nested package, but not if they are + -- package renamings (in particular renamings of the + -- enclosing package, as for some Java bindings and + -- for generic instances). + + if (Ekind (E) = E_Package + and then No (Renamed_Object (E))) + or else + Ekind (E) = E_Protected_Type + or else + Ekind (E) = E_Task_Type + or else + Ekind (E) = E_Subprogram_Body + or else + Ekind (E) = E_Package_Body + or else + Ekind (E) = E_Task_Body + or else + Ekind (E) = E_Protected_Body + then + List_Entities (E); + end if; + end if; + + E := Next_Entity (E); + end loop; + end if; + end List_Entities; + + ------------------------- + -- List_GCC_Expression -- + ------------------------- + + procedure List_GCC_Expression (U : Node_Ref_Or_Val) is + + procedure P (Val : Node_Ref_Or_Val); + -- Internal recursive procedure to print expression + + procedure P (Val : Node_Ref_Or_Val) is + begin + if Val >= 0 then + UI_Write (Val, Decimal); + + else + declare + Node : Exp_Node renames Rep_Table.Table (-UI_To_Int (Val)); + + procedure Binop (S : String); + -- Output text for binary operator with S being operator name + + procedure Binop (S : String) is + begin + Write_Char ('('); + P (Node.Op1); + Write_Str (S); + P (Node.Op2); + Write_Char (')'); + end Binop; + + -- Start of processing for P + + begin + case Node.Expr is + when Cond_Expr => + Write_Str ("(if "); + P (Node.Op1); + Write_Str (" then "); + P (Node.Op2); + Write_Str (" else "); + P (Node.Op3); + Write_Str (" end)"); + + when Plus_Expr => + Binop (" + "); + + when Minus_Expr => + Binop (" - "); + + when Mult_Expr => + Binop (" * "); + + when Trunc_Div_Expr => + Binop (" /t "); + + when Ceil_Div_Expr => + Binop (" /c "); + + when Floor_Div_Expr => + Binop (" /f "); + + when Trunc_Mod_Expr => + Binop (" modt "); + + when Floor_Mod_Expr => + Binop (" modf "); + + when Ceil_Mod_Expr => + Binop (" modc "); + + when Exact_Div_Expr => + Binop (" /e "); + + when Negate_Expr => + Write_Char ('-'); + P (Node.Op1); + + when Min_Expr => + Binop (" min "); + + when Max_Expr => + Binop (" max "); + + when Abs_Expr => + Write_Str ("abs "); + P (Node.Op1); + + when Truth_Andif_Expr => + Binop (" and if "); + + when Truth_Orif_Expr => + Binop (" or if "); + + when Truth_And_Expr => + Binop (" and "); + + when Truth_Or_Expr => + Binop (" or "); + + when Truth_Xor_Expr => + Binop (" xor "); + + when Truth_Not_Expr => + Write_Str ("not "); + P (Node.Op1); + + when Lt_Expr => + Binop (" < "); + + when Le_Expr => + Binop (" <= "); + + when Gt_Expr => + Binop (" > "); + + when Ge_Expr => + Binop (" >= "); + + when Eq_Expr => + Binop (" == "); + + when Ne_Expr => + Binop (" != "); + + when Discrim_Val => + Write_Char ('#'); + UI_Write (Node.Op1); + + end case; + end; + end if; + end P; + + -- Start of processing for List_GCC_Expression + + begin + if U = No_Uint then + Write_Line ("??"); + else + P (U); + end if; + end List_GCC_Expression; + + --------------- + -- List_Name -- + --------------- + + procedure List_Name (Ent : Entity_Id) is + begin + if not Is_Compilation_Unit (Scope (Ent)) then + List_Name (Scope (Ent)); + Write_Char ('.'); + end if; + + Get_Unqualified_Decoded_Name_String (Chars (Ent)); + Set_Casing (Unit_Casing); + Write_Str (Name_Buffer (1 .. Name_Len)); + end List_Name; + + --------------------- + -- List_Object_Info -- + --------------------- + + procedure List_Object_Info (Ent : Entity_Id) is + begin + Write_Eol; + + if Known_Esize (Ent) then + Write_Str ("for "); + List_Name (Ent); + Write_Str ("'Size use "); + Write_Val (Esize (Ent)); + Write_Line (";"); + end if; + + if Known_Alignment (Ent) then + Write_Str ("for "); + List_Name (Ent); + Write_Str ("'Alignment use "); + Write_Val (Alignment (Ent)); + Write_Line (";"); + end if; + end List_Object_Info; + + ---------------------- + -- List_Record_Info -- + ---------------------- + + procedure List_Record_Info (Ent : Entity_Id) is + Comp : Entity_Id; + Esiz : Uint; + Cfbit : Uint; + Sunit : Uint; + + Max_Name_Length : Natural; + Max_Suni_Length : Natural; + + begin + List_Type_Info (Ent); + + Write_Str ("for "); + List_Name (Ent); + Write_Line (" use record"); + + -- First loop finds out max line length and max starting position + -- length, for the purpose of lining things up nicely. + + Max_Name_Length := 0; + Max_Suni_Length := 0; + + Comp := First_Entity (Ent); + while Present (Comp) loop + if Ekind (Comp) = E_Component + or else Ekind (Comp) = E_Discriminant + then + Get_Decoded_Name_String (Chars (Comp)); + Max_Name_Length := Natural'Max (Max_Name_Length, Name_Len); + + Cfbit := Component_Bit_Offset (Comp); + + if Rep_Not_Constant (Cfbit) then + UI_Image_Length := 2; + + else + -- Complete annotation in case not done + + Set_Normalized_Position (Comp, Cfbit / SSU); + Set_Normalized_First_Bit (Comp, Cfbit mod SSU); + + Esiz := Esize (Comp); + Sunit := Cfbit / SSU; + UI_Image (Sunit); + end if; + + if Unknown_Normalized_First_Bit (Comp) then + Set_Normalized_First_Bit (Comp, Uint_0); + end if; + + Max_Suni_Length := + Natural'Max (Max_Suni_Length, UI_Image_Length); + end if; + + Comp := Next_Entity (Comp); + end loop; + + -- Second loop does actual output based on those values + + Comp := First_Entity (Ent); + while Present (Comp) loop + if Ekind (Comp) = E_Component + or else Ekind (Comp) = E_Discriminant + then + declare + Esiz : constant Uint := Esize (Comp); + Bofs : constant Uint := Component_Bit_Offset (Comp); + Npos : constant Uint := Normalized_Position (Comp); + Fbit : constant Uint := Normalized_First_Bit (Comp); + Lbit : Uint; + + begin + Write_Str (" "); + Get_Decoded_Name_String (Chars (Comp)); + Set_Casing (Unit_Casing); + Write_Str (Name_Buffer (1 .. Name_Len)); + + for J in 1 .. Max_Name_Length - Name_Len loop + Write_Char (' '); + end loop; + + Write_Str (" at "); + + if Known_Static_Normalized_Position (Comp) then + UI_Image (Npos); + Spaces (Max_Suni_Length - UI_Image_Length); + Write_Str (UI_Image_Buffer (1 .. UI_Image_Length)); + + elsif Known_Component_Bit_Offset (Comp) + and then List_Representation_Info = 3 + then + Spaces (Max_Suni_Length - 2); + Write_Val (Bofs, Paren => True); + Write_Str (" / 8"); + + elsif Known_Normalized_Position (Comp) + and then List_Representation_Info = 3 + then + Spaces (Max_Suni_Length - 2); + Write_Val (Npos); + + else + Write_Str ("??"); + end if; + + Write_Str (" range "); + UI_Write (Fbit); + Write_Str (" .. "); + + if not Is_Dynamic_SO_Ref (Esize (Comp)) then + Lbit := Fbit + Esiz - 1; + + if Lbit < 10 then + Write_Char (' '); + end if; + + UI_Write (Lbit); + + elsif List_Representation_Info < 3 then + Write_Str ("??"); + + else -- List_Representation >= 3 + + Write_Val (Esiz, Paren => True); + + -- If in front end layout mode, then dynamic size is + -- stored in storage units, so renormalize for output + + if not Back_End_Layout then + Write_Str (" * "); + Write_Int (SSU); + end if; + + -- Add appropriate first bit offset + + if Fbit = 0 then + Write_Str (" - 1"); + + elsif Fbit = 1 then + null; + + else + Write_Str (" + "); + Write_Int (UI_To_Int (Fbit) - 1); + end if; + end if; + + Write_Line (";"); + end; + end if; + + Comp := Next_Entity (Comp); + end loop; + + Write_Line ("end record;"); + end List_Record_Info; + + ------------------- + -- List_Rep_Info -- + ------------------- + + procedure List_Rep_Info is + Col : Nat; + + begin + for U in Main_Unit .. Last_Unit loop + if In_Extended_Main_Source_Unit (Cunit_Entity (U)) then + Unit_Casing := Identifier_Casing (Source_Index (U)); + Write_Eol; + Write_Str ("Representation information for unit "); + Write_Unit_Name (Unit_Name (U)); + Col := Column; + Write_Eol; + + for J in 1 .. Col - 1 loop + Write_Char ('-'); + end loop; + + Write_Eol; + List_Entities (Cunit_Entity (U)); + end if; + end loop; + end List_Rep_Info; + + -------------------- + -- List_Type_Info -- + -------------------- + + procedure List_Type_Info (Ent : Entity_Id) is + begin + Write_Eol; + + -- If Esize and RM_Size are the same and known, list as Size. This + -- is a common case, which we may as well list in simple form. + + if Esize (Ent) = RM_Size (Ent) then + if Known_Esize (Ent) then + Write_Str ("for "); + List_Name (Ent); + Write_Str ("'Size use "); + Write_Val (Esize (Ent)); + Write_Line (";"); + end if; + + -- For now, temporary case, to be removed when gigi properly back + -- annotates RM_Size, if RM_Size is not set, then list Esize as + -- Size. This avoids odd Object_Size output till we fix things??? + + elsif Unknown_RM_Size (Ent) then + if Known_Esize (Ent) then + Write_Str ("for "); + List_Name (Ent); + Write_Str ("'Size use "); + Write_Val (Esize (Ent)); + Write_Line (";"); + end if; + + -- Otherwise list size values separately if they are set + + else + if Known_Esize (Ent) then + Write_Str ("for "); + List_Name (Ent); + Write_Str ("'Object_Size use "); + Write_Val (Esize (Ent)); + Write_Line (";"); + end if; + + -- Note on following check: The RM_Size of a discrete type can + -- legitimately be set to zero, so a special check is needed. + + if Known_RM_Size (Ent) or else Is_Discrete_Type (Ent) then + Write_Str ("for "); + List_Name (Ent); + Write_Str ("'Value_Size use "); + Write_Val (RM_Size (Ent)); + Write_Line (";"); + end if; + end if; + + if Known_Alignment (Ent) then + Write_Str ("for "); + List_Name (Ent); + Write_Str ("'Alignment use "); + Write_Val (Alignment (Ent)); + Write_Line (";"); + end if; + end List_Type_Info; + + ---------------------- + -- Rep_Not_Constant -- + ---------------------- + + function Rep_Not_Constant (Val : Node_Ref_Or_Val) return Boolean is + begin + if Val = No_Uint or else Val < 0 then + return True; + else + return False; + end if; + end Rep_Not_Constant; + + --------------- + -- Rep_Value -- + --------------- + + function Rep_Value + (Val : Node_Ref_Or_Val; + D : Discrim_List) + return Uint + is + function B (Val : Boolean) return Uint; + -- Returns Uint_0 for False, Uint_1 for True + + function T (Val : Node_Ref_Or_Val) return Boolean; + -- Returns True for 0, False for any non-zero (i.e. True) + + function V (Val : Node_Ref_Or_Val) return Uint; + -- Internal recursive routine to evaluate tree + + ------- + -- B -- + ------- + + function B (Val : Boolean) return Uint is + begin + if Val then + return Uint_1; + else + return Uint_0; + end if; + end B; + + ------- + -- T -- + ------- + + function T (Val : Node_Ref_Or_Val) return Boolean is + begin + if V (Val) = 0 then + return False; + else + return True; + end if; + end T; + + ------- + -- V -- + ------- + + function V (Val : Node_Ref_Or_Val) return Uint is + L, R, Q : Uint; + + begin + if Val >= 0 then + return Val; + + else + declare + Node : Exp_Node renames Rep_Table.Table (-UI_To_Int (Val)); + + begin + case Node.Expr is + when Cond_Expr => + if T (Node.Op1) then + return V (Node.Op2); + else + return V (Node.Op3); + end if; + + when Plus_Expr => + return V (Node.Op1) + V (Node.Op2); + + when Minus_Expr => + return V (Node.Op1) - V (Node.Op2); + + when Mult_Expr => + return V (Node.Op1) * V (Node.Op2); + + when Trunc_Div_Expr => + return V (Node.Op1) / V (Node.Op2); + + when Ceil_Div_Expr => + return + UR_Ceiling + (V (Node.Op1) / UR_From_Uint (V (Node.Op2))); + + when Floor_Div_Expr => + return + UR_Floor + (V (Node.Op1) / UR_From_Uint (V (Node.Op2))); + + when Trunc_Mod_Expr => + return V (Node.Op1) rem V (Node.Op2); + + when Floor_Mod_Expr => + return V (Node.Op1) mod V (Node.Op2); + + when Ceil_Mod_Expr => + L := V (Node.Op1); + R := V (Node.Op2); + Q := UR_Ceiling (L / UR_From_Uint (R)); + return L - R * Q; + + when Exact_Div_Expr => + return V (Node.Op1) / V (Node.Op2); + + when Negate_Expr => + return -V (Node.Op1); + + when Min_Expr => + return UI_Min (V (Node.Op1), V (Node.Op2)); + + when Max_Expr => + return UI_Max (V (Node.Op1), V (Node.Op2)); + + when Abs_Expr => + return UI_Abs (V (Node.Op1)); + + when Truth_Andif_Expr => + return B (T (Node.Op1) and then T (Node.Op2)); + + when Truth_Orif_Expr => + return B (T (Node.Op1) or else T (Node.Op2)); + + when Truth_And_Expr => + return B (T (Node.Op1) and T (Node.Op2)); + + when Truth_Or_Expr => + return B (T (Node.Op1) or T (Node.Op2)); + + when Truth_Xor_Expr => + return B (T (Node.Op1) xor T (Node.Op2)); + + when Truth_Not_Expr => + return B (not T (Node.Op1)); + + when Lt_Expr => + return B (V (Node.Op1) < V (Node.Op2)); + + when Le_Expr => + return B (V (Node.Op1) <= V (Node.Op2)); + + when Gt_Expr => + return B (V (Node.Op1) > V (Node.Op2)); + + when Ge_Expr => + return B (V (Node.Op1) >= V (Node.Op2)); + + when Eq_Expr => + return B (V (Node.Op1) = V (Node.Op2)); + + when Ne_Expr => + return B (V (Node.Op1) /= V (Node.Op2)); + + when Discrim_Val => + declare + Sub : constant Int := UI_To_Int (Node.Op1); + + begin + pragma Assert (Sub in D'Range); + return D (Sub); + end; + + end case; + end; + end if; + end V; + + -- Start of processing for Rep_Value + + begin + if Val = No_Uint then + return No_Uint; + + else + return V (Val); + end if; + end Rep_Value; + + ------------ + -- Spaces -- + ------------ + + procedure Spaces (N : Natural) is + begin + for J in 1 .. N loop + Write_Char (' '); + end loop; + end Spaces; + + --------------- + -- Tree_Read -- + --------------- + + procedure Tree_Read is + begin + Rep_Table.Tree_Read; + end Tree_Read; + + ---------------- + -- Tree_Write -- + ---------------- + + procedure Tree_Write is + begin + Rep_Table.Tree_Write; + end Tree_Write; + + --------------- + -- Write_Val -- + --------------- + + procedure Write_Val (Val : Node_Ref_Or_Val; Paren : Boolean := False) is + begin + if Rep_Not_Constant (Val) then + if List_Representation_Info < 3 then + Write_Str ("??"); + else + if Back_End_Layout then + Write_Char (' '); + List_GCC_Expression (Val); + Write_Char (' '); + else + Write_Name_Decoded (Chars (Get_Dynamic_SO_Entity (Val))); + end if; + end if; + + else + UI_Write (Val); + end if; + end Write_Val; + +end Repinfo; diff --git a/gcc/ada/repinfo.ads b/gcc/ada/repinfo.ads new file mode 100644 index 00000000000..0b41ba0864b --- /dev/null +++ b/gcc/ada/repinfo.ads @@ -0,0 +1,320 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- R E P I N F O -- +-- -- +-- S p e c -- +-- -- +-- $Revision: 1.20 $ +-- -- +-- Copyright (C) 1999-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- As a special exception, if other files instantiate generics from this -- +-- unit, or you link this unit with other files to produce an executable, -- +-- this unit does not by itself cause the resulting executable to be -- +-- covered by the GNU General Public License. This exception does not -- +-- however invalidate any other reasons why the executable file might be -- +-- covered by the GNU Public License. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +-- This package contains the routines to handle back annotation of the +-- tree to fill in representation information, and also the routine used +-- by -gnatR to print this information. This unit is used both in the +-- compiler and in ASIS (it is used in ASIS as part of the implementation +-- of the data decomposition annex. + +with Types; use Types; +with Uintp; use Uintp; + +package Repinfo is + + -------------------------------- + -- Representation Information -- + -------------------------------- + + -- The representation information of interest here is size and + -- component information for arrays and records. For primitive + -- types, the front end computes the Esize and RM_Size fields of + -- the corresponding entities as constant non-negative integers, + -- and the Uint values are stored directly in these fields. + + -- For composite types, there are three cases: + + -- 1. In some cases the front end knows the values statically, + -- for example in the ase where representation clauses or + -- pragmas specify the values. + + -- 2. If Backend_Layout is True, then the backend is responsible + -- for layout of all types and objects not laid out by the + -- front end. This includes all dynamic values, and also + -- static values (e.g. record sizes) when not set by the + -- front end. + + -- 3. If Backend_Layout is False, then the front end lays out + -- all data, according to target dependent size and alignment + -- information, creating dynamic inlinable functions where + -- needed in the case of sizes not known till runtime. + + ----------------------------- + -- Back-Annotation by Gigi -- + ----------------------------- + + -- The following interface is used by gigi if Backend_Layout is True. + + -- As part of the processing in gigi, the types are laid out and + -- appropriate values computed for the sizes and component positions + -- and sizes of records and arrays. + + -- The back-annotation circuit in gigi is responsible for updating the + -- relevant fields in the tree to reflect these computations, as follows: + + -- For E_Array_Type entities, the Component_Size field + + -- For all record and array types and subtypes, the Esize field, + -- which contains the Size (more accurately the Object_SIze) value + -- for the type or subtype. + + -- For E_Component and E_Distriminant entities, the Esize (size + -- of component) and Component_Bit_Offset fields. Note that gigi + -- does not (yet ???) back annotate Normalized_Position/First_Bit. + + -- There are three cases to consider: + + -- 1. The value is constant. In this case, the back annotation works + -- by simply storing the non-negative universal integer value in + -- the appropriate field corresponding to this constant size. + + -- 2. The value depends on variables other than discriminants of the + -- current record. In this case, the value is not known, even if + -- the complete data of the record is available, and gigi marks + -- this situation by storing the special value No_Uint. + + -- 3. The value depends on the discriminant values for the current + -- record. In this case, gigi back annotates the field with a + -- representation of the expression for computing the value in + -- terms of the discriminants. A negative Uint value is used to + -- represent the value of such an expression, as explained in + -- the following section. + + -- GCC expressions are represented with a Uint value that is negative. + -- See the body of this package for details on the representation used. + + -- One other case in which gigi back annotates GCC expressions is in + -- the Present_Expr field of an N_Variant node. This expression which + -- will always depend on discriminants, and hence always be represented + -- as a negative Uint value, provides an expression which, when evaluated + -- with a given set of discriminant values, indicates whether the variant + -- is present for that set of values (result is True, i.e. non-zero) or + -- not present (result is False, i.e. zero). + + subtype Node_Ref is Uint; + -- Subtype used for negative Uint values used to represent nodes + + subtype Node_Ref_Or_Val is Uint; + -- Subtype used for values that can either be a Node_Ref (negative) + -- or a value (non-negative) + + type TCode is range 0 .. 27; + -- Type used on Ada side to represent DEFTREECODE values defined in + -- tree.def. Only a subset of these tree codes can actually appear. + -- The names are the names from tree.def in Ada casing. + + -- name code description operands + + Cond_Expr : constant TCode := 1; -- conditional 3 + Plus_Expr : constant TCode := 2; -- addition 2 + Minus_Expr : constant TCode := 3; -- subtraction 2 + Mult_Expr : constant TCode := 4; -- multiplication 2 + Trunc_Div_Expr : constant TCode := 5; -- truncating division 2 + Ceil_Div_Expr : constant TCode := 6; -- division rounding up 2 + Floor_Div_Expr : constant TCode := 7; -- division rounding down 2 + Trunc_Mod_Expr : constant TCode := 8; -- mod for trunc_div 2 + Ceil_Mod_Expr : constant TCode := 9; -- mod for ceil_div 2 + Floor_Mod_Expr : constant TCode := 10; -- mod for floor_div 2 + Exact_Div_Expr : constant TCode := 11; -- exact div 2 + Negate_Expr : constant TCode := 12; -- negation 1 + Min_Expr : constant TCode := 13; -- minimum 2 + Max_Expr : constant TCode := 14; -- maximum 2 + Abs_Expr : constant TCode := 15; -- absolute value 1 + Truth_Andif_Expr : constant TCode := 16; -- Boolean and then 2 + Truth_Orif_Expr : constant TCode := 17; -- Boolean or else 2 + Truth_And_Expr : constant TCode := 18; -- Boolean and 2 + Truth_Or_Expr : constant TCode := 19; -- Boolean or 2 + Truth_Xor_Expr : constant TCode := 20; -- Boolean xor 2 + Truth_Not_Expr : constant TCode := 21; -- Boolean not 1 + Lt_Expr : constant TCode := 22; -- comparision < 2 + Le_Expr : constant TCode := 23; -- comparision <= 2 + Gt_Expr : constant TCode := 24; -- comparision > 2 + Ge_Expr : constant TCode := 25; -- comparision >= 2 + Eq_Expr : constant TCode := 26; -- comparision = 2 + Ne_Expr : constant TCode := 27; -- comparision /= 2 + + -- The following entry is used to represent a discriminant value in + -- the tree. It has a special tree code that does not correspond + -- directly to a gcc node. The single operand is the number of the + -- discriminant in the record (1 = first discriminant). + + Discrim_Val : constant TCode := 0; -- discriminant value 1 + + ------------------------ + -- The gigi Interface -- + ------------------------ + + -- The following declarations are for use by gigi for back annotation + + function Create_Node + (Expr : TCode; + Op1 : Node_Ref_Or_Val; + Op2 : Node_Ref_Or_Val := No_Uint; + Op3 : Node_Ref_Or_Val := No_Uint) + return Node_Ref; + -- Creates a node with using the tree code defined by Expr and from + -- 1-3 operands as required (unused operands set as shown to No_Uint) + -- Note that this call can be used to create a discriminant reference + -- by using (Expr => Discrim_Val, Op1 => discriminant_number). + + function Create_Discrim_Ref + (Discr : Entity_Id) + return Node_Ref; + -- Creates a refrerence to the discriminant whose entity is Discr. + + -------------------------------------------------------- + -- Front-End Interface for Dynamic Size/Offset Values -- + -------------------------------------------------------- + + -- If Backend_Layout is False, then the front-end deals with all + -- dynamic size and offset fields. There are two cases: + + -- 1. The value can be computed at the time of type freezing, and + -- is stored in a run-time constant. In this case, the field + -- contains a reference to this entity. In the case of sizes + -- the value stored is the size in storage units, since dynamic + -- sizes are always a multiple of storage units. + + -- 2. The size/offset depends on the value of discriminants at + -- run-time. In this case, the front end builds a function to + -- compute the value. This function has a single parameter + -- which is the discriminated record object in question. Any + -- references to discriminant values are simply references to + -- the appropriate discriminant in this single argument, and + -- to compute the required size/offset value at run time, the + -- code generator simply constructs a call to the function + -- with the appropriate argument. The size/offset field in + -- this case contains a reference to the function entity. + -- Note that as for case 1, if such a function is used to + -- return a size, then the size in storage units is returned, + -- not the size in bits. + + -- The interface here allows these created entities to be referenced + -- using negative Unit values, so that they can be stored in the + -- appropriate size and offset fields in the tree. + + -- In the case of components, if the location of the component is static, + -- then all four fields (Component_Bit_Offset, Normalized_Position, Esize, + -- and Normalized_First_Bit) are set to appropraite values. In the case of + -- a non-static component location, Component_Bit_Offset is not used and + -- is left set to Unknown. Normalized_Position and Normalized_First_Bit + -- are set appropriately. + + subtype SO_Ref is Uint; + -- Type used to represent a Uint value that represents a static or + -- dynamic size/offset value (non-negative if static, negative if + -- the size value is dynamic). + + subtype Dynamic_SO_Ref is Uint; + -- Type used to represent a negative Uint value used to store + -- a dynamic size/offset value. + + function Is_Dynamic_SO_Ref (U : SO_Ref) return Boolean; + pragma Inline (Is_Dynamic_SO_Ref); + -- Given a SO_Ref (Uint) value, returns True iff the SO_Ref value + -- represents a dynamic Size/Offset value (i.e. it is negative). + + function Is_Static_SO_Ref (U : SO_Ref) return Boolean; + pragma Inline (Is_Static_SO_Ref); + -- Given a SO_Ref (Uint) value, returns True iff the SO_Ref value + -- represents a static Size/Offset value (i.e. it is non-negative). + + function Create_Dynamic_SO_Ref + (E : Entity_Id) + return Dynamic_SO_Ref; + -- Given the Entity_Id for a constant (case 1), the Node_Id for an + -- expression (case 2), or the Entity_Id for a function (case 3), + -- this function returns a (negative) Uint value that can be used + -- to retrieve the entity or expression for later use. + + function Get_Dynamic_SO_Entity + (U : Dynamic_SO_Ref) + return Entity_Id; + -- Retrieve the Node_Id or Entity_Id stored by a previous call to + -- Create_Dynamic_SO_Ref. The approach is that the front end makes + -- the necessary Create_Dynamic_SO_Ref calls to associate the node + -- and entity id values and the back end makes Get_Dynamic_SO_Ref + -- calls to retrive them. + + -------------------- + -- ASIS_Interface -- + -------------------- + + type Discrim_List is array (Pos range <>) of Uint; + -- Type used to represent list of discriminant values + + function Rep_Value + (Val : Node_Ref_Or_Val; + D : Discrim_List) + return Uint; + -- Given the contents of a First_Bit_Position or Esize field containing + -- a node reference (i.e. a negative Uint value) and D, the list of + -- discriminant values, returns the interpreted value of this field. + -- For convenience, Rep_Value will take a non-negative Uint value + -- as an argument value, and return it unmodified. A No_Uint value is + -- also returned unmodified. + + procedure Tree_Read; + -- Read in the value of the Rep_Table + + ------------------------ + -- Compiler Interface -- + ------------------------ + + procedure List_Rep_Info; + -- Procedure to list representation information + + procedure Tree_Write; + -- Write out the value of the Rep_Table + + -------------------------- + -- Debugging Procedures -- + -------------------------- + + procedure List_GCC_Expression (U : Node_Ref_Or_Val); + -- Prints out given expression in symbolic form. Constants are listed + -- in decimal numeric form, Discriminants are listed with a # followed + -- by the discriminant number, and operators are output in appropriate + -- symbolic form No_Uint displays as two question marks. The output is + -- on a single line but has no line return after it. This procedure is + -- useful only if operating in backend layout mode. + + procedure lgx (U : Node_Ref_Or_Val); + -- In backend layout mode, this is like List_GCC_Expression, but + -- includes a line return at the end. If operating in front end + -- layout mode, then the name of the entity for the size (either + -- a function of a variable) is listed followed by a line return. + +end Repinfo; diff --git a/gcc/ada/repinfo.h b/gcc/ada/repinfo.h new file mode 100644 index 00000000000..305c818685c --- /dev/null +++ b/gcc/ada/repinfo.h @@ -0,0 +1,79 @@ +/**************************************************************************** + * * + * GNAT COMPILER COMPONENTS * + * * + * R E P I N F O * + * * + * C Header File * + * * + * $Revision: 1.1 $ + * * + * Copyright (C) 1999-2001 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 2, 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 COPYING. If not, write * + * to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, * + * MA 02111-1307, USA. * + * * + * As a special exception, if you link this file with other files to * + * produce an executable, this file does not by itself cause the resulting * + * executable to be covered by the GNU General Public License. This except- * + * ion does not however invalidate any other reasons why the executable * + * file might be covered by the GNU Public License. * + * * + * GNAT was originally developed by the GNAT team at New York University. * + * It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). * + * * + ****************************************************************************/ + +/* This file corresponds to the Ada file repinfo.ads. */ + +typedef Uint Node_Ref; +typedef Uint Node_Ref_Or_Val; +typedef char TCode; + +/* These are the values of TCcode that correspond to tree codes in tree.def, + except for the first, which is how we encode discriminants. */ + +#define Discrim_Val 0 +#define Cond_Expr 1 +#define Plus_Expr 2 +#define Minus_Expr 3 +#define Mult_Expr 4 +#define Trunc_Div_Expr 5 +#define Ceil_Div_Expr 6 +#define Floor_Div_Expr 7 +#define Trunc_Mod_Expr 8 +#define Ceil_Mod_Expr 9 +#define Floor_Mod_Expr 10 +#define Exact_Div_Expr 11 +#define Negate_Expr 12 +#define Min_Expr 13 +#define Max_Expr 14 +#define Abs_Expr 15 +#define Truth_Andif_Expr 16 +#define Truth_Orif_Expr 17 +#define Truth_And_Expr 18 +#define Truth_Or_Expr 19 +#define Truth_Xor_Expr 20 +#define Truth_Not_Expr 21 +#define Lt_Expr 22 +#define Le_Expr 23 +#define Gt_Expr 24 +#define Ge_Expr 25 +#define Eq_Expr 26 +#define Ne_Expr 27 + +/* Creates a node using the tree code defined by Expr and from 1-3 + operands as required (unused operands set as shown to No_Uint) Note + that this call can be used to create a discriminant reference by + using (Expr => Discrim_Val, Op1 => discriminant_number). */ +#define Create_Node repinfo__create_node +extern Node_Ref Create_Node PARAMS((TCode, Node_Ref_Or_Val, + Node_Ref_Or_Val, Node_Ref_Or_Val)); diff --git a/gcc/ada/restrict.adb b/gcc/ada/restrict.adb new file mode 100644 index 00000000000..a284cd42e82 --- /dev/null +++ b/gcc/ada/restrict.adb @@ -0,0 +1,458 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- R E S T R I C T -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.37 $ +-- -- +-- Copyright (C) 1992-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +with Atree; use Atree; +with Casing; use Casing; +with Errout; use Errout; +with Exp_Util; use Exp_Util; +with Fname; use Fname; +with Fname.UF; use Fname.UF; +with Lib; use Lib; +with Namet; use Namet; +with Nmake; use Nmake; +with Opt; use Opt; +with Stand; use Stand; +with Uname; use Uname; + +package body Restrict is + + function Suppress_Restriction_Message (N : Node_Id) return Boolean; + -- N is the node for a possible restriction violation message, but + -- the message is to be suppressed if this is an internal file and + -- this file is not the main unit. + + ------------------- + -- Abort_Allowed -- + ------------------- + + function Abort_Allowed return Boolean is + begin + return + Restrictions (No_Abort_Statements) = False + or else + Restriction_Parameters (Max_Asynchronous_Select_Nesting) /= 0; + end Abort_Allowed; + + ------------------------------------ + -- Check_Elaboration_Code_Allowed -- + ------------------------------------ + + procedure Check_Elaboration_Code_Allowed (N : Node_Id) is + begin + -- Avoid calling Namet.Unlock/Lock except when there is an error. + -- Even in the error case it is a bit dubious, either gigi needs + -- the table locked or it does not! ??? + + if Restrictions (No_Elaboration_Code) + and then not Suppress_Restriction_Message (N) + then + Namet.Unlock; + Check_Restriction (No_Elaboration_Code, N); + Namet.Lock; + end if; + end Check_Elaboration_Code_Allowed; + + --------------------------- + -- Check_Restricted_Unit -- + --------------------------- + + procedure Check_Restricted_Unit (U : Unit_Name_Type; N : Node_Id) is + begin + if Suppress_Restriction_Message (N) then + return; + + elsif Is_Spec_Name (U) then + declare + Fnam : constant File_Name_Type := + Get_File_Name (U, Subunit => False); + R_Id : Restriction_Id; + + begin + if not Is_Predefined_File_Name (Fnam) then + return; + + -- Ada child unit spec, needs checking against list + + else + -- Pad name to 8 characters with blanks + + Get_Name_String (Fnam); + Name_Len := Name_Len - 4; + + while Name_Len < 8 loop + Name_Len := Name_Len + 1; + Name_Buffer (Name_Len) := ' '; + end loop; + + for J in Unit_Array'Range loop + if Name_Len = 8 + and then Name_Buffer (1 .. 8) = Unit_Array (J).Filenm + then + R_Id := Unit_Array (J).Res_Id; + Violations (R_Id) := True; + + if Restrictions (R_Id) then + declare + S : constant String := Restriction_Id'Image (R_Id); + + begin + Error_Msg_Unit_1 := U; + + Error_Msg_N + ("dependence on $ not allowed,", N); + + Name_Buffer (1 .. S'Last) := S; + Name_Len := S'Length; + Set_Casing (All_Lower_Case); + Error_Msg_Name_1 := Name_Enter; + Error_Msg_Sloc := Restrictions_Loc (R_Id); + + Error_Msg_N + ("\violates pragma Restriction (%) #", N); + return; + end; + end if; + end if; + end loop; + end if; + end; + end if; + end Check_Restricted_Unit; + + ----------------------- + -- Check_Restriction -- + ----------------------- + + -- Case of simple identifier (no parameter) + + procedure Check_Restriction (R : Restriction_Id; N : Node_Id) is + begin + Violations (R) := True; + + if Restrictions (R) + and then not Suppress_Restriction_Message (N) + then + declare + S : constant String := Restriction_Id'Image (R); + + begin + Name_Buffer (1 .. S'Last) := S; + Name_Len := S'Length; + Set_Casing (All_Lower_Case); + Error_Msg_Name_1 := Name_Enter; + Error_Msg_Sloc := Restrictions_Loc (R); + Error_Msg_N ("violation of restriction %#", N); + end; + end if; + end Check_Restriction; + + -- Case where a parameter is present (but no count) + + procedure Check_Restriction + (R : Restriction_Parameter_Id; + N : Node_Id) + is + begin + if Restriction_Parameters (R) = Uint_0 + and then not Suppress_Restriction_Message (N) + then + declare + Loc : constant Source_Ptr := Sloc (N); + S : constant String := + Restriction_Parameter_Id'Image (R); + + begin + Error_Msg_NE + ("& will be raised at run time?!", N, Standard_Storage_Error); + Name_Buffer (1 .. S'Last) := S; + Name_Len := S'Length; + Set_Casing (All_Lower_Case); + Error_Msg_Name_1 := Name_Enter; + Error_Msg_Sloc := Restriction_Parameters_Loc (R); + Error_Msg_N ("violation of restriction %?#!", N); + + Insert_Action (N, + Make_Raise_Storage_Error (Loc)); + end; + end if; + end Check_Restriction; + + -- Case where a parameter is present, with a count + + procedure Check_Restriction + (R : Restriction_Parameter_Id; + V : Uint; + N : Node_Id) + is + begin + if Restriction_Parameters (R) /= No_Uint + and then V > Restriction_Parameters (R) + and then not Suppress_Restriction_Message (N) + then + declare + S : constant String := Restriction_Parameter_Id'Image (R); + + begin + Name_Buffer (1 .. S'Last) := S; + Name_Len := S'Length; + Set_Casing (All_Lower_Case); + Error_Msg_Name_1 := Name_Enter; + Error_Msg_Sloc := Restriction_Parameters_Loc (R); + Error_Msg_N ("maximum value exceeded for restriction %#", N); + end; + end if; + end Check_Restriction; + + ------------------------------------------- + -- Compilation_Unit_Restrictions_Restore -- + ------------------------------------------- + + procedure Compilation_Unit_Restrictions_Restore + (R : Save_Compilation_Unit_Restrictions) + is + begin + for J in Compilation_Unit_Restrictions loop + Restrictions (J) := R (J); + end loop; + end Compilation_Unit_Restrictions_Restore; + + ---------------------------------------- + -- Compilation_Unit_Restrictions_Save -- + ---------------------------------------- + + function Compilation_Unit_Restrictions_Save + return Save_Compilation_Unit_Restrictions + is + R : Save_Compilation_Unit_Restrictions; + + begin + for J in Compilation_Unit_Restrictions loop + R (J) := Restrictions (J); + Restrictions (J) := False; + end loop; + + return R; + end Compilation_Unit_Restrictions_Save; + + ---------------------------------- + -- Disallow_In_No_Run_Time_Mode -- + ---------------------------------- + + procedure Disallow_In_No_Run_Time_Mode (Enode : Node_Id) is + begin + if No_Run_Time then + Error_Msg_N + ("this construct not allowed in No_Run_Time mode", Enode); + end if; + end Disallow_In_No_Run_Time_Mode; + + ------------------------ + -- Get_Restriction_Id -- + ------------------------ + + function Get_Restriction_Id + (N : Name_Id) + return Restriction_Id + is + J : Restriction_Id; + + begin + Get_Name_String (N); + Set_Casing (All_Upper_Case); + + J := Restriction_Id'First; + while J /= Not_A_Restriction_Id loop + declare + S : constant String := Restriction_Id'Image (J); + + begin + exit when S = Name_Buffer (1 .. Name_Len); + end; + + J := Restriction_Id'Succ (J); + end loop; + + return J; + end Get_Restriction_Id; + + ---------------------------------- + -- Get_Restriction_Parameter_Id -- + ---------------------------------- + + function Get_Restriction_Parameter_Id + (N : Name_Id) + return Restriction_Parameter_Id + is + J : Restriction_Parameter_Id; + + begin + Get_Name_String (N); + Set_Casing (All_Upper_Case); + + J := Restriction_Parameter_Id'First; + while J /= Not_A_Restriction_Parameter_Id loop + declare + S : constant String := Restriction_Parameter_Id'Image (J); + + begin + exit when S = Name_Buffer (1 .. Name_Len); + end; + + J := Restriction_Parameter_Id'Succ (J); + end loop; + + return J; + end Get_Restriction_Parameter_Id; + + ------------------------------- + -- No_Exception_Handlers_Set -- + ------------------------------- + + function No_Exception_Handlers_Set return Boolean is + begin + return Restrictions (No_Exception_Handlers); + end No_Exception_Handlers_Set; + + ------------------------ + -- Restricted_Profile -- + ------------------------ + + -- This implementation must be coordinated with Set_Restricted_Profile + + function Restricted_Profile return Boolean is + begin + return Restrictions (No_Abort_Statements) + and then Restrictions (No_Asynchronous_Control) + and then Restrictions (No_Entry_Queue) + and then Restrictions (No_Task_Hierarchy) + and then Restrictions (No_Task_Allocators) + and then Restrictions (No_Dynamic_Priorities) + and then Restrictions (No_Terminate_Alternatives) + and then Restrictions (No_Dynamic_Interrupts) + and then Restrictions (No_Protected_Type_Allocators) + and then Restrictions (No_Local_Protected_Objects) + and then Restrictions (No_Requeue) + and then Restrictions (No_Task_Attributes) + and then Restriction_Parameters (Max_Asynchronous_Select_Nesting) = 0 + and then Restriction_Parameters (Max_Task_Entries) = 0 + and then Restriction_Parameters (Max_Protected_Entries) <= 1 + and then Restriction_Parameters (Max_Select_Alternatives) = 0; + end Restricted_Profile; + + -------------------------- + -- Set_No_Run_Time_Mode -- + -------------------------- + + procedure Set_No_Run_Time_Mode is + begin + No_Run_Time := True; + Restrictions (No_Exception_Handlers) := True; + end Set_No_Run_Time_Mode; + + ------------------- + -- Set_Ravenscar -- + ------------------- + + procedure Set_Ravenscar is + begin + Set_Restricted_Profile; + Restrictions (Boolean_Entry_Barriers) := True; + Restrictions (No_Select_Statements) := True; + Restrictions (No_Calendar) := True; + Restrictions (Static_Storage_Size) := True; + Restrictions (No_Entry_Queue) := True; + Restrictions (No_Relative_Delay) := True; + Restrictions (No_Task_Termination) := True; + Restrictions (No_Implicit_Heap_Allocations) := True; + end Set_Ravenscar; + + ---------------------------- + -- Set_Restricted_Profile -- + ---------------------------- + + -- This must be coordinated with Restricted_Profile + + procedure Set_Restricted_Profile is + begin + Restrictions (No_Abort_Statements) := True; + Restrictions (No_Asynchronous_Control) := True; + Restrictions (No_Entry_Queue) := True; + Restrictions (No_Task_Hierarchy) := True; + Restrictions (No_Task_Allocators) := True; + Restrictions (No_Dynamic_Priorities) := True; + Restrictions (No_Terminate_Alternatives) := True; + Restrictions (No_Dynamic_Interrupts) := True; + Restrictions (No_Protected_Type_Allocators) := True; + Restrictions (No_Local_Protected_Objects) := True; + Restrictions (No_Requeue) := True; + Restrictions (No_Task_Attributes) := True; + + Restriction_Parameters (Max_Asynchronous_Select_Nesting) := Uint_0; + Restriction_Parameters (Max_Task_Entries) := Uint_0; + Restriction_Parameters (Max_Select_Alternatives) := Uint_0; + + if Restriction_Parameters (Max_Protected_Entries) /= Uint_0 then + Restriction_Parameters (Max_Protected_Entries) := Uint_1; + end if; + end Set_Restricted_Profile; + + ---------------------------------- + -- Suppress_Restriction_Message -- + ---------------------------------- + + function Suppress_Restriction_Message (N : Node_Id) return Boolean is + begin + -- If main unit is library unit, then we will output message + + if In_Extended_Main_Source_Unit (N) then + return False; + + -- If loaded by rtsfind, then suppress message + + elsif Sloc (N) <= No_Location then + return True; + + -- Otherwise suppress message if internal file + + else + return + Is_Internal_File_Name (Unit_File_Name (Get_Source_Unit (N))); + end if; + end Suppress_Restriction_Message; + + --------------------- + -- Tasking_Allowed -- + --------------------- + + function Tasking_Allowed return Boolean is + begin + return + Restriction_Parameters (Max_Tasks) /= 0; + end Tasking_Allowed; + +end Restrict; diff --git a/gcc/ada/restrict.ads b/gcc/ada/restrict.ads new file mode 100644 index 00000000000..426149efaaf --- /dev/null +++ b/gcc/ada/restrict.ads @@ -0,0 +1,253 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- R E S T R I C T -- +-- -- +-- S p e c -- +-- -- +-- $Revision: 1.27 $ +-- -- +-- Copyright (C) 1992-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +-- This package deals with the implementation of the Restrictions pragma + +with Rident; +with Types; use Types; +with Uintp; use Uintp; + +package Restrict is + + type Restriction_Id is new Rident.Restriction_Id; + -- The type Restriction_Id defines the set of restriction identifiers, + -- which take no parameter (i.e. they are either present or not present). + -- The actual definition is in the separate package Rident, so that it + -- can easily be accessed by the binder without dragging in lots of stuff. + + subtype Partition_Restrictions is + Restriction_Id range + Restriction_Id (Rident.Partition_Restrictions'First) .. + Restriction_Id (Rident.Partition_Restrictions'Last); + -- Range of restriction identifiers that are checked by the binder + + subtype Compilation_Unit_Restrictions is + Restriction_Id range + Restriction_Id (Rident.Compilation_Unit_Restrictions'First) .. + Restriction_Id (Rident.Compilation_Unit_Restrictions'Last); + -- Range of restriction identifiers not checked by binder + + type Restriction_Parameter_Id is new Rident.Restriction_Parameter_Id; + -- The type Restriction_Parameter_Id records cases where a parameter is + -- present in the corresponding pragma. These cases are not checked for + -- consistency by the binder. The actual definition is in the separate + -- package Rident for consistency. + + type Restrictions_Flags is array (Restriction_Id) of Boolean; + -- Type used for arrays indexed by Restriction_Id. + + Restrictions : Restrictions_Flags := (others => False); + -- Corresponding entry is False if restriction is not active, and + -- True if the restriction is active, i.e. if a pragma Restrictions + -- has been seen anywhere. Note that we are happy to pick up any + -- restrictions pragmas in with'ed units, since we are required to + -- be consistent at link time, and we might as well find the error + -- at compile time. Clients must NOT use this array for checking to + -- see if a restriction is violated, instead it is required that the + -- Check_Restrictions subprograms be used for this purpose. The only + -- legitimate direct use of this array is when the code is modified + -- as a result of the restriction in some way. + + Restrictions_Loc : array (Restriction_Id) of Source_Ptr; + -- Locations of Restrictions pragmas for error message purposes. + -- Valid only if corresponding entry in Restrictions is set. + + Main_Restrictions : Restrictions_Flags := (others => False); + -- This variable saves the cumulative restrictions in effect compiling + -- any unit that is part of the extended main unit (i.e. the compiled + -- unit, its spec if any, and its subunits if any). The reason we keep + -- track of this is for the information that goes to the binder about + -- restrictions that are set. The binder will identify a unit that has + -- a restrictions pragma for error message purposes, and we do not want + -- to pick up a restrictions pragma in a with'ed unit for this purpose. + + Violations : Restrictions_Flags := (others => False); + -- Corresponding entry is False if the restriction has not been + -- violated in the current main unit, and True if it has been violated. + + Restriction_Parameters : + array (Restriction_Parameter_Id) of Uint := (others => No_Uint); + -- This array indicates the setting of restriction parameter identifier + -- values. All values are initially set to No_Uint indicating that the + -- parameter is not set, and are set to the appropriate non-negative + -- value if a Restrictions pragma specifies the corresponding + -- restriction parameter identifier with an appropriate value. + + Restriction_Parameters_Loc : + array (Restriction_Parameter_Id) of Source_Ptr; + -- Locations of Restrictions pragmas for error message purposes. + -- Valid only if corresponding entry in Restriction_Parameters is + -- set to a value other than No_Uint. + + type Unit_Entry is record + Res_Id : Restriction_Id; + Filenm : String (1 .. 8); + end record; + + type Unit_Array_Type is array (Positive range <>) of Unit_Entry; + + Unit_Array : constant Unit_Array_Type := ( + (No_Asynchronous_Control, "a-astaco"), + (No_Calendar, "a-calend"), + (No_Calendar, "calendar"), + (No_Delay, "a-calend"), + (No_Delay, "calendar"), + (No_Dynamic_Priorities, "a-dynpri"), + (No_IO, "a-direio"), + (No_IO, "directio"), + (No_IO, "a-sequio"), + (No_IO, "sequenio"), + (No_IO, "a-ststio"), + (No_IO, "a-textio"), + (No_IO, "text_io "), + (No_IO, "a-witeio"), + (No_Task_Attributes, "a-tasatt"), + (No_Streams, "a-stream"), + (No_Unchecked_Conversion, "a-unccon"), + (No_Unchecked_Conversion, "unchconv"), + (No_Unchecked_Deallocation, "a-uncdea"), + (No_Unchecked_Deallocation, "unchdeal")); + -- This array defines the mapping between restriction identifiers and + -- predefined language files containing units for which the identifier + -- forbids semantic dependence. + + type Save_Compilation_Unit_Restrictions is private; + -- Type used for saving and restoring compilation unit restrictions. + -- See Compilation_Unit_Restrictions_[Save|Restore] subprograms. + + ----------------- + -- Subprograms -- + ----------------- + + procedure Check_Restricted_Unit (U : Unit_Name_Type; N : Node_Id); + -- Checks if loading of unit U is prohibited by the setting of some + -- restriction (e.g. No_IO restricts the loading of unit Ada.Text_IO). + -- If a restriction exists post error message at the given node. + + procedure Check_Restriction (R : Restriction_Id; N : Node_Id); + -- Checks that the given restriction is not set, and if it is set, an + -- appropriate message is posted on the given node. Also records the + -- violation in the violations array. Note that it is mandatory to + -- always use this routine to check if a restriction is violated. Such + -- checks must never be done directly by the caller, since otherwise + -- they are not properly recorded in the violations array. + + procedure Check_Restriction + (R : Restriction_Parameter_Id; + N : Node_Id); + -- Checks that the given restriction parameter identifier is not set to + -- zero. If it is set to zero, then the node N is replaced by a node + -- that raises Storage_Error, and a warning is issued. + + procedure Check_Restriction + (R : Restriction_Parameter_Id; + V : Uint; + N : Node_Id); + -- Checks that the count in V does not exceed the maximum value of the + -- restriction parameter value corresponding to the given restriction + -- parameter identifier (if it has been set). If the count in V exceeds + -- the maximum, then post an error message on node N. + + procedure Check_Elaboration_Code_Allowed (N : Node_Id); + -- Tests to see if elaboration code is allowed by the current restrictions + -- settings. This function is called by Gigi when it needs to define + -- an elaboration routine. If elaboration code is not allowed, an error + -- message is posted on the node given as argument. + + function No_Exception_Handlers_Set return Boolean; + -- Test to see if current restrictions settings specify that no exception + -- handlers are present. This function is called by Gigi when it needs to + -- expand an AT END clean up identifier with no exception handler. + + function Compilation_Unit_Restrictions_Save + return Save_Compilation_Unit_Restrictions; + -- This function saves the compilation unit restriction settings, and + -- resets them to False. This is used e.g. when compiling a with'ed + -- unit to avoid incorrectly propagating restrictions. Note that it + -- would not be wrong to also save and reset the partition restrictions, + -- since the binder would catch inconsistencies, but actually it is a + -- good thing to acquire restrictions from with'ed units if they are + -- required to be partition wide, because it allows the restriction + -- violation message to be given at compile time instead of link time. + + procedure Compilation_Unit_Restrictions_Restore + (R : Save_Compilation_Unit_Restrictions); + -- This is the corresponding restore procedure to restore restrictions + -- previously saved by Compilation_Unit_Restrictions_Save. + + procedure Disallow_In_No_Run_Time_Mode (Enode : Node_Id); + -- If in No_Run_Time mode, then the construct represented by Enode is + -- not permitted, and will be appropriately flagged. + + procedure Set_No_Run_Time_Mode; + -- Set the no run time mode, and associated restriction pragmas. + + function Get_Restriction_Id + (N : Name_Id) + return Restriction_Id; + -- Given an identifier name, determines if it is a valid restriction + -- identifier, and if so returns the corresponding Restriction_Id + -- value, otherwise returns Not_A_Restriction_Id. + + function Get_Restriction_Parameter_Id + (N : Name_Id) + return Restriction_Parameter_Id; + -- Given an identifier name, determines if it is a valid restriction + -- parameter identifier, and if so returns the corresponding + -- Restriction_Parameter_Id value, otherwise returns + -- Not_A_Restriction_Parameter_Id. + + function Abort_Allowed return Boolean; + pragma Inline (Abort_Allowed); + -- Tests to see if abort is allowed by the current restrictions settings. + -- For abort to be allowed, either No_Abort_Statements must be False, + -- or Max_Asynchronous_Select_Nesting must be non-zero. + + function Restricted_Profile return Boolean; + -- Tests to see if tasking operations follow the GNAT restricted run time + -- profile. + + procedure Set_Ravenscar; + -- Sets the set of rerstrictions fro Ravenscar + + procedure Set_Restricted_Profile; + -- Sets the set of restrictions for pragma Restricted_Run_Time + + function Tasking_Allowed return Boolean; + pragma Inline (Tasking_Allowed); + -- Tests to see if tasking operations are allowed by the current + -- restrictions settings. For tasking to be allowed Max_Tasks must + -- be non-zero. + +private + type Save_Compilation_Unit_Restrictions is + array (Compilation_Unit_Restrictions) of Boolean; + -- Type used for saving and restoring compilation unit restrictions. + -- See Compilation_Unit_Restrictions_[Save|Restore] subprograms. + +end Restrict; diff --git a/gcc/ada/rident.ads b/gcc/ada/rident.ads new file mode 100644 index 00000000000..3eb65408433 --- /dev/null +++ b/gcc/ada/rident.ads @@ -0,0 +1,139 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- R I D E N T -- +-- -- +-- S p e c -- +-- -- +-- $Revision: 1.12 $ +-- -- +-- Copyright (C) 1992-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +-- This package defines the set of restriction identifiers. It is in a +-- separate package from Restrict so that it can be easily used by the +-- binder without dragging in a lot of stuff. + +package Rident is + + -- The following enumeration type defines the set of restriction + -- identifiers not taking a parameter that are implemented in GNAT. + -- To add a new restriction identifier, add an entry with the name + -- to be used in the pragma, and add appropriate calls to the + -- Check_Restriction routine. + + type Restriction_Id is ( + + -- The following cases are checked for consistency in the binder + + Boolean_Entry_Barriers, -- GNAT (Ravenscar) + No_Abort_Statements, -- (RM D.7(5), H.4(3)) + No_Access_Subprograms, -- (RM H.4(17)) + No_Allocators, -- (RM H.4(7)) + No_Asynchronous_Control, -- (RM D.9(10)) + No_Calendar, -- GNAT + No_Delay, -- (RM H.4(21)) + No_Dispatch, -- (RM H.4(19)) + No_Dynamic_Interrupts, -- GNAT + No_Dynamic_Priorities, -- (RM D.9(9)) + No_Enumeration_Maps, -- GNAT + No_Entry_Calls_In_Elaboration_Code, -- GNAT + No_Entry_Queue, -- GNAT + No_Exception_Handlers, -- GNAT + No_Exceptions, -- (RM H.4(12)) + No_Fixed_Point, -- (RM H.4(15)) + No_Floating_Point, -- (RM H.4(14)) + No_IO, -- (RM H.4(20)) + No_Implicit_Conditionals, -- GNAT + No_Implicit_Dynamic_Code, -- GNAT + No_Implicit_Heap_Allocations, -- (RM D.8(8), H.4(3)) + No_Implicit_Loops, -- GNAT + No_Local_Allocators, -- (RM H.4(8)) + No_Local_Protected_Objects, -- GNAT + No_Nested_Finalization, -- (RM D.7(4)) + No_Protected_Type_Allocators, -- GNAT + No_Protected_Types, -- (RM H.4(5)) + No_Recursion, -- (RM H.4(22)) + No_Reentrancy, -- (RM H.4(23)) + No_Relative_Delay, -- GNAT + No_Requeue, -- GNAT + No_Select_Statements, -- GNAT (Ravenscar) + No_Standard_Storage_Pools, -- GNAT + No_Streams, -- GNAT + No_Task_Allocators, -- (RM D.7(7)) + No_Task_Attributes, -- GNAT + No_Task_Hierarchy, -- (RM D.7(3), H.4(3)) + No_Task_Termination, -- GNAT + No_Terminate_Alternatives, -- (RM D.7(6)) + No_Unchecked_Access, -- (RM H.4(18)) + No_Unchecked_Conversion, -- (RM H.4(16)) + No_Unchecked_Deallocation, -- (RM H.4(9)) + No_Wide_Characters, -- GNAT + Static_Priorities, -- GNAT + Static_Storage_Size, -- GNAT + + -- The following cases do not require partition-wide checks + + Immediate_Reclamation, -- (RM H.4(10)) + No_Implementation_Attributes, -- GNAT + No_Implementation_Pragmas, -- GNAT + No_Implementation_Restrictions, -- GNAT + No_Elaboration_Code, -- GNAT + + Not_A_Restriction_Id); + + -- The following range of Restriction identifiers is checked for + -- consistency across a partition. The generated ali file is marked + -- for each entry to show one of three possibilities: + -- + -- Corresponding restriction is set (so unit does not violate it) + -- Corresponding restriction is not violated + -- Corresponding restriction is violated + + subtype Partition_Restrictions is + Restriction_Id range Boolean_Entry_Barriers .. Static_Storage_Size; + + -- The following set of Restriction identifiers is not checked for + -- consistency across a partition, and the generated ali files does + -- not carry any indications with respect to such restrictions. + + subtype Compilation_Unit_Restrictions is + Restriction_Id range Immediate_Reclamation .. No_Elaboration_Code; + + -- The following enumeration type defines the set of restriction + -- parameter identifiers taking a parameter that are implemented in + -- GNAT. To add a new restriction parameter identifier, add an entry + -- with the name to be used in the pragma, and add appropriate + -- calls to Check_Restriction. + + -- Note: the GNAT implementation currently only accomodates restriction + -- parameter identifiers whose expression value is a non-negative + -- integer. This is true for all language defined parameters. + + type Restriction_Parameter_Id is ( + Max_Asynchronous_Select_Nesting, -- (RM D.7(18), H.4(3)) + Max_Entry_Queue_Depth, -- GNAT + Max_Protected_Entries, -- (RM D.7(14)) + Max_Select_Alternatives, -- (RM D.7(12)) + Max_Storage_At_Blocking, -- (RM D.7(17)) + Max_Task_Entries, -- (RM D.7(13), H.4(3)) + Max_Tasks, -- (RM D.7(19), H.4(3)) + Not_A_Restriction_Parameter_Id); + +end Rident; diff --git a/gcc/ada/rtsfind.adb b/gcc/ada/rtsfind.adb new file mode 100644 index 00000000000..1299e1e2a13 --- /dev/null +++ b/gcc/ada/rtsfind.adb @@ -0,0 +1,913 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- R T S F I N D -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.96 $ +-- -- +-- Copyright (C) 1992-2001, 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +with Atree; use Atree; +with Casing; use Casing; +with Csets; use Csets; +with Debug; use Debug; +with Einfo; use Einfo; +with Elists; use Elists; +with Fname; use Fname; +with Fname.UF; use Fname.UF; +with Lib; use Lib; +with Lib.Load; use Lib.Load; +with Namet; use Namet; +with Nlists; use Nlists; +with Nmake; use Nmake; +with Output; use Output; +with Opt; use Opt; +with Restrict; use Restrict; +with Sem; use Sem; +with Sem_Ch7; use Sem_Ch7; +with Sem_Util; use Sem_Util; +with Sinfo; use Sinfo; +with Stand; use Stand; +with Snames; use Snames; +with Tbuild; use Tbuild; +with Uname; use Uname; + +package body Rtsfind is + + ---------------- + -- Unit table -- + ---------------- + + -- The unit table has one entry for each unit included in the definition + -- of the type RTU_Id in the spec. The table entries are initialized in + -- Initialize to set the Entity field to Empty, indicating that the + -- corresponding unit has not yet been loaded. The fields are set when + -- a unit is loaded to contain the defining entity for the unit, the + -- unit name, and the unit number. + + type RT_Unit_Table_Record is record + Entity : Entity_Id; + Uname : Unit_Name_Type; + Unum : Unit_Number_Type; + Withed : Boolean; + end record; + + RT_Unit_Table : array (RTU_Id) of RT_Unit_Table_Record; + + -------------------------- + -- Runtime Entity Table -- + -------------------------- + + -- There is one entry in the runtime entity table for each entity that is + -- included in the definition of the RE_Id type in the spec. The entries + -- are set by Initialize_Rtsfind to contain Empty, indicating that the + -- entity has not yet been located. Once the entity is located for the + -- first time, its ID is stored in this array, so that subsequent calls + -- for the same entity can be satisfied immediately. + + RE_Table : array (RE_Id) of Entity_Id; + + -------------------------- + -- Generation of WITH's -- + -------------------------- + + -- When a unit is implicitly loaded as a result of a call to RTE, it + -- is necessary to create an implicit with to ensure that the object + -- is correctly loaded by the binder. Such with statements are only + -- required when the request is from the extended main unit (if a + -- client needs a with, that will be taken care of when the client + -- is compiled. + + -- We always attach the with to the main unit. This is not perfectly + -- accurate in terms of elaboration requirements, but it is close + -- enough, since the units that are accessed using rtsfind do not + -- have delicate elaboration requirements. + + -- The flag Withed in the unit table record is initially set to False. + -- It is set True if a with has been generated for the main unit for + -- the corresponding unit. + + ----------------------- + -- Local Subprograms -- + ----------------------- + + procedure Load_Fail (S : String; U_Id : RTU_Id; Ent_Name : String := ""); + -- Internal procedure called if we can't find the entity or unit. + -- The parameter is a detailed error message that is to be given. + -- S is a reason for failing to compile the file. U_Id is the unit + -- id, and Ent_Name, if non-null, is the associated entity name. + + function Get_Unit_Name (U_Id : RTU_Id) return Unit_Name_Type; + -- Retrieves the Unit Name given a unit id represented by its + -- enumaration value in RTU_Id. + + procedure Load_RTU (U_Id : RTU_Id; Use_Setting : Boolean := False); + -- Load the unit whose Id is given if not already loaded. The unit is + -- loaded, analyzed, and added to the with list, and the entry in + -- RT_Unit_Table is updated to reflect the load. The second parameter + -- indicates the initial setting for the Is_Potentially_Use_Visible + -- flag of the entity for the loaded unit (if it is indeed loaded). + -- A value of False means nothing special need be done. A value of + -- True indicates that this flag must be set to True. It is needed + -- only in the Text_IO_Kludge procedure, which may materialize an + -- entity of Text_IO (or Wide_Text_IO) that was previously unknown. + + function RE_Chars (E : RE_Id) return Name_Id; + -- Given a RE_Id value returns the Chars of the corresponding entity. + + ------------------- + -- Get_Unit_Name -- + ------------------- + + function Get_Unit_Name (U_Id : RTU_Id) return Unit_Name_Type is + Uname_Chars : constant String := RTU_Id'Image (U_Id); + + begin + Name_Len := Uname_Chars'Length; + Name_Buffer (1 .. Name_Len) := Uname_Chars; + Set_Casing (All_Lower_Case); + + if U_Id in Ada_Child then + Name_Buffer (4) := '.'; + + if U_Id in Ada_Calendar_Child then + Name_Buffer (13) := '.'; + + elsif U_Id in Ada_Finalization_Child then + Name_Buffer (17) := '.'; + + elsif U_Id in Ada_Real_Time_Child then + Name_Buffer (14) := '.'; + + elsif U_Id in Ada_Streams_Child then + Name_Buffer (12) := '.'; + + elsif U_Id in Ada_Text_IO_Child then + Name_Buffer (12) := '.'; + + elsif U_Id in Ada_Wide_Text_IO_Child then + Name_Buffer (17) := '.'; + end if; + + elsif U_Id in Interfaces_Child then + Name_Buffer (11) := '.'; + + elsif U_Id in System_Child then + Name_Buffer (7) := '.'; + + if U_Id in System_Tasking_Child then + Name_Buffer (15) := '.'; + end if; + + if U_Id in System_Tasking_Restricted_Child then + Name_Buffer (26) := '.'; + end if; + + if U_Id in System_Tasking_Protected_Objects_Child then + Name_Buffer (33) := '.'; + end if; + + if U_Id in System_Tasking_Async_Delays_Child then + Name_Buffer (28) := '.'; + end if; + end if; + + -- Add %s at end for spec + + Name_Buffer (Name_Len + 1) := '%'; + Name_Buffer (Name_Len + 2) := 's'; + Name_Len := Name_Len + 2; + + return Name_Find; + end Get_Unit_Name; + + ---------------- + -- Initialize -- + ---------------- + + procedure Initialize is + begin + -- Initialize the unit table + + for J in RTU_Id loop + RT_Unit_Table (J).Entity := Empty; + end loop; + + for J in RE_Id loop + RE_Table (J) := Empty; + end loop; + end Initialize; + + ------------ + -- Is_RTE -- + ------------ + + function Is_RTE (Ent : Entity_Id; E : RE_Id) return Boolean is + E_Unit_Name : Unit_Name_Type; + Ent_Unit_Name : Unit_Name_Type; + + S : Entity_Id; + E1 : Entity_Id; + E2 : Entity_Id; + + begin + if No (Ent) then + return False; + + -- If E has already a corresponding entity, check it directly, + -- going to full views if they exist to deal with the incomplete + -- and private type cases properly. + + elsif Present (RE_Table (E)) then + E1 := Ent; + + if Is_Type (E1) and then Present (Full_View (E1)) then + E1 := Full_View (E1); + end if; + + E2 := RE_Table (E); + + if Is_Type (E2) and then Present (Full_View (E2)) then + E2 := Full_View (E2); + end if; + + return E1 = E2; + end if; + + -- If the unit containing E is not loaded, we already know that + -- the entity we have cannot have come from this unit. + + E_Unit_Name := Get_Unit_Name (RE_Unit_Table (E)); + + if not Is_Loaded (E_Unit_Name) then + return False; + end if; + + -- Here the unit containing the entity is loaded. We have not made + -- an explicit call to RTE to get the entity in question, but we may + -- have obtained a reference to it indirectly from some other entity + -- in the same unit, or some other unit that references it. + + -- Get the defining unit of the entity + + S := Scope (Ent); + + if Ekind (S) /= E_Package then + return False; + end if; + + Ent_Unit_Name := Get_Unit_Name (Unit_Declaration_Node (S)); + + -- If the defining unit of the entity we are testing is not the + -- unit containing E, then they cannot possibly match. + + if Ent_Unit_Name /= E_Unit_Name then + return False; + end if; + + -- If the units match, then compare the names (remember that no + -- overloading is permitted in entities fetched using Rtsfind). + + if RE_Chars (E) = Chars (Ent) then + RE_Table (E) := Ent; + + -- If front-end inlining is enabled, we may be within a body that + -- contains inlined functions, which has not been retrieved through + -- rtsfind, and therefore is not yet recorded in the RT_Unit_Table. + -- Add the unit information now, it must be fully available. + + declare + U : RT_Unit_Table_Record + renames RT_Unit_Table (RE_Unit_Table (E)); + begin + if No (U.Entity) then + U.Entity := S; + U.Uname := E_Unit_Name; + U.Unum := Get_Source_Unit (S); + end if; + end; + + return True; + else + return False; + end if; + end Is_RTE; + + ---------------------------- + -- Is_Text_IO_Kludge_Unit -- + ---------------------------- + + function Is_Text_IO_Kludge_Unit (Nam : Node_Id) return Boolean is + Prf : Node_Id; + Sel : Node_Id; + + begin + if Nkind (Nam) /= N_Expanded_Name then + return False; + end if; + + Prf := Prefix (Nam); + Sel := Selector_Name (Nam); + + if Nkind (Sel) /= N_Expanded_Name + or else Nkind (Prf) /= N_Identifier + or else Chars (Prf) /= Name_Ada + then + return False; + end if; + + Prf := Prefix (Sel); + Sel := Selector_Name (Sel); + + return + Nkind (Prf) = N_Identifier + and then + (Chars (Prf) = Name_Text_IO or else Chars (Prf) = Name_Wide_Text_IO) + and then + Nkind (Sel) = N_Identifier + and then + Chars (Sel) in Text_IO_Package_Name; + + end Is_Text_IO_Kludge_Unit; + + --------------- + -- Load_Fail -- + --------------- + + procedure Load_Fail (S : String; U_Id : RTU_Id; Ent_Name : String := "") is + begin + Set_Standard_Error; + + Write_Str ("fatal error: run-time library configuration error"); + Write_Eol; + + if Ent_Name /= "" then + Write_Str ("cannot locate """); + + -- Copy name skipping initial RE_ or RO_XX characters + + if Ent_Name (1 .. 2) = "RE" then + for J in 4 .. Ent_Name'Length loop + Name_Buffer (J - 3) := Ent_Name (J); + end loop; + else + for J in 7 .. Ent_Name'Length loop + Name_Buffer (J - 6) := Ent_Name (J); + end loop; + end if; + + Name_Len := Ent_Name'Length - 3; + Set_Casing (Mixed_Case); + Write_Str (Name_Buffer (1 .. Name_Len)); + Write_Str (""" in file """); + + else + Write_Str ("cannot load file """); + end if; + + Write_Name + (Get_File_Name (RT_Unit_Table (U_Id).Uname, Subunit => False)); + Write_Str (""" ("); + Write_Str (S); + Write_Char (')'); + Write_Eol; + Set_Standard_Output; + raise Unrecoverable_Error; + end Load_Fail; + + -------------- + -- Load_RTU -- + -------------- + + procedure Load_RTU (U_Id : RTU_Id; Use_Setting : Boolean := False) is + Loaded : Boolean; + U : RT_Unit_Table_Record renames RT_Unit_Table (U_Id); + Priv_Par : Elist_Id := New_Elmt_List; + Lib_Unit : Node_Id; + + procedure Save_Private_Visibility; + -- If the current unit is the body of child unit or the spec of a + -- private child unit, the private declarations of the parent (s) + -- are visible. If the unit to be loaded is another public sibling, + -- its compilation will affect the visibility of the common ancestors. + -- Indicate those that must be restored. + + procedure Restore_Private_Visibility; + -- Restore the visibility of ancestors after compiling RTU. + + -------------------------------- + -- Restore_Private_Visibility -- + -------------------------------- + + procedure Restore_Private_Visibility is + E_Par : Elmt_Id; + + begin + E_Par := First_Elmt (Priv_Par); + + while Present (E_Par) loop + if not In_Private_Part (Node (E_Par)) then + Install_Private_Declarations (Node (E_Par)); + end if; + + Next_Elmt (E_Par); + end loop; + end Restore_Private_Visibility; + + ----------------------------- + -- Save_Private_Visibility -- + ----------------------------- + + procedure Save_Private_Visibility is + Par : Entity_Id; + + begin + Par := Scope (Current_Scope); + + while Present (Par) + and then Par /= Standard_Standard + loop + if Ekind (Par) = E_Package + and then Is_Compilation_Unit (Par) + and then In_Private_Part (Par) + then + Append_Elmt (Par, Priv_Par); + end if; + + Par := Scope (Par); + end loop; + end Save_Private_Visibility; + + -- Start of processing for Load_RTU + + begin + -- Nothing to do if unit is already loaded + + if Present (U.Entity) then + return; + end if; + + -- Otherwise we need to load the unit, First build unit name + -- from the enumeration literal name in type RTU_Id. + + U.Uname := Get_Unit_Name (U_Id); + U.Withed := False; + Loaded := Is_Loaded (U.Uname); + + -- Now do the load call, note that setting Error_Node to Empty is + -- a signal to Load_Unit that we will regard a failure to find the + -- file as a fatal error, and that it should not output any kind + -- of diagnostics, since we will take care of it here. + + U.Unum := + Load_Unit + (Load_Name => U.Uname, + Required => False, + Subunit => False, + Error_Node => Empty); + + if U.Unum = No_Unit then + Load_Fail ("unit not found", U_Id); + + elsif Fatal_Error (U.Unum) then + Load_Fail ("parser errors", U_Id); + end if; + + -- Make sure that the unit is analyzed + + declare + Was_Analyzed : Boolean := Analyzed (Cunit (Current_Sem_Unit)); + + begin + -- Pretend that the current unit is analysed, in case it is + -- System or some such. This allows us to put some declarations, + -- such as exceptions and packed arrays of Boolean, into System + -- even though expanding them requires System... + + -- This is a bit odd but works fine. If the RTS unit does not depend + -- in any way on the current unit, then it never gets back into the + -- current unit's tree, and the change we make to the current unit + -- tree is never noticed by anyone (it is undone in a moment). That + -- is the normal situation. + + -- If the RTS Unit *does* depend on the current unit, for instance, + -- when you are compiling System, then you had better have finished + -- Analyzing the part of System that is depended on before you try + -- to load the RTS Unit. This means having the System ordered in an + -- appropriate manner. + + Set_Analyzed (Cunit (Current_Sem_Unit), True); + + if not Analyzed (Cunit (U.Unum)) then + + Save_Private_Visibility; + Semantics (Cunit (U.Unum)); + Restore_Private_Visibility; + + if Fatal_Error (U.Unum) then + Load_Fail ("semantic errors", U_Id); + end if; + end if; + + -- Undo the pretence + + Set_Analyzed (Cunit (Current_Sem_Unit), Was_Analyzed); + end; + + Lib_Unit := Unit (Cunit (U.Unum)); + U.Entity := Defining_Entity (Lib_Unit); + + if Use_Setting then + Set_Is_Potentially_Use_Visible (U.Entity, True); + end if; + end Load_RTU; + + -------------- + -- RE_Chars -- + -------------- + + function RE_Chars (E : RE_Id) return Name_Id is + RE_Name_Chars : constant String := RE_Id'Image (E); + + begin + -- Copy name skipping initial RE_ or RO_XX characters + + if RE_Name_Chars (1 .. 2) = "RE" then + for J in 4 .. RE_Name_Chars'Last loop + Name_Buffer (J - 3) := Fold_Lower (RE_Name_Chars (J)); + end loop; + + Name_Len := RE_Name_Chars'Length - 3; + + else + for J in 7 .. RE_Name_Chars'Last loop + Name_Buffer (J - 6) := Fold_Lower (RE_Name_Chars (J)); + end loop; + + Name_Len := RE_Name_Chars'Length - 6; + end if; + + return Name_Find; + end RE_Chars; + + --------- + -- RTE -- + --------- + + function RTE (E : RE_Id) return Entity_Id is + U_Id : constant RTU_Id := RE_Unit_Table (E); + U : RT_Unit_Table_Record renames RT_Unit_Table (U_Id); + + Ent : Entity_Id; + Lib_Unit : Node_Id; + Pkg_Ent : Entity_Id; + Ename : Name_Id; + Enode : Node_Id; + + procedure Check_RPC; + -- Reject programs that make use of distribution features not supported + -- on the current target. On such targets (VMS, Vxworks, others?) we + -- only provide a minimal body for System.Rpc that only supplies an + -- implementation of partition_id. + + function Find_Local_Entity (E : RE_Id) return Entity_Id; + -- This function is used when entity E is in this compilation's main + -- unit. It gets the value from the already compiled declaration. + + function Make_Unit_Name (N : Node_Id) return Node_Id; + -- If the unit is a child unit, build fully qualified name for use + -- in with_clause. + + --------------- + -- Check_RPC -- + --------------- + + procedure Check_RPC is + Body_Name : Unit_Name_Type; + Unum : Unit_Number_Type; + + begin + -- Bypass this check if debug flag -gnatdR set + + if Debug_Flag_RR then + return; + end if; + + -- Otherwise we need the check if we are going after one of + -- the critical entities in System.RPC in stubs mode. + + if (Distribution_Stub_Mode = Generate_Receiver_Stub_Body + or else + Distribution_Stub_Mode = Generate_Caller_Stub_Body) + and then (E = RE_Do_Rpc + or else E = RE_Do_Apc + or else E = RE_Params_Stream_Type + or else E = RE_RPC_Receiver) + then + -- Load body of System.Rpc, and abort if this is the body that is + -- provided by GNAT, for which these features are not supported + -- on current target. We identify the gnat body by the presence + -- of a local entity called Gnat in the first declaration. + + Lib_Unit := Unit (Cunit (U.Unum)); + Body_Name := Get_Body_Name (Get_Unit_Name (Lib_Unit)); + Unum := + Load_Unit + (Load_Name => Body_Name, + Required => False, + Subunit => False, + Error_Node => Empty, + Renamings => True); + + if Unum /= No_Unit then + declare + Decls : List_Id := Declarations (Unit (Cunit (Unum))); + + begin + if Present (Decls) + and then Nkind (First (Decls)) = N_Object_Declaration + and then + Chars (Defining_Identifier (First (Decls))) = Name_Gnat + then + Set_Standard_Error; + Write_Str ("distribution feature not supported"); + Write_Eol; + raise Unrecoverable_Error; + end if; + end; + end if; + end if; + end Check_RPC; + + ------------------------ + -- Find_System_Entity -- + ------------------------ + + function Find_Local_Entity (E : RE_Id) return Entity_Id is + RE_Str : String renames RE_Id'Image (E); + Ent : Entity_Id; + + Save_Nam : constant String := Name_Buffer (1 .. Name_Len); + -- Save name buffer and length over call + + begin + Name_Len := Natural'Max (0, RE_Str'Length - 3); + Name_Buffer (1 .. Name_Len) := + RE_Str (RE_Str'First + 3 .. RE_Str'Last); + + Ent := Entity_Id (Get_Name_Table_Info (Name_Find)); + + Name_Len := Save_Nam'Length; + Name_Buffer (1 .. Name_Len) := Save_Nam; + + return Ent; + end Find_Local_Entity; + + -------------------- + -- Make_Unit_Name -- + -------------------- + + function Make_Unit_Name (N : Node_Id) return Node_Id is + Nam : Node_Id; + Scop : Entity_Id; + + begin + Nam := New_Reference_To (U.Entity, Standard_Location); + Scop := Scope (U.Entity); + + if Nkind (N) = N_Defining_Program_Unit_Name then + while Scop /= Standard_Standard loop + Nam := + Make_Expanded_Name (Standard_Location, + Chars => Chars (U.Entity), + Prefix => New_Reference_To (Scop, Standard_Location), + Selector_Name => Nam); + Set_Entity (Nam, U.Entity); + + Scop := Scope (Scop); + end loop; + end if; + + return Nam; + end Make_Unit_Name; + + -- Start of processing for RTE + + begin + -- Doing a rtsfind in system.ads is special, as we cannot do this + -- when compiling System itself. So if we are compiling system then + -- we should already have acquired and processed the declaration + -- of the entity. The test is to see if this compilation's main unit + -- is System. If so, return the value from the already compiled + -- declaration and otherwise do a regular find. + + -- Not pleasant, but these kinds of annoying recursion when + -- writing an Ada compiler in Ada have to be broken somewhere! + + if Present (Main_Unit_Entity) + and then Chars (Main_Unit_Entity) = Name_System + and then Analyzed (Main_Unit_Entity) + and then not Is_Child_Unit (Main_Unit_Entity) + then + return Find_Local_Entity (E); + end if; + + Enode := Current_Error_Node; + + -- Load unit if unit not previously loaded + + if No (RE_Table (E)) then + Load_RTU (U_Id); + Lib_Unit := Unit (Cunit (U.Unum)); + + -- In the subprogram case, we are all done, the entity we want + -- is the entity for the subprogram itself. Note that we do not + -- bother to check that it is the entity that was requested. + -- the only way that could fail to be the case is if runtime is + -- hopelessly misconfigured, and it isn't worth testing for this. + + if Nkind (Lib_Unit) = N_Subprogram_Declaration then + RE_Table (E) := U.Entity; + + -- Otherwise we must have the package case, and here we have to + -- search the package entity chain for the entity we want. The + -- entity we want must be present in this chain, or we have a + -- misconfigured runtime. + + else + pragma Assert (Nkind (Lib_Unit) = N_Package_Declaration); + Ename := RE_Chars (E); + + Pkg_Ent := First_Entity (U.Entity); + + while Present (Pkg_Ent) loop + if Ename = Chars (Pkg_Ent) then + RE_Table (E) := Pkg_Ent; + Check_RPC; + goto Found; + end if; + + Next_Entity (Pkg_Ent); + end loop; + + -- If we didn't find the unit we want, something is wrong! + + Load_Fail ("entity not in package", U_Id, RE_Id'Image (E)); + raise Program_Error; + end if; + end if; + + -- See if we have to generate a with for this entity. We generate + -- a with if the current unit is part of the extended main code + -- unit, and if we have not already added the with. The with is + -- added to the appropriate unit (the current one). + + <<Found>> + if (not U.Withed) + and then + In_Extended_Main_Code_Unit (Cunit_Entity (Current_Sem_Unit)) + then + U.Withed := True; + + declare + Withn : Node_Id; + Lib_Unit : Node_Id; + + begin + Lib_Unit := Unit (Cunit (U.Unum)); + Withn := + Make_With_Clause (Standard_Location, + Name => + Make_Unit_Name + (Defining_Unit_Name (Specification (Lib_Unit)))); + Set_Library_Unit (Withn, Cunit (U.Unum)); + Set_Corresponding_Spec (Withn, U.Entity); + Set_First_Name (Withn, True); + Set_Implicit_With (Withn, True); + + Mark_Rewrite_Insertion (Withn); + Append (Withn, Context_Items (Cunit (Current_Sem_Unit))); + end; + end if; + + -- We can now obtain the entity. Check that the No_Run_Time condition + -- is not violated. Note that we do not signal the error if we detect + -- it in a runtime unit. This can only arise if the user explicitly + -- with'ed the runtime unit (or another runtime unit that uses it + -- transitively), or if some acceptable (e.g. inlined) entity is + -- fetched from a unit, some of whose other routines or entities + -- violate the conditions. In the latter case, it does not matter, + -- since we won't be using those entities. + + Ent := RE_Table (E); + + if Is_Subprogram (Ent) + and then not Is_Inlined (Ent) + and then Sloc (Enode) /= Standard_Location + and then not + Is_Predefined_File_Name (Unit_File_Name (Get_Source_Unit (Enode))) + then + Disallow_In_No_Run_Time_Mode (Enode); + end if; + + return Ent; + end RTE; + + -------------------- + -- Text_IO_Kludge -- + -------------------- + + procedure Text_IO_Kludge (Nam : Node_Id) is + Chrs : Name_Id; + + type Name_Map_Type is array (Text_IO_Package_Name) of RTU_Id; + + Name_Map : Name_Map_Type := Name_Map_Type'( + Name_Decimal_IO => Ada_Text_IO_Decimal_IO, + Name_Enumeration_IO => Ada_Text_IO_Enumeration_IO, + Name_Fixed_IO => Ada_Text_IO_Fixed_IO, + Name_Float_IO => Ada_Text_IO_Float_IO, + Name_Integer_IO => Ada_Text_IO_Integer_IO, + Name_Modular_IO => Ada_Text_IO_Modular_IO); + + Wide_Name_Map : Name_Map_Type := Name_Map_Type'( + Name_Decimal_IO => Ada_Wide_Text_IO_Decimal_IO, + Name_Enumeration_IO => Ada_Wide_Text_IO_Enumeration_IO, + Name_Fixed_IO => Ada_Wide_Text_IO_Fixed_IO, + Name_Float_IO => Ada_Wide_Text_IO_Float_IO, + Name_Integer_IO => Ada_Wide_Text_IO_Integer_IO, + Name_Modular_IO => Ada_Wide_Text_IO_Modular_IO); + + begin + -- Nothing to do if name is not identifier or a selected component + -- whose selector_name is not an identifier. + + if Nkind (Nam) = N_Identifier then + Chrs := Chars (Nam); + + elsif Nkind (Nam) = N_Selected_Component + and then Nkind (Selector_Name (Nam)) = N_Identifier + then + Chrs := Chars (Selector_Name (Nam)); + + else + return; + end if; + + -- Nothing to do if name is not one of the Text_IO subpackages + -- Otherwise look through loaded units, and if we find Text_IO + -- or Wide_Text_IO already loaded, then load the proper child. + + if Chrs in Text_IO_Package_Name then + for U in Main_Unit .. Last_Unit loop + Get_Name_String (Unit_File_Name (U)); + + if Name_Len = 12 then + + -- Here is where we do the loads if we find one of the + -- units Ada.Text_IO or Ada.Wide_Text_IO. An interesting + -- detail is that these units may already be used (i.e. + -- their In_Use flags may be set). Normally when the In_Use + -- flag is set, the Is_Potentially_Use_Visible flag of all + -- entities in the package is set, but the new entity we + -- are mysteriously adding was not there to have its flag + -- set at the time. So that's why we pass the extra parameter + -- to RTU_Find, to make sure the flag does get set now. + -- Given that those generic packages are in fact child units, + -- we must indicate that they are visible. + + if Name_Buffer (1 .. 12) = "a-textio.ads" then + Load_RTU (Name_Map (Chrs), In_Use (Cunit_Entity (U))); + Set_Is_Visible_Child_Unit + (RT_Unit_Table (Name_Map (Chrs)).Entity); + + elsif Name_Buffer (1 .. 12) = "a-witeio.ads" then + Load_RTU (Wide_Name_Map (Chrs), In_Use (Cunit_Entity (U))); + Set_Is_Visible_Child_Unit + (RT_Unit_Table (Wide_Name_Map (Chrs)).Entity); + end if; + end if; + end loop; + end if; + end Text_IO_Kludge; + +end Rtsfind; diff --git a/gcc/ada/rtsfind.ads b/gcc/ada/rtsfind.ads new file mode 100644 index 00000000000..11304f625a8 --- /dev/null +++ b/gcc/ada/rtsfind.ads @@ -0,0 +1,2324 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- R T S F I N D -- +-- -- +-- S p e c -- +-- -- +-- $Revision: 1.216 $ +-- -- +-- Copyright (C) 1992-2001, 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +with Types; use Types; + +package Rtsfind is + +-- This package contains the routine that is used to obtain runtime library +-- entities, loading in the required runtime library packages on demand. It +-- is also used for such purposes as finding System.Address when System has +-- not been explicitly With'ed. + + ------------------------ + -- Runtime Unit Table -- + ------------------------ + + -- The following type includes an enumeration entry for each runtime + -- unit. The enumeration literal represents the fully qualified + -- name of the unit, as follows: + + -- Names of the form Ada_xxx are first level children of Ada, whose + -- name is Ada.xxx. For example, the name Ada_Tags refers to package + -- Ada.Tags. + + -- Names of the form Ada_Calendar_xxx are second level children + -- of Ada.Calendar. This is part of a temporary implementation of + -- delays; eventually, packages implementing delays will be found + -- relative to the package that declares the time type. + + -- Names of the form Interfaces_xxx are first level children of + -- Interfaces_CPP refers to package Interfaces.CPP + + -- Names of the form System_xxx are first level children of System, whose + -- name is System.xxx. For example, the name System_Str_Concat refers to + -- package System.Str_Concat. + + -- Names of the form System_Tasking_xxx are second level children of the + -- package System.Tasking. For example, System_Tasking_Stages refers to + -- refers to the package System.Tasking.Stages. + + -- Other names stand for themselves (e.g. System for package System) + + -- This list can contain both subprogram and package unit names. For + -- packages, the accessible entities in the package are separately + -- listed in the package entity table. The units must be either library + -- level package declarations, or library level subprogram declarations. + -- Generic units, library level instantiations and subprogram bodies + -- acting as specs may not be referenced (all these cases could be added + -- at the expense of additional complexity in the body of Rtsfind, but + -- it doesn't seem worth while, since the implementation controls the + -- set of units that are referenced, and this restrictions is easily met. + + -- IMPORTANT NOTE: the specs of packages and procedures with'ed using + -- this mechanism may not contain use clauses. This is because these + -- subprograms are compiled in the current visibility environment, and + -- it would be too much trouble to establish a clean environment for the + -- compilation. The presence of extraneous visible stuff has no effect + -- on the compilation except in the presence of use clauses (which might + -- result in unexpected ambiguities). + + type RTU_Id is ( + -- Runtime packages, for list of accessible entities in each + -- package see declarations in the runtime entity table below. + + RTU_Null, + -- Used as a null entry. Will cause an error if referenced. + + -- Children of Ada + + Ada_Calendar, + Ada_Exceptions, + Ada_Finalization, + Ada_Interrupts, + Ada_Real_Time, + Ada_Streams, + Ada_Tags, + Ada_Task_Identification, + + -- Children of Ada.Calendar + + Ada_Calendar_Delays, + + -- Children of Ada.Finalization + + Ada_Finalization_List_Controller, + + -- Children of Ada.Real_Time + + Ada_Real_Time_Delays, + + -- Children of Ada.Streams + + Ada_Streams_Stream_IO, + + -- Children of Ada.Text_IO (for Text_IO_Kludge) + + Ada_Text_IO_Decimal_IO, + Ada_Text_IO_Enumeration_IO, + Ada_Text_IO_Fixed_IO, + Ada_Text_IO_Float_IO, + Ada_Text_IO_Integer_IO, + Ada_Text_IO_Modular_IO, + + -- Children of Ada.Wide_Text_IO (for Text_IO_Kludge) + + Ada_Wide_Text_IO_Decimal_IO, + Ada_Wide_Text_IO_Enumeration_IO, + Ada_Wide_Text_IO_Fixed_IO, + Ada_Wide_Text_IO_Float_IO, + Ada_Wide_Text_IO_Integer_IO, + Ada_Wide_Text_IO_Modular_IO, + + -- Interfaces + + Interfaces, + + -- Children of Interfaces + + Interfaces_CPP, + Interfaces_Packed_Decimal, + + -- Package System + + System, + + -- Children of System + + System_Arith_64, + System_AST_Handling, + System_Assertions, + System_Aux_DEC, + System_Bit_Ops, + System_Checked_Pools, + System_Exception_Table, + System_Exceptions, + System_Delay_Operations, + System_Exn_Flt, + System_Exn_Int, + System_Exn_LFlt, + System_Exn_LInt, + System_Exn_LLF, + System_Exn_LLI, + System_Exn_SFlt, + System_Exn_SInt, + System_Exn_SSI, + System_Exp_Flt, + System_Exp_Int, + System_Exp_LFlt, + System_Exp_LInt, + System_Exp_LLF, + System_Exp_LLI, + System_Exp_LLU, + System_Exp_Mod, + System_Exp_SFlt, + System_Exp_SInt, + System_Exp_SSI, + System_Exp_Uns, + System_Fat_Flt, + System_Fat_LFlt, + System_Fat_LLF, + System_Fat_SFlt, + System_Finalization_Implementation, + System_Finalization_Root, + System_Fore, + System_Img_Bool, + System_Img_Char, + System_Img_Dec, + System_Img_Enum, + System_Img_Int, + System_Img_LLD, + System_Img_LLI, + System_Img_LLU, + System_Img_Name, + System_Img_Real, + System_Img_Uns, + System_Img_WChar, + System_Interrupts, + System_Machine_Code, + System_Mantissa, + System_Pack_03, + System_Pack_05, + System_Pack_06, + System_Pack_07, + System_Pack_09, + System_Pack_10, + System_Pack_11, + System_Pack_12, + System_Pack_13, + System_Pack_14, + System_Pack_15, + System_Pack_17, + System_Pack_18, + System_Pack_19, + System_Pack_20, + System_Pack_21, + System_Pack_22, + System_Pack_23, + System_Pack_24, + System_Pack_25, + System_Pack_26, + System_Pack_27, + System_Pack_28, + System_Pack_29, + System_Pack_30, + System_Pack_31, + System_Pack_33, + System_Pack_34, + System_Pack_35, + System_Pack_36, + System_Pack_37, + System_Pack_38, + System_Pack_39, + System_Pack_40, + System_Pack_41, + System_Pack_42, + System_Pack_43, + System_Pack_44, + System_Pack_45, + System_Pack_46, + System_Pack_47, + System_Pack_48, + System_Pack_49, + System_Pack_50, + System_Pack_51, + System_Pack_52, + System_Pack_53, + System_Pack_54, + System_Pack_55, + System_Pack_56, + System_Pack_57, + System_Pack_58, + System_Pack_59, + System_Pack_60, + System_Pack_61, + System_Pack_62, + System_Pack_63, + System_Parameters, + System_Partition_Interface, + System_Pool_Global, + System_Pool_Empty, + System_Pool_Local, + System_Pool_Size, + System_RPC, + System_Scalar_Values, + System_Secondary_Stack, + System_Shared_Storage, + System_Soft_Links, + System_Standard_Library, + System_Storage_Elements, + System_Storage_Pools, + System_Stream_Attributes, + System_String_Ops, + System_String_Ops_Concat_3, + System_String_Ops_Concat_4, + System_String_Ops_Concat_5, + System_Task_Info, + System_Tasking, + System_Unsigned_Types, + System_Val_Bool, + System_Val_Char, + System_Val_Dec, + System_Val_Enum, + System_Val_Int, + System_Val_LLD, + System_Val_LLI, + System_Val_LLU, + System_Val_Name, + System_Val_Real, + System_Val_Uns, + System_Val_WChar, + System_Vax_Float_Operations, + System_Version_Control, + System_VMS_Exception_Table, + System_WCh_StW, + System_WCh_WtS, + System_Wid_Bool, + System_Wid_Char, + System_Wid_Enum, + System_Wid_LLI, + System_Wid_LLU, + System_Wid_Name, + System_Wid_WChar, + System_WWd_Char, + System_WWd_Enum, + System_WWd_Wchar, + + -- Children of System.Tasking + + System_Tasking_Async_Delays, + System_Tasking_Async_Delays_Enqueue_Calendar, + System_Tasking_Async_Delays_Enqueue_RT, + System_Tasking_Protected_Objects, + System_Tasking_Protected_Objects_Entries, + System_Tasking_Protected_Objects_Operations, + System_Tasking_Protected_Objects_Single_Entry, + System_Tasking_Restricted_Stages, + System_Tasking_Rendezvous, + System_Tasking_Stages); + + subtype Ada_Child is RTU_Id + range Ada_Calendar .. Ada_Wide_Text_IO_Modular_IO; + -- Range of values for children or grand-children of Ada + + subtype Ada_Calendar_Child is Ada_Child + range Ada_Calendar_Delays .. Ada_Calendar_Delays; + -- Range of values for children of Ada.Calendar + + subtype Ada_Finalization_Child is Ada_Child range + Ada_Finalization_List_Controller .. Ada_Finalization_List_Controller; + -- Range of values for children of Ada.Finalization + + subtype Ada_Real_Time_Child is Ada_Child + range Ada_Real_Time_Delays .. Ada_Real_Time_Delays; + -- Range of values for children of Ada.Real_Time + + subtype Ada_Streams_Child is Ada_Child + range Ada_Streams_Stream_IO .. Ada_Streams_Stream_IO; + + subtype Ada_Text_IO_Child is Ada_Child + range Ada_Text_IO_Decimal_IO .. Ada_Text_IO_Modular_IO; + -- Range of values for children of Ada.Text_IO + + subtype Ada_Wide_Text_IO_Child is Ada_Child + range Ada_Wide_Text_IO_Decimal_IO .. Ada_Wide_Text_IO_Modular_IO; + -- Range of values for children of Ada.Text_IO + + subtype Interfaces_Child is RTU_Id + range Interfaces_CPP .. Interfaces_Packed_Decimal; + -- Range of values for children of Interfaces + + subtype System_Child is RTU_Id + range System_Arith_64 .. System_Tasking_Stages; + -- Range of values for children or grandchildren of System + + subtype System_Tasking_Child is System_Child + range System_Tasking_Async_Delays .. System_Tasking_Stages; + -- Range of values for children of System.Tasking + + subtype System_Tasking_Protected_Objects_Child is System_Tasking_Child + range System_Tasking_Protected_Objects_Entries .. + System_Tasking_Protected_Objects_Single_Entry; + -- Range of values for children of System.Tasking.Protected_Objects + + subtype System_Tasking_Restricted_Child is System_Tasking_Child + range System_Tasking_Restricted_Stages .. + System_Tasking_Restricted_Stages; + -- Range of values for children of System.Tasking.Restricted + + subtype System_Tasking_Async_Delays_Child is System_Tasking_Child + range System_Tasking_Async_Delays_Enqueue_Calendar .. + System_Tasking_Async_Delays_Enqueue_RT; + -- Range of values for children of System.Tasking.Async_Delays + + -------------------------- + -- Runtime Entity Table -- + -------------------------- + + -- This is the enumeration type used to define the argument passed to + -- the RTE function. The name must exactly match the name of the entity + -- involved, and in the case of a package entity, this name must uniquely + -- imply the package containing the entity. + + -- As far as possible, we avoid duplicate names in runtime packages, so + -- that the name RE_nnn uniquely identifies the entity nnn. In some cases, + -- it is impossible to avoid such duplication because the names come from + -- RM defined packages. In such cases, the name is of the form RO_XX_nnn + -- where XX is two letters used to differentiate the multiple occurrences + -- of the name xx, and nnn is the entity name. + + -- Note that not all entities in the units contained in the run-time unit + -- table are included in the following table, only those that actually + -- have to be referenced from generated code. + + -- Note on RE_Null. This value is used as a null entry where an RE_Id + -- value is required syntactically, but no real entry is required or + -- needed. Use of this value will cause a fatal error in an RTE call. + + type RE_Id is ( + + RE_Null, + + RE_Code_Loc, -- Ada.Exceptions + RE_Current_Target_Exception, -- Ada.Exceptions (JGNAT use only) + RE_Exception_Id, -- Ada.Exceptions + RE_Exception_Information, -- Ada.Exceptions + RE_Exception_Message, -- Ada.Exceptions + RE_Exception_Name_Simple, -- Ada.Exceptions + RE_Exception_Occurrence, -- Ada.Exceptions + RE_Null_Id, -- Ada.Exceptions + RE_Null_Occurrence, -- Ada.Exceptions + RE_Poll, -- Ada.Exceptions + RE_Raise_Exception, -- Ada.Exceptions + RE_Raise_Exception_Always, -- Ada.Exceptions + RE_Reraise_Occurrence, -- Ada.Exceptions + RE_Reraise_Occurrence_Always, -- Ada.Exceptions + RE_Reraise_Occurrence_No_Defer, -- Ada.Exceptions + RE_Save_Occurrence, -- Ada.Exceptions + + RE_Simple_List_Controller, -- Ada.Finalization.List_Controller + RE_List_Controller, -- Ada.Finalization.List_Controller + + RE_Interrupt_Id, -- Ada.Interrupts + + RE_Root_Stream_Type, -- Ada.Streams + RE_Stream_Element, -- Ada.Streams + RE_Stream_Element_Offset, -- Ada.Streams + RE_Stream_Element_Array, -- Ada.Streams + + RE_Stream_Access, -- Ada.Streams.Stream_IO + + RE_CW_Membership, -- Ada.Tags + RE_DT_Entry_Size, -- Ada.Tags + RE_DT_Prologue_Size, -- Ada.Tags + RE_External_Tag, -- Ada.Tags + RE_Get_Expanded_Name, -- Ada.Tags + RE_Get_External_Tag, -- Ada.Tags + RE_Get_Prim_Op_Address, -- Ada.Tags + RE_Get_RC_Offset, -- Ada.Tags + RE_Get_Remotely_Callable, -- Ada.Tags + RE_Get_TSD, -- Ada.Tags + RE_Inherit_DT, -- Ada.Tags + RE_Inherit_TSD, -- Ada.Tags + RE_Internal_Tag, -- Ada.Tags + RE_Register_Tag, -- Ada.Tags + RE_Set_Expanded_Name, -- Ada.Tags + RE_Set_External_Tag, -- Ada.Tags + RE_Set_Prim_Op_Address, -- Ada.Tags + RE_Set_RC_Offset, -- Ada.Tags + RE_Set_Remotely_Callable, -- Ada.Tags + RE_Set_TSD, -- Ada.Tags + RE_Tag_Error, -- Ada.Tags + RE_TSD_Entry_Size, -- Ada.Tags + RE_TSD_Prologue_Size, -- Ada.Tags + RE_Tag, -- Ada.Tags + RE_Address_Array, -- Ada.Tags + + RE_Current_Task, -- Ada.Task_Identification + RO_AT_Task_ID, -- Ada.Task_Identification + + RO_CA_Time, -- Ada.Calendar + + RO_CA_Delay_For, -- Ada.Calendar.Delays + RO_CA_Delay_Until, -- Ada.Calendar.Delays + RO_CA_To_Duration, -- Ada.Calendar.Delays + + RO_RT_Time, -- Ada.Real_Time + + RO_RT_Delay_Until, -- Ada.Real_Time.Delays + RO_RT_To_Duration, -- Ada.Real_Time.Delays + + RE_Integer_64, -- Interfaces + RE_Unsigned_8, -- Interfaces + RE_Unsigned_16, -- Interfaces + RE_Unsigned_32, -- Interfaces + RE_Unsigned_64, -- Interfaces + + RE_Vtable_Ptr, -- Interfaces.CPP + RE_Displaced_This, -- Interfaces.CPP + RE_CPP_CW_Membership, -- Interfaces.CPP + RE_CPP_DT_Entry_Size, -- Interfaces.CPP + RE_CPP_DT_Prologue_Size, -- Interfaces.CPP + RE_CPP_Get_Expanded_Name, -- Interfaces.CPP + RE_CPP_Get_External_Tag, -- Interfaces.CPP + RE_CPP_Get_Prim_Op_Address, -- Interfaces.CPP + RE_CPP_Get_RC_Offset, -- Interfaces.CPP + RE_CPP_Get_Remotely_Callable, -- Interfaces.CPP + RE_CPP_Get_TSD, -- Interfaces.CPP + RE_CPP_Inherit_DT, -- Interfaces.CPP + RE_CPP_Inherit_TSD, -- Interfaces.CPP + RE_CPP_Register_Tag, -- Interfaces.CPP + RE_CPP_Set_Expanded_Name, -- Interfaces.CPP + RE_CPP_Set_External_Tag, -- Interfaces.CPP + RE_CPP_Set_Prim_Op_Address, -- Interfaces.CPP + RE_CPP_Set_RC_Offset, -- Interfaces.CPP + RE_CPP_Set_Remotely_Callable, -- Interfaces.CPP + RE_CPP_Set_TSD, -- Interfaces.CPP + RE_CPP_TSD_Entry_Size, -- Interfaces.CPP + RE_CPP_TSD_Prologue_Size, -- Interfaces.CPP + + RE_Packed_Size, -- Interfaces.Packed_Decimal + RE_Packed_To_Int32, -- Interfaces.Packed_Decimal + RE_Packed_To_Int64, -- Interfaces.Packed_Decimal + RE_Int32_To_Packed, -- Interfaces.Packed_Decimal + RE_Int64_To_Packed, -- Interfaces.Packed_Decimal + + RE_Address, -- System + RE_Any_Priority, -- System + RE_Bit_Order, -- System + RE_Default_Priority, -- System + RE_High_Order_First, -- System + RE_Interrupt_Priority, -- System + RE_Lib_Stop, -- System + RE_Low_Order_First, -- System + RE_Max_Interrupt_Priority, -- System + RE_Max_Priority, -- System + RE_Null_Address, -- System + RE_Priority, -- System + + RE_Add_With_Ovflo_Check, -- System.Arith_64 + RE_Double_Divide, -- System.Arith_64 + RE_Multiply_With_Ovflo_Check, -- System.Arith_64 + RE_Scaled_Divide, -- System.Arith_64 + RE_Subtract_With_Ovflo_Check, -- System.Arith_64 + + RE_Create_AST_Handler, -- System.AST_Handling + + RE_Raise_Assert_Failure, -- System.Assertions + + RE_AST_Handler, -- System.Aux_DEC + RE_Import_Value, -- System.Aux_DEC + RE_No_AST_Handler, -- System.Aux_DEC + RE_Type_Class, -- System.Aux_DEC + RE_Type_Class_Enumeration, -- System.Aux_DEC + RE_Type_Class_Integer, -- System.Aux_DEC + RE_Type_Class_Fixed_Point, -- System.Aux_DEC + RE_Type_Class_Floating_Point, -- System.Aux_DEC + RE_Type_Class_Array, -- System.Aux_DEC + RE_Type_Class_Record, -- System.Aux_DEC + RE_Type_Class_Access, -- System.Aux_DEC + RE_Type_Class_Task, -- System.Aux_DEC + RE_Type_Class_Address, -- System.Aux_DEC + + RE_Bit_And, -- System.Bit_Ops + RE_Bit_Eq, -- System.Bit_Ops + RE_Bit_Not, -- System.Bit_Ops + RE_Bit_Or, -- System.Bit_Ops + RE_Bit_Xor, -- System.Bit_Ops + + RE_Checked_Pool, -- System.Checked_Pools + + RE_Register_Exception, -- System.Exception_Table + + RE_All_Others_Id, -- System.Exceptions + RE_Handler_Record, -- System.Exceptions + RE_Handler_Record_Ptr, -- System.Exceptions + RE_Others_Id, -- System.Exceptions + RE_Subprogram_Descriptor, -- System.Exceptions + RE_Subprogram_Descriptor_0, -- System.Exceptions + RE_Subprogram_Descriptor_1, -- System.Exceptions + RE_Subprogram_Descriptor_2, -- System.Exceptions + RE_Subprogram_Descriptor_3, -- System.Exceptions + RE_Subprogram_Descriptor_List, -- System.Exceptions + RE_Subprogram_Descriptor_Ptr, -- System.Exceptions + RE_Subprogram_Descriptors_Record, -- System.Exceptions + RE_Subprogram_Descriptors_Ptr, -- System.Exceptions + + RE_Exn_Float, -- System.Exn_Flt + + RE_Exn_Integer, -- System.Exn_Int + + RE_Exn_Long_Float, -- System.Exn_LFlt + + RE_Exn_Long_Integer, -- System.Exn_LInt + + RE_Exn_Long_Long_Float, -- System.Exn_LLF + + RE_Exn_Long_Long_Integer, -- System.Exn_LLI + + RE_Exn_Short_Float, -- System.Exn_SFlt + + RE_Exn_Short_Integer, -- System.Exn_SInt + + RE_Exn_Short_Short_Integer, -- System.Exn_SSI + + RE_Exp_Float, -- System.Exp_Flt + + RE_Exp_Integer, -- System.Exp_Int + + RE_Exp_Long_Float, -- System.Exp_LFlt + + RE_Exp_Long_Integer, -- System.Exp_LInt + + RE_Exp_Long_Long_Float, -- System.Exp_LLF + + RE_Exp_Long_Long_Integer, -- System.Exp_LLI + + RE_Exp_Long_Long_Unsigned, -- System.Exp_LLU + + RE_Exp_Modular, -- System.Exp_Mod + + RE_Exp_Short_Float, -- System.Exp_SFlt + + RE_Exp_Short_Integer, -- System.Exp_SInt + + RE_Exp_Short_Short_Integer, -- System.Exp_SSI + + RE_Exp_Unsigned, -- System.Exp_Uns + + RE_Fat_Float, -- System.Fat_Flt + + RE_Fat_Long_Float, -- System.Fat_LFlt + + RE_Fat_Long_Long_Float, -- System.Fat_LLF + + RE_Fat_Short_Float, -- System.Fat_SFlt + + RE_Attach_To_Final_List, -- System.Finalization_Implementation + RE_Finalize_List, -- System.Finalization_Implementation + RE_Finalize_One, -- System.Finalization_Implementation + RE_Global_Final_List, -- System.Finalization_Implementation + RE_Record_Controller, -- System.Finalization_Implementation + RE_Limited_Record_Controller, -- System.Finalization_Implementation + RE_Deep_Tag_Initialize, -- System.Finalization_Implementation + RE_Deep_Tag_Adjust, -- System.Finalization_Implementation + RE_Deep_Tag_Finalize, -- System.Finalization_Implementation + RE_Deep_Tag_Attach, -- System.Finalization_Implementation + RE_Deep_Rec_Initialize, -- System.Finalization_Implementation + RE_Deep_Rec_Adjust, -- System.Finalization_Implementation + RE_Deep_Rec_Finalize, -- System.Finalization_Implementation + + RE_Root_Controlled, -- System.Finalization_Root + RE_Finalizable, -- System.Finalization_Root + RE_Finalizable_Ptr, -- System.Finalization_Root + + RE_Fore, -- System.Fore + + RE_Image_Boolean, -- System.Img_Bool + + RE_Image_Character, -- System.Img_Char + + RE_Image_Decimal, -- System.Img_Dec + + RE_Image_Enumeration_8, -- System.Img_Enum + RE_Image_Enumeration_16, -- System.Img_Enum + RE_Image_Enumeration_32, -- System.Img_Enum + + RE_Image_Integer, -- System.Img_Int + + RE_Image_Long_Long_Decimal, -- System.Img_LLD + + RE_Image_Long_Long_Integer, -- System.Img_LLI + + RE_Image_Long_Long_Unsigned, -- System.Img_LLU + + RE_Image_Ordinary_Fixed_Point, -- System.Img_Real + RE_Image_Floating_Point, -- System.Img_Real + + RE_Image_Unsigned, -- System.Img_Uns + + RE_Image_Wide_Character, -- System.Img_WChar + + RE_Bind_Interrupt_To_Entry, -- System.Interrupts + RE_Default_Interrupt_Priority, -- System.Interrupts + RE_Dynamic_Interrupt_Protection, -- System.Interrupts + RE_Install_Handlers, -- System.Interrupts + RE_Register_Interrupt_Handler, -- System.Interrupts + RE_Static_Interrupt_Protection, -- System.Interrupts + + RE_Asm_Insn, -- System.Machine_Code + RE_Asm_Input_Operand, -- System.Machine_Code + RE_Asm_Output_Operand, -- System.Machine_Code + + RE_Mantissa_Value, -- System_Mantissa + + RE_Bits_03, -- System.Pack_03 + RE_Get_03, -- System.Pack_03 + RE_Set_03, -- System.Pack_03 + + RE_Bits_05, -- System.Pack_05 + RE_Get_05, -- System.Pack_05 + RE_Set_05, -- System.Pack_05 + + RE_Bits_06, -- System.Pack_06 + RE_Get_06, -- System.Pack_06 + RE_GetU_06, -- System.Pack_06 + RE_Set_06, -- System.Pack_06 + RE_SetU_06, -- System.Pack_06 + + RE_Bits_07, -- System.Pack_07 + RE_Get_07, -- System.Pack_07 + RE_Set_07, -- System.Pack_07 + + RE_Bits_09, -- System.Pack_09 + RE_Get_09, -- System.Pack_09 + RE_Set_09, -- System.Pack_09 + + RE_Bits_10, -- System.Pack_10 + RE_Get_10, -- System.Pack_10 + RE_GetU_10, -- System.Pack_10 + RE_Set_10, -- System.Pack_10 + RE_SetU_10, -- System.Pack_10 + + RE_Bits_11, -- System.Pack_11 + RE_Get_11, -- System.Pack_11 + RE_Set_11, -- System.Pack_11 + + RE_Bits_12, -- System.Pack_12 + RE_Get_12, -- System.Pack_12 + RE_GetU_12, -- System.Pack_12 + RE_Set_12, -- System.Pack_12 + RE_SetU_12, -- System.Pack_12 + + RE_Bits_13, -- System.Pack_13 + RE_Get_13, -- System.Pack_13 + RE_Set_13, -- System.Pack_13 + + RE_Bits_14, -- System.Pack_14 + RE_Get_14, -- System.Pack_14 + RE_GetU_14, -- System.Pack_14 + RE_Set_14, -- System.Pack_14 + RE_SetU_14, -- System.Pack_14 + + RE_Bits_15, -- System.Pack_15 + RE_Get_15, -- System.Pack_15 + RE_Set_15, -- System.Pack_15 + + RE_Bits_17, -- System.Pack_17 + RE_Get_17, -- System.Pack_17 + RE_Set_17, -- System.Pack_17 + + RE_Bits_18, -- System.Pack_18 + RE_Get_18, -- System.Pack_18 + RE_GetU_18, -- System.Pack_18 + RE_Set_18, -- System.Pack_18 + RE_SetU_18, -- System.Pack_18 + + RE_Bits_19, -- System.Pack_19 + RE_Get_19, -- System.Pack_19 + RE_Set_19, -- System.Pack_19 + + RE_Bits_20, -- System.Pack_20 + RE_Get_20, -- System.Pack_20 + RE_GetU_20, -- System.Pack_20 + RE_Set_20, -- System.Pack_20 + RE_SetU_20, -- System.Pack_20 + + RE_Bits_21, -- System.Pack_21 + RE_Get_21, -- System.Pack_21 + RE_Set_21, -- System.Pack_21 + + RE_Bits_22, -- System.Pack_22 + RE_Get_22, -- System.Pack_22 + RE_GetU_22, -- System.Pack_22 + RE_Set_22, -- System.Pack_22 + RE_SetU_22, -- System.Pack_22 + + RE_Bits_23, -- System.Pack_23 + RE_Get_23, -- System.Pack_23 + RE_Set_23, -- System.Pack_23 + + RE_Bits_24, -- System.Pack_24 + RE_Get_24, -- System.Pack_24 + RE_GetU_24, -- System.Pack_24 + RE_Set_24, -- System.Pack_24 + RE_SetU_24, -- System.Pack_24 + + RE_Bits_25, -- System.Pack_25 + RE_Get_25, -- System.Pack_25 + RE_Set_25, -- System.Pack_25 + + RE_Bits_26, -- System.Pack_26 + RE_Get_26, -- System.Pack_26 + RE_GetU_26, -- System.Pack_26 + RE_Set_26, -- System.Pack_26 + RE_SetU_26, -- System.Pack_26 + + RE_Bits_27, -- System.Pack_27 + RE_Get_27, -- System.Pack_27 + RE_Set_27, -- System.Pack_27 + + RE_Bits_28, -- System.Pack_28 + RE_Get_28, -- System.Pack_28 + RE_GetU_28, -- System.Pack_28 + RE_Set_28, -- System.Pack_28 + RE_SetU_28, -- System.Pack_28 + + RE_Bits_29, -- System.Pack_29 + RE_Get_29, -- System.Pack_29 + RE_Set_29, -- System.Pack_29 + + RE_Bits_30, -- System.Pack_30 + RE_Get_30, -- System.Pack_30 + RE_GetU_30, -- System.Pack_30 + RE_Set_30, -- System.Pack_30 + RE_SetU_30, -- System.Pack_30 + + RE_Bits_31, -- System.Pack_31 + RE_Get_31, -- System.Pack_31 + RE_Set_31, -- System.Pack_31 + + RE_Bits_33, -- System.Pack_33 + RE_Get_33, -- System.Pack_33 + RE_Set_33, -- System.Pack_33 + + RE_Bits_34, -- System.Pack_34 + RE_Get_34, -- System.Pack_34 + RE_GetU_34, -- System.Pack_34 + RE_Set_34, -- System.Pack_34 + RE_SetU_34, -- System.Pack_34 + + RE_Bits_35, -- System.Pack_35 + RE_Get_35, -- System.Pack_35 + RE_Set_35, -- System.Pack_35 + + RE_Bits_36, -- System.Pack_36 + RE_Get_36, -- System.Pack_36 + RE_GetU_36, -- System.Pack_36 + RE_Set_36, -- System.Pack_36 + RE_SetU_36, -- System.Pack_36 + + RE_Bits_37, -- System.Pack_37 + RE_Get_37, -- System.Pack_37 + RE_Set_37, -- System.Pack_37 + + RE_Bits_38, -- System.Pack_38 + RE_Get_38, -- System.Pack_38 + RE_GetU_38, -- System.Pack_38 + RE_Set_38, -- System.Pack_38 + RE_SetU_38, -- System.Pack_38 + + RE_Bits_39, -- System.Pack_39 + RE_Get_39, -- System.Pack_39 + RE_Set_39, -- System.Pack_39 + + RE_Bits_40, -- System.Pack_40 + RE_Get_40, -- System.Pack_40 + RE_GetU_40, -- System.Pack_40 + RE_Set_40, -- System.Pack_40 + RE_SetU_40, -- System.Pack_40 + + RE_Bits_41, -- System.Pack_41 + RE_Get_41, -- System.Pack_41 + RE_Set_41, -- System.Pack_41 + + RE_Bits_42, -- System.Pack_42 + RE_Get_42, -- System.Pack_42 + RE_GetU_42, -- System.Pack_42 + RE_Set_42, -- System.Pack_42 + RE_SetU_42, -- System.Pack_42 + + RE_Bits_43, -- System.Pack_43 + RE_Get_43, -- System.Pack_43 + RE_Set_43, -- System.Pack_43 + + RE_Bits_44, -- System.Pack_44 + RE_Get_44, -- System.Pack_44 + RE_GetU_44, -- System.Pack_44 + RE_Set_44, -- System.Pack_44 + RE_SetU_44, -- System.Pack_44 + + RE_Bits_45, -- System.Pack_45 + RE_Get_45, -- System.Pack_45 + RE_Set_45, -- System.Pack_45 + + RE_Bits_46, -- System.Pack_46 + RE_Get_46, -- System.Pack_46 + RE_GetU_46, -- System.Pack_46 + RE_Set_46, -- System.Pack_46 + RE_SetU_46, -- System.Pack_46 + + RE_Bits_47, -- System.Pack_47 + RE_Get_47, -- System.Pack_47 + RE_Set_47, -- System.Pack_47 + + RE_Bits_48, -- System.Pack_48 + RE_Get_48, -- System.Pack_48 + RE_GetU_48, -- System.Pack_48 + RE_Set_48, -- System.Pack_48 + RE_SetU_48, -- System.Pack_48 + + RE_Bits_49, -- System.Pack_49 + RE_Get_49, -- System.Pack_49 + RE_Set_49, -- System.Pack_49 + + RE_Bits_50, -- System.Pack_50 + RE_Get_50, -- System.Pack_50 + RE_GetU_50, -- System.Pack_50 + RE_Set_50, -- System.Pack_50 + RE_SetU_50, -- System.Pack_50 + + RE_Bits_51, -- System.Pack_51 + RE_Get_51, -- System.Pack_51 + RE_Set_51, -- System.Pack_51 + + RE_Bits_52, -- System.Pack_52 + RE_Get_52, -- System.Pack_52 + RE_GetU_52, -- System.Pack_52 + RE_Set_52, -- System.Pack_52 + RE_SetU_52, -- System.Pack_52 + + RE_Bits_53, -- System.Pack_53 + RE_Get_53, -- System.Pack_53 + RE_Set_53, -- System.Pack_53 + + RE_Bits_54, -- System.Pack_54 + RE_Get_54, -- System.Pack_54 + RE_GetU_54, -- System.Pack_54 + RE_Set_54, -- System.Pack_54 + RE_SetU_54, -- System.Pack_54 + + RE_Bits_55, -- System.Pack_55 + RE_Get_55, -- System.Pack_55 + RE_Set_55, -- System.Pack_55 + + RE_Bits_56, -- System.Pack_56 + RE_Get_56, -- System.Pack_56 + RE_GetU_56, -- System.Pack_56 + RE_Set_56, -- System.Pack_56 + RE_SetU_56, -- System.Pack_56 + + RE_Bits_57, -- System.Pack_57 + RE_Get_57, -- System.Pack_57 + RE_Set_57, -- System.Pack_57 + + RE_Bits_58, -- System.Pack_58 + RE_Get_58, -- System.Pack_58 + RE_GetU_58, -- System.Pack_58 + RE_Set_58, -- System.Pack_58 + RE_SetU_58, -- System.Pack_58 + + RE_Bits_59, -- System.Pack_59 + RE_Get_59, -- System.Pack_59 + RE_Set_59, -- System.Pack_59 + + RE_Bits_60, -- System.Pack_60 + RE_Get_60, -- System.Pack_60 + RE_GetU_60, -- System.Pack_60 + RE_Set_60, -- System.Pack_60 + RE_SetU_60, -- System.Pack_60 + + RE_Bits_61, -- System.Pack_61 + RE_Get_61, -- System.Pack_61 + RE_Set_61, -- System.Pack_61 + + RE_Bits_62, -- System.Pack_62 + RE_Get_62, -- System.Pack_62 + RE_GetU_62, -- System.Pack_62 + RE_Set_62, -- System.Pack_62 + RE_SetU_62, -- System.Pack_62 + + RE_Bits_63, -- System.Pack_63 + RE_Get_63, -- System.Pack_63 + RE_Set_63, -- System.Pack_63 + + RE_Adjust_Storage_Size, -- System_Parameters + RE_Default_Stack_Size, -- System.Parameters + RE_Garbage_Collected, -- System.Parameters + RE_Size_Type, -- System.Parameters + RE_Unspecified_Size, -- System.Parameters + + RE_Get_Active_Partition_Id, -- System.Partition_Interface + RE_Get_Passive_Partition_Id, -- System.Partition_Interface + RE_Get_Local_Partition_Id, -- System.Partition_Interface + RE_Get_RCI_Package_Receiver, -- System.Partition_Interface + RE_Get_Unique_Remote_Pointer, -- System.Partition_Interface + RE_RACW_Stub_Type, -- System.Partition_Interface + RE_RACW_Stub_Type_Access, -- System.Partition_Interface + RE_Raise_Program_Error_For_E_4_18, -- System.Partition_Interface + RE_Raise_Program_Error_Unknown_Tag, -- System.Partition_Interface + RE_Register_Passive_Package, -- System.Partition_Interface + RE_Register_Receiving_Stub, -- System.Partition_Interface + RE_RCI_Info, -- System.Partition_Interface + RE_Subprogram_Id, -- System.Partition_Interface + + RE_Global_Pool_Object, -- System.Pool_Global + + RE_Unbounded_Reclaim_Pool, -- System.Pool_Local + + RE_Stack_Bounded_Pool, -- System.Pool_Size + + RE_Do_Apc, -- System.RPC + RE_Do_Rpc, -- System.RPC + RE_Params_Stream_Type, -- System.RPC + RE_Partition_ID, -- System.RPC + RE_RPC_Receiver, -- System.RPC + + RE_IS_Is1, -- System.Scalar_Values + RE_IS_Is2, -- System.Scalar_Values + RE_IS_Is4, -- System.Scalar_Values + RE_IS_Is8, -- System.Scalar_Values + RE_IS_Iu1, -- System.Scalar_Values + RE_IS_Iu2, -- System.Scalar_Values + RE_IS_Iu4, -- System.Scalar_Values + RE_IS_Iu8, -- System.Scalar_Values + RE_IS_Isf, -- System.Scalar_Values + RE_IS_Ifl, -- System.Scalar_Values + RE_IS_Ilf, -- System.Scalar_Values + RE_IS_Ill, -- System.Scalar_Values + + RE_Mark_Id, -- System.Secondary_Stack + RE_SS_Allocate, -- System.Secondary_Stack + RE_SS_Pool, -- System.Secondary_Stack + RE_SS_Mark, -- System.Secondary_Stack + RE_SS_Release, -- System.Secondary_Stack + + RE_Shared_Var_Close, -- System.Shared_Storage + RE_Shared_Var_Lock, -- System.Shared_Storage + RE_Shared_Var_ROpen, -- System.Shared_Storage + RE_Shared_Var_Unlock, -- System.Shared_Storage + RE_Shared_Var_WOpen, -- System.Shared_Storage + + RE_Abort_Undefer_Direct, -- System.Standard_Library + RE_Exception_Data, -- System.Standard_Library + RE_Exception_Data_Ptr, -- System.Standard_Library + + RE_Integer_Address, -- System.Storage_Elements + RE_Storage_Offset, -- System.Storage_Elements + RE_Storage_Array, -- System.Storage_Elements + RE_To_Address, -- System.Storage_Elements + + RE_Root_Storage_Pool, -- System.Storage_Pools + + RE_Thin_Pointer, -- System.Stream_Attributes + RE_Fat_Pointer, -- System.Stream_Attributes + + RE_I_AD, -- System.Stream_Attributes + RE_I_AS, -- System.Stream_Attributes + RE_I_B, -- System.Stream_Attributes + RE_I_C, -- System.Stream_Attributes + RE_I_F, -- System.Stream_Attributes + RE_I_I, -- System.Stream_Attributes + RE_I_LF, -- System.Stream_Attributes + RE_I_LI, -- System.Stream_Attributes + RE_I_LLF, -- System.Stream_Attributes + RE_I_LLI, -- System.Stream_Attributes + RE_I_LLU, -- System.Stream_Attributes + RE_I_LU, -- System.Stream_Attributes + RE_I_SF, -- System.Stream_Attributes + RE_I_SI, -- System.Stream_Attributes + RE_I_SSI, -- System.Stream_Attributes + RE_I_SSU, -- System.Stream_Attributes + RE_I_SU, -- System.Stream_Attributes + RE_I_U, -- System.Stream_Attributes + RE_I_WC, -- System.Stream_Attributes + + RE_W_AD, -- System.Stream_Attributes + RE_W_AS, -- System.Stream_Attributes + RE_W_B, -- System.Stream_Attributes + RE_W_C, -- System.Stream_Attributes + RE_W_F, -- System.Stream_Attributes + RE_W_I, -- System.Stream_Attributes + RE_W_LF, -- System.Stream_Attributes + RE_W_LI, -- System.Stream_Attributes + RE_W_LLF, -- System.Stream_Attributes + RE_W_LLI, -- System.Stream_Attributes + RE_W_LLU, -- System.Stream_Attributes + RE_W_LU, -- System.Stream_Attributes + RE_W_SF, -- System.Stream_Attributes + RE_W_SI, -- System.Stream_Attributes + RE_W_SSI, -- System.Stream_Attributes + RE_W_SSU, -- System.Stream_Attributes + RE_W_SU, -- System.Stream_Attributes + RE_W_U, -- System.Stream_Attributes + RE_W_WC, -- System.Stream_Attributes + + RE_Str_Concat, -- System.String_Ops + RE_Str_Concat_CC, -- System.String_Ops + RE_Str_Concat_CS, -- System.String_Ops + RE_Str_Concat_SC, -- System.String_Ops + RE_Str_Equal, -- System.String_Ops + RE_Str_Normalize, -- System.String_Ops + RE_Wide_Str_Normalize, -- System.String_Ops + + RE_Str_Concat_3, -- System.String_Ops_Concat_3 + + RE_Str_Concat_4, -- System.String_Ops_Concat_4 + + RE_Str_Concat_5, -- System.String_Ops_Concat_5 + + RE_Free_Task_Image, -- System.Task_Info + RE_Task_Info_Type, -- System.Task_Info + RE_Task_Image_Type, -- System_Task_Info + RE_Unspecified_Task_Info, -- System.Task_Info + + RE_Library_Task_Level, -- System.Tasking + + RE_Task_Procedure_Access, -- System.Tasking + + RO_ST_Task_ID, -- System.Tasking + + RE_Call_Modes, -- System.Tasking + RE_Simple_Call, -- System.Tasking + RE_Conditional_Call, -- System.Tasking + RE_Asynchronous_Call, -- System.Tasking + RE_Timed_Call, -- System.Tasking + + RE_Task_List, -- System.Tasking + + RE_Accept_Alternative, -- System.Tasking + RE_Accept_List, -- System.Tasking + RE_Accept_List_Access, -- System.Tasking + RE_Max_Select, -- System.Tasking + RE_Max_Task_Entry, -- System.Tasking + RE_No_Rendezvous, -- System.Tasking + RE_Null_Task_Entry, -- System.Tasking + RE_Positive_Select_Index, -- System.Tasking + RE_Select_Index, -- System.Tasking + RE_Select_Modes, -- System.Tasking + RE_Else_Mode, -- System.Tasking + RE_Simple_Mode, -- System.Tasking + RE_Terminate_Mode, -- System.Tasking + RE_Delay_Mode, -- System.Tasking + RE_Task_Entry_Index, -- System.Tasking + RE_Self, -- System.Tasking + + RE_Master_Id, -- System.Tasking + RE_Unspecified_Priority, -- System.Tasking + + RE_Activation_Chain, -- System.Tasking + + RE_Abort_Defer, -- System.Soft_Links + RE_Abort_Undefer, -- System.Soft_Links + RE_Complete_Master, -- System.Soft_Links + RE_Current_Master, -- System.Soft_Links + RE_Enter_Master, -- System.Soft_Links + RE_Get_Current_Excep, -- System.Soft_Links + RE_Get_GNAT_Exception, -- System.Soft_Links + RE_Update_Exception, -- System.Soft_Links + + RE_Bits_1, -- System.Unsigned_Types + RE_Bits_2, -- System.Unsigned_Types + RE_Bits_4, -- System.Unsigned_Types + RE_Float_Unsigned, -- System.Unsigned_Types + RE_Long_Long_Unsigned, -- System.Unsigned_Types + RE_Packed_Byte, -- System.Unsigned_Types + RE_Packed_Bytes1, -- System.Unsigned_Types + RE_Packed_Bytes2, -- System.Unsigned_Types + RE_Packed_Bytes4, -- System.Unsigned_Types + RE_Unsigned, -- System.Unsigned_Types + + RE_Value_Boolean, -- System.Val_Bool + + RE_Value_Character, -- System.Val_Char + + RE_Value_Decimal, -- System.Val_Dec + + RE_Value_Enumeration_8, -- System.Val_Enum + RE_Value_Enumeration_16, -- System.Val_Enum + RE_Value_Enumeration_32, -- System.Val_Enum + + RE_Value_Integer, -- System.Val_Int + + RE_Value_Long_Long_Decimal, -- System.Val_LLD + + RE_Value_Long_Long_Integer, -- System.Val_LLI + + RE_Value_Long_Long_Unsigned, -- System.Val_LLU + + RE_Value_Real, -- System.Val_Real + + RE_Value_Unsigned, -- System.Val_Uns + + RE_Value_Wide_Character, -- System.Val_WChar + + RE_D, -- System.Vax_Float_Operations + RE_F, -- System.Vax_Float_Operations + RE_G, -- System.Vax_Float_Operations + RE_Q, -- System.Vax_Float_Operations + RE_S, -- System.Vax_Float_Operations + RE_T, -- System.Vax_Float_Operations + + RE_D_To_G, -- System.Vax_Float_Operations + RE_F_To_G, -- System.Vax_Float_Operations + RE_F_To_Q, -- System.Vax_Float_Operations + RE_F_To_S, -- System.Vax_Float_Operations + RE_G_To_D, -- System.Vax_Float_Operations + RE_G_To_F, -- System.Vax_Float_Operations + RE_G_To_Q, -- System.Vax_Float_Operations + RE_G_To_T, -- System.Vax_Float_Operations + RE_Q_To_F, -- System.Vax_Float_Operations + RE_Q_To_G, -- System.Vax_Float_Operations + RE_S_To_F, -- System.Vax_Float_Operations + RE_T_To_D, -- System.Vax_Float_Operations + RE_T_To_G, -- System.Vax_Float_Operations + + RE_Abs_F, -- System.Vax_Float_Operations + RE_Abs_G, -- System.Vax_Float_Operations + RE_Add_F, -- System.Vax_Float_Operations + RE_Add_G, -- System.Vax_Float_Operations + RE_Div_F, -- System.Vax_Float_Operations + RE_Div_G, -- System.Vax_Float_Operations + RE_Mul_F, -- System.Vax_Float_Operations + RE_Mul_G, -- System.Vax_Float_Operations + RE_Neg_F, -- System.Vax_Float_Operations + RE_Neg_G, -- System.Vax_Float_Operations + RE_Sub_F, -- System.Vax_Float_Operations + RE_Sub_G, -- System.Vax_Float_Operations + + RE_Eq_F, -- System.Vax_Float_Operations + RE_Eq_G, -- System.Vax_Float_Operations + RE_Le_F, -- System.Vax_Float_Operations + RE_Le_G, -- System.Vax_Float_Operations + RE_Lt_F, -- System.Vax_Float_Operations + RE_Lt_G, -- System.Vax_Float_Operations + + RE_Version_String, -- System.Version_Control + RE_Get_Version_String, -- System.Version_Control + + RE_Register_VMS_Exception, -- System.VMS_Exception_Table + + RE_String_To_Wide_String, -- System.WCh_StW + + RE_Wide_String_To_String, -- System.WCh_WtS + + RE_Wide_Width_Character, -- System.WWd_Char + + RE_Wide_Width_Enumeration_8, -- System.WWd_Enum + RE_Wide_Width_Enumeration_16, -- System.WWd_Enum + RE_Wide_Width_Enumeration_32, -- System.WWd_Enum + + RE_Wide_Width_Wide_Character, -- System.WWd_Wchar + + RE_Width_Boolean, -- System.Wid_Bool + + RE_Width_Character, -- System.Wid_Char + + RE_Width_Enumeration_8, -- System.Wid_Enum + RE_Width_Enumeration_16, -- System.Wid_Enum + RE_Width_Enumeration_32, -- System.Wid_Enum + + RE_Width_Long_Long_Integer, -- System.Wid_LLI + + RE_Width_Long_Long_Unsigned, -- System.Wid_LLU + + RE_Width_Wide_Character, -- System.Wid_WChar + + RE_Protected_Entry_Body_Array, -- Tasking.Protected_Objects.Entries + RE_Protection_Entries, -- Tasking.Protected_Objects.Entries + RE_Initialize_Protection_Entries, -- Tasking.Protected_Objects.Entries + RE_Lock_Entries, -- Tasking.Protected_Objects.Entries + RE_Lock_Read_Only_Entries, -- Tasking.Protected_Objects.Entries + RE_Unlock_Entries, -- Tasking.Protected_Objects.Entries + RE_Communication_Block, -- Protected_Objects.Operations + RE_Protected_Entry_Call, -- Protected_Objects.Operations + RE_Service_Entries, -- Protected_Objects.Operations + RE_Cancel_Protected_Entry_Call, -- Protected_Objects.Operations + RE_Enqueued, -- Protected_Objects.Operations + RE_Cancelled, -- Protected_Objects.Operations + RE_Complete_Entry_Body, -- Protected_Objects.Operations + RE_Exceptional_Complete_Entry_Body, -- Protected_Objects.Operations + RE_Requeue_Protected_Entry, -- Protected_Objects.Operations + RE_Requeue_Task_To_Protected_Entry, -- Protected_Objects.Operations + RE_Protected_Count, -- Protected_Objects.Operations + RE_Protected_Entry_Caller, -- Protected_Objects.Operations + RE_Timed_Protected_Entry_Call, -- Protected_Objects.Operations + + RE_Protection_Entry, -- Protected_Objects.Single_Entry + RE_Initialize_Protection_Entry, -- Protected_Objects.Single_Entry + RE_Lock_Entry, -- Protected_Objects.Single_Entry + RE_Lock_Read_Only_Entry, -- Protected_Objects.Single_Entry + RE_Unlock_Entry, -- Protected_Objects.Single_Entry + RE_Protected_Single_Entry_Call, -- Protected_Objects.Single_Entry + RE_Service_Entry, -- Protected_Objects.Single_Entry + RE_Complete_Single_Entry_Body, -- Protected_Objects.Single_Entry + RE_Exceptional_Complete_Single_Entry_Body, + RE_Protected_Count_Entry, -- Protected_Objects.Single_Entry + RE_Protected_Single_Entry_Caller, -- Protected_Objects.Single_Entry + RE_Timed_Protected_Single_Entry_Call, + + RE_Protected_Entry_Index, -- System.Tasking.Protected_Objects + RE_Entry_Body, -- System.Tasking.Protected_Objects + RE_Protection, -- System.Tasking.Protected_Objects + RE_Initialize_Protection, -- System.Tasking.Protected_Objects + RE_Finalize_Protection, -- System.Tasking.Protected_Objects + RE_Lock, -- System.Tasking.Protected_Objects + RE_Lock_Read_Only, -- System.Tasking.Protected_Objects + RE_Unlock, -- System.Tasking.Protected_Objects + + RE_Delay_Block, -- System.Tasking.Async_Delays + RE_Timed_Out, -- System.Tasking.Async_Delays + RE_Cancel_Async_Delay, -- System.Tasking.Async_Delays + RE_Enqueue_Duration, -- System.Tasking.Async_Delays + RE_Enqueue_Calendar, -- System.Tasking.Async_Delays + RE_Enqueue_RT, -- System.Tasking.Async_Delays + + RE_Accept_Call, -- System.Tasking.Rendezvous + RE_Accept_Trivial, -- System.Tasking.Rendezvous + RE_Callable, -- System.Tasking.Rendezvous + RE_Call_Simple, -- System.Tasking.Rendezvous + RE_Requeue_Task_Entry, -- System.Tasking.Rendezvous + RE_Requeue_Protected_To_Task_Entry, -- System.Tasking.Rendezvous + RE_Cancel_Task_Entry_Call, -- System.Tasking.Rendezvous + RE_Complete_Rendezvous, -- System.Tasking.Rendezvous + RE_Task_Count, -- System.Tasking.Rendezvous + RE_Exceptional_Complete_Rendezvous, -- System.Tasking.Rendezvous + RE_Selective_Wait, -- System.Tasking.Rendezvous + RE_Task_Entry_Call, -- System.Tasking.Rendezvous + RE_Task_Entry_Caller, -- System.Tasking.Rendezvous + RE_Timed_Task_Entry_Call, -- System.Tasking.Rendezvous + RE_Timed_Selective_Wait, -- System.Tasking.Rendezvous + + RE_Activate_Restricted_Tasks, -- System.Tasking.Restricted.Stages + RE_Complete_Restricted_Activation, -- System.Tasking.Restricted.Stages + RE_Create_Restricted_Task, -- System.Tasking.Restricted.Stages + RE_Complete_Restricted_Task, -- System.Tasking.Restricted.Stages + RE_Restricted_Terminated, -- System.Tasking.Restricted.Stages + + RE_Abort_Tasks, -- System.Tasking.Stages + RE_Activate_Tasks, -- System.Tasking.Stages + RE_Complete_Activation, -- System.Tasking.Stages + RE_Create_Task, -- System.Tasking.Stages + RE_Complete_Task, -- System.Tasking.Stages + RE_Free_Task, -- System.Tasking.Stages + RE_Expunge_Unactivated_Tasks, -- System.Tasking.Stages + RE_Terminated); -- System.Tasking.Stages + + -- The following declarations build a table that is indexed by the + -- RTE function to determine the unit containing the given entity. + -- This table is sorted in order of package names. + + RE_Unit_Table : array (RE_Id) of RTU_Id := ( + + RE_Null => RTU_Null, + + RE_Code_Loc => Ada_Exceptions, + RE_Current_Target_Exception => Ada_Exceptions, -- of JGNAT + RE_Exception_Id => Ada_Exceptions, + RE_Exception_Information => Ada_Exceptions, + RE_Exception_Message => Ada_Exceptions, + RE_Exception_Name_Simple => Ada_Exceptions, + RE_Exception_Occurrence => Ada_Exceptions, + RE_Null_Id => Ada_Exceptions, + RE_Null_Occurrence => Ada_Exceptions, + RE_Poll => Ada_Exceptions, + RE_Raise_Exception => Ada_Exceptions, + RE_Raise_Exception_Always => Ada_Exceptions, + RE_Reraise_Occurrence => Ada_Exceptions, + RE_Reraise_Occurrence_Always => Ada_Exceptions, + RE_Reraise_Occurrence_No_Defer => Ada_Exceptions, + RE_Save_Occurrence => Ada_Exceptions, + + RE_Simple_List_Controller => Ada_Finalization_List_Controller, + RE_List_Controller => Ada_Finalization_List_Controller, + + RE_Interrupt_Id => Ada_Interrupts, + + RE_Root_Stream_Type => Ada_Streams, + RE_Stream_Element => Ada_Streams, + RE_Stream_Element_Offset => Ada_Streams, + RE_Stream_Element_Array => Ada_Streams, + + RE_Stream_Access => Ada_Streams_Stream_IO, + + RE_CW_Membership => Ada_Tags, + RE_DT_Entry_Size => Ada_Tags, + RE_DT_Prologue_Size => Ada_Tags, + RE_External_Tag => Ada_Tags, + RE_Get_Expanded_Name => Ada_Tags, + RE_Get_External_Tag => Ada_Tags, + RE_Get_Prim_Op_Address => Ada_Tags, + RE_Get_RC_Offset => Ada_Tags, + RE_Get_Remotely_Callable => Ada_Tags, + RE_Get_TSD => Ada_Tags, + RE_Inherit_DT => Ada_Tags, + RE_Inherit_TSD => Ada_Tags, + RE_Internal_Tag => Ada_Tags, + RE_Register_Tag => Ada_Tags, + RE_Set_Expanded_Name => Ada_Tags, + RE_Set_External_Tag => Ada_Tags, + RE_Set_Prim_Op_Address => Ada_Tags, + RE_Set_RC_Offset => Ada_Tags, + RE_Set_Remotely_Callable => Ada_Tags, + RE_Set_TSD => Ada_Tags, + RE_Tag_Error => Ada_Tags, + RE_TSD_Entry_Size => Ada_Tags, + RE_TSD_Prologue_Size => Ada_Tags, + RE_Tag => Ada_Tags, + RE_Address_Array => Ada_Tags, + + RE_Current_Task => Ada_Task_Identification, + RO_AT_Task_ID => Ada_Task_Identification, + + RO_CA_Time => Ada_Calendar, + RO_CA_Delay_For => Ada_Calendar_Delays, + RO_CA_Delay_Until => Ada_Calendar_Delays, + RO_CA_To_Duration => Ada_Calendar_Delays, + + RO_RT_Time => Ada_Real_Time, + RO_RT_Delay_Until => Ada_Real_Time_Delays, + RO_RT_To_Duration => Ada_Real_Time_Delays, + + RE_Integer_64 => Interfaces, + RE_Unsigned_8 => Interfaces, + RE_Unsigned_16 => Interfaces, + RE_Unsigned_32 => Interfaces, + RE_Unsigned_64 => Interfaces, + + RE_Vtable_Ptr => Interfaces_CPP, + RE_Displaced_This => Interfaces_CPP, + RE_CPP_CW_Membership => Interfaces_CPP, + RE_CPP_DT_Entry_Size => Interfaces_CPP, + RE_CPP_DT_Prologue_Size => Interfaces_CPP, + RE_CPP_Get_Expanded_Name => Interfaces_CPP, + RE_CPP_Get_External_Tag => Interfaces_CPP, + RE_CPP_Get_Prim_Op_Address => Interfaces_CPP, + RE_CPP_Get_RC_Offset => Interfaces_CPP, + RE_CPP_Get_Remotely_Callable => Interfaces_CPP, + RE_CPP_Get_TSD => Interfaces_CPP, + RE_CPP_Inherit_DT => Interfaces_CPP, + RE_CPP_Inherit_TSD => Interfaces_CPP, + RE_CPP_Register_Tag => Interfaces_CPP, + RE_CPP_Set_Expanded_Name => Interfaces_CPP, + RE_CPP_Set_External_Tag => Interfaces_CPP, + RE_CPP_Set_Prim_Op_Address => Interfaces_CPP, + RE_CPP_Set_RC_Offset => Interfaces_CPP, + RE_CPP_Set_Remotely_Callable => Interfaces_CPP, + RE_CPP_Set_TSD => Interfaces_CPP, + RE_CPP_TSD_Entry_Size => Interfaces_CPP, + RE_CPP_TSD_Prologue_Size => Interfaces_CPP, + + RE_Packed_Size => Interfaces_Packed_Decimal, + RE_Packed_To_Int32 => Interfaces_Packed_Decimal, + RE_Packed_To_Int64 => Interfaces_Packed_Decimal, + RE_Int32_To_Packed => Interfaces_Packed_Decimal, + RE_Int64_To_Packed => Interfaces_Packed_Decimal, + + RE_Address => System, + RE_Any_Priority => System, + RE_Bit_Order => System, + RE_Default_Priority => System, + RE_High_Order_First => System, + RE_Interrupt_Priority => System, + RE_Lib_Stop => System, + RE_Low_Order_First => System, + RE_Max_Interrupt_Priority => System, + RE_Max_Priority => System, + RE_Null_Address => System, + RE_Priority => System, + + RE_Add_With_Ovflo_Check => System_Arith_64, + RE_Double_Divide => System_Arith_64, + RE_Multiply_With_Ovflo_Check => System_Arith_64, + RE_Scaled_Divide => System_Arith_64, + RE_Subtract_With_Ovflo_Check => System_Arith_64, + + RE_Create_AST_Handler => System_AST_Handling, + + RE_Raise_Assert_Failure => System_Assertions, + + RE_AST_Handler => System_Aux_DEC, + RE_Import_Value => System_Aux_DEC, + RE_No_AST_Handler => System_Aux_DEC, + RE_Type_Class => System_Aux_DEC, + RE_Type_Class_Enumeration => System_Aux_DEC, + RE_Type_Class_Integer => System_Aux_DEC, + RE_Type_Class_Fixed_Point => System_Aux_DEC, + RE_Type_Class_Floating_Point => System_Aux_DEC, + RE_Type_Class_Array => System_Aux_DEC, + RE_Type_Class_Record => System_Aux_DEC, + RE_Type_Class_Access => System_Aux_DEC, + RE_Type_Class_Task => System_Aux_DEC, + RE_Type_Class_Address => System_Aux_DEC, + + RE_Bit_And => System_Bit_Ops, + RE_Bit_Eq => System_Bit_Ops, + RE_Bit_Not => System_Bit_Ops, + RE_Bit_Or => System_Bit_Ops, + RE_Bit_Xor => System_Bit_Ops, + + RE_Checked_Pool => System_Checked_Pools, + + RE_Register_Exception => System_Exception_Table, + + RE_All_Others_Id => System_Exceptions, + RE_Handler_Record => System_Exceptions, + RE_Handler_Record_Ptr => System_Exceptions, + RE_Others_Id => System_Exceptions, + RE_Subprogram_Descriptor => System_Exceptions, + RE_Subprogram_Descriptor_0 => System_Exceptions, + RE_Subprogram_Descriptor_1 => System_Exceptions, + RE_Subprogram_Descriptor_2 => System_Exceptions, + RE_Subprogram_Descriptor_3 => System_Exceptions, + RE_Subprogram_Descriptor_List => System_Exceptions, + RE_Subprogram_Descriptor_Ptr => System_Exceptions, + RE_Subprogram_Descriptors_Record => System_Exceptions, + RE_Subprogram_Descriptors_Ptr => System_Exceptions, + + RE_Exn_Float => System_Exn_Flt, + + RE_Exn_Integer => System_Exn_Int, + + RE_Exn_Long_Float => System_Exn_LFlt, + + RE_Exn_Long_Integer => System_Exn_LInt, + + RE_Exn_Long_Long_Float => System_Exn_LLF, + + RE_Exn_Long_Long_Integer => System_Exn_LLI, + + RE_Exn_Short_Float => System_Exn_SFlt, + + RE_Exn_Short_Integer => System_Exn_SInt, + + RE_Exn_Short_Short_Integer => System_Exn_SSI, + + RE_Exp_Float => System_Exp_Flt, + + RE_Exp_Integer => System_Exp_Int, + + RE_Exp_Long_Float => System_Exp_LFlt, + + RE_Exp_Long_Integer => System_Exp_LInt, + + RE_Exp_Long_Long_Float => System_Exp_LLF, + + RE_Exp_Long_Long_Integer => System_Exp_LLI, + + RE_Exp_Long_Long_Unsigned => System_Exp_LLU, + + RE_Exp_Modular => System_Exp_Mod, + + RE_Exp_Short_Float => System_Exp_SFlt, + + RE_Exp_Short_Integer => System_Exp_SInt, + + RE_Exp_Short_Short_Integer => System_Exp_SSI, + + RE_Exp_Unsigned => System_Exp_Uns, + + RE_Fat_Float => System_Fat_Flt, + + RE_Fat_Long_Float => System_Fat_LFlt, + + RE_Fat_Long_Long_Float => System_Fat_LLF, + + RE_Fat_Short_Float => System_Fat_SFlt, + + RE_Attach_To_Final_List => System_Finalization_Implementation, + RE_Finalize_List => System_Finalization_Implementation, + RE_Finalize_One => System_Finalization_Implementation, + RE_Global_Final_List => System_Finalization_Implementation, + RE_Record_Controller => System_Finalization_Implementation, + RE_Limited_Record_Controller => System_Finalization_Implementation, + RE_Deep_Tag_Initialize => System_Finalization_Implementation, + RE_Deep_Tag_Adjust => System_Finalization_Implementation, + RE_Deep_Tag_Finalize => System_Finalization_Implementation, + RE_Deep_Tag_Attach => System_Finalization_Implementation, + RE_Deep_Rec_Initialize => System_Finalization_Implementation, + RE_Deep_Rec_Adjust => System_Finalization_Implementation, + RE_Deep_Rec_Finalize => System_Finalization_Implementation, + + RE_Root_Controlled => System_Finalization_Root, + RE_Finalizable => System_Finalization_Root, + RE_Finalizable_Ptr => System_Finalization_Root, + + RE_Fore => System_Fore, + + RE_Image_Boolean => System_Img_Bool, + + RE_Image_Character => System_Img_Char, + + RE_Image_Decimal => System_Img_Dec, + + RE_Image_Enumeration_8 => System_Img_Enum, + RE_Image_Enumeration_16 => System_Img_Enum, + RE_Image_Enumeration_32 => System_Img_Enum, + + RE_Image_Integer => System_Img_Int, + + RE_Image_Long_Long_Decimal => System_Img_LLD, + + RE_Image_Long_Long_Integer => System_Img_LLI, + + RE_Image_Long_Long_Unsigned => System_Img_LLU, + + RE_Image_Ordinary_Fixed_Point => System_Img_Real, + RE_Image_Floating_Point => System_Img_Real, + + RE_Image_Unsigned => System_Img_Uns, + + RE_Image_Wide_Character => System_Img_WChar, + + RE_Bind_Interrupt_To_Entry => System_Interrupts, + RE_Default_Interrupt_Priority => System_Interrupts, + RE_Dynamic_Interrupt_Protection => System_Interrupts, + RE_Install_Handlers => System_Interrupts, + RE_Register_Interrupt_Handler => System_Interrupts, + RE_Static_Interrupt_Protection => System_Interrupts, + + RE_Asm_Insn => System_Machine_Code, + RE_Asm_Input_Operand => System_Machine_Code, + RE_Asm_Output_Operand => System_Machine_Code, + + RE_Mantissa_Value => System_Mantissa, + + RE_Bits_03 => System_Pack_03, + RE_Get_03 => System_Pack_03, + RE_Set_03 => System_Pack_03, + + RE_Bits_05 => System_Pack_05, + RE_Get_05 => System_Pack_05, + RE_Set_05 => System_Pack_05, + + RE_Bits_06 => System_Pack_06, + RE_Get_06 => System_Pack_06, + RE_GetU_06 => System_Pack_06, + RE_Set_06 => System_Pack_06, + RE_SetU_06 => System_Pack_06, + + RE_Bits_07 => System_Pack_07, + RE_Get_07 => System_Pack_07, + RE_Set_07 => System_Pack_07, + + RE_Bits_09 => System_Pack_09, + RE_Get_09 => System_Pack_09, + RE_Set_09 => System_Pack_09, + + RE_Bits_10 => System_Pack_10, + RE_Get_10 => System_Pack_10, + RE_GetU_10 => System_Pack_10, + RE_Set_10 => System_Pack_10, + RE_SetU_10 => System_Pack_10, + + RE_Bits_11 => System_Pack_11, + RE_Get_11 => System_Pack_11, + RE_Set_11 => System_Pack_11, + + RE_Bits_12 => System_Pack_12, + RE_Get_12 => System_Pack_12, + RE_GetU_12 => System_Pack_12, + RE_Set_12 => System_Pack_12, + RE_SetU_12 => System_Pack_12, + + RE_Bits_13 => System_Pack_13, + RE_Get_13 => System_Pack_13, + RE_Set_13 => System_Pack_13, + + RE_Bits_14 => System_Pack_14, + RE_Get_14 => System_Pack_14, + RE_GetU_14 => System_Pack_14, + RE_Set_14 => System_Pack_14, + RE_SetU_14 => System_Pack_14, + + RE_Bits_15 => System_Pack_15, + RE_Get_15 => System_Pack_15, + RE_Set_15 => System_Pack_15, + + RE_Bits_17 => System_Pack_17, + RE_Get_17 => System_Pack_17, + RE_Set_17 => System_Pack_17, + + RE_Bits_18 => System_Pack_18, + RE_Get_18 => System_Pack_18, + RE_GetU_18 => System_Pack_18, + RE_Set_18 => System_Pack_18, + RE_SetU_18 => System_Pack_18, + + RE_Bits_19 => System_Pack_19, + RE_Get_19 => System_Pack_19, + RE_Set_19 => System_Pack_19, + + RE_Bits_20 => System_Pack_20, + RE_Get_20 => System_Pack_20, + RE_GetU_20 => System_Pack_20, + RE_Set_20 => System_Pack_20, + RE_SetU_20 => System_Pack_20, + + RE_Bits_21 => System_Pack_21, + RE_Get_21 => System_Pack_21, + RE_Set_21 => System_Pack_21, + + RE_Bits_22 => System_Pack_22, + RE_Get_22 => System_Pack_22, + RE_GetU_22 => System_Pack_22, + RE_Set_22 => System_Pack_22, + RE_SetU_22 => System_Pack_22, + + RE_Bits_23 => System_Pack_23, + RE_Get_23 => System_Pack_23, + RE_Set_23 => System_Pack_23, + + RE_Bits_24 => System_Pack_24, + RE_Get_24 => System_Pack_24, + RE_GetU_24 => System_Pack_24, + RE_Set_24 => System_Pack_24, + RE_SetU_24 => System_Pack_24, + + RE_Bits_25 => System_Pack_25, + RE_Get_25 => System_Pack_25, + RE_Set_25 => System_Pack_25, + + RE_Bits_26 => System_Pack_26, + RE_Get_26 => System_Pack_26, + RE_GetU_26 => System_Pack_26, + RE_Set_26 => System_Pack_26, + RE_SetU_26 => System_Pack_26, + + RE_Bits_27 => System_Pack_27, + RE_Get_27 => System_Pack_27, + RE_Set_27 => System_Pack_27, + + RE_Bits_28 => System_Pack_28, + RE_Get_28 => System_Pack_28, + RE_GetU_28 => System_Pack_28, + RE_Set_28 => System_Pack_28, + RE_SetU_28 => System_Pack_28, + + RE_Bits_29 => System_Pack_29, + RE_Get_29 => System_Pack_29, + RE_Set_29 => System_Pack_29, + + RE_Bits_30 => System_Pack_30, + RE_Get_30 => System_Pack_30, + RE_GetU_30 => System_Pack_30, + RE_Set_30 => System_Pack_30, + RE_SetU_30 => System_Pack_30, + + RE_Bits_31 => System_Pack_31, + RE_Get_31 => System_Pack_31, + RE_Set_31 => System_Pack_31, + + RE_Bits_33 => System_Pack_33, + RE_Get_33 => System_Pack_33, + RE_Set_33 => System_Pack_33, + + RE_Bits_34 => System_Pack_34, + RE_Get_34 => System_Pack_34, + RE_GetU_34 => System_Pack_34, + RE_Set_34 => System_Pack_34, + RE_SetU_34 => System_Pack_34, + + RE_Bits_35 => System_Pack_35, + RE_Get_35 => System_Pack_35, + RE_Set_35 => System_Pack_35, + + RE_Bits_36 => System_Pack_36, + RE_Get_36 => System_Pack_36, + RE_GetU_36 => System_Pack_36, + RE_Set_36 => System_Pack_36, + RE_SetU_36 => System_Pack_36, + + RE_Bits_37 => System_Pack_37, + RE_Get_37 => System_Pack_37, + RE_Set_37 => System_Pack_37, + + RE_Bits_38 => System_Pack_38, + RE_Get_38 => System_Pack_38, + RE_GetU_38 => System_Pack_38, + RE_Set_38 => System_Pack_38, + RE_SetU_38 => System_Pack_38, + + RE_Bits_39 => System_Pack_39, + RE_Get_39 => System_Pack_39, + RE_Set_39 => System_Pack_39, + + RE_Bits_40 => System_Pack_40, + RE_Get_40 => System_Pack_40, + RE_GetU_40 => System_Pack_40, + RE_Set_40 => System_Pack_40, + RE_SetU_40 => System_Pack_40, + + RE_Bits_41 => System_Pack_41, + RE_Get_41 => System_Pack_41, + RE_Set_41 => System_Pack_41, + + RE_Bits_42 => System_Pack_42, + RE_Get_42 => System_Pack_42, + RE_GetU_42 => System_Pack_42, + RE_Set_42 => System_Pack_42, + RE_SetU_42 => System_Pack_42, + + RE_Bits_43 => System_Pack_43, + RE_Get_43 => System_Pack_43, + RE_Set_43 => System_Pack_43, + + RE_Bits_44 => System_Pack_44, + RE_Get_44 => System_Pack_44, + RE_GetU_44 => System_Pack_44, + RE_Set_44 => System_Pack_44, + RE_SetU_44 => System_Pack_44, + + RE_Bits_45 => System_Pack_45, + RE_Get_45 => System_Pack_45, + RE_Set_45 => System_Pack_45, + + RE_Bits_46 => System_Pack_46, + RE_Get_46 => System_Pack_46, + RE_GetU_46 => System_Pack_46, + RE_Set_46 => System_Pack_46, + RE_SetU_46 => System_Pack_46, + + RE_Bits_47 => System_Pack_47, + RE_Get_47 => System_Pack_47, + RE_Set_47 => System_Pack_47, + + RE_Bits_48 => System_Pack_48, + RE_Get_48 => System_Pack_48, + RE_GetU_48 => System_Pack_48, + RE_Set_48 => System_Pack_48, + RE_SetU_48 => System_Pack_48, + + RE_Bits_49 => System_Pack_49, + RE_Get_49 => System_Pack_49, + RE_Set_49 => System_Pack_49, + + RE_Bits_50 => System_Pack_50, + RE_Get_50 => System_Pack_50, + RE_GetU_50 => System_Pack_50, + RE_Set_50 => System_Pack_50, + RE_SetU_50 => System_Pack_50, + + RE_Bits_51 => System_Pack_51, + RE_Get_51 => System_Pack_51, + RE_Set_51 => System_Pack_51, + + RE_Bits_52 => System_Pack_52, + RE_Get_52 => System_Pack_52, + RE_GetU_52 => System_Pack_52, + RE_Set_52 => System_Pack_52, + RE_SetU_52 => System_Pack_52, + + RE_Bits_53 => System_Pack_53, + RE_Get_53 => System_Pack_53, + RE_Set_53 => System_Pack_53, + + RE_Bits_54 => System_Pack_54, + RE_Get_54 => System_Pack_54, + RE_GetU_54 => System_Pack_54, + RE_Set_54 => System_Pack_54, + RE_SetU_54 => System_Pack_54, + + RE_Bits_55 => System_Pack_55, + RE_Get_55 => System_Pack_55, + RE_Set_55 => System_Pack_55, + + RE_Bits_56 => System_Pack_56, + RE_Get_56 => System_Pack_56, + RE_GetU_56 => System_Pack_56, + RE_Set_56 => System_Pack_56, + RE_SetU_56 => System_Pack_56, + + RE_Bits_57 => System_Pack_57, + RE_Get_57 => System_Pack_57, + RE_Set_57 => System_Pack_57, + + RE_Bits_58 => System_Pack_58, + RE_Get_58 => System_Pack_58, + RE_GetU_58 => System_Pack_58, + RE_Set_58 => System_Pack_58, + RE_SetU_58 => System_Pack_58, + + RE_Bits_59 => System_Pack_59, + RE_Get_59 => System_Pack_59, + RE_Set_59 => System_Pack_59, + + RE_Bits_60 => System_Pack_60, + RE_Get_60 => System_Pack_60, + RE_GetU_60 => System_Pack_60, + RE_Set_60 => System_Pack_60, + RE_SetU_60 => System_Pack_60, + + RE_Bits_61 => System_Pack_61, + RE_Get_61 => System_Pack_61, + RE_Set_61 => System_Pack_61, + + RE_Bits_62 => System_Pack_62, + RE_Get_62 => System_Pack_62, + RE_GetU_62 => System_Pack_62, + RE_Set_62 => System_Pack_62, + RE_SetU_62 => System_Pack_62, + + RE_Bits_63 => System_Pack_63, + RE_Get_63 => System_Pack_63, + RE_Set_63 => System_Pack_63, + + RE_Adjust_Storage_Size => System_Parameters, + RE_Default_Stack_Size => System_Parameters, + RE_Garbage_Collected => System_Parameters, + RE_Size_Type => System_Parameters, + RE_Unspecified_Size => System_Parameters, + + RE_Get_Active_Partition_Id => System_Partition_Interface, + RE_Get_Passive_Partition_Id => System_Partition_Interface, + RE_Get_Local_Partition_Id => System_Partition_Interface, + RE_Get_RCI_Package_Receiver => System_Partition_Interface, + RE_Get_Unique_Remote_Pointer => System_Partition_Interface, + RE_RACW_Stub_Type => System_Partition_Interface, + RE_RACW_Stub_Type_Access => System_Partition_Interface, + RE_Raise_Program_Error_For_E_4_18 => System_Partition_Interface, + RE_Raise_Program_Error_Unknown_Tag => System_Partition_Interface, + RE_Register_Passive_Package => System_Partition_Interface, + RE_Register_Receiving_Stub => System_Partition_Interface, + RE_RCI_Info => System_Partition_Interface, + RE_Subprogram_Id => System_Partition_Interface, + + RE_Global_Pool_Object => System_Pool_Global, + + RE_Unbounded_Reclaim_Pool => System_Pool_Local, + + RE_Stack_Bounded_Pool => System_Pool_Size, + + RE_Do_Apc => System_RPC, + RE_Do_Rpc => System_RPC, + RE_Params_Stream_Type => System_RPC, + RE_Partition_ID => System_RPC, + RE_RPC_Receiver => System_RPC, + + RE_IS_Is1 => System_Scalar_Values, + RE_IS_Is2 => System_Scalar_Values, + RE_IS_Is4 => System_Scalar_Values, + RE_IS_Is8 => System_Scalar_Values, + RE_IS_Iu1 => System_Scalar_Values, + RE_IS_Iu2 => System_Scalar_Values, + RE_IS_Iu4 => System_Scalar_Values, + RE_IS_Iu8 => System_Scalar_Values, + RE_IS_Isf => System_Scalar_Values, + RE_IS_Ifl => System_Scalar_Values, + RE_IS_Ilf => System_Scalar_Values, + RE_IS_Ill => System_Scalar_Values, + + RE_Mark_Id => System_Secondary_Stack, + RE_SS_Allocate => System_Secondary_Stack, + RE_SS_Mark => System_Secondary_Stack, + RE_SS_Pool => System_Secondary_Stack, + RE_SS_Release => System_Secondary_Stack, + + RE_Shared_Var_Close => System_Shared_Storage, + RE_Shared_Var_Lock => System_Shared_Storage, + RE_Shared_Var_ROpen => System_Shared_Storage, + RE_Shared_Var_Unlock => System_Shared_Storage, + RE_Shared_Var_WOpen => System_Shared_Storage, + + RE_Abort_Undefer_Direct => System_Standard_Library, + RE_Exception_Data => System_Standard_Library, + RE_Exception_Data_Ptr => System_Standard_Library, + + RE_Integer_Address => System_Storage_Elements, + RE_Storage_Offset => System_Storage_Elements, + RE_Storage_Array => System_Storage_Elements, + RE_To_Address => System_Storage_Elements, + + RE_Root_Storage_Pool => System_Storage_Pools, + + RE_Thin_Pointer => System_Stream_Attributes, + RE_Fat_Pointer => System_Stream_Attributes, + + RE_I_AD => System_Stream_Attributes, + RE_I_AS => System_Stream_Attributes, + RE_I_B => System_Stream_Attributes, + RE_I_C => System_Stream_Attributes, + RE_I_F => System_Stream_Attributes, + RE_I_I => System_Stream_Attributes, + RE_I_LF => System_Stream_Attributes, + RE_I_LI => System_Stream_Attributes, + RE_I_LLF => System_Stream_Attributes, + RE_I_LLI => System_Stream_Attributes, + RE_I_LLU => System_Stream_Attributes, + RE_I_LU => System_Stream_Attributes, + RE_I_SF => System_Stream_Attributes, + RE_I_SI => System_Stream_Attributes, + RE_I_SSI => System_Stream_Attributes, + RE_I_SSU => System_Stream_Attributes, + RE_I_SU => System_Stream_Attributes, + RE_I_U => System_Stream_Attributes, + RE_I_WC => System_Stream_Attributes, + + RE_W_AD => System_Stream_Attributes, + RE_W_AS => System_Stream_Attributes, + RE_W_B => System_Stream_Attributes, + RE_W_C => System_Stream_Attributes, + RE_W_F => System_Stream_Attributes, + RE_W_I => System_Stream_Attributes, + RE_W_LF => System_Stream_Attributes, + RE_W_LI => System_Stream_Attributes, + RE_W_LLF => System_Stream_Attributes, + RE_W_LLI => System_Stream_Attributes, + RE_W_LLU => System_Stream_Attributes, + RE_W_LU => System_Stream_Attributes, + RE_W_SF => System_Stream_Attributes, + RE_W_SI => System_Stream_Attributes, + RE_W_SSI => System_Stream_Attributes, + RE_W_SSU => System_Stream_Attributes, + RE_W_SU => System_Stream_Attributes, + RE_W_U => System_Stream_Attributes, + RE_W_WC => System_Stream_Attributes, + + RE_Str_Concat => System_String_Ops, + RE_Str_Equal => System_String_Ops, + RE_Str_Normalize => System_String_Ops, + RE_Wide_Str_Normalize => System_String_Ops, + RE_Str_Concat_CC => System_String_Ops, + RE_Str_Concat_CS => System_String_Ops, + RE_Str_Concat_SC => System_String_Ops, + + RE_Str_Concat_3 => System_String_Ops_Concat_3, + + RE_Str_Concat_4 => System_String_Ops_Concat_4, + + RE_Str_Concat_5 => System_String_Ops_Concat_5, + + RE_Free_Task_Image => System_Task_Info, + RE_Task_Info_Type => System_Task_Info, + RE_Task_Image_Type => System_Task_Info, + RE_Unspecified_Task_Info => System_Task_Info, + + RE_Library_Task_Level => System_Tasking, + + RE_Task_Procedure_Access => System_Tasking, + + RO_ST_Task_ID => System_Tasking, + + RE_Call_Modes => System_Tasking, + RE_Simple_Call => System_Tasking, + RE_Conditional_Call => System_Tasking, + RE_Asynchronous_Call => System_Tasking, + RE_Timed_Call => System_Tasking, + + RE_Task_List => System_Tasking, + + RE_Accept_Alternative => System_Tasking, + RE_Accept_List => System_Tasking, + RE_Accept_List_Access => System_Tasking, + RE_Max_Select => System_Tasking, + RE_Max_Task_Entry => System_Tasking, + RE_No_Rendezvous => System_Tasking, + RE_Null_Task_Entry => System_Tasking, + RE_Positive_Select_Index => System_Tasking, + RE_Select_Index => System_Tasking, + RE_Select_Modes => System_Tasking, + RE_Else_Mode => System_Tasking, + RE_Simple_Mode => System_Tasking, + RE_Terminate_Mode => System_Tasking, + RE_Delay_Mode => System_Tasking, + RE_Task_Entry_Index => System_Tasking, + RE_Self => System_Tasking, + + RE_Master_Id => System_Tasking, + RE_Unspecified_Priority => System_Tasking, + + RE_Activation_Chain => System_Tasking, + + RE_Abort_Defer => System_Soft_Links, + RE_Abort_Undefer => System_Soft_Links, + RE_Complete_Master => System_Soft_Links, + RE_Current_Master => System_Soft_Links, + RE_Enter_Master => System_Soft_Links, + RE_Get_Current_Excep => System_Soft_Links, + RE_Get_GNAT_Exception => System_Soft_Links, + RE_Update_Exception => System_Soft_Links, + + RE_Bits_1 => System_Unsigned_Types, + RE_Bits_2 => System_Unsigned_Types, + RE_Bits_4 => System_Unsigned_Types, + RE_Float_Unsigned => System_Unsigned_Types, + RE_Long_Long_Unsigned => System_Unsigned_Types, + RE_Packed_Byte => System_Unsigned_Types, + RE_Packed_Bytes1 => System_Unsigned_Types, + RE_Packed_Bytes2 => System_Unsigned_Types, + RE_Packed_Bytes4 => System_Unsigned_Types, + RE_Unsigned => System_Unsigned_Types, + + RE_Value_Boolean => System_Val_Bool, + + RE_Value_Character => System_Val_Char, + + RE_Value_Decimal => System_Val_Dec, + + RE_Value_Enumeration_8 => System_Val_Enum, + RE_Value_Enumeration_16 => System_Val_Enum, + RE_Value_Enumeration_32 => System_Val_Enum, + + RE_Value_Integer => System_Val_Int, + + RE_Value_Long_Long_Decimal => System_Val_LLD, + + RE_Value_Long_Long_Integer => System_Val_LLI, + + RE_Value_Long_Long_Unsigned => System_Val_LLU, + + RE_Value_Real => System_Val_Real, + + RE_Value_Unsigned => System_Val_Uns, + + RE_Value_Wide_Character => System_Val_WChar, + + RE_D => System_Vax_Float_Operations, + RE_F => System_Vax_Float_Operations, + RE_G => System_Vax_Float_Operations, + RE_Q => System_Vax_Float_Operations, + RE_S => System_Vax_Float_Operations, + RE_T => System_Vax_Float_Operations, + + RE_D_To_G => System_Vax_Float_Operations, + RE_F_To_G => System_Vax_Float_Operations, + RE_F_To_Q => System_Vax_Float_Operations, + RE_F_To_S => System_Vax_Float_Operations, + RE_G_To_D => System_Vax_Float_Operations, + RE_G_To_F => System_Vax_Float_Operations, + RE_G_To_Q => System_Vax_Float_Operations, + RE_G_To_T => System_Vax_Float_Operations, + RE_Q_To_F => System_Vax_Float_Operations, + RE_Q_To_G => System_Vax_Float_Operations, + RE_S_To_F => System_Vax_Float_Operations, + RE_T_To_D => System_Vax_Float_Operations, + RE_T_To_G => System_Vax_Float_Operations, + + RE_Abs_F => System_Vax_Float_Operations, + RE_Abs_G => System_Vax_Float_Operations, + RE_Add_F => System_Vax_Float_Operations, + RE_Add_G => System_Vax_Float_Operations, + RE_Div_F => System_Vax_Float_Operations, + RE_Div_G => System_Vax_Float_Operations, + RE_Mul_F => System_Vax_Float_Operations, + RE_Mul_G => System_Vax_Float_Operations, + RE_Neg_F => System_Vax_Float_Operations, + RE_Neg_G => System_Vax_Float_Operations, + RE_Sub_F => System_Vax_Float_Operations, + RE_Sub_G => System_Vax_Float_Operations, + + RE_Eq_F => System_Vax_Float_Operations, + RE_Eq_G => System_Vax_Float_Operations, + RE_Le_F => System_Vax_Float_Operations, + RE_Le_G => System_Vax_Float_Operations, + RE_Lt_F => System_Vax_Float_Operations, + RE_Lt_G => System_Vax_Float_Operations, + + RE_Version_String => System_Version_Control, + RE_Get_Version_String => System_Version_Control, + + RE_Register_VMS_Exception => System_VMS_Exception_Table, + + RE_String_To_Wide_String => System_WCh_StW, + + RE_Wide_String_To_String => System_WCh_WtS, + + RE_Wide_Width_Character => System_WWd_Char, + + RE_Wide_Width_Enumeration_8 => System_WWd_Enum, + RE_Wide_Width_Enumeration_16 => System_WWd_Enum, + RE_Wide_Width_Enumeration_32 => System_WWd_Enum, + + RE_Wide_Width_Wide_Character => System_WWd_Wchar, + + RE_Width_Boolean => System_Wid_Bool, + + RE_Width_Character => System_Wid_Char, + + RE_Width_Enumeration_8 => System_Wid_Enum, + RE_Width_Enumeration_16 => System_Wid_Enum, + RE_Width_Enumeration_32 => System_Wid_Enum, + + RE_Width_Long_Long_Integer => System_Wid_LLI, + + RE_Width_Long_Long_Unsigned => System_Wid_LLU, + + RE_Width_Wide_Character => System_Wid_WChar, + + RE_Protected_Entry_Body_Array => + System_Tasking_Protected_Objects_Entries, + RE_Protection_Entries => + System_Tasking_Protected_Objects_Entries, + RE_Initialize_Protection_Entries => + System_Tasking_Protected_Objects_Entries, + RE_Lock_Entries => + System_Tasking_Protected_Objects_Entries, + RE_Lock_Read_Only_Entries => + System_Tasking_Protected_Objects_Entries, + RE_Unlock_Entries => + System_Tasking_Protected_Objects_Entries, + RE_Communication_Block => + System_Tasking_Protected_Objects_Operations, + RE_Protected_Entry_Call => + System_Tasking_Protected_Objects_Operations, + RE_Service_Entries => + System_Tasking_Protected_Objects_Operations, + RE_Cancel_Protected_Entry_Call => + System_Tasking_Protected_Objects_Operations, + RE_Enqueued => + System_Tasking_Protected_Objects_Operations, + RE_Cancelled => + System_Tasking_Protected_Objects_Operations, + RE_Complete_Entry_Body => + System_Tasking_Protected_Objects_Operations, + RE_Exceptional_Complete_Entry_Body => + System_Tasking_Protected_Objects_Operations, + RE_Requeue_Protected_Entry => + System_Tasking_Protected_Objects_Operations, + RE_Requeue_Task_To_Protected_Entry => + System_Tasking_Protected_Objects_Operations, + RE_Protected_Count => + System_Tasking_Protected_Objects_Operations, + RE_Protected_Entry_Caller => + System_Tasking_Protected_Objects_Operations, + RE_Timed_Protected_Entry_Call => + System_Tasking_Protected_Objects_Operations, + + RE_Protection_Entry => + System_Tasking_Protected_Objects_Single_Entry, + RE_Initialize_Protection_Entry => + System_Tasking_Protected_Objects_Single_Entry, + RE_Lock_Entry => + System_Tasking_Protected_Objects_Single_Entry, + RE_Lock_Read_Only_Entry => + System_Tasking_Protected_Objects_Single_Entry, + RE_Unlock_Entry => + System_Tasking_Protected_Objects_Single_Entry, + RE_Protected_Single_Entry_Call => + System_Tasking_Protected_Objects_Single_Entry, + RE_Service_Entry => + System_Tasking_Protected_Objects_Single_Entry, + RE_Complete_Single_Entry_Body => + System_Tasking_Protected_Objects_Single_Entry, + RE_Exceptional_Complete_Single_Entry_Body => + System_Tasking_Protected_Objects_Single_Entry, + RE_Protected_Count_Entry => + System_Tasking_Protected_Objects_Single_Entry, + RE_Protected_Single_Entry_Caller => + System_Tasking_Protected_Objects_Single_Entry, + RE_Timed_Protected_Single_Entry_Call => + System_Tasking_Protected_Objects_Single_Entry, + + RE_Protected_Entry_Index => System_Tasking_Protected_Objects, + RE_Entry_Body => System_Tasking_Protected_Objects, + RE_Protection => System_Tasking_Protected_Objects, + RE_Initialize_Protection => System_Tasking_Protected_Objects, + RE_Finalize_Protection => System_Tasking_Protected_Objects, + RE_Lock => System_Tasking_Protected_Objects, + RE_Lock_Read_Only => System_Tasking_Protected_Objects, + RE_Unlock => System_Tasking_Protected_Objects, + + RE_Delay_Block => System_Tasking_Async_Delays, + RE_Timed_Out => System_Tasking_Async_Delays, + RE_Cancel_Async_Delay => System_Tasking_Async_Delays, + RE_Enqueue_Duration => System_Tasking_Async_Delays, + + RE_Enqueue_Calendar => + System_Tasking_Async_Delays_Enqueue_Calendar, + RE_Enqueue_RT => + System_Tasking_Async_Delays_Enqueue_RT, + + RE_Accept_Call => System_Tasking_Rendezvous, + RE_Accept_Trivial => System_Tasking_Rendezvous, + RE_Callable => System_Tasking_Rendezvous, + RE_Call_Simple => System_Tasking_Rendezvous, + RE_Cancel_Task_Entry_Call => System_Tasking_Rendezvous, + RE_Requeue_Task_Entry => System_Tasking_Rendezvous, + RE_Requeue_Protected_To_Task_Entry => System_Tasking_Rendezvous, + RE_Complete_Rendezvous => System_Tasking_Rendezvous, + RE_Task_Count => System_Tasking_Rendezvous, + RE_Exceptional_Complete_Rendezvous => System_Tasking_Rendezvous, + RE_Selective_Wait => System_Tasking_Rendezvous, + RE_Task_Entry_Call => System_Tasking_Rendezvous, + RE_Task_Entry_Caller => System_Tasking_Rendezvous, + RE_Timed_Task_Entry_Call => System_Tasking_Rendezvous, + RE_Timed_Selective_Wait => System_Tasking_Rendezvous, + + RE_Activate_Restricted_Tasks => System_Tasking_Restricted_Stages, + RE_Complete_Restricted_Activation => System_Tasking_Restricted_Stages, + RE_Create_Restricted_Task => System_Tasking_Restricted_Stages, + RE_Complete_Restricted_Task => System_Tasking_Restricted_Stages, + RE_Restricted_Terminated => System_Tasking_Restricted_Stages, + + RE_Abort_Tasks => System_Tasking_Stages, + RE_Activate_Tasks => System_Tasking_Stages, + RE_Complete_Activation => System_Tasking_Stages, + RE_Create_Task => System_Tasking_Stages, + RE_Complete_Task => System_Tasking_Stages, + RE_Free_Task => System_Tasking_Stages, + RE_Expunge_Unactivated_Tasks => System_Tasking_Stages, + RE_Terminated => System_Tasking_Stages); + + ----------------- + -- Subprograms -- + ----------------- + + procedure Initialize; + -- Procedure to initialize data structures used by RTE. Called at the + -- start of processing a new main source file. Must be called after + -- Initialize_Snames (since names it enters into name table must come + -- after names entered by Snames). + + function RTE (E : RE_Id) return Entity_Id; + -- Given the entity defined in the above tables, as identified by the + -- corresponding value in the RE_Id enumeration type, returns the Id + -- of the corresponding entity, first loading in (parsing, analyzing and + -- expanding) its spec if the unit has not already been loaded. If the + -- unit cannot be found, or if it does not contain the specified entity, + -- then an appropriate error message is output ("run-time configuration + -- error") and an Unrecoverable_Error exception is raised. + + function Is_RTE (Ent : Entity_Id; E : RE_Id) return Boolean; + -- This function determines if the given entity corresponds to the entity + -- referenced by RE_Id. It is similar in effect to (Ent = RTE (E)) except + -- that the latter would unconditionally load the unit containing E. For + -- this call, if the unit is not loaded, then a result of False is returned + -- immediately, since obviously Ent cannot be the entity in question if the + -- corresponding unit has not been loaded. + + procedure Text_IO_Kludge (Nam : Node_Id); + -- In Ada 83, and hence for compatibility in Ada 9X, package Text_IO has + -- generic subpackages (e.g. Integer_IO). They really should be child + -- packages, and in GNAT, they *are* child packages. To maintain the + -- required compatibility, this routine is called for package renamings + -- and generic instantiations, with the simple name of the referenced + -- package. If Text_IO has been with'ed and if the simple name of Nam + -- matches one of the subpackages of Text_IO, then this subpackage is + -- with'ed automatically. The important result of this approach is that + -- Text_IO does not drag in all the code for the subpackages unless they + -- are used. Our test is a little crude, and could drag in stuff when it + -- is not necessary, but that doesn't matter. Wide_Text_IO is handled in + -- a similar manner. + + function Is_Text_IO_Kludge_Unit (Nam : Node_Id) return Boolean; + -- Returns True if the given Nam is an Expanded Name, whose Prefix is + -- Ada, and whose selector is either Text_IO.xxx or Wide_Text_IO.xxx + -- where xxx is one of the subpackages of Text_IO that is specially + -- handled as described above for Text_IO_Kludge. + +end Rtsfind; |