| ------------------------------------------------------------------------------ |
| -- -- |
| -- GNAT COMPILER COMPONENTS -- |
| -- -- |
| -- P A R . C H 1 0 -- |
| -- -- |
| -- B o d y -- |
| -- -- |
| -- Copyright (C) 1992-2022, Free Software Foundation, Inc. -- |
| -- -- |
| -- GNAT is free software; you can redistribute it and/or modify it under -- |
| -- terms of the GNU General Public License as published by the Free Soft- -- |
| -- ware Foundation; either version 3, or (at your option) any later ver- -- |
| -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- |
| -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- |
| -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- |
| -- for more details. You should have received a copy of the GNU General -- |
| -- Public License distributed with GNAT; see file COPYING3. If not, go to -- |
| -- http://www.gnu.org/licenses for a complete copy of the license. -- |
| -- -- |
| -- GNAT was originally developed by the GNAT team at New York University. -- |
| -- Extensive contributions were provided by Ada Core Technologies Inc. -- |
| -- -- |
| ------------------------------------------------------------------------------ |
| |
| pragma Style_Checks (All_Checks); |
| -- Turn off subprogram body ordering check. Subprograms are in order |
| -- by RM section rather than alphabetical |
| |
| with Fname.UF; use Fname.UF; |
| 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 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; |
| No_Body : 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 syntax 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 we see a pragma No_Body, remember not to complain about no body |
| |
| No_Body := False; |
| |
| if Token = Tok_Pragma then |
| Save_Scan_State (Scan_State); |
| Item := P_Pragma; |
| |
| if Item = Error |
| or else Pragma_Name_Unmapped (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 and then Pragma_Name_Unmapped (Item) = Name_No_Body |
| then |
| No_Body := True; |
| end if; |
| |
| if Item = Error |
| or else |
| not Is_Configuration_Pragma_Name (Pragma_Name_Unmapped (Item)) |
| 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 |
| if Operating_Mode = Check_Syntax and then Token = Tok_EOF then |
| |
| -- Do not complain if there is a pragma No_Body |
| |
| if not No_Body then |
| Error_Msg_SC ("??file contains no compilation units"); |
| end if; |
| |
| else |
| Error_Msg_SC ("compilation unit expected"); |
| Cunit_Error_Flag := True; |
| Resync_Cunit; |
| end if; |
| |
| -- 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 the file we |
| -- are compiling has a name that requires a body to be found. |
| |
| Save_Scan_State (Scan_State); |
| Scan; -- past Package keyword |
| |
| if Token /= Tok_Body |
| and then |
| Get_Expected_Unit_Type |
| (File_Name (Current_Source_File)) = Expect_Body |
| then |
| Error_Msg_BC -- CODEFIX |
| ("keyword BODY expected here '[see file name']"); |
| Restore_Scan_State (Scan_State); |
| Set_Unit (Comp_Unit_Node, P_Package (Pf_Pbod_Pexp)); |
| else |
| Restore_Scan_State (Scan_State); |
| Set_Unit (Comp_Unit_Node, P_Package (Pf_Decl_Gins_Pbod_Rnam_Pexp)); |
| 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_Function |
| or else Token = Tok_Not |
| or else Token = Tok_Overriding |
| or else Token = Tok_Procedure |
| then |
| Set_Unit (Comp_Unit_Node, P_Subprogram (Pf_Decl_Gins_Pbod_Rnam_Pexp)); |
| |
| -- 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; |
| Scopes (Scope.Last).Etyp := E_Name; |
| Scopes (Scope.Last).Sloc := SIS_Sloc; |
| Scopes (Scope.Last).Ecol := SIS_Ecol; |
| Scopes (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 -- CODEFIX |
| (""";"" 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)) not in N_Subprogram_Instantiation |
| and then |
| Nkind (Unit (Comp_Unit_Node)) /= N_Subprogram_Renaming_Declaration |
| 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) in N_Subprogram_Body_Stub | 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) in N_Package_Declaration |
| | N_Subprogram_Declaration |
| | N_Subprogram_Body |
| | N_Subprogram_Renaming_Declaration |
| then |
| if Nkind (Unit_Node) = N_Subprogram_Renaming_Declaration |
| and then Ada_Version = Ada_83 |
| then |
| Error_Msg_N |
| ("(Ada 83) library unit renaming not allowed", Unit_Node); |
| end if; |
| |
| Unit_Node := Specification (Unit_Node); |
| end if; |
| |
| if Nkind (Unit_Node) in N_Task_Body |
| | N_Protected_Body |
| | N_Task_Type_Declaration |
| | N_Protected_Type_Declaration |
| | N_Single_Task_Declaration |
| | N_Single_Protected_Declaration |
| then |
| Name_Node := Defining_Identifier (Unit_Node); |
| |
| elsif Nkind (Unit_Node) in N_Function_Instantiation |
| | N_Function_Specification |
| | N_Generic_Function_Renaming_Declaration |
| | N_Generic_Package_Renaming_Declaration |
| | N_Generic_Procedure_Renaming_Declaration |
| | N_Package_Body |
| | N_Package_Instantiation |
| | N_Package_Renaming_Declaration |
| | N_Package_Specification |
| | N_Procedure_Instantiation |
| | N_Procedure_Specification |
| then |
| Name_Node := Defining_Unit_Name (Unit_Node); |
| |
| elsif Nkind (Unit_Node) = N_Expression_Function then |
| Error_Msg_SP |
| ("expression function cannot be used as compilation unit"); |
| return Comp_Unit_Node; |
| |
| -- Anything else is a serious error, abandon scan |
| |
| else |
| raise Error_Resync; |
| 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, Error_Detected); |
| 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 (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 |
| (Is_Configuration_Pragma_Name (Token_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_Version = 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 seems 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; |
| |
| -- We also allow multiple units if we are in multiple unit mode |
| |
| elsif Multiple_Unit_Index /= 0 then |
| |
| -- Skip tokens to end of file, so that the -gnatl listing |
| -- will be complete in this situation, but no need to parse |
| -- the remaining units; no style checking either. |
| |
| declare |
| Save_Style_Check : constant Boolean := Style_Check; |
| |
| begin |
| Style_Check := False; |
| |
| while Token /= Tok_EOF loop |
| Scan; |
| end loop; |
| |
| Style_Check := Save_Style_Check; |
| end; |
| |
| 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 Fatal_Error (Current_Source_Unit) /= Error_Detected 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, Error_Detected); |
| 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 ::= |
| -- [LIMITED] [PRIVATE] with library_unit_NAME {,library_unit_NAME}; |
| -- Note: the two qualifiers are Ada 2005 extensions. |
| |
| -- WITH_TYPE_CLAUSE ::= |
| -- with type type_NAME is access; | with type type_NAME is tagged; |
| -- Note: this form is obsolete (old GNAT extension). |
| |
| -- Error recovery: Cannot raise Error_Resync |
| |
| function P_Context_Clause return List_Id is |
| Item_List : List_Id; |
| Has_Limited : Boolean := False; |
| Has_Private : Boolean := False; |
| Scan_State : Saved_Scan_State; |
| 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 |
| |
| -- Ada 2005 (AI-50217, AI-262): First check for LIMITED WITH, |
| -- PRIVATE WITH, or both. |
| |
| if Token = Tok_Limited then |
| Has_Limited := True; |
| Has_Private := False; |
| Scan; -- past LIMITED |
| |
| -- In the context, LIMITED can only appear in a with_clause |
| |
| if Token = Tok_Private then |
| Has_Private := True; |
| Scan; -- past PRIVATE |
| end if; |
| |
| if Token /= Tok_With then |
| Error_Msg_SC -- CODEFIX |
| ("unexpected LIMITED ignored"); |
| end if; |
| |
| Error_Msg_Ada_2005_Extension ("`LIMITED WITH`"); |
| |
| elsif Token = Tok_Private then |
| Has_Limited := False; |
| Has_Private := True; |
| Save_Scan_State (Scan_State); |
| Scan; -- past PRIVATE |
| |
| if Token /= Tok_With then |
| |
| -- Keyword is beginning of private child unit |
| |
| Restore_Scan_State (Scan_State); -- to PRIVATE |
| return Item_List; |
| end if; |
| |
| Error_Msg_Ada_2005_Extension ("`PRIVATE WITH`"); |
| |
| else |
| Has_Limited := False; |
| Has_Private := False; |
| end if; |
| |
| if Token = Tok_With then |
| Scan; -- past WITH |
| |
| if Token = Tok_Type then |
| |
| -- WITH TYPE is an obsolete GNAT specific extension |
| |
| Error_Msg_SP ("`WITH TYPE` is an obsolete 'G'N'A'T extension"); |
| Error_Msg_SP ("\use Ada 2005 `LIMITED WITH` clause instead"); |
| |
| Scan; -- past TYPE |
| |
| T_Is; |
| |
| if Token = Tok_Tagged then |
| 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 name 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); |
| if Name (With_Node) = Error then |
| Remove (With_Node); |
| end if; |
| |
| Set_First_Name (With_Node, First_Flag); |
| Set_Limited_Present (With_Node, Has_Limited); |
| Set_Private_Present (With_Node, Has_Private); |
| First_Flag := False; |
| |
| -- All done if no comma |
| |
| exit when Token /= Tok_Comma; |
| |
| -- If comma is followed by compilation unit token |
| -- or by USE, or PRAGMA, then it should have been a |
| -- semicolon after all |
| |
| Save_Scan_State (Scan_State); |
| Scan; -- past comma |
| |
| if Token in Token_Class_Cunit |
| or else Token = Tok_Use |
| or else Token = Tok_Pragma |
| then |
| Restore_Scan_State (Scan_State); |
| exit; |
| end if; |
| end loop; |
| |
| Set_Last_Name (With_Node, True); |
| TF_Semicolon; |
| end if; |
| |
| -- Processing for USE clause |
| |
| elsif Token = Tok_Use then |
| 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; |
| |
| U_Left_Paren; |
| Set_Name (Subunit_Node, P_Qualified_Simple_Name); |
| U_Right_Paren; |
| |
| Ignore (Tok_Semicolon); |
| |
| if Token = Tok_Function |
| or else Token = Tok_Not |
| or else Token = Tok_Overriding |
| or else Token = Tok_Procedure |
| then |
| Body_Node := P_Subprogram (Pf_Pbod_Pexp); |
| |
| elsif Token = Tok_Package then |
| Body_Node := P_Package (Pf_Pbod_Pexp); |
| |
| 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; |
| |
| -- Should we worry about UTF_32 line terminators here |
| |
| 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 |
| 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 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; |