home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gnat-2.06-src.tgz / tar.out / fsf / gnat / ada / par-ch10.adb < prev    next >
Text File  |  1996-09-28  |  23KB  |  694 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                         GNAT COMPILER COMPONENTS                         --
  4. --                                                                          --
  5. --                             P A R . C H 1 0                              --
  6. --                                                                          --
  7. --                                 B o d y                                  --
  8. --                                                                          --
  9. --                            $Revision: 1.66 $                             --
  10. --                                                                          --
  11. --           Copyright (c) 1992,1993,1994 NYU, All Rights Reserved          --
  12. --                                                                          --
  13. -- GNAT is free software;  you can  redistribute it  and/or modify it under --
  14. -- terms of the  GNU General Public License as published  by the Free Soft- --
  15. -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
  16. -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
  17. -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  18. -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
  19. -- for  more details.  You should have  received  a copy of the GNU General --
  20. -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
  21. -- to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. --
  22. --                                                                          --
  23. ------------------------------------------------------------------------------
  24.  
  25. with Fname; use Fname;
  26. with Uname; use Uname;
  27.  
  28. separate (Par)
  29. package body Ch10 is
  30.  
  31.    --  Local functions, used only in this chapter
  32.  
  33.    function P_Context_Clause    return List_Id;
  34.    function P_Subunit           return Node_Id;
  35.  
  36.    procedure Unit_Display (Cunit : Node_Id; Loc : Source_Ptr);
  37.    --  This procedure is used to generate a line of output for the a unit in
  38.    --  the source program. Cunit is the node for the compilation unit, and
  39.    --  Loc is the source location for the start of the unit in the source
  40.    --  file (which is not necessarily the Sloc of the Cunit node). This
  41.    --  output is written to the standard output file for use by gnatchop.
  42.  
  43.    -------------------------
  44.    -- 10.1.1  Compilation --
  45.    -------------------------
  46.  
  47.    --  COMPILATION ::= {COMPILATION_UNIT}
  48.  
  49.    --  There is no specific parsing routine for a compilation, since we only
  50.    --  permit a single compilation in a source file, so there is no explicit
  51.    --  occurrence of compilations as such (our representation of a compilation
  52.    --  is a series of separate source files).
  53.  
  54.    ------------------------------
  55.    -- 10.1.1  Compilation unit --
  56.    ------------------------------
  57.  
  58.    --  COMPILATION_UNIT ::=
  59.    --    CONTEXT_CLAUSE LIBRARY_ITEM
  60.    --  | CONTEXT_CLAUSE SUBUNIT
  61.  
  62.    --  LIBRARY_ITEM ::=
  63.    --    private LIBRARY_UNIT_DECLARATION
  64.    --  | LIBRARY_UNIT_BODY
  65.    --  | [private] LIBRARY_UNIT_RENAMING_DECLARATION
  66.  
  67.    --  LIBRARY_UNIT_DECLARATION ::=
  68.    --    SUBPROGRAM_DECLARATION | PACKAGE_DECLARATION
  69.    --  | GENERIC_DECLARATION    | GENERIC_INSTANTIATION
  70.  
  71.    --  LIBRARY_UNIT_RENAMING_DECLARATION ::=
  72.    --    PACKAGE_RENAMING_DECLARATION
  73.    --  | GENERIC_RENAMING_DECLARATION
  74.    --  | SUBPROGRAM_RENAMING_DECLARATION
  75.  
  76.    --  LIBRARY_UNIT_BODY ::= SUBPROGRAM_BODY | PACKAGE_BODY
  77.  
  78.    --  Error recovery: cannot raise Error_Resync. If an error occurs, tokens
  79.    --  are skipped up to the next possible beginning of a compilation unit.
  80.  
  81.    function P_Compilation_Unit return Node_Id is
  82.       Scan_State         : Saved_Scan_State;
  83.       Body_Node          : Node_Id;
  84.       Spec_Node          : Node_Id;
  85.       Specification_Node : Node_Id;
  86.       Unit_Node          : Node_Id;
  87.       Comp_Unit_Node     : Node_Id;
  88.       Name_Node          : Node_Id;
  89.       Item               : Node_Id;
  90.       Private_Sloc       : Source_Ptr;
  91.  
  92.       Cunit_Error_Flag   : Boolean := False;
  93.       --  This flag is set True if we have to scan for a compilation unit
  94.       --  token. It is used to ensure clean termination in such cases by
  95.       --  not insisting on being at the end of file, and, in the sytax only
  96.       --  case by not scanning for additional compilation units.
  97.  
  98.       Cunit_Location : Source_Ptr;
  99.       --  Location of unit for unit identification output (List_Unit option)
  100.  
  101.       Physical : Boolean;
  102.  
  103.    begin
  104.       --  Set location of the compilation unit if unit list option set
  105.       --  and we are in syntax check only mode
  106.  
  107.       if List_Units and then Operating_Mode = Check_Syntax then
  108.  
  109.          --  If we are at the start of the file, then we take the starting
  110.          --  point for this unit as being at the start of the entire file.
  111.  
  112.          if Num_Library_Units = 0 then
  113.             Cunit_Location := Source_First (Current_Source_File);
  114.             Num_Library_Units := 1;
  115.  
  116.          --  If not at start of file, the starting point is the start of
  117.          --  the line after the last token of the previous compilation unit,
  118.          --  or the start of the current unit, whichever comes first.
  119.  
  120.          else
  121.             Num_Library_Units := Num_Library_Units + 1;
  122.             Cunit_Location := Prev_Token_Ptr;
  123.  
  124.             loop
  125.                exit when Cunit_Location = Token_Ptr;
  126.  
  127.                if Source (Cunit_Location) in Line_Terminator then
  128.                   Skip_Line_Terminators (Cunit_Location, Physical);
  129.                   exit when Physical;
  130.                end if;
  131.  
  132.                Cunit_Location := Cunit_Location + 1;
  133.             end loop;
  134.          end if;
  135.       end if;
  136.  
  137.       --  Establish compilation unit node and scan context items
  138.  
  139.       Comp_Unit_Node := New_Node (N_Compilation_Unit, No_Location);
  140.       Set_Cunit (Current_Source_Unit, Comp_Unit_Node);
  141.       Set_Context_Items (Comp_Unit_Node, P_Context_Clause);
  142.  
  143.       --  Check for PRIVATE. Note that for the moment we allow this in
  144.       --  Ada_83 mode, since we do not yet know if we are compiling a
  145.       --  predefined unit, and if we are then it would be allowed anyway.
  146.  
  147.       if Token = Tok_Private then
  148.          Private_Sloc := Token_Ptr;
  149.          Set_Keyword_Casing (Current_Source_File, Determine_Token_Casing);
  150.          if Style_Check then Style.Check_Indentation; end if;
  151.  
  152.          Save_Scan_State (Scan_State); -- at PRIVATE
  153.          Note_Feature (Private_Child, Token_Ptr);
  154.          Scan; -- past PRIVATE
  155.  
  156.          if Token = Tok_Separate then
  157.             Error_Msg_SP ("cannot have private subunits!");
  158.  
  159.          elsif Token = Tok_Package then
  160.             Scan; -- past PACKAGE
  161.  
  162.             if Token = Tok_Body then
  163.                Restore_Scan_State (Scan_State); -- to PRIVATE
  164.                Error_Msg_SC ("cannot have private package body!");
  165.                Scan; -- ignore PRIVATE
  166.             else
  167.                Restore_Scan_State (Scan_State); -- to PRIVATE
  168.                Scan; -- past PRIVATE
  169.                Set_Private_Present (Comp_Unit_Node, True);
  170.             end if;
  171.          end if;
  172.       end if;
  173.  
  174.       --  Loop to find our way to a compilation unit token
  175.  
  176.       loop
  177.          exit when Token in Token_Class_Cunit and then Token /= Tok_With;
  178.  
  179.          exit when Bad_Spelling_Of (Tok_Procedure)
  180.            or else Bad_Spelling_Of (Tok_Package)
  181.            or else Bad_Spelling_Of (Tok_Function)
  182.            or else Bad_Spelling_Of (Tok_Generic);
  183.  
  184.          if Token = Tok_With then
  185.             Error_Msg_SC ("misplaced WITH");
  186.             Append_List (P_Context_Clause, Context_Items (Comp_Unit_Node));
  187.  
  188.          elsif Bad_Spelling_Of (Tok_With) then
  189.             Append_List (P_Context_Clause, Context_Items (Comp_Unit_Node));
  190.  
  191.          else
  192.             Error_Msg_SC ("compilation unit expected");
  193.             Cunit_Error_Flag := True;
  194.             Resync_Cunit;
  195.  
  196.             --  If we are at an end of file, then just quit, the above error
  197.             --  message was complaint enough.
  198.  
  199.             if Token = Tok_EOF then
  200.                return Error;
  201.             end if;
  202.          end if;
  203.       end loop;
  204.  
  205.       --  We have a compilation unit token, so that's a reasonable choice for
  206.       --  determining the standard casing convention used for keywords in case
  207.       --  it hasn't already been done on seeing a WITH or PRIVATE.
  208.  
  209.       Set_Keyword_Casing (Current_Source_File, Determine_Token_Casing);
  210.       if Style_Check then Style.Check_Indentation; end if;
  211.  
  212.       --  Remaining processing depends on particular type of compilation unit
  213.  
  214.       if Token = Tok_Package then
  215.  
  216.          --  A common error is to omit the body keyword after package. We can
  217.          --  often diagnose this early on (before getting loads of errors from
  218.          --  contained subprogram bodies), by knowing that that the file we
  219.          --  are compiling has a name that requires a body to be found.
  220.  
  221.          --  However, we do not do this check if we are operating in syntax
  222.          --  checking only mode, because in that case there may be multiple
  223.          --  units in the same file, and the file name is not a reliable guide.
  224.  
  225.          Save_Scan_State (Scan_State);
  226.          Scan; -- past Package keyword
  227.  
  228.          if Token /= Tok_Body
  229.            and then Operating_Mode /= Check_Syntax
  230.            and then
  231.              Get_Expected_Unit_Type
  232.                (File_Name (Current_Source_File)) = Expect_Body
  233.          then
  234.             Error_Msg_BC ("keyword BODY expected here [see file name]");
  235.             Restore_Scan_State (Scan_State);
  236.             Set_Unit (Comp_Unit_Node, P_Package (Pf_Pbod));
  237.          else
  238.             Restore_Scan_State (Scan_State);
  239.             Set_Unit (Comp_Unit_Node, P_Package (Pf_Decl_Gins_Pbod_Rnam));
  240.          end if;
  241.  
  242.       elsif Token = Tok_Generic then
  243.          Set_Unit (Comp_Unit_Node, P_Generic);
  244.  
  245.       elsif Token = Tok_Separate then
  246.          Set_Unit (Comp_Unit_Node, P_Subunit);
  247.  
  248.       else
  249.          pragma Assert (Token = Tok_Procedure or else Token = Tok_Function);
  250.          Set_Unit (Comp_Unit_Node, P_Subprogram (Pf_Decl_Gins_Pbod_Rnam));
  251.  
  252.          --  A little bit of an error recovery check here. If we just scanned
  253.          --  a subprogram declaration (as indicated by an SIS entry being
  254.          --  active), then if the following token is BEGIN or an identifier,
  255.          --  or a token which can reasonably start a declaration but cannot
  256.          --  start a compilation unit, then we assume that the semicolon in
  257.          --  the declaration should have been IS.
  258.  
  259.          if SIS_Entry_Active then
  260.  
  261.             if Token = Tok_Begin
  262.                or else Token = Tok_Identifier
  263.                or else Token in Token_Class_Deckn
  264.             then
  265.                Push_Scope_Stack;
  266.                Scope.Table (Scope.Last).Etyp := E_Name;
  267.                Scope.Table (Scope.Last).Sloc := SIS_Sloc;
  268.                Scope.Table (Scope.Last).Ecol := SIS_Ecol;
  269.                Scope.Table (Scope.Last).Lreq := False;
  270.                SIS_Entry_Active := False;
  271.                Error_Msg_SP (""";"" should be IS!");
  272.  
  273.                Body_Node := Unit (Comp_Unit_Node);
  274.                Specification_Node := Specification (Body_Node);
  275.                Change_Node (Body_Node, N_Subprogram_Body);
  276.                Set_Specification (Body_Node, Specification_Node);
  277.                Parse_Decls_Begin_End (Body_Node);
  278.                Set_Unit (Comp_Unit_Node, Body_Node);
  279.             end if;
  280.  
  281.          end if;
  282.       end if;
  283.  
  284.       --  Here is where we set the Sloc field of the N_Compilation_Unit node,
  285.       --  which must point to the name of the unit, which is a bit hard to
  286.       --  find in some cases (which is why we set it in the node!)
  287.  
  288.       Unit_Node := Unit (Comp_Unit_Node);
  289.  
  290.       --  Only try this if we got an OK unit!
  291.  
  292.       if Unit_Node /= Error then
  293.          if Nkind (Unit_Node) = N_Subunit then
  294.             Unit_Node := Proper_Body (Unit_Node);
  295.          end if;
  296.  
  297.          if Nkind (Unit_Node) in N_Generic_Declaration then
  298.             Unit_Node := Specification (Unit_Node);
  299.          end if;
  300.  
  301.          if Nkind (Unit_Node) = N_Package_Declaration
  302.            or else Nkind (Unit_Node) = N_Subprogram_Declaration
  303.            or else Nkind (Unit_Node) = N_Subprogram_Body
  304.            or else Nkind (Unit_Node) = N_Subprogram_Renaming_Declaration
  305.          then
  306.             Unit_Node := Specification (Unit_Node);
  307.  
  308.          elsif Nkind (Unit_Node) = N_Subprogram_Renaming_Declaration then
  309.             Note_Feature (Library_Unit_Renaming, Sloc (Unit_Node));
  310.  
  311.             if Ada_83 then
  312.                Error_Msg_N
  313.                  ("(Ada 83) library unit renaming not allowed", Unit_Node);
  314.             end if;
  315.          end if;
  316.  
  317.          if Nkind (Unit_Node) = N_Task_Body
  318.            or else Nkind (Unit_Node) = N_Protected_Body
  319.          then
  320.             Name_Node := Defining_Identifier (Unit_Node);
  321.          else
  322.             Name_Node := Defining_Unit_Name (Unit_Node);
  323.          end if;
  324.  
  325.          Set_Sloc (Comp_Unit_Node, Sloc (Name_Node));
  326.  
  327.          --  Set Entity field in file table. Easier now that we have name!
  328.          --  Note that this is also skipped if we had a bad unit
  329.  
  330.          if Nkind (Name_Node) = N_Defining_Program_Unit_Name then
  331.             Set_Cunit_Entity
  332.               (Current_Source_Unit, Defining_Identifier (Name_Node));
  333.          else
  334.             Set_Cunit_Entity (Current_Source_Unit, Name_Node);
  335.          end if;
  336.  
  337.          Set_Unit_Name
  338.            (Current_Source_Unit, Get_Unit_Name (Unit (Comp_Unit_Node)));
  339.  
  340.       --  If we had a bad unit, make sure the fatal flag is set in the file
  341.       --  table entry, since this is surely a fatal error and also set our
  342.       --  flag to inhibit the requirement that we be at end of file.
  343.  
  344.       else
  345.          Cunit_Error_Flag := True;
  346.          Set_Fatal_Error (Current_Source_Unit);
  347.       end if;
  348.  
  349.       --  Clear away any missing semicolon indication, we are done with that
  350.       --  unit, so what's done is done, and we don't want anything hanging
  351.       --  around from the attempt to parse it!
  352.  
  353.       SIS_Entry_Active := False;
  354.  
  355.       --  Any final pragmas get appended to the context clause
  356.  
  357.       if Token = Tok_Pragma then
  358.          Set_Following_Pragmas (Comp_Unit_Node, New_List);
  359.          P_Pragmas_Opt (Following_Pragmas (Comp_Unit_Node));
  360.       end if;
  361.  
  362.       --  Ada 83 error checks
  363.  
  364.       if Ada_83 then
  365.  
  366.          --  Check we did not with any child units
  367.  
  368.          Item := First (Context_Items (Comp_Unit_Node));
  369.  
  370.          while Present (Item) loop
  371.             if Nkind (Item) = N_With_Clause
  372.               and then Nkind (Name (Item)) /= N_Identifier
  373.             then
  374.                Error_Msg_N ("(Ada 83) child units not allowed", Item);
  375.             end if;
  376.  
  377.             Item := Next (Item);
  378.          end loop;
  379.  
  380.          --  Check that we did not have a PRIVATE keyword present
  381.  
  382.          if Private_Present (Comp_Unit_Node) then
  383.             Error_Msg
  384.               ("(Ada 83) private units not allowed", Private_Sloc);
  385.          end if;
  386.       end if;
  387.  
  388.       --  If no serious error, then output possible unit information line
  389.  
  390.       if not Cunit_Error_Flag
  391.         and then List_Units
  392.         and then Operating_Mode = Check_Syntax
  393.       then
  394.          Unit_Display (Comp_Unit_Node, Cunit_Location);
  395.       end if;
  396.  
  397.       --  And now we should be at the end of file, except that if we had to
  398.       --  scan for a compilation unit, then we don't check this, since it
  399.       --  seems in practice to often make things worse, and we already gave
  400.       --  a serious error message.
  401.  
  402.       if Token /= Tok_EOF and then not Cunit_Error_Flag then
  403.  
  404.          --  If we are not at end of file, then fatal error unless we are
  405.          --  syntax checking only mode, where we do allow additional units
  406.          --  by making a recursive call to this routine. Skip this message
  407.          --  if we already had some fatal error.
  408.  
  409.          if Operating_Mode = Check_Syntax then
  410.             return P_Compilation_Unit;
  411.  
  412.          else
  413.             if not Fatal_Error (Current_Source_Unit) then
  414.  
  415.                if Token in Token_Class_Cunit then
  416.                   Error_Msg_SC
  417.                     ("end of file expected, " &
  418.                      "file can have only one compilation unit");
  419.  
  420.                else
  421.                   Error_Msg_SC ("end of file expected");
  422.                end if;
  423.             end if;
  424.  
  425.             return Error;
  426.          end if;
  427.  
  428.       --  This is the normal return
  429.  
  430.       else
  431.          return Comp_Unit_Node;
  432.       end if;
  433.  
  434.    exception
  435.  
  436.       --  An error resync is a serious bomb, so indicate result unit no good
  437.  
  438.       when Error_Resync =>
  439.          Set_Fatal_Error (Current_Source_Unit);
  440.          return Error;
  441.  
  442.    end P_Compilation_Unit;
  443.  
  444.    --------------------------
  445.    -- 10.1.1  Library Item --
  446.    --------------------------
  447.  
  448.    --  Parsed by P_Compilation_Unit (10.1.1)
  449.  
  450.    --------------------------------------
  451.    -- 10.1.1  Library Unit Declaration --
  452.    --------------------------------------
  453.  
  454.    --  Parsed by P_Compilation_Unit (10.1.1)
  455.  
  456.    ------------------------------------------------
  457.    -- 10.1.1  Library Unit Renaming Declaration  --
  458.    ------------------------------------------------
  459.  
  460.    --  Parsed by P_Compilation_Unit (10.1.1)
  461.  
  462.    -------------------------------
  463.    -- 10.1.1  Library Unit Body --
  464.    -------------------------------
  465.  
  466.    --  Parsed by P_Compilation_Unit (10.1.1)
  467.  
  468.    ------------------------------
  469.    -- 10.1.1  Parent Unit Name --
  470.    ------------------------------
  471.  
  472.    --  Parsed (as a name) by its parent construct
  473.  
  474.    ----------------------------
  475.    -- 10.1.2  Context Clause --
  476.    ----------------------------
  477.  
  478.    --  CONTEXT_CLAUSE ::= {CONTEXT_ITEM}
  479.  
  480.    --  CONTEXT_ITEM ::= WITH_CLAUSE | USE_CLAUSE
  481.  
  482.    --  WITH_CLAUSE ::=
  483.    --    with library_unit_NAME {,library_unit_NAME};
  484.  
  485.    --  Error recovery: Cannot raise Error_Resync
  486.  
  487.    function P_Context_Clause return List_Id is
  488.       Item_List  : List_Id;
  489.       Scan_State : Saved_Scan_State;
  490.       With_Node  : Node_Id;
  491.       Id_Node    : Node_Id;
  492.       First_Flag : Boolean;
  493.  
  494.    begin
  495.       Item_List := New_List;
  496.  
  497.       --  Get keyword casing from WITH keyword in case not set yet
  498.  
  499.       if Token = Tok_With then
  500.          Set_Keyword_Casing (Current_Source_File, Determine_Token_Casing);
  501.       end if;
  502.  
  503.       --  Loop through context items
  504.  
  505.       loop
  506.          if Style_Check then Style.Check_Indentation; end if;
  507.  
  508.          --  Gather any pragmas appearing in the context clause
  509.  
  510.          P_Pragmas_Opt (Item_List);
  511.  
  512.          --  Processing for WITH clause
  513.  
  514.          if Token = Tok_With then
  515.             Scan; -- past WITH
  516.             First_Flag := True;
  517.  
  518.             --  Loop through names in one with clause, generating a separate
  519.             --  N_With_Clause node for each nam encountered.
  520.  
  521.             loop
  522.                With_Node := New_Node (N_With_Clause, Token_Ptr);
  523.                Append (With_Node, Item_List);
  524.  
  525.                --  Note that we allow with'ing of child units, even in Ada 83
  526.                --  mode, since presumably if this is not desired, then the
  527.                --  compilation of the child unit itself is the place where
  528.                --  such an "error" should be caught.
  529.  
  530.                Set_Name (With_Node, P_Qualified_Simple_Name);
  531.                Set_First_Name (With_Node, First_Flag);
  532.                First_Flag := False;
  533.                exit when Token /= Tok_Comma;
  534.                Scan; -- past comma
  535.             end loop;
  536.  
  537.             Set_Last_Name (With_Node, True);
  538.             TF_Semicolon;
  539.  
  540.  
  541.          --  Processing for USE clause
  542.  
  543.          elsif Token = Tok_Use then
  544.             Append (P_Use_Clause, Item_List);
  545.  
  546.          --  Anything else is end of context clause
  547.  
  548.          else
  549.             exit;
  550.          end if;
  551.       end loop;
  552.  
  553.       return Item_List;
  554.    end P_Context_Clause;
  555.  
  556.    --------------------------
  557.    -- 10.1.2  Context Item --
  558.    --------------------------
  559.  
  560.    --  Parsed by P_Context_Clause (10.1.2)
  561.  
  562.    -------------------------
  563.    -- 10.1.2  With Clause --
  564.    -------------------------
  565.  
  566.    --  Parsed by P_Context_Clause (10.1.2)
  567.  
  568.    -----------------------
  569.    -- 10.1.3  Body Stub --
  570.    -----------------------
  571.  
  572.    --  Subprogram stub parsed by P_Subprogram (6.1)
  573.    --  Package stub parsed by P_Package (7.1)
  574.    --  Task stub parsed by P_Task (9.1)
  575.    --  Protected stub parsed by P_Protected (9.4)
  576.  
  577.    ----------------------------------
  578.    -- 10.1.3  Subprogram Body Stub --
  579.    ----------------------------------
  580.  
  581.    --  Parsed by P_Subprogram (6.1)
  582.  
  583.    -------------------------------
  584.    -- 10.1.3  Package Body Stub --
  585.    -------------------------------
  586.  
  587.    --  Parsed by P_Package (7.1)
  588.  
  589.    ----------------------------
  590.    -- 10.1.3  Task Body Stub --
  591.    ----------------------------
  592.  
  593.    --  Parsed by P_Task (9.1)
  594.  
  595.    ---------------------------------
  596.    -- 10.1.3  Protected Body Stub --
  597.    ---------------------------------
  598.  
  599.    --  Parsed by P_Protected (9.4)
  600.  
  601.    ---------------------
  602.    -- 10.1.3  Subunit --
  603.    ---------------------
  604.  
  605.    --  SUBUNIT ::= separate (PARENT_UNIT_NAME) PROPER_BODY
  606.  
  607.    --  PARENT_UNIT_NAME ::= NAME
  608.  
  609.    --  The caller has checked that the initial token is SEPARATE
  610.  
  611.    --  Error recovery: cannot raise Error_Resync
  612.  
  613.    function P_Subunit return Node_Id is
  614.       Subunit_Node : Node_Id;
  615.       Body_Node    : Node_Id;
  616.  
  617.    begin
  618.       Subunit_Node := New_Node (N_Subunit, Token_Ptr);
  619.       Body_Node := Error; -- in case no good body found
  620.       Scan; -- past SEPARATE;
  621.  
  622.       T_Left_Paren;
  623.       Set_Name (Subunit_Node, P_Qualified_Simple_Name);
  624.       T_Right_Paren;
  625.  
  626.       if Token = Tok_Semicolon then
  627.          Error_Msg_SC ("unexpected semicolon ignored");
  628.          Scan;
  629.       end if;
  630.  
  631.       if Token = Tok_Function or else Token = Tok_Procedure then
  632.          Body_Node := P_Subprogram (Pf_Pbod);
  633.  
  634.       elsif Token = Tok_Package then
  635.          Body_Node := P_Package (Pf_Pbod);
  636.  
  637.       elsif Token = Tok_Protected then
  638.          Scan; -- past PROTECTED
  639.  
  640.          if Token = Tok_Body then
  641.             Body_Node := P_Protected;
  642.          else
  643.             Error_Msg_AP ("BODY expected");
  644.             return Error;
  645.          end if;
  646.  
  647.       elsif Token = Tok_Task then
  648.          Scan; -- past TASK
  649.  
  650.          if Token = Tok_Body then
  651.             Body_Node := P_Task;
  652.          else
  653.             Error_Msg_AP ("BODY expected");
  654.             return Error;
  655.          end if;
  656.  
  657.       else
  658.          Error_Msg_SC ("proper body expected");
  659.          return Error;
  660.       end if;
  661.  
  662.       Set_Proper_Body  (Subunit_Node, Body_Node);
  663.       return Subunit_Node;
  664.  
  665.    end P_Subunit;
  666.  
  667.    ------------------
  668.    -- Unit_Display --
  669.    ------------------
  670.  
  671.    procedure Unit_Display (Cunit : Node_Id; Loc : Source_Ptr) is
  672.       Unum : constant Unit_Number_Type    := Get_Cunit_Unit_Number (Cunit);
  673.       Sind : constant Source_File_Index   := Source_Index (Unum);
  674.       Line : constant Logical_Line_Number := Get_Line_Number (Loc);
  675.       Unam : constant Unit_Name_Type      := Unit_Name (Unum);
  676.  
  677.    begin
  678.       if List_Units then
  679.          Write_Str ("Unit ");
  680.          Write_Unit_Name (Unit_Name (Unum));
  681.          Write_Str (" line ");
  682.          Write_Int (Int (Line));
  683.  
  684.          Write_Str (", file offset ");
  685.          Write_Int (Int (Loc) - Int (Source_Text (Sind)'First));
  686.  
  687.          Write_Str (", file name ");
  688.          Write_Name (Get_File_Name (Unam));
  689.          Write_Eol;
  690.       end if;
  691.    end Unit_Display;
  692.  
  693. end Ch10;
  694.