------------------------------------------------------------------------------
--                                                                          --
--                           POLYORB COMPONENTS                             --
--                                                                          --
--                               P A R S E R                                --
--                                                                          --
--                                 B o d y                                  --
--                                                                          --
--         Copyright (C) 2005-2017, Free Software Foundation, Inc.          --
--                                                                          --
-- This 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.  This software is distributed in the hope  that it will be useful, --
-- but WITHOUT ANY WARRANTY;  without even the implied warranty of MERCHAN- --
-- TABILITY 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 and    --
-- a copy of the GCC Runtime Library Exception along with this program;     --
-- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
-- <http://www.gnu.org/licenses/>.                                          --
--                                                                          --
--                  PolyORB is maintained by AdaCore                        --
--                     (email: sales@adacore.com)                           --
--                                                                          --
------------------------------------------------------------------------------

with GNAT.Directory_Operations;
with GNAT.Table;
with GNAT.OS_Lib;       use GNAT.OS_Lib;

with Errors;       use Errors;
with Namet;        use Namet;
with Scopes;
with Values;       use Values;

with Frontend.Nodes;  use Frontend.Nodes;
with Frontend.Nutils; use Frontend.Nutils;

package body Parser is

   package FEN renames Frontend.Nodes;

   Specification : Node_Id;

   procedure Declare_Base_Type (L : Token_List_Type; K : Node_Kind);
   --  L denotes a token list used to name an IDL base type. Allocate
   --  a node for it and associate it to the concatenated names.

   function Is_Param_Type_Spec (E : Node_Id) return Boolean;
   --  Return true when the type specifier N belongs to the restricted
   --  parameter type specifier set.

   function Locate_Imported_File (Scoped_Name : Node_Id) return Name_Id;
   --  Locate the IDL file corresponding to the imported scope.

   procedure Skip_Annapp_Scan_Token (T : Token_Type := T_Error);
   --  Similar to Scan_Token but skip any annotation applications that
   --  may exist at the scanner's current location.
   --  The optional parameter T is the expected token type.
   --  If left at its default (T_Error), no specific token type is
   --  expected and T will not be used.
   --  The subprogram may be renamed to Save_Annapp_Scan_Token or similar
   --  once annotation applications are evaluated.

   procedure Skip_Annapp_Scan_Token (State : in out Location);
   --  Similar to above but update the given scanner state on skipping
   --  annotation applications.

   function Skip_Annapp_Next_Token return Token_Type;
   --  Similar to Next_Token but skip any annotation applications that
   --  may exist at the scanner's current location, advancing the scanner
   --  location while this is the case.
   --  The subprogram may be renamed to Save_Annapp_Next_Token or similar
   --  once annotation applications are evaluated.

   Sequencing_Level : Natural := 0;

   function P_No_Such_Node return Node_Id;
   pragma Unreferenced (P_No_Such_Node);

   procedure P_Specification (Imported : Boolean := False);

   function P_Attribute_Declaration return Node_Id;
   function P_Constant_Declaration return Node_Id;
   function P_Constant_Expression
     (Optional : Boolean := False;
      First_Of_Range : Boolean := False) return Node_Id;
   --  First_Of_Range is True for the first expression in a range pragma. This
   --  is needed to correctly parse negative numbers, because the preceding
   --  token is T_Identifier (the type name). Otherwise, it thinks "-" is a
   --  binary operator.
   function P_Constant_Type return Node_Id;
   function P_Declarator return Node_Id;
   function P_Declarator_List return List_Id;
   function P_Definition return Node_Id;
   function P_Enumeration_Type return Node_Id;
   function P_Exception_Declaration return Node_Id;
   function P_Exception_List return List_Id;
   function P_Export return Node_Id;
   function P_Fixed_Point_Type return Node_Id;
   function P_Identifier return Node_Id;
   function P_Import return Node_Id;
   function P_Initializer_Declaration return Node_Id;
   function P_Interface return Node_Id;
   function P_Interface_Declaration return Node_Id;
   function P_Interface_Name return Node_Id;
   function P_Member return Node_Id;
   function P_Module return Node_Id;
   function P_Operation_Declaration return Node_Id;
   function P_Parameter_Declaration return Node_Id;
   function P_Pragma return Node_Id;
   function P_Scoped_Name return Node_Id;
   function P_Sequence_Type return Node_Id;
   function P_Simple_Declarator return Node_Id;
   function P_Simple_Type_Spec return Node_Id;
   function P_State_Member return Node_Id;
   function P_Structure_Type return Node_Id;
   function P_String_Type return Node_Id;
   function P_Type_Declaration return Node_Id;
   function P_Type_Id_Declaration return Node_Id;
   function P_Type_Prefix_Declaration return Node_Id;
   function P_Type_Spec return Node_Id;
   function P_Union_Type return Node_Id;
   function P_Value return Node_Id;
   function P_Value_Abstract_Declaration return Node_Id;
   function P_Value_Box_Declaration return Node_Id;
   function P_Value_Declaration return Node_Id;
   function P_Value_Forward_Declaration return Node_Id;
   function P_Value_Spec return Node_Id;

   package Expressions is new GNAT.Table (Node_Id, Natural, 1, 100, 10);

   Preferences : constant array (T_Tilde .. T_Less_Less) of Natural
     := (T_Tilde            => 0,
         T_Percent          => 1,
         T_Slash            => 2,
         T_Star             => 3,
         T_Minus            => 4,
         T_Plus             => 5,
         T_Less_Less        => 6,
         T_Greater_Greater  => 7,
         T_Ampersand        => 8,
         T_Circumflex       => 9,
         T_Bar              => 10);

   -----------------------
   -- Declare_Base_Type --
   -----------------------

   procedure Declare_Base_Type (L : Token_List_Type; K : Node_Kind) is
      E : Node_Id;
      N : Name_Id;
   begin

      --  Create a fake node located at the beginning of the
      --  specification (current token location).

      E := New_Node (K, No_Location);

      --  Accumulate token names and store node id as table info

      Set_Str_To_Name_Buffer (Image (L (L'First)));
      for I in L'First + 1 .. L'Last loop
         Add_Char_To_Name_Buffer (' ');
         Add_Str_To_Name_Buffer (Image (L (I)));
      end loop;
      N := Name_Find;
      Set_Name_Table_Info (N, Int (E));
      Set_Image (Base_Type (E), N);
   end Declare_Base_Type;

   ------------------------
   -- Is_Param_Type_Spec --
   ------------------------

   --  (95) <param_type_spec> ::= <base_type_spec>
   --                           | <string_type>
   --                           | <wide_string_type>
   --                           | <scoped_name>

   function Is_Param_Type_Spec (E : Node_Id) return Boolean is
   begin
      case Kind (E) is
         when K_Float
           | K_Double
           | K_Long_Double
           | K_Short
           | K_Long
           | K_Long_Long
           | K_Unsigned_Short
           | K_Unsigned_Long
           | K_Unsigned_Long_Long
           | K_Char
           | K_Wide_Char
           | K_Boolean
           | K_Any
           | K_Object
           | K_Octet
           | K_Value_Base
           | K_String
           | K_Wide_String
           | K_String_Type
           | K_Wide_String_Type
           | K_Scoped_Name =>
            return True;

         when others =>
            return False;
      end case;
   end Is_Param_Type_Spec;

   --------------------------
   -- Locate_Imported_File --
   --------------------------

   function Locate_Imported_File (Scoped_Name : Node_Id) return Name_Id is
      pragma Assert (Kind (Scoped_Name) = K_Scoped_Name);

      --  Whatever the nature of the scoped name is (::X, ::X::Y::Z, X::Y...),
      --  the file name is deduced from the deepest parent entity

      Parent            : Node_Id := Parent_Entity (Scoped_Name);
      Parent_Enity_Name : Name_Id := IDL_Name (Identifier (Scoped_Name));
   begin
      while Present (Parent) loop
         if IDL_Name (Identifier (Parent)) /= No_Name then
            Parent_Enity_Name := IDL_Name (Identifier (Parent));
         end if;
         Parent := Parent_Entity (Parent);
      end loop;

      Get_Name_String (Parent_Enity_Name);

      --  Handling the particular cases :
      --   CORBA module is declared in the orb.idl file

      if Name_Buffer (1 .. Name_Len) = "CORBA" then
         Set_Str_To_Name_Buffer ("orb");
      end if;

      --  Adding the file suffix
      Add_Str_To_Name_Buffer (".idl");

      --  Locating the file in the IAC_Search_Paths set

      declare
         File_Name_Str : constant String := Name_Buffer (1 .. Name_Len);
      begin
         for P of IAC_Search_Paths loop
            declare
               Full_Path : constant String
                 := P.all
                 & GNAT.Directory_Operations.Dir_Separator
                 & File_Name_Str;
            begin
               if Is_Regular_File (Full_Path) then
                  Set_Str_To_Name_Buffer (Full_Path);
                  return Name_Find;
               end if;
            end;
         end loop;
      end;

      return No_Name;
   end Locate_Imported_File;

   ----------------------------
   -- Skip_Annapp_Scan_Token --
   ----------------------------

   procedure Skip_Annapp_Scan_Token (T : Token_Type := T_Error) is
      Ann_Name : Node_Id := No_Node;
   begin
      loop
         exit when Next_Token /= T_At;
         Scan_Token; --  past T_At
         Ann_Name := P_Scoped_Name;
         if No (Ann_Name) then
            return;
         end if;

         if Next_Token = T_Left_Paren then
            Scan_Token;
            declare
               Parentheses : Integer := 1;
            begin
               loop
                  case Next_Token is
                     when T_EOF =>
                        exit;
                     when T_Left_Paren =>
                        Parentheses := Parentheses + 1;
                     when T_Right_Paren =>
                        exit when Parentheses <= 0;
                        Parentheses := Parentheses - 1;
                     when others =>
                        exit when Parentheses <= 0;
                  end case;
                  Scan_Token;
               end loop;
            end;
         end if;
      end loop;

      --  T = T_Error means no specific token expected / do not use T

      if T = T_Error then
         Scan_Token;
      else
         Scan_Token (T);
      end if;
   end Skip_Annapp_Scan_Token;

   ----------------------------
   -- Skip_Annapp_Scan_Token --
   ----------------------------

   procedure Skip_Annapp_Scan_Token (State : in out Location) is
      Ann_Name : Node_Id := No_Node;
   begin
      Scan_Token;
      loop
         exit when Token /= T_At;
         Ann_Name := P_Scoped_Name;
         if No (Ann_Name) then
            return;
         end if;
         Save_Lexer (State);
         Scan_Token;
         if Token = T_Left_Paren then
            declare
               Parentheses : Integer := 1;
            begin
               loop
                  Save_Lexer (State);
                  Scan_Token;
                  exit when Token = T_EOF;
                  if Token = T_Left_Paren then
                     Parentheses := Parentheses + 1;
                  elsif Token = T_Right_Paren then
                     exit when Parentheses <= 0;
                     Parentheses := Parentheses - 1;
                  else
                     exit when Parentheses <= 0;
                  end if;
               end loop;
            end;
         end if;
      end loop;
   end Skip_Annapp_Scan_Token;

   ----------------------------
   -- Skip_Annapp_Next_Token --
   ----------------------------

   function Skip_Annapp_Next_Token return Token_Type is
      Next : Token_Type;
      Ann_Name : Node_Id := No_Node;
   begin
      loop
         Next := Next_Token;
         exit when Next /= T_At;
         Scan_Token;  --  past '@'
         Ann_Name := P_Scoped_Name;
         if No (Ann_Name) then
            return T_Error;
         end if;
         Next := Next_Token;
         if Next = T_Left_Paren then
            Scan_Token;  --  past '('
            declare
               Parentheses : Integer := 1;
            begin
               loop
                  Next := Next_Token;
                  exit when Next = T_EOF;
                  if Next = T_Left_Paren then
                     Parentheses := Parentheses + 1;
                  elsif Next = T_Right_Paren then
                     exit when Parentheses <= 0;
                     Parentheses := Parentheses - 1;
                  else
                     exit when Parentheses <= 0;
                  end if;
               end loop;
            end;
         end if;
      end loop;
      return Next;
   end Skip_Annapp_Next_Token;

   -----------------------------
   -- P_Attribute_Declaration --
   -----------------------------

   --  (85) <attr_dcl> ::= <readonly_attr_spec>
   --                  | <attr_spec>

   --  (104) <readonly_attr_spec> ::= "readonly" "attribute" <param_type_spec>
   --                                 <readonly_attr_declarator>

   --  (105) <readonly_attr_declarator > ::= <simple_declarator> <raises_expr>
   --                                    |   <simple_declarator>
   --                                        { "," <simple_declarator> }*

   --  (106) <attr_spec> ::= "attribute" <param_type_spec>
   --                        <attr_declarator>

   --  (107) <attr_declarator> ::= <simple_declarator> <attr_raises_expr>
   --                          |   <simple_declarator>
   --                              { "," <simple_declarator> }*

   --  (108) <attr_raises_expr> ::= <get_excep_expr> [ <set_excep_expr> ]
   --                           | <set_excep_expr>

   function P_Attribute_Declaration return Node_Id is
      Attribute_Decl  : Node_Id;
      Attr_Type_Spec  : Node_Id;
      Is_Readonly     : Boolean := False;
      Declarators     : List_Id;
      Declarator      : Node_Id;
      Getter_Excps    : List_Id := No_List;
      Setter_Excps    : List_Id := No_List;

   begin
      Skip_Annapp_Scan_Token; --  past "readonly" or "attribute"

      if Token = T_Readonly then
         Is_Readonly := True;
         Scan_Token (T_Attribute);
         if Token = T_Error then
            return No_Node;
         end if;
      end if;

      --  Read general type specifier

      Attr_Type_Spec := P_Type_Spec;
      if No (Attr_Type_Spec) then
         return No_Node;
      end if;

      --  Check that the type specifier follows the restriction of the
      --  parameter type specifier.

      if not Is_Param_Type_Spec (Attr_Type_Spec) then
         Error_Loc (1) := Loc (Attr_Type_Spec);
         DE ("incorrect attribute type spec");
         return No_Node;
      end if;

      Declarators := P_Declarator_List;
      if Is_Empty (Declarators) then
         return No_Node;
      end if;

      --  Parsing the exception list of the attribute :
      --  According to the CORBA 3.0 IDL grammar (rules 105 and 107), only
      --  attributes that have one single declarator can throw exceptions.
      --  This limitation is not justifyed in the CORBA Spec.
      --  In IAC, we accept that attributes that have more than one declarator
      --  throw exceptions

      --  Case of a readonly attribute :

      if Next_Token = T_Raises then
         if not Is_Readonly then
            Error_Loc (1) := Token_Location;
            DE ("Key word 'raises' not allowed for read-write attributes");
            return No_Node;
         end if;

         Getter_Excps := P_Exception_List;
         if Getter_Excps = No_List then
            return No_Node;
         end if;
      end if;

      --  Case of read-write attributes

      if Next_Token = T_Get_Raises then
         if Is_Readonly then
            Error_Loc (1) := Token_Location;
            DE ("Key word 'getraises' not allowed for readonly attributes");
            return No_Node;
         end if;
         Getter_Excps := P_Exception_List;
         if Getter_Excps = No_List then
            return No_Node;
         end if;
      end if;

      if Next_Token = T_Set_Raises then
         if Is_Readonly then
            Error_Loc (1) := Token_Location;
            DE ("Key word 'setraises' not allowed for readonly attributes");
            return No_Node;
         end if;
         Setter_Excps := P_Exception_List;
         if Setter_Excps = No_List then
            return No_Node;
         end if;
      end if;

      Attribute_Decl := New_Node (K_Attribute_Declaration,
                                    Loc (Attr_Type_Spec));
      Set_Is_Readonly (Attribute_Decl, Is_Readonly);
      Set_Type_Spec   (Attribute_Decl, Attr_Type_Spec);
      Set_Declarators (Attribute_Decl, Declarators);
      Bind_Declarators_To_Entity (Declarators, Attribute_Decl);
      Set_Getter_Exceptions (Attribute_Decl, Getter_Excps);
      Set_Setter_Exceptions (Attribute_Decl, Setter_Excps);

      Declarator := First_Entity (Declarators);
      while Present (Declarator) loop
         if Kind (Declarator) /= K_Simple_Declarator then
            Error_Loc (1) := Loc (Declarator);
            DE ("incorrect attribute declarator");
            return No_Node;
         end if;
         Declarator := Next_Entity (Declarator);
      end loop;

      return Attribute_Decl;
   end P_Attribute_Declaration;

   ----------------------------
   -- P_Constant_Declaration --
   ----------------------------

   --  (27) <const_dcl> ::= "const" <const_type> <identifier> "=" <const_exp>

   function P_Constant_Declaration return Node_Id is
      Constant_Decl   : Node_Id;
      Const_Type_Spec : Node_Id;
      Const_Expr      : Node_Id;
   begin
      Scan_Token; --  past "const"

      Const_Type_Spec := P_Constant_Type;
      if No (Const_Type_Spec) then
         return No_Node;
      end if;

      Constant_Decl := P_Simple_Declarator;
      if No (Constant_Decl) then
         return No_Node;
      end if;

      Set_Kind (Constant_Decl, K_Constant_Declaration);
      Set_Type_Spec (Constant_Decl, Const_Type_Spec);

      Scan_Token (T_Equal);
      if Token = T_Error then
         return No_Node;
      end if;

      Const_Expr := P_Constant_Expression;
      if No (Const_Expr) then
         return No_Node;
      end if;
      Set_Expression (Constant_Decl, Const_Expr);

      return Constant_Decl;
   end P_Constant_Declaration;

   ---------------------------
   -- P_Constant_Expression --
   ---------------------------

   --  (29) <const_exp> ::= <or_expr>
   --  (30) <or_expr> ::= <xor_expr>
   --                   | <or_expr> "|" <xor_expr>

   --  (31) <xor_expr> ::= <and_expr>
   --                    | <xor_expr> "^" <and_expr>

   --  (32) <and_expr> ::= <shift_expr>
   --                    | <and_expr> "&" <shift_expr>

   --  (33) <shift_expr> ::= <add_expr>
   --                      | <shift_expr> ">>" <add_expr>
   --                      | <shift_expr> "<<" <add_expr>

   --  (34) <add_expr> ::= <mult_expr>
   --                    | <add_expr> "+" <mult_expr>
   --                    | <add_expr> "-" <mult_expr>

   --  (35) <mult_expr> ::= <unary_expr>
   --                     | <mult_expr> "*" <unary_expr>
   --                     | <mult_expr> "/" <unary_expr>
   --                     | <mult_expr> "%" <unary_expr>

   --  (36) <unary_expr> ::= <unary_operator> <primary_expr>
   --                      | <primary_expr>

   --  (37) <unary_operator> ::= "-"
   --                          | "+"
   --                          | "~"

   --  (38) <primary_expr> ::= <scoped_name>
   --                        | <literal>
   --                        | "(" <const_exp> ")"

   function P_Constant_Expression
     (Optional : Boolean := False;
      First_Of_Range : Boolean := False) return Node_Id is
      use Expressions;

      --  There are two kinds of expressions. A binary operator has two inner
      --  expressions (left and right). When the right expression is assigned
      --  and not the left one, the operator is a unary operator and this
      --  expression is considered as an expression value. When both inner
      --  expressions are assigned, this is also an expression value. An
      --  operator is a binary operator when at least the right expression is
      --  not assigned. An expression value can be an operator with at least a
      --  right expression assigned or a literal or a scoped name.

      function Is_Expression_Completed return Boolean;
      --  Return True when there are no more token to read to complete the
      --  current expression.

      function P_Expression_Part return Node_Id;
      --  LP: Cannot parse comment???
      --  Return a node describing an expression. It is either a binary
      --  operator (an operator with no right expression assigned) or an
      --  expression value (a scoped name, a literal or an expression with an
      --  unary operator - that is a binary operator with a right inner
      --  expression and no left inner expression - or an expression with both
      --  inner expressions assigned). Note that whether an operator is a
      --  binary or unary operator is resolved in this routine. For a unary
      --  operator, we check that the previous token was a binary operator.

      function Is_Binary_Operator (E : Node_Id) return Boolean;
      --  Return True when N is an operator with the right expression still not
      --  assigned. Otherwise, an operator with a right expression is a value
      --  expression.

      function Is_Expression_Value (E : Node_Id) return Boolean;
      --  Return True when N is not an operator (literal or scoped name) or
      --  else when its right expression is assigned (unary operator).

      function Precede (L, R : Node_Id) return Boolean;
      --  True if operator L has precedence over operator R

      procedure Exp_Err_Msg;
      --  Output a generic error message

      -----------------
      -- Exp_Err_Msg --
      -----------------

      procedure Exp_Err_Msg is
      begin
         DE ("cannot parse expression");
      end Exp_Err_Msg;

      -----------------------------
      -- Is_Expression_Completed --
      -----------------------------

      function Is_Expression_Completed return Boolean is
         T : constant Token_Type := Next_Token;
      begin
         return T not in Literal_Type
           and then T /= T_Identifier
           and then T /= T_Colon_Colon
           and then T /= T_Left_Paren
           and then T not in Operator_Type;
      end Is_Expression_Completed;

      -------------------------
      -- Is_Expression_Value --
      -------------------------

      function Is_Expression_Value (E : Node_Id) return Boolean is
      begin
         return Kind (E) in K_Integer_Literal .. K_Boolean_Literal
           or else Kind (E) = K_Scoped_Name
           or else (Operator (E) in Unary_Operator_Type
                      and then Present (Right_Expr (E)))
           or else (Operator (E) in Binary_Operator_Type
                      and then Present (Left_Expr  (E))
                      and then Present (Right_Expr (E)));
      end Is_Expression_Value;

      ------------------------
      -- Is_Binary_Operator --
      ------------------------

      function Is_Binary_Operator (E : Node_Id) return Boolean is
      begin
         return Kind (E) = K_Expression
           and then Operator (E) in Binary_Operator_Type
           and then No (Right_Expr (E));
      end Is_Binary_Operator;

      -----------------------
      -- P_Expression_Part --
      -----------------------

      function P_Expression_Part return Node_Id
      is
         Expression     : Node_Id := No_Node;
         Right_Expr     : Node_Id;
         Previous_Token : Token_Type;
      begin
         case Next_Token is
            when T_Identifier
               | T_Colon_Colon =>

               --  Look for a scoped name

               Expression := P_Scoped_Name;
               if No (Expression) then
                  return No_Node;
               end if;

            when T_Left_Paren =>

               --  Look for a parenthesized expression value

               Scan_Token;  --  past '('
               Expression := P_Constant_Expression;

               Scan_Token (T_Right_Paren);
               if Token = T_Error then
                  return No_Node;
               end if;

            when T_Integer_Literal        =>
               Scan_Token;  --  past literal
               Expression := New_Node (K_Integer_Literal, Token_Location);
               Set_Value
                 (Expression,
                  New_Integer_Value (Value => Integer_Literal_Value,
                                     Sign  => 1,
                                     Base  => Integer_Literal_Base));

            when T_Fixed_Point_Literal    =>
               Scan_Token;  --  past literal
               Expression := New_Node (K_Fixed_Point_Literal, Token_Location);
               Set_Value
                 (Expression,
                  New_Fixed_Point_Value
                    (Value => Integer_Literal_Value,
                     Sign  => 1,
                     Total => Unsigned_Short_Short (Name_Len),
                     Scale => Decimal_Point_Position));

            when T_Boolean_Literal    =>
               Scan_Token;  --  past literal
               Expression := New_Node (K_Boolean_Literal, Token_Location);
               Set_Value
                 (Expression,
                  New_Boolean_Value (Value => (Integer_Literal_Value = 1)));

            when T_Floating_Point_Literal =>
               Scan_Token;  --  past literal
               Expression :=
                 New_Node (K_Floating_Point_Literal, Token_Location);
               Set_Value
                 (Expression,
                  New_Floating_Point_Value (Float_Literal_Value));

            when T_Character_Literal
               | T_Wide_Character_Literal =>
               Scan_Token;  --  past literal
               if Character_Literal_Value /= Incorrect_Character then
                  Expression := New_Node (K_Character_Literal, Token_Location);
                  Set_Value
                    (Expression,
                     New_Character_Value
                       (Character_Literal_Value,
                        Wide => Token /= T_Character_Literal));
               end if;

            when T_String_Literal
              |  T_Wide_String_Literal =>
               Scan_Token;  --  past literal
               if String_Literal_Value /= Incorrect_String then
                  Expression := New_Node (K_String_Literal, Token_Location);
                  Set_Value
                    (Expression,
                     New_String_Value
                       (String_Literal_Value,
                        Wide => Token /= T_String_Literal));
               end if;

            when T_Tilde .. T_Less_Less =>

               --  Look for a binary/unary operator

               Previous_Token := Token;
               Scan_Token;  --  past binary/unary operator

               Expression := New_Node (K_Expression, Token_Location);
               Set_Operator (Expression, Token);

               --  Token is a real unary operator. Normally, if we see "X -",
               --  the "-" is a binary operator. However if First_Of_Range is
               --  True, it is a unary operator, because in that case X is the
               --  subtype name, as in:
               --
               --     #pragma range X -1 .. 10

               if Token = T_Tilde
                 or else (Token in T_Minus .. T_Plus
                            and then
                            ((not Is_Literal (Previous_Token)
                              and then not Is_Scoped_Name (Previous_Token)
                              and then Previous_Token /= T_Right_Paren)
                             or else First_Of_Range))
               then
                  case Next_Token is
                     when T_Identifier
                        | T_Colon_Colon
                        | T_Left_Paren
                        | Literal_Type =>

                        --  Look for an expression value (a scoped name, a
                        --  literal or a parenthesized expression).

                        Right_Expr := P_Constant_Expression;
                        if No (Right_Expr) then
                           Error_Loc (1) := Loc (Expression);
                           Exp_Err_Msg;
                           return No_Node;
                        end if;
                        Set_Right_Expr (Expression, Right_Expr);

                     when others =>
                        Unexpected_Token (Token, "expression");
                        return No_Node;
                  end case;

               --  Cannot have two operators in sequence except in the special
               --  case above.

               elsif Is_Operator (Previous_Token) then
                  Unexpected_Token (Token, "expression");
                  return No_Node;
               end if;

            when others =>
               if not Optional then
                  Error_Loc (1) := Token_Location;
                  Exp_Err_Msg;
               end if;
               return No_Node;
         end case;

         return Expression;
      end P_Expression_Part;

      -------------
      -- Precede --
      -------------

      function Precede (L, R : Node_Id) return Boolean is
         Op_L : constant Token_Type := Operator (L);
         Op_R : constant Token_Type := Operator (R);
      begin
         return Preferences (Op_L) <= Preferences (Op_R);
      end Precede;

      Expr     : Node_Id;
      First    : Natural;

   --  Start of processing for P_Constant_Expression

   begin
      --  Read enough expressions to push as first expression a binary operator
      --  with no right expression

      Expr := P_Expression_Part;
      if No (Expr) then
         return No_Node;
      end if;

      --  We must have first an expression value

      if Is_Binary_Operator (Expr) then
         Error_Loc (1) := Loc (Expr);
         Exp_Err_Msg;
         return No_Node;
      end if;

      --  We have only one expression value

      if Is_Expression_Completed then
         return Expr;
      end if;

      Increment_Last;
      Table (Last) := Expr;
      First := Last;

      Expr := P_Expression_Part;
      if No (Expr) then
         Set_Last (First - 1);
         return No_Node;
      end if;

      --  We must have a binary operator as the first expression in an
      --  expression value.

      if not Is_Binary_Operator (Expr) then
         Error_Loc (1) := Loc (Expr);
         Exp_Err_Msg;
         Set_Last (First - 1);
         return No_Node;
      end if;

      Set_Left_Expr (Expr, Table (Last));
      Table (Last) := Expr;

      --  Push expressions on stack and check that the top of the stack
      --  consists of one or more binary operators with no right expr and zero
      --  or one expression value.

      while not Is_Expression_Completed loop
         Expr := P_Expression_Part;
         if No (Expr) then
            return No_Node;
         end if;

         Increment_Last;
         Table (Last) := Expr;

         --  Check that this new expression is not a binary operator when the
         --  previous one is a binary operator with no right expression.

         if First < Last
           and then Is_Binary_Operator (Expr)
           and then No (Left_Expr (Expr))
           and then Is_Binary_Operator (Table (Last - 1))
         then
            Error_Loc (1) := Loc (Expr);
            Exp_Err_Msg;
            Set_Last (First - 1);
            return No_Node;
         end if;

         --  Check whether we have a sequence of a binary operator (left
         --  operator), an expression value and another binary operator (right
         --  operator). In this case, if the left operator has a better
         --  precedence than the right one, we can reduce the global expression
         --  by assigning the expression value to the right expression of the
         --  left operator. Then as the left operator has already a left
         --  expression, it becomes an expression value which can be assigned
         --  to the left expression of the right operation. Recompute the size
         --  of the expression stack.

         while First + 1 < Last
           and then Is_Expression_Value (Table (Last - 1))
           and then Precede (Table (Last - 2), Expr)
         loop
            Set_Right_Expr (Table (Last - 2), Table (Last - 1));
            Table (Last - 1) := Table (Last);
            Set_Last (Last - 1);
            if No (Left_Expr (Table (Last - 1))) then
               Set_Left_Expr (Table (Last - 1), Table (Last - 2));
               Table (Last - 2) := Table (Last - 1);
               Table (Last - 1) := Table (Last);
               Set_Last (Last - 1);
            end if;
         end loop;
      end loop;

      --  The last expression is not a value. We cannot reduce the global
      --  expression.

      if Is_Binary_Operator (Table (Last)) then
         Error_Loc (1) := Loc (Table (Last));
         Exp_Err_Msg;
         Set_Last (First - 1);
         return No_Node;
      end if;

      --  Reduce the global expression

      while First < Last loop
         Set_Right_Expr (Table (Last - 1), Table (Last));
         Set_Last (Last - 1);
         if No (Left_Expr (Table (Last))) then
            Set_Left_Expr (Table (Last), Table (Last - 1));
            Table (Last - 1) := Table (Last);
            Set_Last (Last - 1);
         end if;
      end loop;

      Expr := Table (First);
      Set_Last (First - 1);

      return Expr;
   end P_Constant_Expression;

   ---------------------
   -- P_Constant_Type --
   ---------------------

   --  (28) <const_type> ::= <floating_pt_type>
   --                      | <integer_type>
   --                      | <char_type>
   --                      | <wide_char_type>
   --                      | <boolean_type>
   --                      | <octet_type>
   --                      | <string_type>
   --                      | <wide_string_type>
   --                      | <fixed_pt_const_type>
   --                      | <scoped_name>

   function P_Constant_Type return Node_Id is
      Const_Type : Node_Id;
      State      : Location;
   begin
      --  Use P_Simple_Type_Spec and reject incorrect type specifiers

      Save_Lexer (State);
      Const_Type := P_Simple_Type_Spec;

      if Present (Const_Type) then
         case Kind (Const_Type) is
            when K_Any
              | K_Object
              | K_Value_Base
              | K_Sequence_Type
              | K_Fixed_Point_Type =>
               Restore_Lexer (State);
               Unexpected_Token (Next_Token, "type specifier");
               return No_Node;

            when others =>
               return Const_Type;
         end case;
      else
         return No_Node;
      end if;
   end P_Constant_Type;

   ------------------
   -- P_Declarator --
   ------------------

   --  (50) <declarator> ::= <simple_declarator>
   --                      | <complex_declarator>
   --  (51) <simple_declarator> ::= <identifier>
   --  (52) <complex_declarator> ::= <array_declarator>
   --
   --  (83) <array_declarator> ::= <identifier> <fixed_array_size> +
   --  (84) <fixed_array_size> ::= "[" <positive_int_const> "]"

   function P_Declarator return Node_Id is
      Identifier  : Node_Id;
      Array_Sizes : List_Id;
      Array_Size  : Node_Id;
      Node        : Node_Id;

   begin
      Identifier := P_Identifier;
      if No (Identifier) then
         return No_Node;
      end if;

      if Next_Token /= T_Left_Bracket then
         Node := New_Node (K_Simple_Declarator, Loc (Identifier));
         Bind_Identifier_To_Entity (Identifier, Node);
         return Node;
      end if;

      Node := New_Node (K_Complex_Declarator, Loc (Identifier));
      Bind_Identifier_To_Entity (Identifier, Node);

      Array_Sizes := New_List (Token_Location);
      Set_Array_Sizes (Node, Array_Sizes);

      loop
         Scan_Token; --  past '['

         Array_Size := P_Constant_Expression;
         if No (Array_Size) then
            return No_Node;
         end if;

         Append_To (Array_Sizes, Array_Size);

         Scan_Token (T_Right_Bracket);
         if Token = T_Error then
            return No_Node;
         end if;

         exit when Next_Token /= T_Left_Bracket;
      end loop;

      return Node;
   end P_Declarator;

   -----------------------
   -- P_Declarator_List --
   -----------------------

   --  (49) <declarators> ::= <declarator> { "," <declarator> }

   function P_Declarator_List return List_Id
   is
      List : List_Id;
      Node : Node_Id;
   begin
      List := New_List (Token_Location);
      loop
         Node := P_Declarator;
         if No (Node) then
            return List;
         end if;

         Append_To (List, Node);
         exit when Next_Token /= T_Comma;
         Scan_Token; --  past ','
      end loop;

      return List;
   end P_Declarator_List;

   ------------------
   -- P_Definition --
   ------------------

   --  (2) <definition> ::= <type_dcl> ";"
   --                     | <const_dcl> ";"
   --                     | <except_dcl> ";"
   --                     | <interface> ";"
   --                     | <module> ";"
   --                     | <value> ";"
   --                     | <type_id_dcl> ";"
   --                     | <type_prefix_dcl> ";"

   function P_Definition return Node_Id is
      Definition : Node_Id := No_Node;
      State      : Location;
      Token_Backup : Token_Type;
   begin
      Save_Lexer (State);
      Skip_Annapp_Scan_Token (State);
      Token_Backup := Token;
      case Token is
         when T_Typedef
           | T_Struct
           | T_Union
           | T_Enum
           | T_Native =>
            Restore_Lexer (State);
            Definition := P_Type_Declaration;

         when T_Const =>
            Restore_Lexer (State);
            Definition := P_Constant_Declaration;

         when T_Exception =>
            Restore_Lexer (State);
            Definition := P_Exception_Declaration;

         when T_Abstract
           | T_Local =>
            Scan_Token ((T_Interface, T_Value_Type));
            if Token = T_Interface then
               Restore_Lexer (State);
               Definition := P_Interface;

            elsif Token = T_Value_Type then
               Restore_Lexer (State);
               Definition := P_Value;
            end if;

         when T_Interface =>
            Restore_Lexer (State);
            Definition := P_Interface;

         when T_Module =>
            Restore_Lexer (State);
            Definition := P_Module;

         when T_Value_Type
           | T_Custom =>
            Restore_Lexer (State);
            Definition := P_Value;

         when T_Pragma =>
            Restore_Lexer (State);
            Definition := P_Pragma;

         when T_Type_Id =>
            Restore_Lexer (State);
            Definition := P_Type_Id_Declaration;

         when T_Type_Prefix =>
            Restore_Lexer (State);
            Definition := P_Type_Prefix_Declaration;

         when others =>
            Unexpected_Token (Token, "definition");
      end case;

      --  The definition is successfully parsed

      --  Particular case when parsing a typeprefix or a typeid statement:
      --  The IDL grammar is clear:
      --  (2) <definition> ::= <type_dcl> ";"
      --                     | <const_dcl> ";"
      --                     | <except_dcl> ";"
      --                     | <interface> ";"
      --                     | <module> ";"
      --                     | <value> ";"
      --                     | <type_id_dcl> ";"
      --                     | <type_prefix_dcl> ";"

      --  The last two lines show that a semi-colon is required after a
      --  <type_id_dcl> and <type_prefix_dcl>.

      --  However, in some OMG idl files (including orb.idl), there is no
      --  semi-colon after typeprefix statement. This issue has been discussed
      --  in OMG issue 3299: http://www.omg.org/issues/issue3299.txt
      --  but no solution has been accepted, and the issue is still pending.

      --  We therefore support a relaxed IDL syntax for the purpose of parsing
      --  standard OMG idl files, accepting specifications lacking the
      --  semicolon. When OMG standard IDLs are fixed, this work-around can
      --  be removed.

      --  The same situation is encountered when parsing an import statement.

      if Present (Definition)
           and then Kind (Definition) /= K_Pragma
           and then Kind (Definition) /= K_Pragma_Range_Idl
      then
         Save_Lexer (State);
         Scan_Token;
         if Token /= T_Semi_Colon then
            Error_Loc (1) := Token_Location;
            if Token_Backup = T_Type_Id
              or else Token_Backup = T_Type_Prefix
            then
               DE ("?semicolon expected");
            else
               DE ("semicolon expected");
               Definition := No_Node;
            end if;
            Restore_Lexer (State);
         end if;

      elsif No (Definition) then
         Restore_Lexer (State);
         Skip_Declaration (T_Semi_Colon);
      end if;

      return Definition;
   end P_Definition;

   ------------------------
   -- P_Enumeration_Type --
   ------------------------

   --  (78) <enum_type> ::= "enum" <identifier>
   --                       "{" <enumerator> { "," <enumerator> } "}"
   --
   --  (79) <enumerator> ::= <identifier>

   function P_Enumeration_Type return Node_Id is
      Identifier  : Node_Id;
      Node        : Node_Id;
      Enumerator  : Node_Id;
      Enumerators : List_Id;
      State       : Location;
      Position    : Unsigned_Long_Long := 0;

   begin
      Scan_Token; --  past "enum"
      Node := New_Node (K_Enumeration_Type, Token_Location);

      Identifier := P_Identifier;
      if No (Identifier) then
         return No_Node;
      end if;
      Bind_Identifier_To_Entity (Identifier, Node);

      Scan_Token (T_Left_Brace);
      if Token = T_Error then
         return No_Node;
      end if;

      Enumerators := New_List (Token_Location);
      Set_Enumerators (Node, Enumerators);

      loop

         --  Save lexer state in order to skip the enumerator list on error

         Save_Lexer (State);
         Identifier := P_Identifier;
         if No (Identifier) then
            Restore_Lexer (State);
            Skip_Declaration (T_Right_Brace);
            exit;
         end if;

         Enumerator := New_Node (K_Enumerator, Loc (Identifier));
         Bind_Identifier_To_Entity (Identifier, Enumerator);

         Append_To (Enumerators, Enumerator);
         Position := Position + 1;
         Set_Value
           (Enumerator,
            New_Enumerator (IDL_Name (Identifier), Position));

         Save_Lexer (State);
         Scan_Token ((T_Comma, T_Right_Brace));
         if Token /= T_Comma then
            if Token = T_Error then
               Restore_Lexer (State);
               Skip_Declaration (T_Right_Brace);
            end if;
            exit;
         end if;
      end loop;

      return Node;
   end P_Enumeration_Type;

   -----------------------------
   -- P_Exception_Declaration --
   -----------------------------

   --  (86) <except_dcl> ::= "exception" <identifier> "{" <member>* "}"

   function P_Exception_Declaration return Node_Id is
      Identifier : Node_Id;
      Node     : Node_Id;
      Member     : Node_Id;
      Members    : List_Id;
      State      : Location;

   begin
      Scan_Token; --  past "exception"
      Node := New_Node (K_Exception_Declaration, Token_Location);

      Identifier := P_Identifier;
      if No (Identifier) then
         return No_Node;
      end if;
      Bind_Identifier_To_Entity (Identifier, Node);

      Scan_Token (T_Left_Brace);
      if Token = T_Error then
         return No_Node;
      end if;

      Members := New_List (Token_Location);
      Set_Members      (Node, Members);

      loop
         if Next_Token = T_Right_Brace then
            Scan_Token; --  past '}'
            exit;
         end if;

         --  Save lexer state to skip exception member list on error

         Save_Lexer (State);
         Member := P_Member;
         if No (Member) then
            Restore_Lexer (State);
            Skip_Declaration (T_Right_Brace);
            exit;
         end if;

         Append_To (Members, Member);
      end loop;

      return Node;
   end P_Exception_Declaration;

   ----------------------
   -- P_Exception_List --
   ----------------------

   --  (93) <raises_expr> ::= "raises" "(" <scoped_name>
   --                                { "," <scoped_name> } ")"

   --  (109) <get_excep_expr> ::= "getraises" <exception_list>

   --  (110) <set_excep_expr> ::= "setraises" <exception_list>

   --  (111) <exception_list> ::= "(" <scoped_name>
   --                              { "," <scoped_name> } * ")"

   function P_Exception_List return List_Id is
      Exception_List : List_Id;
      Scoped_Name    : Node_Id;
      State          : Location;
   begin
      Scan_Token; --  past "raises", "getraises" or "setraises"
      Scan_Token (T_Left_Paren);
      if Token = T_Error then
         return No_List;
      end if;

      Exception_List := New_List (Token_Location);
      loop
         Save_Lexer (State);
         Scoped_Name := P_Scoped_Name;
         if No (Scoped_Name) then
            Restore_Lexer (State);
            Skip_Declaration (T_Right_Paren);
            exit;
         end if;

         Append_To (Exception_List, Scoped_Name);

         Save_Lexer (State);
         Scan_Token ((T_Comma, T_Right_Paren));
         if Token /= T_Comma then
            if Token = T_Error then
               Restore_Lexer (State);
               Skip_Declaration (T_Right_Paren);
            end if;
            exit;
         end if;
      end loop;

      return Exception_List;
   end P_Exception_List;

   --------------
   -- P_Export --
   --------------

   --  (9) <export> ::= <type_dcl> ";"
   --                 | <const_dcl> ";"
   --                 | <except_dcl> ";"
   --                 | <attr_dcl> ";"
   --                 | <op_dcl> ";"

   function P_Export return Node_Id is
      State  : Location;
      Export : Node_Id;

   begin

      --  Save lexer state to skip declaration on error

      Save_Lexer (State);
      Scan_Token;
      case Token is
         when T_Const =>
            Restore_Lexer (State);
            Export := P_Constant_Declaration;

         when T_Exception =>
            Restore_Lexer (State);
            Export := P_Exception_Declaration;

         when T_Attribute
           | T_Readonly =>
            Restore_Lexer (State);
            Export := P_Attribute_Declaration;

         when T_Typedef
           | T_Struct
           | T_Union
           | T_Enum
           | T_Native =>
            Restore_Lexer (State);
            Export := P_Type_Declaration;

         when T_Pragma =>
            Restore_Lexer (State);
            Export := P_Pragma;

         when T_Type_Id =>
            Restore_Lexer (State);
            Export := P_Type_Id_Declaration;

         when T_Type_Prefix =>
            Restore_Lexer (State);
            Export := P_Type_Prefix_Declaration;

         when others =>
            Restore_Lexer (State);
            Export := P_Operation_Declaration;
      end case;

      if Present (Export) and then Kind (Export) /= K_Pragma then
         Scan_Token (T_Semi_Colon);
      end if;

      if Token = T_Error then
         Export := No_Node;
      end if;

      if No (Export) then
         Restore_Lexer (State);
         Skip_Declaration (T_Semi_Colon);
         return No_Node;
      end if;

      return Export;
   end P_Export;

   ------------------------
   -- P_Fixed_Point_Type --
   ------------------------

   --  (96) <fixed_pt_type> ::= "fixed" "<" <positive_int_const> ","
   --                                       <positive_int_const> ">"
   --
   --  (97) <fixed_pt_const_type> ::= "fixed"

   function P_Fixed_Point_Type return Node_Id is
      Node : Node_Id;

   begin
      Scan_Token; --  past "fixed"
      Node := New_Node (K_Fixed_Point_Type, Token_Location);

      if Next_Token = T_Less then
         Scan_Token; --  past '<'

         Scan_Token (T_Integer_Literal);
         if Token = T_Error then
            return No_Node;
         end if;
         if Integer_Literal_Sign < 0
           or else Integer_Literal_Value > 31
         then
            Error_Loc (1) := Token_Location;
            DE ("fixed point values must have between 0 and 31 digits");
            return No_Node;
         end if;
         Set_N_Total (Node, Int (Integer_Literal_Value));

         Scan_Token (T_Comma);
         if Token = T_Error then
            return No_Node;
         end if;

         Scan_Token (T_Integer_Literal);
         if Token = T_Error then
            return No_Node;
         end if;
         if Integer_Literal_Sign < 0
           or else Integer_Literal_Value > 31
         then
            Error_Loc (1) := Token_Location;
            DE ("fixed point values must have between 0 and 31 digits");
            return No_Node;
         end if;
         if N_Total (Node) < Int (Integer_Literal_Value) then
            Error_Loc (1) := Token_Location;
            DE ("fixed point scale factor is greater than number of digits");
            return No_Node;
         end if;
         Set_N_Scale (Node, Int (Integer_Literal_Value));

         Scan_Token (T_Greater);
         if Token = T_Error then
            return No_Node;
         end if;
      end if;

      return Node;
   end P_Fixed_Point_Type;

   ------------------
   -- P_Identifier --
   ------------------

   function P_Identifier return Node_Id is
   begin
      Skip_Annapp_Scan_Token (T_Identifier);
      if Token = T_Error then
         return No_Node;
      end if;
      return Make_Identifier (Token_Location, Token_Name, No_Node, No_Node);
   end P_Identifier;

   --------------
   -- P_Import --
   --------------

   --  (100) <import> ::= "import" <imported_scope> ";"
   --  (101) <imported_scope> ::= <scoped_name> | <string_literal>

   --  The string literal is an interface repository ID of an IDL scoped name
   --  The import of interface repository ID is not supported by IAC

   function P_Import return Node_Id is
      State           : Location;
      Import_Node     : Node_Id;
      Import_Location : Location;
      Imported_Scope  : Node_Id;
   begin
      Scan_Token; --  past import
      Import_Location := Token_Location;

      Save_Lexer (State);
      Scan_Token; --  past "::"
      if Token /= T_Colon_Colon then
         Error_Loc (1) := Token_Location;
         DE ("Only identifier relative global scope now allowed "
             & "(IAC restriction)");
         return No_Node;
      end if;
      Restore_Lexer (State);
      Imported_Scope := P_Scoped_Name;
      Import_Node := New_Node (K_Import, Import_Location);
      Set_Imported_Scope (Import_Node, Imported_Scope);

      --  The import is successfully parsed

      --  See discussion in P_Definition for relaxed syntax exception (we
      --  accept an import declaration without a terminating semicolon).

      if Present (Imported_Scope) then
         Save_Lexer (State);
         Scan_Token;
         if Token /= T_Semi_Colon then
            Restore_Lexer (State);
            Error_Loc (1) := Token_Location;
            DE ("?semicolon expected");
         end if;
      end if;

      --  Now, we parse the file corresponding to the imported scope

      --  FIXME: Note that even if the imported scope covers only a part
      --  of a file and not a whole file, all the entities in this file
      --  will be visible

      declare
         Imported_File_Name : constant Name_Id :=
           Locate_Imported_File (Imported_Scope);
      begin
         if Imported_File_Name = No_Name then
            Error_Loc (1) := Loc (Imported_Scope);
            Error_Name (1) := IDL_Name (Identifier (Imported_Scope));
            DE ("declaration of imported scope# not found");
            return No_Node;
         end if;

         if not Handled (Imported_File_Name) then
            Set_Handled (Imported_File_Name);

            Lexer.Process (Lexer.Preprocess (Imported_File_Name));
            P_Specification (Imported => True);
            Finalize_Imported;
         end if;
      end;

      return Import_Node;
   end P_Import;

   -------------------------------
   -- P_Initializer_Declaration --
   -------------------------------

   --  (23) <init_dcl> ::= "factory" <identifier>
   --                           "(" [ <init_param_decls> ] ")" ";"
   --  (24) <init_param_decls> ::= <init_param_decl>
   --                        { "," <init_param_decl> }*
   --  (25) <init_param_decl> ::= <init_param_attribute> <param_type_spec>
   --                                                    <simple_declarator>

   function P_Initializer_Declaration return Node_Id is
      Identifier : Node_Id;
      Node     : Node_Id;
      Parameters : List_Id;
      Parameter  : Node_Id;
      State      : Location;

   begin
      Scan_Token; -- past "factory"
      Node := New_Node (K_Initializer_Declaration, Token_Location);

      Identifier := P_Identifier;
      if No (Identifier) then
         return No_Node;
      end if;
      Bind_Identifier_To_Entity (Identifier, Node);

      Scan_Token (T_Left_Paren);
      if Token = T_Error then
         return No_Node;
      end if;

      Parameters := New_List (Token_Location);
      Set_Parameters   (Node, Parameters);

      loop
         --  Check the parameter mode is "in". Then parse a general
         --  parameter declaration.

         Save_Lexer (State);
         if Next_Token = T_In then
            Parameter := P_Parameter_Declaration;
            if No (Parameter) then
               Restore_Lexer (State);
               Skip_Declaration (T_Right_Paren);
               exit;
            end if;

            Append_To (Parameters, Parameter);
         end if;

         Save_Lexer (State);
         Scan_Token ((T_Right_Paren, T_Comma));
         if Token /= T_Comma then
            if Token = T_Error then
               Restore_Lexer (State);
               Skip_Declaration (T_Right_Paren);
            end if;
            exit;
         end if;
      end loop;

      Scan_Token (T_Semi_Colon);
      if Token = T_Error then
         Restore_Lexer (State);
         Skip_Declaration (T_Semi_Colon);
         Node := No_Node;
      end if;

      return Node;
   end P_Initializer_Declaration;

   -----------------
   -- P_Interface --
   -----------------

   --  (4) <interface> ::= <interface_dcl>
   --                    | <forward_dcl>

   function P_Interface return Node_Id is
      Identifier  : Node_Id;
      Node        : Node_Id;
      Is_Abstract : Boolean := False;
      Is_Local    : Boolean := False;
      State       : Location;
      Fwd_Loc     : Location;

   begin
      Save_Lexer (State);

      Scan_Token; --  past "abstract", "local" or "interface"
      Fwd_Loc := Token_Location;
      if Token = T_Abstract then
         Is_Abstract := True;
         Scan_Token; --  past "interface"

      elsif Token = T_Local then
         Is_Local := True;
         Scan_Token; --  past "interface"
      end if;

      Identifier := P_Identifier;
      if No (Identifier) then
         return No_Node;
      end if;

      case Next_Token is
         when T_Semi_Colon =>
            Node := New_Node (K_Forward_Interface_Declaration, Fwd_Loc);
            Bind_Identifier_To_Entity (Identifier, Node);
            Set_Is_Abstract_Interface (Node, Is_Abstract);
            Set_Is_Local_Interface (Node, Is_Local);

         when T_Left_Brace
           | T_Colon =>
            Restore_Lexer (State);
            return P_Interface_Declaration;

         when others =>
            return No_Node;
      end case;

      return Node;
   end P_Interface;

   -----------------------------
   -- P_Interface_Declaration --
   -----------------------------

   --  (5) <interface_dcl> ::= <interface_header> "{" <interface_body> "}"
   --  (7) <interface_header> ::=
   --         [ "abstract" | "local" ] "interface" <identifier>
   --            [ <interface_inheritance_spec> ]
   --  (8) <interface_body> ::=  <export> *
   --  (10) <interface_inheritance_spec>::= ":" <interface_name>
   --                                     { "," <interface_name> } *

   function P_Interface_Declaration return Node_Id is
      Identifier     : Node_Id;
      Node           : Node_Id;
      Interface_Body : List_Id;
      Export         : Node_Id;
      Interface_Spec : List_Id;
      Interface_Name : Node_Id;
      State          : Location;

   begin
      Scan_Token; --  past "abstract" or "interface"
      Node := New_Node (K_Interface_Declaration, Token_Location);

      if Token = T_Abstract then
         Set_Is_Abstract_Interface (Node, True);
         Scan_Token; --  past "interface"

      elsif Token = T_Local then
         Set_Is_Local_Interface (Node, True);
         Scan_Token; --  past "interface"
      end if;

      Identifier := P_Identifier;
      Bind_Identifier_To_Entity (Identifier, Node);

      --  Always create an interface inheritance specifier even if it
      --  is left empty.

      Interface_Spec := New_List (Token_Location);
      Set_Interface_Spec (Node, Interface_Spec);

      --  Parse interface inheritance specifier

      if Next_Token = T_Colon then
         Scan_Token; --  past ':'

         loop
            Interface_Name := P_Interface_Name;
            if No (Interface_Name) then
               return No_Node;
            end if;

            Append_To (Interface_Spec, Interface_Name);

            exit when Next_Token /= T_Comma;
            Scan_Token; --  past ','
         end loop;
      end if;

      --  Parse interface body

      Scan_Token (T_Left_Brace);
      if Token = T_Error then
         return No_Node;
      end if;

      Interface_Body := New_List (Token_Location);
      Set_Interface_Body (Node, Interface_Body);

      loop
         if Next_Token = T_Right_Brace then
            Scan_Token; --  past '}'
            exit;
         end if;

         --  Parse export. Save lexer state to skip interface body on
         --  error.

         Save_Lexer (State);
         Export := P_Export;
         if No (Export) then
            Restore_Lexer (State);
            Skip_Declaration (T_Right_Brace);
            exit;
         end if;

         Append_To (Interface_Body, Export);
      end loop;

      return Node;
   end P_Interface_Declaration;

   ----------------------
   -- P_Interface_Name --
   ----------------------

   --  (11) <interface_name> ::= <scoped_name>

   function P_Interface_Name return Node_Id is
   begin
      return P_Scoped_Name;
   end P_Interface_Name;

   --------------
   -- P_Member --
   --------------

   --  (71) <member> ::= <type_spec> <declarators> ";"
   --  (49) <declarators> ::= <declarator> { "," <declarator> }

   function P_Member return Node_Id is
      Member       : Node_Id;
      Declarators  : List_Id;
      Type_Spec    : Node_Id;
      State        : Location;
   begin
      --  Parse type specifier. Save lexer state to skip declaration
      --  on error.

      Save_Lexer (State);
      Type_Spec := P_Type_Spec;
      if No (Type_Spec) then
         Restore_Lexer (State);
         Skip_Declaration (T_Semi_Colon);
         return No_Node;
      end if;

      --  Parse declarators. Save lexer state to skip declarators on
      --  error.

      Save_Lexer (State);
      Declarators := P_Declarator_List;
      if No (Declarators) then
         Restore_Lexer (State);
         Skip_Declaration (T_Semi_Colon);
         return No_Node;
      end if;

      Member := New_Node (K_Member, Loc (Type_Spec));
      Set_Type_Spec   (Member, Type_Spec);
      Set_Declarators (Member, Declarators);
      Bind_Declarators_To_Entity (Declarators, Member);

      Scan_Token (T_Semi_Colon);
      if Token = T_Error then
         return No_Node;
      end if;

      return Member;
   end P_Member;

   --------------
   -- P_Module --
   --------------

   --  (3) <module> ::= "module" <identifier> "{" <definition> + "}"

   function P_Module return Node_Id is
      Identifier  : Node_Id;
      Node        : Node_Id;
      Definitions : List_Id;
      Definition  : Node_Id;

   begin
      Scan_Token; -- past "module"
      Node := New_Node (K_Module, Token_Location);

      --  Save module declaration location since we may have to reopen
      --  a previous declaration.

      Identifier := P_Identifier;
      if No (Identifier) then
         return No_Node;
      end if;
      Bind_Identifier_To_Entity (Identifier, Node);

      Scan_Token (T_Left_Brace);
      if Token = T_Error then
         return No_Node;
      end if;

      Definitions := New_List (Token_Location);
      Set_Definitions  (Node, Definitions);

      loop
         Definition := P_Definition;
         if Present (Definition) then
            Append_To (Definitions, Definition);
         end if;

         case Next_Token is
            when T_Right_Brace =>
               Scan_Token; --  past '}'
               exit;

            when T_EOF =>
               exit;

            when others =>
               null;
         end case;
      end loop;

      return Node;
   end P_Module;

   --------------------
   -- P_No_Such_Node --
   --------------------

   function P_No_Such_Node return Node_Id is
   begin
      Scan_Token;
      Error_Loc (1) := Token_Location;
      DE ("not implemented");
      return No_Node;
   end P_No_Such_Node;

   -----------------------------
   -- P_Operation_Declaration --
   -----------------------------

   --  (87) <op_dcl> ::= [ <op_attribute> ] <op_type_spec>
   --                                       <identifier> <parameter_dcls>
   --                    [ <raises_expr> ] [ <context_expr> ]
   --
   --  (88) <op_attribute> ::= "oneway"
   --  (89) <op_type_spec> ::= <param_type_spec>
   --                        | "void"
   --
   --  (90) <parameter_dcls> ::= "(" <param_dcl> { "," <param_dcl> } ")"
   --                          | "(" ")"
   --
   --  (91) <param_dcl> ::= <param_attribute> <param_type_spec>
   --                                         <simple_declarator>
   --
   --  (92) <param_attribute> ::= "in"
   --                           | "out"
   --                           | "inout"
   --
   --  (93) <raises_expr> ::= "raises" "(" <scoped_name>
   --                                { "," <scoped_name> } ")"
   --
   --  (94) <context_expr> ::= "context" "(" <string_literal>
   --                                  { "," <string_literal> } ")"

   function P_Operation_Declaration return Node_Id is
      function P_Context_List return List_Id;

      --------------------
      -- P_Context_List --
      --------------------

      --  (94) <context_expr> ::= "context" "(" <string_literal>
      --                                  { "," <string_literal> } ")"

      function P_Context_List return List_Id is
         Context_List   : List_Id;
         String_Literal : Node_Id;
         State          : Location;
      begin
         Scan_Token; --  past "context"
         Scan_Token (T_Left_Paren);
         if Token = T_Error then
            return No_List;
         end if;

         Context_List := New_List (Token_Location);
         loop
            --  Parse string literal. Save lexer state to skip
            --  literals on error.

            Save_Lexer (State);
            Scan_Token ((T_String_Literal, T_Wide_String_Literal));
            if Token = T_Error then
               Restore_Lexer (State);
               Skip_Declaration (T_Right_Paren);
               exit;
            end if;

            String_Literal := New_Node (K_Literal, Token_Location);
            Set_Value
              (String_Literal,
               New_String_Value (Value => String_Literal_Value,
                                 Wide  => Is_Wide_Literal_Value));

            Append_To (Context_List, String_Literal);

            Save_Lexer (State);
            Scan_Token ((T_Right_Paren, T_Comma));
            if Token /= T_Comma then
               if Token = T_Error then
                  Restore_Lexer (State);
                  Skip_Declaration (T_Right_Paren);
               end if;
               exit;
            end if;
         end loop;

         return Context_List;
      end P_Context_List;

      Identifier      : Node_Id;
      Node          : Node_Id;
      Parameter       : Node_Id;
      Parameters      : List_Id;
      Param_Type_Spec : Node_Id;
      Contexts        : List_Id;
      Exceptions      : List_Id;
      State           : Location;

   begin
      Save_Lexer (State);
      Skip_Annapp_Scan_Token (State);
      Node := New_Node (K_Operation_Declaration, Token_Location);

      if Token = T_Oneway then
         Set_Is_Oneway (Node, True);
         Save_Lexer (State);
         Skip_Annapp_Scan_Token (State);
      end if;

      if Token = T_Void then
         Param_Type_Spec := Resolve_Base_Type ((1 => T_Void), Token_Location);

      else
         Restore_Lexer (State);

         Param_Type_Spec := P_Simple_Type_Spec;

         --  Guard against previously detected error

         if No (Param_Type_Spec) then
            return No_Node;
         end if;

         if not Is_Param_Type_Spec (Param_Type_Spec) then
            Error_Loc (1) := Loc (Param_Type_Spec);
            DE ("incorrect param type spec");
            return No_Node;
         end if;
      end if;
      Set_Type_Spec (Node, Param_Type_Spec);

      Identifier := P_Identifier;
      if No (Identifier) then
         return No_Node;
      end if;
      Bind_Identifier_To_Entity (Identifier, Node);

      Scan_Token (T_Left_Paren);
      if Token = T_Error then
         return No_Node;
      end if;

      Parameters := New_List (Token_Location);
      Set_Parameters (Node, Parameters);

      if Next_Token = T_Right_Paren then
         Scan_Token; --  past ')'

      else
         Save_Lexer (State);
         loop
            Parameter := P_Parameter_Declaration;
            if No (Parameter) then
               Restore_Lexer (State);
               Skip_Declaration (T_Right_Paren);
               exit;
            end if;

            Append_To (Parameters, Parameter);

            Save_Lexer (State);
            Scan_Token ((T_Right_Paren, T_Comma));
            if Token /= T_Comma then
               if Token = T_Error then
                  Restore_Lexer (State);
                  Skip_Declaration (T_Right_Paren);
               end if;
               exit;
            end if;
         end loop;
      end if;

      if Next_Token = T_Raises then
         Exceptions := P_Exception_List;
         if Exceptions = No_List then
            return No_Node;
         end if;
         Set_Exceptions (Node, Exceptions);
      end if;

      if Next_Token = T_Context then
         Contexts := P_Context_List;
         if Contexts = No_List then
            return No_Node;
         end if;
         Set_Contexts (Node, Contexts);
      end if;

      return Node;
   end P_Operation_Declaration;

   -----------------------------
   -- P_Parameter_Declaration --
   -----------------------------

   --  (91) <param_dcl> ::= <param_attribute> <param_type_spec>
   --                                         <simple_declarator>
   --
   --  (92) <param_attribute> ::= "in"
   --                           | "out"
   --                           | "inout"

   function P_Parameter_Declaration return Node_Id is
      Param_Declaration : Node_Id;
      Param_Declarator  : Node_Id;
      Param_Type_Spec   : Node_Id;
      Param_Mode        : Mode_Id;
      Param_Location    : Location;

   begin
      Scan_Token ((T_In, T_Inout, T_Out));
      Param_Location := Token_Location;
      if Token = T_Error then
         return No_Node;
      end if;
      Param_Mode := Parameter_Mode (Token);

      Param_Type_Spec := P_Simple_Type_Spec;

      --  Guard against previously detected error

      if No (Param_Type_Spec) then
         return No_Node;
      end if;

      if not Is_Param_Type_Spec (Param_Type_Spec) then
         Error_Loc (1) := Loc (Param_Type_Spec);
         DE ("incorrect param type spec");
         return No_Node;
      end if;

      Param_Declarator := P_Simple_Declarator;
      if No (Param_Declarator) then
         return No_Node;
      end if;

      Param_Declaration :=
        New_Node (K_Parameter_Declaration, Param_Location);
      Set_Parameter_Mode (Param_Declaration, Param_Mode);
      Set_Type_Spec      (Param_Declaration, Param_Type_Spec);
      Set_Declarator     (Param_Declaration, Param_Declarator);
      Bind_Declarator_To_Entity (Param_Declarator, Param_Declaration);

      return Param_Declaration;
   end P_Parameter_Declaration;

   --------------
   -- P_Pragma --
   --------------

   --  There are three standard IDL pragmas :
   --  #pragma ID <name> "<id>"
   --  #pragma prefix "<string>"
   --  #pragma version <name> <major>.<minor>
   --
   --  In the IDL to Ada mapping version 1.3, there are further pragmas:
   --  #pragma range <name> <optional_lower_bound> .. <optional_upper_bound>
   --  #pragma range <name> "<ada_range_expr>"
   --  #pragma subtype <name>
   --  #pragma derived <name>

   --  However an IDL compiler "must not refuse to compile IDL source
   --  containing non-standard pragmas that are not understood by the
   --  compiler" CORBA, v3.0 $10.7.5

   --  Not understood pragmas will be ignored

   function P_Pragma return Node_Id is
      Pragma_Kind  : Pragma_Type;
      Pragma_Node  : Node_Id;
      Scoped_Name  : Node_Id := No_Node;

   begin
      Scan_Token; -- Past #pragma
      Pragma_Node := New_Node (K_Pragma, Token_Location);

      --  We scan an identifier, then we convert it into a pragma related token
      --  because pragma kinds (id, prefix, version) can be used as legal
      --  identifiers in other locations
      Scan_Token (T_Identifier);

      if Token = T_Error then
         return Pragma_Node;
      end if;

      --  Converting the identifier into a pragma related token

      declare
         Pragma_Image : constant String := Get_Name_String (Token_Name);
      begin
         if Pragma_Image = Image (T_Pragma_Id) then
            Token := T_Pragma_Id;
         elsif Pragma_Image = Image (T_Pragma_Prefix) then
            Token := T_Pragma_Prefix;
         elsif Pragma_Image = Image (T_Pragma_Version) then
            Token := T_Pragma_Version;
         elsif Pragma_Image = Image (T_Pragma_Range) then
            Token := T_Pragma_Range;
         elsif Pragma_Image = Image (T_Pragma_Subtype) then
            Token := T_Pragma_Subtype;
         elsif Pragma_Image = Image (T_Pragma_Derived) then
            Token := T_Pragma_Derived;
         elsif Pragma_Image = Image (T_Pragma_Switchname) then
            Token := T_Pragma_Switchname;
         elsif Pragma_Image = Image (T_Pragma_javaPackage) then
            Token := T_Pragma_javaPackage;
         end if;
      end;

      --  Unrecognized pragma

      if Token = T_Identifier then
         Token := T_Pragma_Unrecognized;
      end if;

      Pragma_Kind := Get_Pragma_Type (Token);

      case Pragma_Kind is
         when Pragma_Id =>
            Set_Pragma_Kind (Pragma_Node, Pragma_Kind);

            Scoped_Name := P_Scoped_Name;
            if No (Scoped_Name) then
               Error_Loc (1) := Token_Location;
               DE ("incorrect #pragma ID syntax");
            end if;

            Set_Target (Pragma_Node, Scoped_Name);

            --  Getting the "<id>"

            Scan_Token (T_String_Literal);
            Set_Data (Pragma_Node, Name_Find);

         when Pragma_Prefix =>
            Set_Pragma_Kind (Pragma_Node, Pragma_Kind);

            --  Getting the "<prefix>"

            Scan_Token (T_String_Literal);
            Set_Data (Pragma_Node, Name_Find);

         when Pragma_Version =>
            Set_Pragma_Kind (Pragma_Node, Pragma_Kind);

            Scoped_Name := P_Scoped_Name;
            if No (Scoped_Name) then
               Error_Loc (1) := Token_Location;
               DE ("incorrect #pragma version syntax");
            end if;

            Set_Target (Pragma_Node, Scoped_Name);

            --  Getting the <major>.<minor>
            --  We don't want to get a floating point value, so we take the
            --  value from the Name_Buffer

            Scan_Token (T_Floating_Point_Literal);
            Set_Data (Pragma_Node, Name_Find);

         when Pragma_Range =>
            Scoped_Name := P_Scoped_Name;
            if No (Scoped_Name) then
               Error_Loc (1) := Token_Location;
               DE ("incorrect #pragma range syntax");
            end if;

            Set_Target (Pragma_Node, Scoped_Name);

            --  The are two forms of range expression:
            --
            --  - A double-quote delimited string designates an Ada
            --    range expression.  Example:
            --      #pragma range myfloat_t "0.0 .. CORBA.Float'Last"
            --    Here, the double quotes shall be removed and the contents
            --    shall be copied verbatim to the generated Ada range.
            --
            --  - If the expression is not delimited by double quotes then
            --    it designates IDL expressions for the lower and upper
            --    bound.  Example:
            --      #pragma range myfloat_t -100.0 .. mymodule::myconstant
            --    The upper bound expression is delimited from the lower
            --    bound expression by two adjacent dots.  Both the lower and
            --    the upper bound expression is optional; if not given, the
            --    'First or 'Last value of the target type shall be used.
            --    In this form, we change Pragma_Range to Pragma_Range_Idl.

            if Next_Token = T_String_Literal then
               Set_Pragma_Kind (Pragma_Node, Pragma_Range);

               Scan_Token;  --  past literal
               Set_Data (Pragma_Node, Name_Find);
            else
               Set_Kind (Pragma_Node, K_Pragma_Range_Idl);
               Set_Pragma_Kind (Pragma_Node, Pragma_Range_Idl);
               declare
                  Lowerbound_Expr : Node_Id := No_Node;
                  Upperbound_Expr : Node_Id := No_Node;
               begin
                  --  Pass First_Of_Range => True for the expression before
                  --  "..", not for the one after. Both are Optional.

                  Lowerbound_Expr := P_Constant_Expression
                    (Optional => True, First_Of_Range => True);
                  Set_Lower_Bound_Expr (Pragma_Node, Lowerbound_Expr);
                  if Next_Token = T_Dot_Dot then
                     Scan_Token;  --  past ".."
                     Upperbound_Expr :=
                       P_Constant_Expression (Optional => True);
                     Set_Upper_Bound_Expr (Pragma_Node, Upperbound_Expr);
                  else
                     Error_Loc (1) := Token_Location;
                     DE ("incorrect #pragma range syntax");
                  end if;
               end;
            end if;

         when Pragma_Range_Idl =>
            --  This is a synthetic value (see handling of Pragma_Range)
            --  which shall not be accessible from user code
            Set_Pragma_Kind (Pragma_Node, Pragma_Unrecognized);

         when Pragma_Subtype =>
            Set_Pragma_Kind (Pragma_Node, Pragma_Kind);

            Scoped_Name := P_Scoped_Name;
            if No (Scoped_Name) then
               Error_Loc (1) := Token_Location;
               DE ("incorrect #pragma subtype syntax");
            end if;

            Set_Target (Pragma_Node, Scoped_Name);
            Set_Data (Pragma_Node, No_Name);

         when Pragma_Derived =>
            Set_Pragma_Kind (Pragma_Node, Pragma_Kind);

            Scoped_Name := P_Scoped_Name;
            if No (Scoped_Name) then
               Error_Loc (1) := Token_Location;
               DE ("incorrect #pragma derived syntax");
            end if;

            Set_Target (Pragma_Node, Scoped_Name);
            Set_Data (Pragma_Node, No_Name);

         when Pragma_Switchname =>
            Set_Pragma_Kind (Pragma_Node, Pragma_Kind);

            Scoped_Name := P_Scoped_Name;
            if No (Scoped_Name) then
               Error_Loc (1) := Token_Location;
               DE ("incorrect #pragma switchname syntax");
            end if;

            Set_Target (Pragma_Node, Scoped_Name);

            --  Getting the switch name

            Scan_Token (T_Identifier);
            Set_Data (Pragma_Node, Name_Find);

         when Pragma_javaPackage =>
            Set_Pragma_Kind (Pragma_Node, Pragma_Kind);
            Skip_Line; -- skip string literal and newline

         when Pragma_Unrecognized =>
            Set_Pragma_Kind (Pragma_Node, Pragma_Kind);

            --  We ignore unrecognized pragmas

            Skip_Line;
      end case;
      return Pragma_Node;
   end P_Pragma;

   -------------------
   -- P_Scoped_Name --
   -------------------

   --  (12) <scoped_name> ::= <identifier>
   --                       | "::" <identifier>
   --                       | <scoped_name> "::" <identifier>

   function P_Scoped_Name return Node_Id is
      Scoped_Name : Node_Id := No_Node;
      Parent      : Node_Id := No_Node;
      Identifier  : Node_Id;
      Scope_Depth : Int;

   begin
      --  Scoped name starts with a '::'

      if Next_Token = T_Colon_Colon then
         Scan_Token;  --  past '::'
         Identifier  := Make_Identifier
           (Token_Location, No_Name, No_Node, No_Node);
         Scoped_Name := New_Node
           (K_Scoped_Name, Token_Location);
         Bind_Identifier_To_Entity
           (Identifier, Scoped_Name);
      end if;

      --  start loop with an identifier

      loop
         Identifier := P_Identifier;
         if No (Identifier) then
            return No_Node;
         end if;

         Parent      := Scoped_Name;
         Scoped_Name := New_Node (K_Scoped_Name, Token_Location);
         Bind_Identifier_To_Entity  (Identifier, Scoped_Name);
         Set_Parent_Entity (Scoped_Name, Parent);

         exit when Next_Token /= T_Colon_Colon;
         Scan_Token; --  past '::'
      end loop;

      Parent      := Parent_Entity (Scoped_Name);
      Scope_Depth := Depth (Scoped_Name);
      while Present (Parent) loop
         Scope_Depth := Scope_Depth + 1;
         Set_Depth (Parent, Scope_Depth);
         Parent := Parent_Entity (Parent);
      end loop;

      return Scoped_Name;
   end P_Scoped_Name;

   ---------------------
   -- P_Sequence_Type --
   ---------------------

   --  (80) <sequence_type> ::= "sequence" "<" <simple_type_spec> ","
   --                                          <positive_int_const> ">"
   --                         | "sequence" "<" <simple_type_spec> ">"

   function P_Sequence_Type return Node_Id is
      Node          : Node_Id;
      Seq_Type_Spec : Node_Id;
      Seq_Level     : Natural;
      Size          : Node_Id;

   begin
      Scan_Token; --  past "sequence"
      Node := New_Node (K_Sequence_Type, Token_Location);

      Scan_Token (T_Less);
      if Token = T_Error then
         return No_Node;
      end if;
      Sequencing_Level := Sequencing_Level + 1;
      Seq_Level := Sequencing_Level;

      Seq_Type_Spec := P_Type_Spec;
      if No (Seq_Type_Spec) then
         return No_Node;
      end if;
      Set_Type_Spec (Node, Seq_Type_Spec);

      if Seq_Level > Sequencing_Level then
         return Node;
      end if;

      if Sequencing_Level > 1 then
         Scan_Token ((T_Comma, T_Greater, T_Greater_Greater));
      else
         Scan_Token ((T_Comma, T_Greater));
      end if;

      if Token = T_Error then
         return No_Node;
      end if;

      if Token = T_Comma then
         Size := P_Constant_Expression;

         if Sequencing_Level > 1 then
            Scan_Token ((T_Greater, T_Greater_Greater));
         else
            Scan_Token (T_Greater);
         end if;

         if Token = T_Error then
            return No_Node;
         end if;

      --  No max size means no size

      else
         Size := No_Node;
      end if;
      Set_Max_Size (Node, Size);

      if Token = T_Greater_Greater then
         Sequencing_Level := Sequencing_Level - 2;
      else
         Sequencing_Level := Sequencing_Level - 1;
      end if;

      return Node;
   end P_Sequence_Type;

   -------------------------
   -- P_Simple_Declarator --
   -------------------------

   --  (51) <simple_declarator> ::= <identifier>

   function P_Simple_Declarator return Node_Id is
      Identifier : Node_Id;
      Node     : Node_Id;

   begin
      Identifier := P_Identifier;
      if No (Identifier) then
         return No_Node;
      end if;

      Node := New_Node (K_Simple_Declarator, Loc (Identifier));
      Bind_Identifier_To_Entity (Identifier, Node);

      return Node;
   end P_Simple_Declarator;

   ------------------------
   -- P_Simple_Type_Spec --
   ------------------------

   --  (45) <simple_type_spec> ::= <base_type_spec>
   --                            | <template_type_spec>
   --                            | <scoped_name>
   --
   --  (46) <base_type_spec> ::= <floating_pt_type>
   --                          | <integer_type>
   --                          | <char_type>
   --                          | <wide_char_type>
   --                          | <boolean_type>
   --                          | <octet_type>
   --                          | <any_type>
   --                          | <object_type>
   --                          | <value_base_type>
   --
   --  (47) <template_type_spec> ::= <sequence_type>
   --                              | <string_type>
   --                              | <wide_string_type>
   --                              | <fixed_pt_type>

   function P_Simple_Type_Spec return Node_Id is
      List  : Token_List_Type (1 .. 3) := (others => T_Error);
      Size  : Natural := 0;
      Next  : Token_Type;
      Loc   : Location;

      procedure Push_Base_Type_Token (T : Token_Type);
      --  Push token in the list above. This token is either T_Float,
      --  T_Double, T_Short, T_Long, T_Unsigned, T_Char, T_Wchar or T_Octet.

      function Resolve_Base_Type return Node_Id;

      --------------------------
      -- Push_Base_Type_Token --
      --------------------------

      procedure Push_Base_Type_Token (T : Token_Type) is
      begin
         Size := Size + 1;
         List (Size) := T;
      end Push_Base_Type_Token;

      -----------------------
      -- Resolve_Base_Type --
      -----------------------

      function Resolve_Base_Type return Node_Id is
      begin
         return Resolve_Base_Type (List (1 .. Size), Loc);
      end Resolve_Base_Type;

   begin
      Size := 0;
      Next := Skip_Annapp_Next_Token;
      Push_Base_Type_Token (Next);
      case Next is
         when T_Long =>
            Scan_Token; -- skip long
            Loc := Token_Location;
            Next := Next_Token;
            if Next = T_Double
              or else Next = T_Long
            then
               Scan_Token;
               Push_Base_Type_Token (Next);
            end if;
            return Resolve_Base_Type;

         when T_Short
           | T_Float
           | T_Double
           | T_Char
           | T_Wchar
           | T_Boolean
           | T_Octet
           | T_Any
           | T_Object
           | T_Value_Base =>
            Scan_Token;
            Loc := Token_Location;
            return Resolve_Base_Type;

         when T_Unsigned =>
            Scan_Token; --  skip unsigned
            Loc := Token_Location;
            Scan_Token ((T_Short, T_Long));
            Push_Base_Type_Token (Token);
            if Token = T_Error then
               return No_Node;

            elsif Token = T_Long then
               Next := Next_Token;
               if Next = T_Long then
                  Scan_Token; -- skip long
                  Push_Base_Type_Token (Next);
               end if;
            end if;
            return Resolve_Base_Type;

         when T_String
           | T_Wstring =>
            return P_String_Type;

         when T_Fixed =>
            return P_Fixed_Point_Type;

         when T_Identifier
           | T_Colon_Colon =>
            return P_Scoped_Name;

         when T_Sequence =>
            return P_Sequence_Type;

         when others =>
            Scan_Token;
            Unexpected_Token (Token, "type specifier");
            return No_Node;
      end case;
   end P_Simple_Type_Spec;

   ---------------------
   -- P_Specification --
   ---------------------

   --  (1) <specification> ::= <import>* <definition>+

   procedure P_Specification (Imported : Boolean := False)
   is
      Definitions : List_Id;
      Imports     : List_Id;
      Definition  : Node_Id;
      Import      : Node_Id;
      Identifier  : Node_Id;
      Next        : Token_Type;

   begin
      --  If we parse an imported specification, we don't create a new node
      --  K_Specification, we append the imported entities to the original
      --  specification

      if Imported then
         Definitions := FEN.Definitions (Specification);
         Imports     := FEN.Imports (Specification);
      else
         Identifier := Make_Identifier
           (Token_Location, Scopes.IDL_Spec_Name, No_Node, No_Node);
         Specification := New_Node (K_Specification, Token_Location);
         Bind_Identifier_To_Entity (Identifier, Specification);
         Definitions   := New_List (Token_Location);
         Set_Definitions (Specification, Definitions);
         Imports := New_List (Token_Location);
         Set_Imports (Specification, Imports);
      end if;

      --  Scanning the imported scopes to the current global scope
      Next := Next_Token;
      while Next = T_Import loop
         Import := P_Import;
         if Present (Import) then
            Set_Imported (Import, Imported);
            Append_To (Imports, Import);
         end if;
         Next := Next_Token;
      end loop;

      loop
         Definition := P_Definition;
         if Present (Definition) then
            Set_Imported (Definition, Imported);
            Append_To (Definitions, Definition);
         end if;
         exit when Next_Token = T_EOF;
      end loop;

   end P_Specification;

   --------------------
   -- P_State_Member --
   --------------------

   --  (22) <state_member> ::= ( "public" | "private" )
   --                          <type_spec> <declarators> ";"
   --  (49) <declarators> ::= <declarator> { "," <declarator> }

   function P_State_Member return Node_Id is
      Declarators  : List_Id;
      Type_Spec    : Node_Id;
      State_Member : Node_Id := No_Node;
      Is_Public    : Boolean := False;
      State        : Location;
   begin
      State := Token_Location;
      Skip_Annapp_Scan_Token (State); --  past "public" or "private"
      if Token = T_Public then
         Is_Public := True;
      end if;

      Type_Spec := P_Type_Spec;
      if No (Type_Spec) then
         return No_Node;
      end if;

      Declarators := P_Declarator_List;
      if Is_Empty (Declarators) then
         return No_Node;
      end if;

      Scan_Token (T_Semi_Colon);
      if Token = T_Error then
         Restore_Lexer (State);
         Skip_Declaration (T_Semi_Colon);
         return No_Node;
      end if;

      State_Member := New_Node (K_State_Member, State);
      Set_Type_Spec   (State_Member, Type_Spec);
      Set_Is_Public   (State_Member, Is_Public);
      Set_Declarators (State_Member, Declarators);

      return State_Member;
   end P_State_Member;

   -------------------
   -- P_String_Type --
   -------------------

   --  (81) <string_type> ::= "string" "<" <positive_int_const> ">"
   --                       | "string"
   --
   --  (82) <wide_string_type> ::= "wstring" "<" <positive_int_const> ">"
   --                            | "wstring"

   function P_String_Type return Node_Id is
      Node     : Node_Id;
      Size     : Node_Id;
      subtype Any_String is Token_Type range T_String .. T_Wstring;
   begin
      Scan_Token;

      case Any_String'(Token) is
         when T_String =>
            Node := New_Node (K_String_Type, Token_Location);
         when T_Wstring =>
            Node := New_Node (K_Wide_String_Type, Token_Location);
      end case;

      if Next_Token /= T_Less then
         return Resolve_Base_Type ((1 => Token), Token_Location);
      end if;

      Scan_Token; --  past '<'
      Size := P_Constant_Expression;
      Set_Max_Size (Node, Size);

      Scan_Token (T_Greater);
      if Token = T_Error then
         return No_Node;
      end if;

      return Node;
   end P_String_Type;

   ----------------------
   -- P_Structure_Type --
   ----------------------

   --  (69) <struct_type> ::= "struct" <identifier> "{" <member_list> "}"
   --  (70) <member_list> ::= <member> +

   function P_Structure_Type return Node_Id is
      Identifier  : Node_Id;
      Node        : Node_Id;
      Members     : List_Id;
      Member      : Node_Id;
      State       : Location;

   begin
      Scan_Token; --  past "struct";
      Node := New_Node (K_Structure_Type, Token_Location);

      Identifier := P_Identifier;
      if No (Identifier) then
         return No_Node;
      end if;
      Bind_Identifier_To_Entity (Identifier, Node);

      Members := New_List (Token_Location);
      Set_Members      (Node, Members);

      Scan_Token; --  past '{'

      loop
         Save_Lexer (State);
         Member := P_Member;
         if No (Member) then
            Restore_Lexer (State);
            Skip_Declaration (T_Right_Brace);
            exit;
         end if;

         Append_To (Members, Member);

         if Next_Token = T_Right_Brace then
            Scan_Token;
            exit;
         end if;
      end loop;

      return Node;
   end P_Structure_Type;

   ------------------------
   -- P_Type_Declaration --
   ------------------------

   --  (42) <type_dcl> ::= "typedef" <type_declarator>
   --                    | <struct_type>
   --                    | <union_type>
   --                    | <enum_type>
   --                    | "native" <simple_declarator>
   --                    | <constr_forward_decl>
   --  (43) <type_declarator> ::= <type_spec> <declarators>

   function P_Type_Declaration return Node_Id is
      Identifier  : Node_Id;
      Node        : Node_Id := No_Node;
      Type_Spec   : Node_Id;
      Declarator  : Node_Id;
      Declarators : List_Id;
      State       : Location;

   begin
      Save_Lexer (State);
      Scan_Token;

      case Token is
         when T_Typedef =>
            Type_Spec := P_Type_Spec;
            if No (Type_Spec) then
               return No_Node;
            end if;

            Declarators := P_Declarator_List;
            if Is_Empty (Declarators) then
               return No_Node;
            end if;
            Node := New_Node (K_Type_Declaration, State);
            Set_Type_Spec   (Node, Type_Spec);
            Set_Declarators (Node, Declarators);
            Set_Marked_As_Subtype (Node, False);
            Bind_Declarators_To_Entity (Declarators, Node);

         when T_Native =>

            Declarator := P_Simple_Declarator;
            if No (Declarator) then
               return No_Node;
            end if;

            Node := New_Node (K_Native_Type, State);
            Set_Declarator (Node, Declarator);
            Bind_Declarator_To_Entity (Declarator, Node);

         when T_Struct =>
            Identifier := P_Identifier;
            if No (Identifier) then
               return No_Node;
            end if;

            if Next_Token = T_Semi_Colon then
               Node := New_Node (K_Forward_Structure_Type, State);
               Bind_Identifier_To_Entity (Identifier, Node);

            else
               Restore_Lexer (State);
               return P_Structure_Type;
            end if;

         when T_Union =>
            Identifier := P_Identifier;
            if No (Identifier) then
               return No_Node;
            end if;

            if Next_Token = T_Semi_Colon then
               Node := New_Node (K_Forward_Union_Type, State);
               Bind_Identifier_To_Entity (Identifier, Node);

            else
               Restore_Lexer (State);
               return P_Union_Type;
            end if;

         when T_Enum =>
            Restore_Lexer (State);
            return P_Enumeration_Type;

         when others =>
            return No_Node;
      end case;

      return Node;
   end P_Type_Declaration;

   ---------------
   -- P_Type_Id --
   ---------------

   --  (102) <type_id_dcl> ::= "typeid" <scoped_name> <string_literal>

   function P_Type_Id_Declaration return Node_Id is
      Node        : Node_Id;
      Scoped_Name : Node_Id;
   begin
      Scan_Token; --  past "typeid";
      Node := New_Node (K_Type_Id_Declaration, Token_Location);

      Scoped_Name := P_Scoped_Name;
      if No (Scoped_Name) then
         Error_Loc (1) := Token_Location;
         DE ("Scoped name expected after typeid");
      end if;

      Set_Target (Node, Scoped_Name);

      --  Getting the "<string_literal>"

      Scan_Token (T_String_Literal);
      Set_Data (Node, Name_Find);

      return Node;
   end P_Type_Id_Declaration;

   -------------------
   -- P_Type_Prefix --
   -------------------

   --  (103) <type_prefix_dcl> ::= "typeprefix" <scoped_name> <string_literal>

   function P_Type_Prefix_Declaration return Node_Id is
      Node        : Node_Id;
      Scoped_Name : Node_Id;
   begin
      Scan_Token; --  past "typeprefix";
      Node := New_Node (K_Type_Prefix_Declaration, Token_Location);

      Scoped_Name := P_Scoped_Name;
      if No (Scoped_Name) then
         Error_Loc (1) := Token_Location;
         DE ("Scoped name expected after typeprefix");
      end if;

      Set_Target (Node, Scoped_Name);

      --  Getting the "<string_literal>"

      Scan_Token (T_String_Literal);
      Set_Data (Node, Name_Find);

      return Node;
   end P_Type_Prefix_Declaration;

   -----------------
   -- P_Type_Spec --
   -----------------

   --  (44) <type_spec> ::= <simple_type_spec>
   --                     | <constr_type_spec>
   --
   --  (45) <simple_type_spec> ::= <base_type_spec>
   --                            | <template_type_spec>
   --                            | <scoped_name>
   --
   --  (46) <base_type_spec> ::= <floating_pt_type>
   --                          | <integer_type>
   --                          | <char_type>
   --                          | <wide_char_type>
   --                          | <boolean_type>
   --                          | <octet_type>
   --                          | <any_type>
   --                          | <object_type>
   --                          | <value_base_type>
   --
   --  (47) <template_type_spec> ::= <sequence_type>
   --                              | <string_type>
   --                              | <wide_string_type>
   --                              | <fixed_pt_type>
   --
   --  (48) <constr_type_spec> ::= <struct_type>
   --                            | <union_type>
   --                            | <enum_type>

   function P_Type_Spec return Node_Id is
   begin
      case Next_Token is
         when T_Struct =>
            return P_Structure_Type;

         when T_Enum =>
            return P_Enumeration_Type;

         when T_Union =>
            return P_Union_Type;

         when others =>
            return P_Simple_Type_Spec;
      end case;
   end P_Type_Spec;

   ------------------
   -- P_Union_Type --
   ------------------

   --  (72) <union_type> ::= "union" <identifier> "switch"
   --                        "(" <switch_type_spec> ")"
   --                        "{" <switch_body> "}"
   --
   --  (73) <switch_type_spec> ::= <integer_type>
   --                            | <char_type>
   --                            | <boolean_type>
   --                            | <enum_type>
   --                            | <scoped_name>
   --
   --  (74) <switch_body> ::= <case> +
   --  (75) <case> ::= <case_label> + <element_spec> ";"
   --  (76) <case_label> ::= "case" <const_exp> ":"
   --                      | "default" ":"
   --
   --  (77) <element_spec> ::= <type_spec> <declarator>

   function P_Union_Type return Node_Id is
      function Is_Switch_Type_Spec (K : Node_Kind) return Boolean;

      --------------------
      -- Is_Switch_Spec --
      --------------------

      --  (73) <switch_type_spec> ::= <integer_type>
      --                            | <char_type>
      --                            | <boolean_type>
      --                            | <enum_type>
      --                            | <scoped_name>

      function Is_Switch_Type_Spec (K : Node_Kind) return Boolean is
      begin
         case K is
            when K_Short
              | K_Long
              | K_Long_Long
              | K_Unsigned_Short
              | K_Unsigned_Long
              | K_Unsigned_Long_Long
              | K_Char
              | K_Boolean
              | K_Enumeration_Type
              | K_Scoped_Name =>
               return True;

            when others =>
               return False;
         end case;
      end Is_Switch_Type_Spec;

      Identifier         : Node_Id;
      Node               : Node_Id;
      Switch_Type_Spec   : Node_Id;
      Switch_Type_Body   : List_Id;
      Switch_Alt_Decl    : Node_Id;
      Element_Type_Spec  : Node_Id;
      Element_Declarator : Node_Id;
      Element            : Node_Id;
      Case_Labels        : List_Id;
      Case_Label         : Node_Id;
      Expression         : Node_Id;
      State              : Location;

   begin

      --  (72) <union_type> ::= "union" <identifier> "switch"
      --                        "(" <switch_type_spec> ")"
      --                        "{" <switch_body> "}"

      Scan_Token; --  past "union"
      Node := New_Node (K_Union_Type, Token_Location);

      Identifier := P_Identifier;
      if No (Identifier) then
         return No_Node;
      end if;
      Bind_Identifier_To_Entity (Identifier, Node);

      Scan_Token (T_Switch);
      if Token = T_Error then
         return No_Node;
      end if;

      Scan_Token (T_Left_Paren);
      if Token = T_Error then
         return No_Node;
      end if;

      --  (73) <switch_type_spec> ::= <integer_type>
      --                            | <char_type>
      --                            | <boolean_type>
      --                            | <enum_type>
      --                            | <scoped_name>

      Save_Lexer (State);
      Switch_Type_Spec := P_Type_Spec;
      if Present (Switch_Type_Spec)
        and then not Is_Switch_Type_Spec (Kind (Switch_Type_Spec))
      then
         Error_Loc (1) := Loc (Switch_Type_Spec);
         DE ("unexpected switch type spec");
         Switch_Type_Spec := No_Node;
      end if;

      if No (Switch_Type_Spec) then
         Restore_Lexer (State);
         Skip_Declaration (T_Right_Paren);

      else
         Save_Lexer (State);
         Scan_Token (T_Right_Paren);
         if Token = T_Error then
            Restore_Lexer (State);
            Skip_Declaration (T_Right_Paren);
         end if;
      end if;
      Set_Switch_Type_Spec (Node, Switch_Type_Spec);

      Scan_Token (T_Left_Brace);
      if Token = T_Error then
         return No_Node;
      end if;

      Switch_Type_Body := New_List (Token_Location);
      Set_Switch_Type_Body (Node, Switch_Type_Body);

      Switch_Alternative_Declaration :
      loop
         Save_Lexer (State);
         Scan_Token ((T_Default, T_Case));
         if Token = T_Error then
            Restore_Lexer (State);
            Skip_Declaration (T_Right_Brace);
            exit Switch_Alternative_Declaration;
         end if;

         Switch_Alt_Decl := New_Node (K_Switch_Alternative, Token_Location);
         Case_Labels := New_List (Token_Location);
         Set_Labels (Switch_Alt_Decl, Case_Labels);

         --  (74) <switch_body> ::= <case> +

         Case_Label_List :
         loop
            Save_Lexer (State);
            Case_Label := New_Node (K_Case_Label, Token_Location);
            Set_Declaration (Case_Label, Switch_Alt_Decl);

            --  (75) <case> ::= <case_label> + <element_spec> ";"

            Expression := No_Node;
            if Token = T_Case then
               Expression := P_Constant_Expression;
               if No (Expression) then
                  Restore_Lexer (State);
                  Skip_Declaration (T_Right_Brace);
                  exit Switch_Alternative_Declaration;
               end if;
            end if;

            Scan_Token (T_Colon);
            if Token = T_Error then
               Restore_Lexer (State);
               Skip_Declaration (T_Right_Brace);
               exit Switch_Alternative_Declaration;
            end if;

            Set_Expression (Case_Label, Expression);
            Append_To (Case_Labels, Case_Label);

            --  (76) <case_label> ::= "case" <const_exp> ":"
            --                      | "default" ":"

            case Next_Token is
               when T_Case
                 | T_Default =>
                  Scan_Token;

               when others =>
                  exit Case_Label_List;
            end case;
         end loop Case_Label_List;

         --  (77) <element_spec> ::= <type_spec> <declarator>

         Save_Lexer (State);
         Element_Type_Spec := P_Type_Spec;
         if No (Element_Type_Spec) then
            Restore_Lexer (State);
            Skip_Declaration (T_Right_Brace);
            exit Switch_Alternative_Declaration;
         end if;

         Save_Lexer (State);
         Element_Declarator := P_Declarator;
         if No (Element_Declarator) then
            Restore_Lexer (State);
            Skip_Declaration (T_Right_Brace);
            exit Switch_Alternative_Declaration;
         end if;

         --  Assemble Element and append it to Switch Alternative

         Element := New_Node (K_Element, Loc (Element_Type_Spec));
         Set_Type_Spec  (Element, Element_Type_Spec);
         Set_Declarator (Element, Element_Declarator);
         Bind_Declarator_To_Entity (Element_Declarator, Element);

         Set_Element     (Switch_Alt_Decl, Element);
         Set_Declaration (Switch_Alt_Decl, Node);

         Append_To (Switch_Type_Body, Switch_Alt_Decl);

         Save_Lexer (State);
         Scan_Token (T_Semi_Colon);
         if Token = T_Error then
            Restore_Lexer (State);
            Skip_Declaration (T_Right_Brace);
            exit Switch_Alternative_Declaration;
         end if;

         if Next_Token = T_Right_Brace then
            Scan_Token; --  past '}'
            exit Switch_Alternative_Declaration;
         end if;
      end loop Switch_Alternative_Declaration;

      return Node;
   end P_Union_Type;

   -------------
   -- P_Value --
   -------------

   --  (13) <value> ::= <value_dcl>
   --                 | <value_abs_dcl>
   --                 | <value_box_dcl>
   --                 | <value_forward_dcl>)

   function P_Value return Node_Id is
      State      : Location;
      Value_Abs  : Boolean := False;

   begin
      Save_Lexer (State);

      Scan_Token; --  past "abstract" or "custom" or "valuetype"
      if Token = T_Abstract then
         Value_Abs := True;
         Scan_Token; --  past "valuetype"

      elsif Token = T_Custom then
         Scan_Token; --  past "valuetype"
      end if;

      if No (P_Identifier) then
         return No_Node;
      end if;

      Scan_Token;
      case Token is
         when T_Semi_Colon =>
            Restore_Lexer (State);
            return P_Value_Forward_Declaration;

         when T_Custom =>
            Restore_Lexer (State);
            return P_Value_Declaration;

         when T_Colon | T_Left_Brace | T_Supports =>
            Restore_Lexer (State);
            if Value_Abs then
               return P_Value_Abstract_Declaration;
            else
               return P_Value_Declaration;
            end if;

         when others =>
            Restore_Lexer (State);
            return P_Value_Box_Declaration;
      end case;
   end P_Value;

   ----------------------------------
   -- P_Value_Abstract_Declaration --
   ----------------------------------

   --  (16) <value_abs_dcl> ::= "abstract" "valuetype" <identifier>
   --                         [ <value_inheritance_spec> ] "{" <export>* "}"

   function P_Value_Abstract_Declaration return Node_Id is
      Identifier  : Node_Id;
      Node      : Node_Id;
      Value_Spec  : Node_Id;
      Value_Body  : List_Id;
      Export      : Node_Id;
      State       : Location;

   begin
      Scan_Token; --  past "abstract"
      Node := New_Node (K_Abstract_Value_Declaration, Token_Location);

      Scan_Token; --  past "valuetype"

      Identifier := P_Identifier;
      if No (Identifier) then
         return No_Node;
      end if;
      Bind_Identifier_To_Entity (Identifier, Node);

      Value_Spec := P_Value_Spec;
      Set_Value_Spec (Node, Value_Spec);

      Scan_Token (T_Left_Brace);
      if Token = T_Error then
         return No_Node;
      end if;

      Value_Body := New_List (Token_Location);
      Set_Value_Body   (Node, Value_Body);

      if Next_Token = T_Right_Brace then
         Scan_Token;

      else
         loop
            Save_Lexer (State);
            Export := P_Export;
            if No (Export) then
               Restore_Lexer (State);
               Skip_Declaration (T_Right_Brace);
               exit;
            end if;

            Append_To (Value_Body, Export);

            if Next_Token = T_Right_Brace then
               Scan_Token;
               exit;
            end if;
         end loop;
      end if;

      return Node;
   end P_Value_Abstract_Declaration;

   -----------------------------
   -- P_Value_Box_Declaration --
   -----------------------------

   --  (15) <value_box_dcl> ::= "valuetype" <identifier> <type_spec>

   function P_Value_Box_Declaration return Node_Id is
      Identifier : Node_Id;
      Node     : Node_Id;
      Type_Spec  : Node_Id;

   begin
      Scan_Token; --  past "valuetype"
      Node := New_Node (K_Value_Box_Declaration, Token_Location);

      Identifier := P_Identifier;
      if No (Identifier) then
         return No_Node;
      end if;
      Bind_Identifier_To_Entity (Identifier, Node);

      Type_Spec := P_Type_Spec;
      if No (Type_Spec) then
         return No_Node;
      end if;
      Set_Type_Spec (Node, Type_Spec);

      return Node;
   end P_Value_Box_Declaration;

   -------------------------
   -- P_Value_Declaration --
   -------------------------

   --  (17) <value_dcl> ::= <value_header> "{"  <value_element>* "}"
   --  (18) <value_header> ::= [" custom" ] "valuetype" <identifier>
   --                          [ <value_inheritance_spec> ]
   --
   --  (20) <value_name> ::= <scoped_name>
   --  (21) <value_element> ::= <export> |  <state_member> | <init_dcl>

   function P_Value_Declaration return Node_Id is
      Identifier    : Node_Id;
      Node        : Node_Id;
      Value_Spec    : Node_Id;
      Value_Body    : List_Id;
      Value_Element : Node_Id;
      State         : Location;

   begin
      Scan_Token; --  past "custom" or "valuetype"
      Node := New_Node (K_Value_Declaration, Token_Location);

      if Token = T_Custom then
         Set_Is_Custom (Node, True);

         Scan_Token (T_Value_Type);
         if Token = T_Error then
            return No_Node;
         end if;
      end if;

      Identifier := P_Identifier;
      if No (Identifier) then
         return No_Node;
      end if;
      Bind_Identifier_To_Entity (Identifier, Node);

      Value_Spec := P_Value_Spec;
      Set_Value_Spec (Node, Value_Spec);

      Scan_Token (T_Left_Brace);
      if Token = T_Error then
         return No_Node;
      end if;

      Value_Body := New_List (Token_Location);
      Set_Value_Body   (Node, Value_Body);

      loop
         Save_Lexer (State);
         case Next_Token is
            when T_Factory =>
               Value_Element := P_Initializer_Declaration;

            when T_Public | T_Private =>
               Value_Element := P_State_Member;

            when T_Right_Brace =>
               Scan_Token;  -- past "}"
               exit;

            when others =>
               Value_Element := P_Export;
         end case;

         if No (Value_Element) then
            Restore_Lexer (State);
            Skip_Declaration (T_Right_Brace);
            exit;
         end if;

         Append_To (Value_Body, Value_Element);
      end loop;

      return Node;
   end P_Value_Declaration;

   ---------------------------------
   -- P_Value_Forward_Declaration --
   ---------------------------------

   --  (14) <value_forward_dcl> ::= [ "abstract" ] "valuetype" <identifier>

   function P_Value_Forward_Declaration return Node_Id is
      Identifier : Node_Id;
      Node       : Node_Id;

   begin
      Scan_Token; --  past "valuetype" or "abstract"
      Node := New_Node (K_Value_Forward_Declaration, Token_Location);

      if Token = T_Abstract then
         Set_Is_Abstract_Value (Node, True);
         Scan_Token (T_Value_Type);
      end if;

      Identifier := P_Identifier;
      if No (Identifier) then
         return No_Node;
      end if;
      Bind_Identifier_To_Entity (Identifier, Node);

      return Node;
   end P_Value_Forward_Declaration;

   ------------------
   -- P_Value_Spec --
   ------------------

   --  (19) <value_inheritance_spec> ::=
   --            [ ":" [ "truncatable" ] <value_name>
   --                              { "," <value_name> }* ]
   --            [ "supports" <interface_name>
   --                   { "," <interface_name> }* ]

   function P_Value_Spec return Node_Id is
      Value_Spec      : Node_Id := No_Node;
      Value_Names     : List_Id;
      Interface_Names : List_Id;
      Scoped_Name     : Node_Id;
      Interface_Name  : Node_Id;

   begin
      Value_Spec := New_Node (K_Value_Spec, Token_Location);

      if Next_Token = T_Colon then
         Scan_Token; --  past ":"
         if Next_Token = T_Truncatable then
            Scan_Token; --  past "truncatable"
            Set_Is_Truncatable (Value_Spec, True);
         end if;

         Value_Names := New_List (Token_Location);
         Set_Value_Names (Value_Spec, Value_Names);

         loop
            Scoped_Name := P_Scoped_Name;
            if No (Scoped_Name) then
               return No_Node;
            end if;

            Append_To (Value_Names, Scoped_Name);

            exit when Next_Token /= T_Comma;
            Scan_Token; --  past ','
         end loop;
      end if;

      if Next_Token = T_Supports then
         Scan_Token;  --  past "supports"
         Interface_Names := New_List (Token_Location);
         Set_Interface_Names (Value_Spec, Interface_Names);

         loop
            Interface_Name := P_Interface_Name;
            if No (Interface_Name) then
               return No_Node;
            end if;

            Append_To (Interface_Names, Interface_Name);

            exit when Next_Token /= T_Comma;
            Scan_Token;  --  past ','
         end loop;
      end if;

      return Value_Spec;
   end P_Value_Spec;

   -------------
   -- Process --
   -------------

   procedure Process (IDL_Spec : out Node_Id) is
   begin
      --  (53) <floating_pt_type> ::= "float"
      --                            | "double"
      --                            | "long" "double"

      Declare_Base_Type ((1 => T_Float), K_Float);
      Declare_Base_Type ((1 => T_Double), K_Double);
      Declare_Base_Type ((T_Long, T_Double), K_Long_Double);

      --  (54) <integer_type> ::= <signed_int>
      --                        | <unsigned_int>
      --
      --  (55) <signed_int> ::= <signed_short_int>
      --                      | <signed_long_int>
      --                      | <signed_longlong_int>
      --
      --  (56) <signed_short_int> ::= "short"
      --  (57) <signed_long_int> ::= "long"
      --  (58) <signed_longlong_int> ::= "long" "long"
      --  (59) <unsigned_int> ::= <unsigned_short_int>
      --                        | <unsigned_long_int>
      --                        | <unsigned_longlong_int>
      --
      --  (60) <unsigned_short_int> ::= "unsigned" "short"
      --  (61) <unsigned_long_int> ::= "unsigned" "long"
      --  (62) <unsigned_longlong_int> ::= "unsigned" "long" "long"

      Declare_Base_Type ((1 => T_Short), K_Short);
      Declare_Base_Type ((1 => T_Long), K_Long);
      Declare_Base_Type ((T_Long, T_Long), K_Long_Long);
      Declare_Base_Type ((T_Unsigned, T_Short), K_Unsigned_Short);
      Declare_Base_Type ((T_Unsigned, T_Long), K_Unsigned_Long);
      Declare_Base_Type ((T_Unsigned, T_Long, T_Long), K_Unsigned_Long_Long);

      --  (63) <char_type> ::= "char"
      --  (64) <wide_char_type> ::= "wchar"

      Declare_Base_Type ((1 => T_Char), K_Char);
      Declare_Base_Type ((1 => T_Wchar), K_Wide_Char);

      Declare_Base_Type ((1 => T_String), K_String);
      Declare_Base_Type ((1 => T_Wstring), K_Wide_String);

      --  (65) <boolean_type> ::= "boolean"
      --  (66) <octet_type> ::= "octet"
      --  (67) <any_type> ::= "any"
      --  (68) <object_type> ::= "Object"

      Declare_Base_Type ((1 => T_Boolean), K_Boolean);
      Declare_Base_Type ((1 => T_Octet), K_Octet);
      Declare_Base_Type ((1 => T_Any), K_Any);
      Declare_Base_Type ((1 => T_Object), K_Object);
      Declare_Base_Type ((1 => T_Value_Base), K_Value_Base);

      --  89) <op_type_spec> ::= <param_type_spec>
      --                       | "void"

      Declare_Base_Type ((1 => T_Void), K_Void);

      P_Specification;
      IDL_Spec := Specification;
   end Process;

   -----------------------
   -- Resolve_Base_Type --
   -----------------------

   function Resolve_Base_Type
     (L   : Token_List_Type;
      Loc : Location) return Node_Id
   is
      Info   : Nat;
      Result : Node_Id;
   begin
      Set_Str_To_Name_Buffer (Image (L (L'First)));
      for I in L'First + 1 .. L'Last loop
         Add_Char_To_Name_Buffer (' ');
         Add_Str_To_Name_Buffer  (Image (L (I)));
      end loop;

      Info := Get_Name_Table_Info (Name_Find);

      if Info = 0 then
         return No_Node;
      else
         Result := New_Node (Kind (Node_Id (Info)), Loc);
         Set_Image (Base_Type (Result), Image (Base_Type (Info)));
         return Result;
      end if;
   end Resolve_Base_Type;

end Parser;
