| ------------------------------------------------------------------------------ | 
 | --                                                                          -- | 
 | --                         GNAT COMPILER COMPONENTS                         -- | 
 | --                                                                          -- | 
 | --                                 P R E P                                  -- | 
 | --                                                                          -- | 
 | --                                 B o d y                                  -- | 
 | --                                                                          -- | 
 | --          Copyright (C) 2002-2005, Free Software Foundation, Inc.         -- | 
 | --                                                                          -- | 
 | -- GNAT is free software;  you can  redistribute it  and/or modify it under -- | 
 | -- terms of the  GNU General Public License as published  by the Free Soft- -- | 
 | -- ware  Foundation;  either version 2,  or (at your option) any later ver- -- | 
 | -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- -- | 
 | -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY -- | 
 | -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License -- | 
 | -- for  more details.  You should have  received  a copy of the GNU General -- | 
 | -- Public License  distributed with GNAT;  see file COPYING.  If not, write -- | 
 | -- to  the  Free Software Foundation,  51  Franklin  Street,  Fifth  Floor, -- | 
 | -- Boston, MA 02110-1301, USA.                                              -- | 
 | --                                                                          -- | 
 | -- GNAT was originally developed  by the GNAT team at  New York University. -- | 
 | -- Extensive contributions were provided by Ada Core Technologies Inc.      -- | 
 | --                                                                          -- | 
 | ------------------------------------------------------------------------------ | 
 |  | 
 | with Csets;    use Csets; | 
 | with Err_Vars; use Err_Vars; | 
 | with Namet;    use Namet; | 
 | with Opt;      use Opt; | 
 | with Osint;    use Osint; | 
 | with Output;   use Output; | 
 | with Scans;    use Scans; | 
 | with Snames;   use Snames; | 
 | with Sinput; | 
 | with Stringt;  use Stringt; | 
 | with Table; | 
 |  | 
 | with GNAT.Heap_Sort_G; | 
 |  | 
 | package body Prep is | 
 |  | 
 |    use Symbol_Table; | 
 |  | 
 |    type Token_Name_Array is array (Token_Type) of Name_Id; | 
 |    Token_Names : constant Token_Name_Array := | 
 |      (Tok_Abort     => Name_Abort, | 
 |       Tok_Abs       => Name_Abs, | 
 |       Tok_Abstract  => Name_Abstract, | 
 |       Tok_Accept    => Name_Accept, | 
 |       Tok_Aliased   => Name_Aliased, | 
 |       Tok_All       => Name_All, | 
 |       Tok_Array     => Name_Array, | 
 |       Tok_And       => Name_And, | 
 |       Tok_At        => Name_At, | 
 |       Tok_Begin     => Name_Begin, | 
 |       Tok_Body      => Name_Body, | 
 |       Tok_Case      => Name_Case, | 
 |       Tok_Constant  => Name_Constant, | 
 |       Tok_Declare   => Name_Declare, | 
 |       Tok_Delay     => Name_Delay, | 
 |       Tok_Delta     => Name_Delta, | 
 |       Tok_Digits    => Name_Digits, | 
 |       Tok_Else      => Name_Else, | 
 |       Tok_Elsif     => Name_Elsif, | 
 |       Tok_End       => Name_End, | 
 |       Tok_Entry     => Name_Entry, | 
 |       Tok_Exception => Name_Exception, | 
 |       Tok_Exit      => Name_Exit, | 
 |       Tok_For       => Name_For, | 
 |       Tok_Function  => Name_Function, | 
 |       Tok_Generic   => Name_Generic, | 
 |       Tok_Goto      => Name_Goto, | 
 |       Tok_If        => Name_If, | 
 |       Tok_Is        => Name_Is, | 
 |       Tok_Limited   => Name_Limited, | 
 |       Tok_Loop      => Name_Loop, | 
 |       Tok_Mod       => Name_Mod, | 
 |       Tok_New       => Name_New, | 
 |       Tok_Null      => Name_Null, | 
 |       Tok_Of        => Name_Of, | 
 |       Tok_Or        => Name_Or, | 
 |       Tok_Others    => Name_Others, | 
 |       Tok_Out       => Name_Out, | 
 |       Tok_Package   => Name_Package, | 
 |       Tok_Pragma    => Name_Pragma, | 
 |       Tok_Private   => Name_Private, | 
 |       Tok_Procedure => Name_Procedure, | 
 |       Tok_Protected => Name_Protected, | 
 |       Tok_Raise     => Name_Raise, | 
 |       Tok_Range     => Name_Range, | 
 |       Tok_Record    => Name_Record, | 
 |       Tok_Rem       => Name_Rem, | 
 |       Tok_Renames   => Name_Renames, | 
 |       Tok_Requeue   => Name_Requeue, | 
 |       Tok_Return    => Name_Return, | 
 |       Tok_Reverse   => Name_Reverse, | 
 |       Tok_Select    => Name_Select, | 
 |       Tok_Separate  => Name_Separate, | 
 |       Tok_Subtype   => Name_Subtype, | 
 |       Tok_Tagged    => Name_Tagged, | 
 |       Tok_Task      => Name_Task, | 
 |       Tok_Terminate => Name_Terminate, | 
 |       Tok_Then      => Name_Then, | 
 |       Tok_Type      => Name_Type, | 
 |       Tok_Until     => Name_Until, | 
 |       Tok_Use       => Name_Use, | 
 |       Tok_When      => Name_When, | 
 |       Tok_While     => Name_While, | 
 |       Tok_With      => Name_With, | 
 |       Tok_Xor       => Name_Xor, | 
 |       others        => No_Name); | 
 |  | 
 |    Already_Initialized : Boolean := False; | 
 |    --  Used to avoid repetition of the part of the initialisation that needs | 
 |    --  to be done only once. | 
 |  | 
 |    Empty_String : String_Id; | 
 |    --  "", as a string_id | 
 |  | 
 |    String_False : String_Id; | 
 |    --  "false", as a string_id | 
 |  | 
 |    Name_Defined : Name_Id; | 
 |    --  defined, as a name_id | 
 |  | 
 |    --------------- | 
 |    -- Behaviour -- | 
 |    --------------- | 
 |  | 
 |    --  Accesses to procedure specified by procedure Initialize | 
 |  | 
 |    Error_Msg : Error_Msg_Proc; | 
 |    --  Report an error | 
 |  | 
 |    Scan : Scan_Proc; | 
 |    --  Scan one token | 
 |  | 
 |    Set_Ignore_Errors : Set_Ignore_Errors_Proc; | 
 |    --  Indicate if error should be taken into account | 
 |  | 
 |    Put_Char : Put_Char_Proc; | 
 |    --  Output one character | 
 |  | 
 |    New_EOL : New_EOL_Proc; | 
 |    --  Output an end of line indication | 
 |  | 
 |    ------------------------------- | 
 |    -- State of the Preprocessor -- | 
 |    ------------------------------- | 
 |  | 
 |    type Pp_State is record | 
 |       If_Ptr : Source_Ptr; | 
 |       --  The location of the #if statement. | 
 |       --  Used to flag #if with no corresponding #end if, at the end. | 
 |  | 
 |       Else_Ptr : Source_Ptr; | 
 |       --  The location of the #else statement. | 
 |       --  Used to detect multiple #else. | 
 |  | 
 |       Deleting : Boolean; | 
 |       --  Set to True when the code should be deleted or commented out | 
 |  | 
 |       Match_Seen : Boolean; | 
 |       --  Set to True when a condition in an #if or an #elsif is True. | 
 |       --  Also set to True if Deleting at the previous level is True. | 
 |       --  Used to decide if Deleting should be set to True in a following | 
 |       --  #elsif or #else. | 
 |  | 
 |    end record; | 
 |  | 
 |    type Pp_Depth is new Nat; | 
 |  | 
 |    Ground : constant Pp_Depth := 0; | 
 |  | 
 |    package Pp_States is new Table.Table | 
 |      (Table_Component_Type => Pp_State, | 
 |       Table_Index_Type     => Pp_Depth, | 
 |       Table_Low_Bound      => 1, | 
 |       Table_Initial        => 10, | 
 |       Table_Increment      => 10, | 
 |       Table_Name           => "Prep.Pp_States"); | 
 |    --  A stack of the states of the preprocessor, for nested #if | 
 |  | 
 |    type Operator is (None, Op_Or, Op_And); | 
 |  | 
 |    ----------------- | 
 |    -- Subprograms -- | 
 |    ----------------- | 
 |  | 
 |    function Deleting return Boolean; | 
 |    --  Return True if code should be deleted or commented out | 
 |  | 
 |    function Expression (Evaluate_It : Boolean) return Boolean; | 
 |    --  Evaluate a condition in an #if or an #elsif statement. | 
 |    --  If Evaluate_It is False, the condition is effectively evaluated, | 
 |    --  otherwise, only the syntax is checked. | 
 |  | 
 |    procedure Go_To_End_Of_Line; | 
 |    --  Advance the scan pointer until we reach an end of line or the end | 
 |    --  of the buffer. | 
 |  | 
 |    function Matching_Strings (S1, S2 : String_Id) return Boolean; | 
 |    --  Returns True if the two string parameters are equal (case insensitive) | 
 |  | 
 |    --------------------------------------- | 
 |    -- Change_Reserved_Keyword_To_Symbol -- | 
 |    --------------------------------------- | 
 |  | 
 |    procedure Change_Reserved_Keyword_To_Symbol | 
 |      (All_Keywords : Boolean := False) | 
 |    is | 
 |       New_Name : constant Name_Id := Token_Names (Token); | 
 |  | 
 |    begin | 
 |       if New_Name /= No_Name then | 
 |          case Token is | 
 |             when Tok_If  | Tok_Else | Tok_Elsif | Tok_End | | 
 |                  Tok_And | Tok_Or   | Tok_Then => | 
 |                if All_Keywords then | 
 |                   Token := Tok_Identifier; | 
 |                   Token_Name := New_Name; | 
 |                end if; | 
 |  | 
 |             when others => | 
 |                Token := Tok_Identifier; | 
 |                Token_Name := New_Name; | 
 |          end case; | 
 |       end if; | 
 |    end Change_Reserved_Keyword_To_Symbol; | 
 |  | 
 |    ------------------------------------------ | 
 |    -- Check_Command_Line_Symbol_Definition -- | 
 |    ------------------------------------------ | 
 |  | 
 |    procedure Check_Command_Line_Symbol_Definition | 
 |      (Definition  : String; | 
 |       Data        : out Symbol_Data) | 
 |    is | 
 |       Index       : Natural := 0; | 
 |       Result      : Symbol_Data; | 
 |  | 
 |    begin | 
 |       --  Look for the character '=' | 
 |  | 
 |       for J in Definition'Range loop | 
 |          if Definition (J) = '=' then | 
 |             Index := J; | 
 |             exit; | 
 |          end if; | 
 |       end loop; | 
 |  | 
 |       --  If no character '=', then the value is True | 
 |  | 
 |       if Index = 0 then | 
 |          --  Put the symbol in the name buffer | 
 |  | 
 |          Name_Len := Definition'Length; | 
 |          Name_Buffer (1 .. Name_Len) := Definition; | 
 |          Result := True_Value; | 
 |  | 
 |       elsif Index = Definition'First then | 
 |          Fail ("invalid symbol definition """, Definition, """"); | 
 |  | 
 |       else | 
 |          --  Put the symbol in the name buffer | 
 |  | 
 |          Name_Len := Index - Definition'First; | 
 |          Name_Buffer (1 .. Name_Len) := | 
 |            String'(Definition (Definition'First .. Index - 1)); | 
 |  | 
 |          --  Check the syntax of the value | 
 |  | 
 |          if Definition (Index + 1) /= '"' | 
 |            or else Definition (Definition'Last) /= '"' | 
 |          then | 
 |             for J in Index + 1 .. Definition'Last loop | 
 |                case Definition (J) is | 
 |                   when '_' | '.' | '0' .. '9' | 'a' .. 'z' | 'A' .. 'Z' => | 
 |                      null; | 
 |  | 
 |                   when others => | 
 |                      Fail ("illegal value """, | 
 |                            Definition (Index + 1 .. Definition'Last), | 
 |                            """"); | 
 |                end case; | 
 |             end loop; | 
 |          end if; | 
 |  | 
 |          --  And put the value in the result | 
 |  | 
 |          Result.Is_A_String := False; | 
 |          Start_String; | 
 |          Store_String_Chars (Definition (Index + 1 .. Definition'Last)); | 
 |          Result.Value := End_String; | 
 |       end if; | 
 |  | 
 |       --  Now, check the syntax of the symbol (we don't allow accented and | 
 |       --  wide characters) | 
 |  | 
 |       if Name_Buffer (1) not in 'a' .. 'z' | 
 |         and then Name_Buffer (1) not in 'A' .. 'Z' | 
 |       then | 
 |          Fail ("symbol """, | 
 |                Name_Buffer (1 .. Name_Len), | 
 |                """ does not start with a letter"); | 
 |       end if; | 
 |  | 
 |       for J in 2 .. Name_Len loop | 
 |          case Name_Buffer (J) is | 
 |             when 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' => | 
 |                null; | 
 |  | 
 |             when '_' => | 
 |                if J = Name_Len then | 
 |                   Fail ("symbol """, | 
 |                         Name_Buffer (1 .. Name_Len), | 
 |                         """ end with a '_'"); | 
 |  | 
 |                elsif Name_Buffer (J + 1) = '_' then | 
 |                   Fail ("symbol """, | 
 |                         Name_Buffer (1 .. Name_Len), | 
 |                         """ contains consecutive '_'"); | 
 |                end if; | 
 |  | 
 |             when others => | 
 |                Fail ("symbol """, | 
 |                      Name_Buffer (1 .. Name_Len), | 
 |                      """ contains illegal character(s)"); | 
 |          end case; | 
 |       end loop; | 
 |  | 
 |       Result.On_The_Command_Line := True; | 
 |  | 
 |       --  Put the symbol name in the result | 
 |  | 
 |       declare | 
 |          Sym : constant String := Name_Buffer (1 .. Name_Len); | 
 |  | 
 |       begin | 
 |          for Index in 1 .. Name_Len loop | 
 |             Name_Buffer (Index) := Fold_Lower (Name_Buffer (Index)); | 
 |          end loop; | 
 |  | 
 |          Result.Symbol := Name_Find; | 
 |          Name_Len := Sym'Length; | 
 |          Name_Buffer (1 .. Name_Len) := Sym; | 
 |          Result.Original := Name_Find; | 
 |       end; | 
 |  | 
 |       Data := Result; | 
 |    end Check_Command_Line_Symbol_Definition; | 
 |  | 
 |    -------------- | 
 |    -- Deleting -- | 
 |    -------------- | 
 |  | 
 |    function Deleting return Boolean is | 
 |    begin | 
 |       --  Always return False when not inside an #if statement | 
 |  | 
 |       if Pp_States.Last = Ground then | 
 |          return False; | 
 |  | 
 |       else | 
 |          return Pp_States.Table (Pp_States.Last).Deleting; | 
 |       end if; | 
 |    end Deleting; | 
 |  | 
 |    ---------------- | 
 |    -- Expression -- | 
 |    ---------------- | 
 |  | 
 |    function Expression (Evaluate_It : Boolean) return Boolean is | 
 |       Evaluation : Boolean := Evaluate_It; | 
 |       --  Is set to False after an "or else" when left term is True and | 
 |       --  after an "and then" when left term is False. | 
 |  | 
 |       Final_Result : Boolean := False; | 
 |  | 
 |       Current_Result : Boolean := False; | 
 |       --  Value of a term | 
 |  | 
 |       Current_Operator : Operator := None; | 
 |       Symbol1          : Symbol_Id; | 
 |       Symbol2          : Symbol_Id; | 
 |       Symbol_Name1     : Name_Id; | 
 |       Symbol_Name2     : Name_Id; | 
 |       Symbol_Pos1      : Source_Ptr; | 
 |       Symbol_Pos2      : Source_Ptr; | 
 |       Symbol_Value1    : String_Id; | 
 |       Symbol_Value2    : String_Id; | 
 |  | 
 |    begin | 
 |       --  Loop for each term | 
 |  | 
 |       loop | 
 |          Change_Reserved_Keyword_To_Symbol; | 
 |  | 
 |          Current_Result := False; | 
 |  | 
 |          case Token is | 
 |  | 
 |             when Tok_Left_Paren => | 
 |  | 
 |                --  ( expression ) | 
 |  | 
 |                Scan.all; | 
 |                Current_Result := Expression (Evaluation); | 
 |  | 
 |                if Token = Tok_Right_Paren then | 
 |                   Scan.all; | 
 |  | 
 |                else | 
 |                   Error_Msg ("`)` expected", Token_Ptr); | 
 |                end if; | 
 |  | 
 |             when Tok_Not => | 
 |  | 
 |                --  not expression | 
 |  | 
 |                Scan.all; | 
 |                Current_Result := not Expression (Evaluation); | 
 |  | 
 |             when Tok_Identifier => | 
 |                Symbol_Name1 := Token_Name; | 
 |                Symbol_Pos1  := Token_Ptr; | 
 |                Scan.all; | 
 |  | 
 |                if Token = Tok_Apostrophe then | 
 |  | 
 |                   --  symbol'Defined | 
 |  | 
 |                   Scan.all; | 
 |  | 
 |                   if Token = Tok_Identifier | 
 |                     and then Token_Name = Name_Defined | 
 |                   then | 
 |                      Scan.all; | 
 |  | 
 |                   else | 
 |                      Error_Msg ("identifier `Defined` expected", Token_Ptr); | 
 |                   end if; | 
 |  | 
 |                   if Evaluation then | 
 |                      Current_Result := Index_Of (Symbol_Name1) /= No_Symbol; | 
 |                   end if; | 
 |  | 
 |                elsif Token = Tok_Equal then | 
 |                   Scan.all; | 
 |  | 
 |                   Change_Reserved_Keyword_To_Symbol; | 
 |  | 
 |                   if Token = Tok_Identifier then | 
 |  | 
 |                      --  symbol = symbol | 
 |  | 
 |                      Symbol_Name2 := Token_Name; | 
 |                      Symbol_Pos2  := Token_Ptr; | 
 |                      Scan.all; | 
 |  | 
 |                      if Evaluation then | 
 |                         Symbol1 := Index_Of (Symbol_Name1); | 
 |  | 
 |                         if Symbol1 = No_Symbol then | 
 |                            if Undefined_Symbols_Are_False then | 
 |                               Symbol_Value1 := String_False; | 
 |  | 
 |                            else | 
 |                               Error_Msg_Name_1 := Symbol_Name1; | 
 |                               Error_Msg ("unknown symbol %", Symbol_Pos1); | 
 |                               Symbol_Value1 := No_String; | 
 |                            end if; | 
 |  | 
 |                         else | 
 |                            Symbol_Value1 := | 
 |                              Mapping.Table (Symbol1).Value; | 
 |                         end if; | 
 |  | 
 |                         Symbol2 := Index_Of (Symbol_Name2); | 
 |  | 
 |                         if Symbol2 = No_Symbol then | 
 |                            if Undefined_Symbols_Are_False then | 
 |                               Symbol_Value2 := String_False; | 
 |  | 
 |                            else | 
 |                               Error_Msg_Name_1 := Symbol_Name2; | 
 |                               Error_Msg ("unknown symbol %", Symbol_Pos2); | 
 |                               Symbol_Value2 := No_String; | 
 |                            end if; | 
 |  | 
 |                         else | 
 |                            Symbol_Value2 := Mapping.Table (Symbol2).Value; | 
 |                         end if; | 
 |  | 
 |                         if Symbol_Value1 /= No_String | 
 |                           and then Symbol_Value2 /= No_String | 
 |                         then | 
 |                            Current_Result := Matching_Strings | 
 |                                                (Symbol_Value1, Symbol_Value2); | 
 |                         end if; | 
 |                      end if; | 
 |  | 
 |                   elsif Token = Tok_String_Literal then | 
 |  | 
 |                      --  symbol = "value" | 
 |  | 
 |                      if Evaluation then | 
 |                         Symbol1 := Index_Of (Symbol_Name1); | 
 |  | 
 |                         if Symbol1 = No_Symbol then | 
 |                            if Undefined_Symbols_Are_False then | 
 |                               Symbol_Value1 := String_False; | 
 |  | 
 |                            else | 
 |                               Error_Msg_Name_1 := Symbol_Name1; | 
 |                               Error_Msg ("unknown symbol %", Symbol_Pos1); | 
 |                               Symbol_Value1 := No_String; | 
 |                            end if; | 
 |  | 
 |                         else | 
 |                            Symbol_Value1 := Mapping.Table (Symbol1).Value; | 
 |                         end if; | 
 |  | 
 |                         if Symbol_Value1 /= No_String then | 
 |                            Current_Result := | 
 |                              Matching_Strings | 
 |                                (Symbol_Value1, | 
 |                                 String_Literal_Id); | 
 |                         end if; | 
 |                      end if; | 
 |  | 
 |                      Scan.all; | 
 |  | 
 |                   else | 
 |                      Error_Msg | 
 |                        ("symbol or literal string expected", Token_Ptr); | 
 |                   end if; | 
 |  | 
 |                else | 
 |                   --  symbol (True or False) | 
 |  | 
 |                   if Evaluation then | 
 |                      Symbol1 := Index_Of (Symbol_Name1); | 
 |  | 
 |                      if Symbol1 = No_Symbol then | 
 |                         if Undefined_Symbols_Are_False then | 
 |                            Symbol_Value1 := String_False; | 
 |  | 
 |                         else | 
 |                            Error_Msg_Name_1 := Symbol_Name1; | 
 |                            Error_Msg ("unknown symbol %", Symbol_Pos1); | 
 |                            Symbol_Value1 := No_String; | 
 |                         end if; | 
 |  | 
 |                      else | 
 |                         Symbol_Value1 := Mapping.Table (Symbol1).Value; | 
 |                      end if; | 
 |  | 
 |                      if Symbol_Value1 /= No_String then | 
 |                         String_To_Name_Buffer (Symbol_Value1); | 
 |  | 
 |                         for Index in 1 .. Name_Len loop | 
 |                            Name_Buffer (Index) := | 
 |                              Fold_Lower (Name_Buffer (Index)); | 
 |                         end loop; | 
 |  | 
 |                         if Name_Buffer (1 .. Name_Len) = "true" then | 
 |                            Current_Result := True; | 
 |  | 
 |                         elsif Name_Buffer (1 .. Name_Len) = "false" then | 
 |                            Current_Result := False; | 
 |  | 
 |                         else | 
 |                            Error_Msg_Name_1 := Symbol_Name1; | 
 |                            Error_Msg | 
 |                              ("value of symbol % is not True or False", | 
 |                               Symbol_Pos1); | 
 |                         end if; | 
 |                      end if; | 
 |                   end if; | 
 |                end if; | 
 |  | 
 |             when others => | 
 |                Error_Msg ("`(`, NOT or symbol expected", Token_Ptr); | 
 |          end case; | 
 |  | 
 |          --  Update the cumulative final result | 
 |  | 
 |          case Current_Operator is | 
 |             when None => | 
 |                Final_Result := Current_Result; | 
 |  | 
 |             when Op_Or => | 
 |                Final_Result := Final_Result or Current_Result; | 
 |  | 
 |             when Op_And => | 
 |                Final_Result := Final_Result and Current_Result; | 
 |          end case; | 
 |  | 
 |          --  Check the next operator | 
 |  | 
 |          if Token = Tok_And then | 
 |             if Current_Operator = Op_Or then | 
 |                Error_Msg ("mixing OR and AND is not allowed", Token_Ptr); | 
 |             end if; | 
 |  | 
 |             Current_Operator := Op_And; | 
 |             Scan.all; | 
 |  | 
 |             if Token = Tok_Then then | 
 |                Scan.all; | 
 |  | 
 |                if Final_Result = False then | 
 |                   Evaluation := False; | 
 |                end if; | 
 |             end if; | 
 |  | 
 |          elsif Token = Tok_Or then | 
 |             if Current_Operator = Op_And then | 
 |                Error_Msg ("mixing AND and OR is not allowed", Token_Ptr); | 
 |             end if; | 
 |  | 
 |             Current_Operator := Op_Or; | 
 |             Scan.all; | 
 |  | 
 |             if Token = Tok_Else then | 
 |                Scan.all; | 
 |  | 
 |                if Final_Result then | 
 |                   Evaluation := False; | 
 |                end if; | 
 |             end if; | 
 |  | 
 |          else | 
 |             --  No operator: exit the term loop | 
 |  | 
 |             exit; | 
 |          end if; | 
 |       end loop; | 
 |  | 
 |       return Final_Result; | 
 |    end Expression; | 
 |  | 
 |    ----------------------- | 
 |    -- Go_To_End_Of_Line -- | 
 |    ----------------------- | 
 |  | 
 |    procedure Go_To_End_Of_Line is | 
 |    begin | 
 |       --  Scan until we get an end of line or we reach the end of the buffer | 
 |  | 
 |       while Token /= Tok_End_Of_Line | 
 |         and then Token /= Tok_EOF | 
 |       loop | 
 |          Scan.all; | 
 |       end loop; | 
 |    end Go_To_End_Of_Line; | 
 |  | 
 |    -------------- | 
 |    -- Index_Of -- | 
 |    -------------- | 
 |  | 
 |    function Index_Of (Symbol : Name_Id) return Symbol_Id is | 
 |    begin | 
 |       if Mapping.Table /= null then | 
 |          for J in Symbol_Id range 1 .. Symbol_Table.Last (Mapping) loop | 
 |             if Mapping.Table (J).Symbol = Symbol then | 
 |                return J; | 
 |             end if; | 
 |          end loop; | 
 |       end if; | 
 |  | 
 |       return No_Symbol; | 
 |    end Index_Of; | 
 |  | 
 |    ---------------- | 
 |    -- Preprocess -- | 
 |    ---------------- | 
 |  | 
 |    procedure Preprocess is | 
 |       Start_Of_Processing : Source_Ptr; | 
 |       Cond : Boolean; | 
 |       Preprocessor_Line : Boolean := False; | 
 |  | 
 |       procedure Output (From, To : Source_Ptr); | 
 |       --  Output the characters with indices From .. To in the buffer | 
 |       --  to the output file. | 
 |  | 
 |       procedure Output_Line (From, To : Source_Ptr); | 
 |       --  Output a line or the end of a line from the buffer to the output | 
 |       --  file, followed by an end of line terminator. Depending on the value | 
 |       --  of Deleting and the switches, the line may be commented out, blank or | 
 |       --  not output at all. | 
 |  | 
 |       ------------ | 
 |       -- Output -- | 
 |       ------------ | 
 |  | 
 |       procedure Output (From, To : Source_Ptr) is | 
 |       begin | 
 |          for J in From .. To loop | 
 |             Put_Char (Sinput.Source (J)); | 
 |          end loop; | 
 |       end Output; | 
 |  | 
 |       ----------------- | 
 |       -- Output_Line -- | 
 |       ----------------- | 
 |  | 
 |       procedure Output_Line (From, To : Source_Ptr) is | 
 |       begin | 
 |          if Deleting or Preprocessor_Line then | 
 |             if Blank_Deleted_Lines then | 
 |                New_EOL.all; | 
 |  | 
 |             elsif Comment_Deleted_Lines then | 
 |                Put_Char ('-'); | 
 |                Put_Char ('-'); | 
 |                Put_Char ('!'); | 
 |  | 
 |                if From < To then | 
 |                   Put_Char (' '); | 
 |                   Output (From, To); | 
 |                end if; | 
 |  | 
 |                New_EOL.all; | 
 |             end if; | 
 |  | 
 |          else | 
 |             Output (From, To); | 
 |             New_EOL.all; | 
 |          end if; | 
 |       end Output_Line; | 
 |  | 
 |    --  Start of processing for Preprocess | 
 |  | 
 |    begin | 
 |       Start_Of_Processing := Scan_Ptr; | 
 |  | 
 |       --  We need to call Scan for the first time, because Initialize_Scanner | 
 |       --  is no longer doing it. | 
 |  | 
 |       Scan.all; | 
 |  | 
 |       Input_Line_Loop : loop | 
 |          exit Input_Line_Loop when Token = Tok_EOF; | 
 |  | 
 |          Preprocessor_Line := False; | 
 |  | 
 |          if Token /= Tok_End_Of_Line then | 
 |  | 
 |             --  Preprocessor line | 
 |  | 
 |             if Token = Tok_Special and then Special_Character = '#' then | 
 |                   Preprocessor_Line := True; | 
 |                   Scan.all; | 
 |  | 
 |                   case Token is | 
 |  | 
 |                      --  #if | 
 |  | 
 |                      when Tok_If => | 
 |                         declare | 
 |                            If_Ptr : constant Source_Ptr := Token_Ptr; | 
 |  | 
 |                         begin | 
 |                            Scan.all; | 
 |                            Cond := Expression (not Deleting); | 
 |  | 
 |                            --  Check for an eventual "then" | 
 |  | 
 |                            if Token = Tok_Then then | 
 |                               Scan.all; | 
 |                            end if; | 
 |  | 
 |                            --  It is an error to have trailing characters after | 
 |                            --  the condition or "then". | 
 |  | 
 |                            if Token /= Tok_End_Of_Line | 
 |                              and then Token /= Tok_EOF | 
 |                            then | 
 |                               Error_Msg | 
 |                                 ("extraneous text on preprocessor line", | 
 |                                  Token_Ptr); | 
 |                               Go_To_End_Of_Line; | 
 |                            end if; | 
 |  | 
 |                            declare | 
 |                               --  Set the initial state of this new "#if". | 
 |                               --  This must be done before incrementing the | 
 |                               --  Last of the table, otherwise function | 
 |                               --  Deleting does not report the correct value. | 
 |  | 
 |                               New_State : constant Pp_State := | 
 |                                 (If_Ptr     => If_Ptr, | 
 |                                  Else_Ptr   => 0, | 
 |                                  Deleting   => Deleting or (not Cond), | 
 |                                  Match_Seen => Deleting or Cond); | 
 |  | 
 |                            begin | 
 |                               Pp_States.Increment_Last; | 
 |                               Pp_States.Table (Pp_States.Last) := New_State; | 
 |                            end; | 
 |                         end; | 
 |  | 
 |                      --  #elsif | 
 |  | 
 |                      when Tok_Elsif => | 
 |                         Cond := False; | 
 |  | 
 |                         if Pp_States.Last = 0 | 
 |                           or else Pp_States.Table (Pp_States.Last).Else_Ptr | 
 |                                                                         /= 0 | 
 |                         then | 
 |                            Error_Msg ("no IF for this ELSIF", Token_Ptr); | 
 |  | 
 |                         else | 
 |                            Cond := | 
 |                              not Pp_States.Table (Pp_States.Last).Match_Seen; | 
 |                         end if; | 
 |  | 
 |                         Scan.all; | 
 |                         Cond := Expression (Cond); | 
 |  | 
 |                         --  Check for an eventual "then" | 
 |  | 
 |                         if Token = Tok_Then then | 
 |                            Scan.all; | 
 |                         end if; | 
 |  | 
 |                         --  It is an error to have trailing characters after | 
 |                         --  the condition or "then". | 
 |  | 
 |                         if Token /= Tok_End_Of_Line | 
 |                           and then Token /= Tok_EOF | 
 |                         then | 
 |                            Error_Msg | 
 |                              ("extraneous text on preprocessor line", | 
 |                               Token_Ptr); | 
 |  | 
 |                            Go_To_End_Of_Line; | 
 |                         end if; | 
 |  | 
 |                         --  Depending on the value of the condition, set the | 
 |                         --  new values of Deleting and Match_Seen. | 
 |                         if Pp_States.Last > 0 then | 
 |                            if Pp_States.Table (Pp_States.Last).Match_Seen then | 
 |                               Pp_States.Table (Pp_States.Last).Deleting := | 
 |                                 True; | 
 |                            else | 
 |                               if Cond then | 
 |                                  Pp_States.Table (Pp_States.Last).Match_Seen := | 
 |                                    True; | 
 |                                  Pp_States.Table (Pp_States.Last).Deleting := | 
 |                                    False; | 
 |                               end if; | 
 |                            end if; | 
 |                         end if; | 
 |  | 
 |                      --  #else | 
 |  | 
 |                      when Tok_Else => | 
 |                         if Pp_States.Last = 0 then | 
 |                            Error_Msg ("no IF for this ELSE", Token_Ptr); | 
 |  | 
 |                         elsif | 
 |                            Pp_States.Table (Pp_States.Last).Else_Ptr /= 0 | 
 |                         then | 
 |                            Error_Msg ("duplicate ELSE line", Token_Ptr); | 
 |                         end if; | 
 |  | 
 |                         --  Set the possibly new values of Deleting and | 
 |                         --  Match_Seen. | 
 |  | 
 |                         if Pp_States.Last > 0 then | 
 |                            if Pp_States.Table (Pp_States.Last).Match_Seen then | 
 |                               Pp_States.Table (Pp_States.Last).Deleting := | 
 |                                 True; | 
 |  | 
 |                            else | 
 |                               Pp_States.Table (Pp_States.Last).Match_Seen := | 
 |                                 True; | 
 |                               Pp_States.Table (Pp_States.Last).Deleting := | 
 |                                 False; | 
 |                            end if; | 
 |  | 
 |                            --  Set the Else_Ptr to check for illegal #elsif | 
 |                            --  later. | 
 |  | 
 |                            Pp_States.Table (Pp_States.Last).Else_Ptr := | 
 |                              Token_Ptr; | 
 |                         end if; | 
 |  | 
 |                         Scan.all; | 
 |  | 
 |                         --  It is an error to have characters after "#else" | 
 |                         if Token /= Tok_End_Of_Line | 
 |                           and then Token /= Tok_EOF | 
 |                         then | 
 |                            Error_Msg | 
 |                              ("extraneous text on preprocessor line", | 
 |                               Token_Ptr); | 
 |                            Go_To_End_Of_Line; | 
 |                         end if; | 
 |  | 
 |                      --  #end if; | 
 |  | 
 |                      when Tok_End => | 
 |                         if Pp_States.Last = 0 then | 
 |                            Error_Msg ("no IF for this END", Token_Ptr); | 
 |                         end if; | 
 |  | 
 |                         Scan.all; | 
 |  | 
 |                         if Token /= Tok_If then | 
 |                            Error_Msg ("IF expected", Token_Ptr); | 
 |  | 
 |                         else | 
 |                            Scan.all; | 
 |  | 
 |                            if Token /= Tok_Semicolon then | 
 |                               Error_Msg ("`;` Expected", Token_Ptr); | 
 |  | 
 |                            else | 
 |                               Scan.all; | 
 |  | 
 |                               --  It is an error to have character after | 
 |                               --  "#end if;". | 
 |                               if Token /= Tok_End_Of_Line | 
 |                                 and then Token /= Tok_EOF | 
 |                               then | 
 |                                  Error_Msg | 
 |                                    ("extraneous text on preprocessor line", | 
 |                                     Token_Ptr); | 
 |                               end if; | 
 |                            end if; | 
 |                         end if; | 
 |  | 
 |                         --  In case of one of the errors above, skip the tokens | 
 |                         --  until the end of line is reached. | 
 |  | 
 |                         Go_To_End_Of_Line; | 
 |  | 
 |                         --  Decrement the depth of the #if stack | 
 |  | 
 |                         if Pp_States.Last > 0 then | 
 |                            Pp_States.Decrement_Last; | 
 |                         end if; | 
 |  | 
 |                      --  Illegal preprocessor line | 
 |  | 
 |                      when others => | 
 |                         if Pp_States.Last = 0 then | 
 |                            Error_Msg ("IF expected", Token_Ptr); | 
 |  | 
 |                         elsif | 
 |                           Pp_States.Table (Pp_States.Last).Else_Ptr = 0 | 
 |                         then | 
 |                            Error_Msg ("IF, ELSIF, ELSE, or `END IF` expected", | 
 |                                       Token_Ptr); | 
 |  | 
 |                         else | 
 |                            Error_Msg ("IF or `END IF` expected", Token_Ptr); | 
 |                         end if; | 
 |  | 
 |                         --  Skip to the end of this illegal line | 
 |  | 
 |                         Go_To_End_Of_Line; | 
 |                   end case; | 
 |  | 
 |             --  Not a preprocessor line | 
 |  | 
 |             else | 
 |                --  Do not report errors for those lines, even if there are | 
 |                --  Ada parsing errors. | 
 |  | 
 |                Set_Ignore_Errors (To => True); | 
 |  | 
 |                if Deleting then | 
 |                   Go_To_End_Of_Line; | 
 |  | 
 |                else | 
 |                   while Token /= Tok_End_Of_Line | 
 |                     and then Token /= Tok_EOF | 
 |                   loop | 
 |                      if Token = Tok_Special | 
 |                        and then Special_Character = '$' | 
 |                      then | 
 |                         declare | 
 |                            Dollar_Ptr : constant Source_Ptr := Token_Ptr; | 
 |                            Symbol     : Symbol_Id; | 
 |  | 
 |                         begin | 
 |                            Scan.all; | 
 |                            Change_Reserved_Keyword_To_Symbol; | 
 |  | 
 |                            if Token = Tok_Identifier | 
 |                              and then Token_Ptr = Dollar_Ptr + 1 | 
 |                            then | 
 |                               --  $symbol | 
 |  | 
 |                               Symbol := Index_Of (Token_Name); | 
 |  | 
 |                               --  If symbol exists, replace by its value | 
 |  | 
 |                               if Symbol /= No_Symbol then | 
 |                                  Output (Start_Of_Processing, Dollar_Ptr - 1); | 
 |                                  Start_Of_Processing := Scan_Ptr; | 
 |                                  String_To_Name_Buffer | 
 |                                    (Mapping.Table (Symbol).Value); | 
 |  | 
 |                                  if Mapping.Table (Symbol).Is_A_String then | 
 |  | 
 |                                     --  Value is an Ada string | 
 |  | 
 |                                     Put_Char ('"'); | 
 |  | 
 |                                     for J in 1 .. Name_Len loop | 
 |                                        Put_Char (Name_Buffer (J)); | 
 |  | 
 |                                        if Name_Buffer (J) = '"' then | 
 |                                           Put_Char ('"'); | 
 |                                        end if; | 
 |                                     end loop; | 
 |  | 
 |                                     Put_Char ('"'); | 
 |  | 
 |                                  else | 
 |                                     --  Value is a sequence of characters, not | 
 |                                     --  an Ada string. | 
 |  | 
 |                                     for J in 1 .. Name_Len loop | 
 |                                        Put_Char (Name_Buffer (J)); | 
 |                                     end loop; | 
 |                                  end if; | 
 |                               end if; | 
 |                            end if; | 
 |                         end; | 
 |                      end if; | 
 |  | 
 |                      Scan.all; | 
 |                   end loop; | 
 |                end if; | 
 |  | 
 |                Set_Ignore_Errors (To => False); | 
 |             end if; | 
 |          end if; | 
 |  | 
 |          pragma Assert (Token = Tok_End_Of_Line or Token = Tok_EOF); | 
 |  | 
 |          --  At this point, the token is either end of line or EOF. | 
 |          --  The line to possibly output stops just before the token. | 
 |  | 
 |          Output_Line (Start_Of_Processing, Token_Ptr - 1); | 
 |  | 
 |          --  If we are at the end of a line, the scan pointer is at the first | 
 |          --  non blank character, not necessarily the first character of the | 
 |          --  line; so, we have to deduct Start_Of_Processing from the token | 
 |          --  pointer. | 
 |  | 
 |          if Token = Tok_End_Of_Line then | 
 |             if (Sinput.Source (Token_Ptr) = ASCII.CR | 
 |                   and then Sinput.Source (Token_Ptr + 1) = ASCII.LF) | 
 |               or else | 
 |                (Sinput.Source (Token_Ptr) = ASCII.CR | 
 |                   and then Sinput.Source (Token_Ptr + 1) = ASCII.LF) | 
 |             then | 
 |                Start_Of_Processing := Token_Ptr + 2; | 
 |             else | 
 |                Start_Of_Processing := Token_Ptr + 1; | 
 |             end if; | 
 |          end if; | 
 |  | 
 |          --  Now, scan the first token of the next line. If the token is EOF, | 
 |          --  the scan ponter will not move, and the token will still be EOF. | 
 |  | 
 |          Set_Ignore_Errors (To => True); | 
 |          Scan.all; | 
 |          Set_Ignore_Errors (To => False); | 
 |       end loop Input_Line_Loop; | 
 |  | 
 |       --  Report an error for any missing some "#end if;" | 
 |  | 
 |       for Level in reverse 1 .. Pp_States.Last loop | 
 |          Error_Msg ("no `END IF` for this IF", Pp_States.Table (Level).If_Ptr); | 
 |       end loop; | 
 |    end Preprocess; | 
 |  | 
 |    ---------------- | 
 |    -- Initialize -- | 
 |    ---------------- | 
 |  | 
 |    procedure Initialize | 
 |      (Error_Msg         : Error_Msg_Proc; | 
 |       Scan              : Scan_Proc; | 
 |       Set_Ignore_Errors : Set_Ignore_Errors_Proc; | 
 |       Put_Char          : Put_Char_Proc; | 
 |       New_EOL           : New_EOL_Proc) | 
 |    is | 
 |    begin | 
 |       if not Already_Initialized then | 
 |          Start_String; | 
 |          Store_String_Chars ("True"); | 
 |          True_Value.Value := End_String; | 
 |  | 
 |          Start_String; | 
 |          Empty_String := End_String; | 
 |  | 
 |          Name_Len := 7; | 
 |          Name_Buffer (1 .. Name_Len) := "defined"; | 
 |          Name_Defined := Name_Find; | 
 |  | 
 |          Start_String; | 
 |          Store_String_Chars ("False"); | 
 |          String_False := End_String; | 
 |  | 
 |          Already_Initialized := True; | 
 |       end if; | 
 |  | 
 |       Prep.Error_Msg         := Error_Msg; | 
 |       Prep.Scan              := Scan; | 
 |       Prep.Set_Ignore_Errors := Set_Ignore_Errors; | 
 |       Prep.Put_Char          := Put_Char; | 
 |       Prep.New_EOL           := New_EOL; | 
 |    end Initialize; | 
 |  | 
 |    ------------------ | 
 |    -- List_Symbols -- | 
 |    ------------------ | 
 |  | 
 |    procedure List_Symbols (Foreword : String) is | 
 |       Order : array (0 ..  Integer (Symbol_Table.Last (Mapping))) | 
 |                  of Symbol_Id; | 
 |       --  After alphabetical sorting, this array stores thehe indices of | 
 |       --  the symbols in the order they are displayed. | 
 |  | 
 |       function Lt (Op1, Op2 : Natural) return Boolean; | 
 |       --  Comparison routine for sort call | 
 |  | 
 |       procedure Move (From : Natural; To : Natural); | 
 |       --  Move routine for sort call | 
 |  | 
 |       -------- | 
 |       -- Lt -- | 
 |       -------- | 
 |  | 
 |       function Lt (Op1, Op2 : Natural) return Boolean is | 
 |          S1 : constant String := | 
 |                 Get_Name_String (Mapping.Table (Order (Op1)).Symbol); | 
 |          S2 : constant String := | 
 |                 Get_Name_String (Mapping.Table (Order (Op2)).Symbol); | 
 |  | 
 |       begin | 
 |          return S1 < S2; | 
 |       end Lt; | 
 |  | 
 |       ---------- | 
 |       -- Move -- | 
 |       ---------- | 
 |  | 
 |       procedure Move (From : Natural; To : Natural) is | 
 |       begin | 
 |          Order (To) := Order (From); | 
 |       end Move; | 
 |  | 
 |       package Sort_Syms is new GNAT.Heap_Sort_G (Move, Lt); | 
 |  | 
 |       Max_L : Natural; | 
 |       --  Maximum length of any symbol | 
 |  | 
 |    --  Start of processing for List_Symbols_Case | 
 |  | 
 |    begin | 
 |       if Symbol_Table.Last (Mapping) = 0 then | 
 |          return; | 
 |       end if; | 
 |  | 
 |       if Foreword'Length > 0 then | 
 |          Write_Eol; | 
 |          Write_Line (Foreword); | 
 |  | 
 |          for J in Foreword'Range loop | 
 |             Write_Char ('='); | 
 |          end loop; | 
 |       end if; | 
 |  | 
 |       --  Initialize the order | 
 |  | 
 |       for J in Order'Range loop | 
 |          Order (J) := Symbol_Id (J); | 
 |       end loop; | 
 |  | 
 |       --  Sort alphabetically | 
 |  | 
 |       Sort_Syms.Sort (Order'Last); | 
 |  | 
 |       Max_L := 7; | 
 |  | 
 |       for J in 1 .. Symbol_Table.Last (Mapping) loop | 
 |          Get_Name_String (Mapping.Table (J).Original); | 
 |          Max_L := Integer'Max (Max_L, Name_Len); | 
 |       end loop; | 
 |  | 
 |       Write_Eol; | 
 |       Write_Str ("Symbol"); | 
 |  | 
 |       for J in 1 .. Max_L - 5 loop | 
 |          Write_Char (' '); | 
 |       end loop; | 
 |  | 
 |       Write_Line ("Value"); | 
 |  | 
 |       Write_Str ("------"); | 
 |  | 
 |       for J in 1 .. Max_L - 5 loop | 
 |          Write_Char (' '); | 
 |       end loop; | 
 |  | 
 |       Write_Line ("------"); | 
 |  | 
 |       for J in 1 .. Order'Last loop | 
 |          declare | 
 |             Data : constant Symbol_Data := Mapping.Table (Order (J)); | 
 |  | 
 |          begin | 
 |             Get_Name_String (Data.Original); | 
 |             Write_Str (Name_Buffer (1 .. Name_Len)); | 
 |  | 
 |             for K in Name_Len .. Max_L loop | 
 |                Write_Char (' '); | 
 |             end loop; | 
 |  | 
 |             String_To_Name_Buffer (Data.Value); | 
 |  | 
 |             if Data.Is_A_String then | 
 |                Write_Char ('"'); | 
 |  | 
 |                for J in 1 .. Name_Len loop | 
 |                   Write_Char (Name_Buffer (J)); | 
 |  | 
 |                   if Name_Buffer (J) = '"' then | 
 |                      Write_Char ('"'); | 
 |                   end if; | 
 |                end loop; | 
 |  | 
 |                Write_Char ('"'); | 
 |  | 
 |             else | 
 |                Write_Str (Name_Buffer (1 .. Name_Len)); | 
 |             end if; | 
 |          end; | 
 |  | 
 |          Write_Eol; | 
 |       end loop; | 
 |  | 
 |       Write_Eol; | 
 |    end List_Symbols; | 
 |  | 
 |    ---------------------- | 
 |    -- Matching_Strings -- | 
 |    ---------------------- | 
 |  | 
 |    function Matching_Strings (S1, S2 : String_Id) return Boolean is | 
 |    begin | 
 |       String_To_Name_Buffer (S1); | 
 |  | 
 |       for Index in 1 .. Name_Len loop | 
 |          Name_Buffer (Index) := Fold_Lower (Name_Buffer (Index)); | 
 |       end loop; | 
 |  | 
 |       declare | 
 |          String1 : constant String := Name_Buffer (1 .. Name_Len); | 
 |  | 
 |       begin | 
 |          String_To_Name_Buffer (S2); | 
 |  | 
 |          for Index in 1 .. Name_Len loop | 
 |             Name_Buffer (Index) := Fold_Lower (Name_Buffer (Index)); | 
 |          end loop; | 
 |  | 
 |          return String1 = Name_Buffer (1 .. Name_Len); | 
 |       end; | 
 |    end Matching_Strings; | 
 |  | 
 |    -------------------- | 
 |    -- Parse_Def_File -- | 
 |    -------------------- | 
 |  | 
 |    procedure Parse_Def_File is | 
 |       Symbol        : Symbol_Id; | 
 |       Symbol_Name   : Name_Id; | 
 |       Original_Name : Name_Id; | 
 |       Data          : Symbol_Data; | 
 |       Value_Start   : Source_Ptr; | 
 |       Value_End     : Source_Ptr; | 
 |       Ch            : Character; | 
 |  | 
 |       use ASCII; | 
 |  | 
 |    begin | 
 |       Def_Line_Loop : | 
 |       loop | 
 |          Scan.all; | 
 |  | 
 |          exit Def_Line_Loop when Token = Tok_EOF; | 
 |  | 
 |          if Token /= Tok_End_Of_Line then | 
 |             Change_Reserved_Keyword_To_Symbol; | 
 |  | 
 |             if Token /= Tok_Identifier then | 
 |                Error_Msg ("identifier expected", Token_Ptr); | 
 |                goto Cleanup; | 
 |             end if; | 
 |  | 
 |             Symbol_Name := Token_Name; | 
 |             Name_Len := 0; | 
 |  | 
 |             for Ptr in Token_Ptr .. Scan_Ptr - 1 loop | 
 |                Name_Len := Name_Len + 1; | 
 |                Name_Buffer (Name_Len) := Sinput.Source (Ptr); | 
 |             end loop; | 
 |  | 
 |             Original_Name := Name_Find; | 
 |             Scan.all; | 
 |  | 
 |             if Token /= Tok_Colon_Equal then | 
 |                Error_Msg ("`:=` expected", Token_Ptr); | 
 |                goto Cleanup; | 
 |             end if; | 
 |  | 
 |             Scan.all; | 
 |  | 
 |             if Token = Tok_String_Literal then | 
 |                Data := (Symbol              => Symbol_Name, | 
 |                         Original            => Original_Name, | 
 |                         On_The_Command_Line => False, | 
 |                         Is_A_String         => True, | 
 |                         Value               => String_Literal_Id); | 
 |  | 
 |                Scan.all; | 
 |  | 
 |                if Token /= Tok_End_Of_Line and then Token /= Tok_EOF then | 
 |                   Error_Msg ("extraneous text in definition", Token_Ptr); | 
 |                   goto Cleanup; | 
 |                end if; | 
 |  | 
 |             elsif Token = Tok_End_Of_Line or Token = Tok_EOF then | 
 |                Data := (Symbol              => Symbol_Name, | 
 |                         Original            => Original_Name, | 
 |                         On_The_Command_Line => False, | 
 |                         Is_A_String         => False, | 
 |                         Value               => Empty_String); | 
 |  | 
 |             else | 
 |                Value_Start := Token_Ptr; | 
 |                Value_End   := Token_Ptr - 1; | 
 |                Scan_Ptr    := Token_Ptr; | 
 |  | 
 |                Value_Chars_Loop : | 
 |                loop | 
 |                   Ch := Sinput.Source (Scan_Ptr); | 
 |  | 
 |                   case Ch is | 
 |                      when '_' | '.' | '0' .. '9' | 'a' .. 'z' | 'A' .. 'Z' => | 
 |                         Value_End := Scan_Ptr; | 
 |                         Scan_Ptr := Scan_Ptr + 1; | 
 |  | 
 |                      when ' ' | HT | VT | CR | LF | FF => | 
 |                         exit Value_Chars_Loop; | 
 |  | 
 |                      when others => | 
 |                         Error_Msg ("illegal character", Scan_Ptr); | 
 |                         goto Cleanup; | 
 |                   end case; | 
 |                end loop Value_Chars_Loop; | 
 |  | 
 |                Scan.all; | 
 |  | 
 |                if Token /= Tok_End_Of_Line and then Token /= Tok_EOF then | 
 |                   Error_Msg ("extraneous text in definition", Token_Ptr); | 
 |                   goto Cleanup; | 
 |                end if; | 
 |  | 
 |                Start_String; | 
 |  | 
 |                while Value_Start <= Value_End loop | 
 |                   Store_String_Char (Sinput.Source (Value_Start)); | 
 |                   Value_Start := Value_Start + 1; | 
 |                end loop; | 
 |  | 
 |                Data := (Symbol              => Symbol_Name, | 
 |                         Original            => Original_Name, | 
 |                         On_The_Command_Line => False, | 
 |                         Is_A_String         => False, | 
 |                         Value               => End_String); | 
 |             end if; | 
 |  | 
 |             --  Now that we have the value, get the symbol index | 
 |  | 
 |             Symbol := Index_Of (Symbol_Name); | 
 |  | 
 |             if Symbol /= No_Symbol then | 
 |                --  If we already have an entry for this symbol, replace it | 
 |                --  with the new value, except if the symbol was declared | 
 |                --  on the command line. | 
 |  | 
 |                if Mapping.Table (Symbol).On_The_Command_Line then | 
 |                   goto Continue; | 
 |                end if; | 
 |  | 
 |             else | 
 |                --  As it is the first time we see this symbol, create a new | 
 |                --  entry in the table. | 
 |  | 
 |                if Mapping.Table = null then | 
 |                   Symbol_Table.Init (Mapping); | 
 |                end if; | 
 |  | 
 |                Symbol_Table.Increment_Last (Mapping); | 
 |                Symbol := Symbol_Table.Last (Mapping); | 
 |             end if; | 
 |  | 
 |             Mapping.Table (Symbol) := Data; | 
 |             goto Continue; | 
 |  | 
 |             <<Cleanup>> | 
 |                Set_Ignore_Errors (To => True); | 
 |  | 
 |                while Token /= Tok_End_Of_Line and Token /= Tok_EOF loop | 
 |                   Scan.all; | 
 |                end loop; | 
 |  | 
 |                Set_Ignore_Errors (To => False); | 
 |  | 
 |             <<Continue>> | 
 |                null; | 
 |          end if; | 
 |       end loop Def_Line_Loop; | 
 |    end Parse_Def_File; | 
 |  | 
 | end Prep; |