OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [gcc/] [ada/] [prepcomp.adb] - Rev 12

Compare with Previous | Blame | View Log

------------------------------------------------------------------------------
--                                                                          --
--                         GNAT COMPILER COMPONENTS                         --
--                                                                          --
--                             P R E P C O M P                              --
--                                                                          --
--                                 B o d y                                  --
--                                                                          --
--          Copyright (C) 2003-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 Ada.Unchecked_Deallocation;
 
with Errout;   use Errout;
with Namet;    use Namet;
with Lib.Writ; use Lib.Writ;
with Opt;      use Opt;
with Osint;    use Osint;
with Prep;     use Prep;
with Scans;    use Scans;
with Scn;      use Scn;
with Sinput.L; use Sinput.L;
with Stringt;  use Stringt;
with Table;
 
package body Prepcomp is
 
   No_Preprocessing : Boolean := True;
   --  Set to True if there is at least one source that needs to be
   --  preprocessed.
 
   Source_Index_Of_Preproc_Data_File : Source_File_Index := No_Source_File;
 
   --  The following variable should be a constant, but this is not
   --  possible. Warnings are Off because it is never assigned a value.
 
   pragma Warnings (Off);
   No_Mapping : Prep.Symbol_Table.Instance;
   pragma Warnings (On);
 
   type String_Ptr is access String;
   type String_Array is array (Positive range <>) of String_Ptr;
   type String_Array_Ptr is access String_Array;
 
   procedure Free is
      new Ada.Unchecked_Deallocation (String_Array, String_Array_Ptr);
 
   Symbol_Definitions : String_Array_Ptr := new String_Array (1 .. 4);
   --  An extensible array to temporarily stores symbol definitions specified
   --  on the command line with -gnateD switches.
 
   Last_Definition : Natural := 0;
   --  Index of last symbol definition in array Symbol_Definitions
 
   type Preproc_Data is record
      Mapping      : Symbol_Table.Instance;
      File_Name    : Name_Id   := No_Name;
      Deffile      : String_Id := No_String;
      Undef_False  : Boolean   := False;
      Always_Blank : Boolean   := False;
      Comments     : Boolean   := False;
      List_Symbols : Boolean   := False;
      Processed    : Boolean   := False;
   end record;
   --  Structure to keep the preprocessing data for a file name or for the
   --  default (when Name_Id = No_Name).
 
   No_Preproc_Data : constant Preproc_Data :=
     (Mapping      => No_Mapping,
      File_Name    => No_Name,
      Deffile      => No_String,
      Undef_False  => False,
      Always_Blank => False,
      Comments     => False,
      List_Symbols => False,
      Processed    => False);
 
   Default_Data : Preproc_Data := No_Preproc_Data;
   --  The preprocessing data to be used when no specific preprocessing data
   --  is specified for a source.
 
   Default_Data_Defined : Boolean := False;
   --  True if source for which no specific preprocessing is specified need to
   --  be preprocess with the Default_Data.
 
   Current_Data : Preproc_Data := No_Preproc_Data;
 
   package Preproc_Data_Table is new Table.Table
     (Table_Component_Type => Preproc_Data,
      Table_Index_Type     => Int,
      Table_Low_Bound      => 1,
      Table_Initial        => 5,
      Table_Increment      => 5,
      Table_Name           => "Prepcomp.Preproc_Data_Table");
   --  Table to store the specific preprocessing data
 
   Command_Line_Symbols : Symbol_Table.Instance;
   --  A table to store symbol definitions specified on the command line with
   --  -gnateD switches.
 
   package Dependencies is new Table.Table
     (Table_Component_Type => Source_File_Index,
      Table_Index_Type     => Int,
      Table_Low_Bound      => 1,
      Table_Initial        => 5,
      Table_Increment      => 5,
      Table_Name           => "Prepcomp.Dependencies");
   --  Table to store the dependencies on preprocessing files
 
   procedure Add_Command_Line_Symbols;
   --  Add the command line symbol definitions, if any, to the
   --  Prep.Mapping table.
 
   procedure Skip_To_End_Of_Line;
   --  Ignore errors and scan up to the next end of line or the end of file
 
   ------------------------------
   -- Add_Command_Line_Symbols --
   ------------------------------
 
   procedure Add_Command_Line_Symbols is
      Symbol_Id : Prep.Symbol_Id;
 
   begin
      for J in 1 .. Symbol_Table.Last (Command_Line_Symbols) loop
         Symbol_Id := Prep.Index_Of (Command_Line_Symbols.Table (J).Symbol);
 
         if Symbol_Id = No_Symbol then
            Symbol_Table.Increment_Last (Prep.Mapping);
            Symbol_Id := Symbol_Table.Last (Prep.Mapping);
         end if;
 
         Prep.Mapping.Table (Symbol_Id) := Command_Line_Symbols.Table (J);
      end loop;
   end Add_Command_Line_Symbols;
 
   ----------------------
   -- Add_Dependencies --
   ----------------------
 
   procedure Add_Dependencies is
   begin
      for Index in 1 .. Dependencies.Last loop
         Add_Preprocessing_Dependency (Dependencies.Table (Index));
      end loop;
   end Add_Dependencies;
 
   ---------------------------
   -- Add_Symbol_Definition --
   ---------------------------
 
   procedure Add_Symbol_Definition (Def : String) is
   begin
      --  If Symbol_Definitions is not large enough, double it
 
      if Last_Definition = Symbol_Definitions'Last then
         declare
            New_Symbol_Definitions : constant String_Array_Ptr :=
              new String_Array (1 .. 2 * Last_Definition);
 
         begin
            New_Symbol_Definitions (Symbol_Definitions'Range) :=
              Symbol_Definitions.all;
            Free (Symbol_Definitions);
            Symbol_Definitions := New_Symbol_Definitions;
         end;
      end if;
 
      Last_Definition := Last_Definition + 1;
      Symbol_Definitions (Last_Definition) := new String'(Def);
   end Add_Symbol_Definition;
 
   -------------------
   -- Check_Symbols --
   -------------------
 
   procedure Check_Symbols is
   begin
      --  If there is at least one switch -gnateD specified
 
      if Symbol_Table.Last (Command_Line_Symbols) >= 1 then
         Current_Data := No_Preproc_Data;
         No_Preprocessing := False;
         Current_Data.Processed := True;
 
         --  Start with an empty, initialized mapping table; use Prep.Mapping,
         --  because Prep.Index_Of uses Prep.Mapping.
 
         Prep.Mapping := No_Mapping;
         Symbol_Table.Init (Prep.Mapping);
 
         --  Add the command line symbols
 
         Add_Command_Line_Symbols;
 
         --  Put the resulting Prep.Mapping in Current_Data, and immediately
         --  set Prep.Mapping to nil.
 
         Current_Data.Mapping := Prep.Mapping;
         Prep.Mapping := No_Mapping;
 
         --  Set the default data
 
         Default_Data := Current_Data;
         Default_Data_Defined := True;
      end if;
   end Check_Symbols;
 
   ------------------------------
   -- Parse_Preprocessing_Data --
   ------------------------------
 
   procedure Parse_Preprocessing_Data_File (N : File_Name_Type) is
      OK            : Boolean := False;
      Dash_Location : Source_Ptr;
      Symbol_Data   : Prep.Symbol_Data;
      Symbol_Id     : Prep.Symbol_Id;
      T             : constant Nat := Total_Errors_Detected;
 
   begin
      --  Load the preprocessing data file
 
      Source_Index_Of_Preproc_Data_File := Load_Preprocessing_Data_File (N);
 
      --  Fail if preprocessing data file cannot be found
 
      if Source_Index_Of_Preproc_Data_File = No_Source_File then
         Get_Name_String (N);
         Fail ("preprocessing data file """,
               Name_Buffer (1 .. Name_Len),
               """ not found");
      end if;
 
      --  Initialize the sanner and set its behavior for a processing data file
 
      Scn.Scanner.Initialize_Scanner
        (No_Unit, Source_Index_Of_Preproc_Data_File);
      Scn.Scanner.Set_End_Of_Line_As_Token (True);
      Scn.Scanner.Reset_Special_Characters;
 
      For_Each_Line : loop
         <<Scan_Line>>
         Scan;
 
         exit For_Each_Line when Token = Tok_EOF;
 
         if Token = Tok_End_Of_Line then
            goto Scan_Line;
         end if;
 
         --  Line is not empty
 
         OK := False;
         No_Preprocessing := False;
         Current_Data := No_Preproc_Data;
 
         case Token is
            when Tok_Asterisk =>
 
               --  Default data
 
               if Default_Data_Defined then
                  Error_Msg
                    ("multiple default preprocessing data", Token_Ptr);
 
               else
                  OK := True;
                  Default_Data_Defined := True;
               end if;
 
            when Tok_String_Literal =>
 
               --  Specific data
 
               String_To_Name_Buffer (String_Literal_Id);
               Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
               Current_Data.File_Name := Name_Find;
               OK := True;
 
               for Index in 1 .. Preproc_Data_Table.Last loop
                  if Current_Data.File_Name =
                       Preproc_Data_Table.Table (Index).File_Name
                  then
                     Error_Msg_Name_1 := Current_Data.File_Name;
                     Error_Msg
                       ("multiple preprocessing data for{", Token_Ptr);
                     OK := False;
                     exit;
                  end if;
               end loop;
 
            when others =>
               Error_Msg ("`'*` or literal string expected", Token_Ptr);
         end case;
 
         --  If there is a problem, skip the line
 
         if not OK then
            Skip_To_End_Of_Line;
            goto Scan_Line;
         end if;
 
         --  Scan past the * or the literal string
 
         Scan;
 
         --  A literal string in second position is a definition file
 
         if Token = Tok_String_Literal then
            Current_Data.Deffile := String_Literal_Id;
            Current_Data.Processed := False;
            Scan;
 
         else
            --  If there is no definition file, set Processed to True now
 
            Current_Data.Processed := True;
         end if;
 
         --  Start with an empty, initialized mapping table; use Prep.Mapping,
         --  because Prep.Index_Of uses Prep.Mapping.
 
         Prep.Mapping := No_Mapping;
         Symbol_Table.Init (Prep.Mapping);
 
         --  Check the switches that may follow
 
         while Token /= Tok_End_Of_Line and then Token /= Tok_EOF loop
            if Token /= Tok_Minus then
               Error_Msg ("`'-` expected", Token_Ptr);
               Skip_To_End_Of_Line;
               goto Scan_Line;
            end if;
 
            --  Keep the location of the '-' for possible error reporting
 
            Dash_Location := Token_Ptr;
 
            --  Scan past the '-'
 
            Scan;
            OK := False;
            Change_Reserved_Keyword_To_Symbol;
 
            --  An identifier (or a reserved word converted to an
            --  identifier) is expected and there must be no blank space
            --  between the '-' and the identifier.
 
            if Token = Tok_Identifier
              and then Token_Ptr = Dash_Location + 1
            then
               Get_Name_String (Token_Name);
 
               --  Check the character in the source, because the case is
               --  significant.
 
               case Sinput.Source (Token_Ptr) is
                  when 'u' =>
 
                     --  Undefined symbol are False
 
                     if Name_Len = 1 then
                        Current_Data.Undef_False := True;
                        OK := True;
                     end if;
 
                  when 'b' =>
 
                     --  Blank lines
 
                     if Name_Len = 1 then
                        Current_Data.Always_Blank := True;
                        OK := True;
                     end if;
 
                  when 'c' =>
 
                     --  Comment removed lines
 
                     if Name_Len = 1 then
                        Current_Data.Comments := True;
                        OK := True;
                     end if;
 
                  when 's' =>
 
                     --  List symbols
 
                     if Name_Len = 1 then
                        Current_Data.List_Symbols := True;
                        OK := True;
                     end if;
 
                  when 'D' =>
 
                     --  Symbol definition
 
                     OK := Name_Len > 1;
 
                     if OK then
 
                        --  A symbol must be an Ada identifier; it cannot start
                        --  with an underline or a digit.
 
                        if Name_Buffer (2) = '_'
                          or Name_Buffer (2) in '0' .. '9'
                        then
                           Error_Msg ("symbol expected", Token_Ptr + 1);
                           Skip_To_End_Of_Line;
                           goto Scan_Line;
                        end if;
 
                        --  Get the name id of the symbol
 
                        Symbol_Data.On_The_Command_Line := True;
                        Name_Buffer (1 .. Name_Len - 1) :=
                          Name_Buffer (2 .. Name_Len);
                        Name_Len := Name_Len - 1;
                        Symbol_Data.Symbol := Name_Find;
 
                        if Name_Buffer (1 .. Name_Len) = "if"
                          or else Name_Buffer (1 .. Name_Len) = "else"
                          or else Name_Buffer (1 .. Name_Len) = "elsif"
                          or else Name_Buffer (1 .. Name_Len) = "end"
                          or else Name_Buffer (1 .. Name_Len) = "not"
                          or else Name_Buffer (1 .. Name_Len) = "and"
                          or else Name_Buffer (1 .. Name_Len) = "then"
                        then
                           Error_Msg ("symbol expected", Token_Ptr + 1);
                           Skip_To_End_Of_Line;
                           goto Scan_Line;
                        end if;
 
                        --  Get the name id of the original symbol, with
                        --  possibly capital letters.
 
                        Name_Len := Integer (Scan_Ptr - Token_Ptr - 1);
 
                        for J in 1 .. Name_Len loop
                           Name_Buffer (J) :=
                             Sinput.Source (Token_Ptr + Text_Ptr (J));
                        end loop;
 
                        Symbol_Data.Original := Name_Find;
 
                        --  Scan past D<symbol>
 
                        Scan;
 
                        if Token /= Tok_Equal then
                           Error_Msg ("`=` expected", Token_Ptr);
                           Skip_To_End_Of_Line;
                           goto Scan_Line;
                        end if;
 
                        --  Scan past '='
 
                        Scan;
 
                        --  Here any reserved word is OK
 
                        Change_Reserved_Keyword_To_Symbol
                          (All_Keywords => True);
 
                        --  Value can be an identifier (or a reserved word)
                        --  or a literal string.
 
                        case Token is
                           when Tok_String_Literal =>
                              Symbol_Data.Is_A_String := True;
                              Symbol_Data.Value := String_Literal_Id;
 
                           when Tok_Identifier =>
                              Symbol_Data.Is_A_String := False;
                              Start_String;
 
                              for J in Token_Ptr .. Scan_Ptr - 1 loop
                                 Store_String_Char (Sinput.Source (J));
                              end loop;
 
                              Symbol_Data.Value := End_String;
 
                           when others =>
                              Error_Msg
                                ("literal string or identifier expected",
                                 Token_Ptr);
                              Skip_To_End_Of_Line;
                              goto Scan_Line;
                        end case;
 
                        --  If symbol already exists, replace old definition
                        --  by new one.
 
                        Symbol_Id := Prep.Index_Of (Symbol_Data.Symbol);
 
                        --  Otherwise, add a new entry in the table
 
                        if Symbol_Id = No_Symbol then
                           Symbol_Table.Increment_Last (Prep.Mapping);
                           Symbol_Id := Symbol_Table.Last (Mapping);
                        end if;
 
                        Prep.Mapping.Table (Symbol_Id) := Symbol_Data;
                     end if;
 
                  when others =>
                     null;
               end case;
 
               Scan;
            end if;
 
            if not OK then
               Error_Msg ("invalid switch", Dash_Location);
               Skip_To_End_Of_Line;
               goto Scan_Line;
            end if;
         end loop;
 
         --  Add the command line symbols, if any, possibly replacing symbols
         --  just defined.
 
         Add_Command_Line_Symbols;
 
         --  Put the resulting Prep.Mapping in Current_Data, and immediately
         --  set Prep.Mapping to nil.
 
         Current_Data.Mapping := Prep.Mapping;
         Prep.Mapping := No_Mapping;
 
         --  Record Current_Data
 
         if Current_Data.File_Name = No_Name then
            Default_Data := Current_Data;
 
         else
            Preproc_Data_Table.Increment_Last;
            Preproc_Data_Table.Table (Preproc_Data_Table.Last) := Current_Data;
         end if;
 
         Current_Data := No_Preproc_Data;
      end loop For_Each_Line;
 
      Scn.Scanner.Set_End_Of_Line_As_Token (False);
 
      --  Fail if there were errors in the preprocessing data file
 
      if Total_Errors_Detected > T then
         Errout.Finalize;
         Fail ("errors found in preprocessing data file """,
               Get_Name_String (N),
               """");
      end if;
 
      --  Record the dependency on the preprocessor data file
 
      Dependencies.Increment_Last;
      Dependencies.Table (Dependencies.Last) :=
        Source_Index_Of_Preproc_Data_File;
   end Parse_Preprocessing_Data_File;
 
   ---------------------------
   -- Prepare_To_Preprocess --
   ---------------------------
 
   procedure Prepare_To_Preprocess
     (Source               : File_Name_Type;
      Preprocessing_Needed : out Boolean)
   is
      Default : Boolean := False;
      Index   : Int := 0;
 
   begin
      --  By default, preprocessing is not needed
 
      Preprocessing_Needed := False;
 
      if No_Preprocessing then
         return;
      end if;
 
      --  First, look for preprocessing data specific to the current source
 
      for J in 1 .. Preproc_Data_Table.Last loop
         if Preproc_Data_Table.Table (J).File_Name = Source then
            Index := J;
            Current_Data := Preproc_Data_Table.Table (J);
            exit;
         end if;
      end loop;
 
      --  If no specific preprocessing data, then take the default
 
      if Index = 0 then
         if Default_Data_Defined then
            Current_Data := Default_Data;
            Default := True;
 
         else
            --  If no default, then nothing to do
 
            return;
         end if;
      end if;
 
      --  Set the preprocessing flags according to the preprocessing data
 
      if Current_Data.Comments and then not Current_Data.Always_Blank then
         Comment_Deleted_Lines := True;
         Blank_Deleted_Lines   := False;
 
      else
         Comment_Deleted_Lines := False;
         Blank_Deleted_Lines   := True;
      end if;
 
      Undefined_Symbols_Are_False := Current_Data.Undef_False;
      List_Preprocessing_Symbols  := Current_Data.List_Symbols;
 
      --  If not already done it, process the definition file
 
      if Current_Data.Processed then
 
         --  Set Prep.Mapping
 
         Prep.Mapping := Current_Data.Mapping;
 
      else
         --  First put the mapping in Prep.Mapping, because Prep.Parse_Def_File
         --  works on Prep.Mapping.
 
         Prep.Mapping := Current_Data.Mapping;
 
         String_To_Name_Buffer (Current_Data.Deffile);
 
         declare
            N : constant Name_Id := Name_Find;
            Deffile : constant Source_File_Index :=  Load_Definition_File (N);
            Add_Deffile : Boolean := True;
            T : constant Nat := Total_Errors_Detected;
 
         begin
            if Deffile = No_Source_File then
               Fail ("definition file """,
                     Get_Name_String (N),
                     """ cannot be found");
            end if;
 
            --  Initialize the preprocessor and set the characteristics of the
            --  scanner for a definition file.
 
            Prep.Initialize
              (Error_Msg         => Errout.Error_Msg'Access,
               Scan              => Scn.Scanner.Scan'Access,
               Set_Ignore_Errors => Errout.Set_Ignore_Errors'Access,
               Put_Char          => null,
               New_EOL           => null);
 
            Scn.Scanner.Set_End_Of_Line_As_Token (True);
            Scn.Scanner.Reset_Special_Characters;
 
            --  Initialize the scanner and process the definition file
 
            Scn.Scanner.Initialize_Scanner (No_Unit, Deffile);
            Prep.Parse_Def_File;
 
            --  Reset the behaviour of the scanner to the default
 
            Scn.Scanner.Set_End_Of_Line_As_Token (False);
 
            --  Fail if errors were found while processing the definition file
 
            if T /= Total_Errors_Detected then
               Errout.Finalize;
               Fail ("errors found in definition file """,
                     Get_Name_String (N),
                     """");
            end if;
 
            for Index in 1 .. Dependencies.Last loop
               if Dependencies.Table (Index) = Deffile then
                  Add_Deffile := False;
                  exit;
               end if;
            end loop;
 
            if Add_Deffile then
               Dependencies.Increment_Last;
               Dependencies.Table (Dependencies.Last) := Deffile;
            end if;
         end;
 
         --  Get back the mapping, indicate that the definition file is
         --  processed and store back the preprocessing data.
 
         Current_Data.Mapping := Prep.Mapping;
         Current_Data.Processed := True;
 
         if Default then
            Default_Data := Current_Data;
 
         else
            Preproc_Data_Table.Table (Index) := Current_Data;
         end if;
      end if;
 
      Preprocessing_Needed := True;
   end Prepare_To_Preprocess;
 
   ---------------------------------------------
   -- Process_Command_Line_Symbol_Definitions --
   ---------------------------------------------
 
   procedure Process_Command_Line_Symbol_Definitions is
      Symbol_Data : Prep.Symbol_Data;
      Found : Boolean := False;
 
   begin
      Symbol_Table.Init (Command_Line_Symbols);
 
      --  The command line definitions have been stored temporarily in
      --  array Symbol_Definitions.
 
      for Index in 1 .. Last_Definition loop
         --  Check each symbol definition, fail immediately if syntax is not
         --  correct.
 
         Check_Command_Line_Symbol_Definition
           (Definition => Symbol_Definitions (Index).all,
            Data => Symbol_Data);
         Found := False;
 
         --  If there is already a definition for this symbol, replace the old
         --  definition by this one.
 
         for J in 1 .. Symbol_Table.Last (Command_Line_Symbols) loop
            if Command_Line_Symbols.Table (J).Symbol = Symbol_Data.Symbol then
               Command_Line_Symbols.Table (J) := Symbol_Data;
               Found := True;
               exit;
            end if;
         end loop;
 
         --  Otherwise, create a new entry in the table
 
         if not Found then
            Symbol_Table.Increment_Last (Command_Line_Symbols);
            Command_Line_Symbols.Table
              (Symbol_Table.Last (Command_Line_Symbols)) := Symbol_Data;
         end if;
      end loop;
   end Process_Command_Line_Symbol_Definitions;
 
   -------------------------
   -- Skip_To_End_Of_Line --
   -------------------------
 
   procedure Skip_To_End_Of_Line is
   begin
      Set_Ignore_Errors (To => True);
 
      while Token /= Tok_End_Of_Line and then Token /= Tok_EOF loop
         Scan;
      end loop;
 
      Set_Ignore_Errors (To => False);
   end Skip_To_End_Of_Line;
 
end Prepcomp;
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.