| ------------------------------------------------------------------------------ |
| -- -- |
| -- GNAT COMPILER COMPONENTS -- |
| -- -- |
| -- G P R E P -- |
| -- -- |
| -- B o d y -- |
| -- -- |
| -- Copyright (C) 2002-2004, 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, 59 Temple Place - Suite 330, Boston, -- |
| -- MA 02111-1307, USA. -- |
| -- -- |
| -- GNAT was originally developed by the GNAT team at New York University. -- |
| -- Extensive contributions were provided by Ada Core Technologies Inc. -- |
| -- -- |
| ------------------------------------------------------------------------------ |
| |
| with Csets; |
| with Err_Vars; use Err_Vars; |
| with Errutil; |
| with Gnatvsn; |
| with Namet; use Namet; |
| with Opt; |
| with Osint; use Osint; |
| with Output; use Output; |
| with Prep; use Prep; |
| with Scng; |
| with Sinput.C; |
| with Snames; |
| with Stringt; use Stringt; |
| with Types; use Types; |
| |
| with Ada.Text_IO; use Ada.Text_IO; |
| with GNAT.Command_Line; |
| with GNAT.OS_Lib; use GNAT.OS_Lib; |
| |
| package body GPrep is |
| |
| Copyright_Displayed : Boolean := False; |
| -- Used to prevent multiple displays of the copyright notice |
| |
| ------------------------ |
| -- Argument Line Data -- |
| ------------------------ |
| |
| Infile_Name : String_Access; |
| Outfile_Name : String_Access; |
| Deffile_Name : String_Access; |
| |
| Source_Ref_Pragma : Boolean := False; |
| -- Record command line options (set if -r switch set) |
| |
| Text_Outfile : aliased Ada.Text_IO.File_Type; |
| Outfile : constant File_Access := Text_Outfile'Access; |
| |
| ----------------- |
| -- Subprograms -- |
| ----------------- |
| |
| procedure Display_Copyright; |
| -- Display the copyright notice |
| |
| procedure Post_Scan; |
| -- Null procedure, needed by instantiation of Scng below |
| |
| package Scanner is new Scng |
| (Post_Scan, |
| Errutil.Error_Msg, |
| Errutil.Error_Msg_S, |
| Errutil.Error_Msg_SC, |
| Errutil.Error_Msg_SP, |
| Errutil.Style); |
| -- The scanner for the preprocessor |
| |
| procedure Process_Command_Line_Symbol_Definition (S : String); |
| -- Process a -D switch on ther command line |
| |
| procedure Put_Char_To_Outfile (C : Character); |
| -- Output one character to the output file. |
| -- Used to initialize the preprocessor. |
| |
| procedure New_EOL_To_Outfile; |
| -- Output a new line to the output file. |
| -- Used to initialize the preprocessor. |
| |
| procedure Scan_Command_Line; |
| -- Scan the switches and the file names |
| |
| procedure Usage; |
| -- Display the usage |
| |
| ----------------------- |
| -- Display_Copyright -- |
| ----------------------- |
| |
| procedure Display_Copyright is |
| begin |
| if not Copyright_Displayed then |
| Write_Line ("GNAT Preprocessor " & |
| Gnatvsn.Gnat_Version_String & |
| " Copyright 1996-2004 Free Software Foundation, Inc."); |
| Copyright_Displayed := True; |
| end if; |
| end Display_Copyright; |
| |
| -------------- |
| -- Gnatprep -- |
| -------------- |
| |
| procedure Gnatprep is |
| Infile : Source_File_Index; |
| |
| begin |
| -- Do some initializations (order is important here!) |
| |
| Csets.Initialize; |
| Namet.Initialize; |
| Snames.Initialize; |
| Stringt.Initialize; |
| |
| -- Initialize the preprocessor |
| |
| Prep.Initialize |
| (Error_Msg => Errutil.Error_Msg'Access, |
| Scan => Scanner.Scan'Access, |
| Set_Ignore_Errors => Errutil.Set_Ignore_Errors'Access, |
| Put_Char => Put_Char_To_Outfile'Access, |
| New_EOL => New_EOL_To_Outfile'Access); |
| |
| -- Set the scanner characteristics for the preprocessor |
| |
| Scanner.Set_Special_Character ('#'); |
| Scanner.Set_Special_Character ('$'); |
| Scanner.Set_End_Of_Line_As_Token (True); |
| |
| -- Initialize the mapping table of symbols to values |
| |
| Prep.Symbol_Table.Init (Prep.Mapping); |
| |
| -- Parse the switches and arguments |
| |
| Scan_Command_Line; |
| |
| if Opt.Verbose_Mode then |
| Display_Copyright; |
| end if; |
| |
| -- Test we had all the arguments needed |
| |
| if Infile_Name = null then |
| -- No input file specified, just output the usage and exit |
| |
| Usage; |
| return; |
| elsif Outfile_Name = null then |
| -- No output file specified, just output the usage and exit |
| |
| Usage; |
| return; |
| end if; |
| |
| -- If a pragma Source_File_Name, we need to keep line numbers. |
| -- So, if the deleted lines are not put as comment, we must output them |
| -- as blank lines. |
| |
| if Source_Ref_Pragma and (not Opt.Comment_Deleted_Lines) then |
| Opt.Blank_Deleted_Lines := True; |
| end if; |
| |
| -- If we have a definition file, parse it |
| |
| if Deffile_Name /= null then |
| declare |
| Deffile : Source_File_Index; |
| |
| begin |
| Errutil.Initialize; |
| Deffile := Sinput.C.Load_File (Deffile_Name.all); |
| |
| -- Set Main_Source_File to the definition file for the benefit of |
| -- Errutil.Finalize. |
| |
| Sinput.Main_Source_File := Deffile; |
| |
| if Deffile = No_Source_File then |
| Fail ("unable to find definition file """, |
| Deffile_Name.all, |
| """"); |
| end if; |
| |
| Scanner.Initialize_Scanner (No_Unit, Deffile); |
| |
| Prep.Parse_Def_File; |
| end; |
| end if; |
| |
| -- If there are errors in the definition file, output these errors |
| -- and exit. |
| |
| if Total_Errors_Detected > 0 then |
| Errutil.Finalize (Source_Type => "definition"); |
| Fail ("errors in definition file """, Deffile_Name.all, """"); |
| end if; |
| |
| -- If -s switch was specified, print a sorted list of symbol names and |
| -- values, if any. |
| |
| if Opt.List_Preprocessing_Symbols then |
| Prep.List_Symbols (Foreword => ""); |
| end if; |
| |
| -- Load the input file |
| |
| Infile := Sinput.C.Load_File (Infile_Name.all); |
| |
| if Infile = No_Source_File then |
| Fail ("unable to find input file """, Infile_Name.all, """"); |
| end if; |
| |
| -- Set Main_Source_File to the input file for the benefit of |
| -- Errutil.Finalize. |
| |
| Sinput.Main_Source_File := Infile; |
| |
| Scanner.Initialize_Scanner (No_Unit, Infile); |
| |
| -- If an output file were specified, create it; fails if this did not |
| -- work. |
| |
| if Outfile_Name /= null then |
| begin |
| Create (Text_Outfile, Out_File, Outfile_Name.all); |
| |
| exception |
| when others => |
| Fail |
| ("unable to create output file """, Outfile_Name.all, """"); |
| end; |
| end if; |
| |
| -- Output the SFN pragma if asked to |
| |
| if Source_Ref_Pragma then |
| Put_Line (Outfile.all, "pragma Source_Reference (1, """ & |
| Get_Name_String (Sinput.File_Name (Infile)) & |
| """);"); |
| end if; |
| |
| -- Preprocess the input file |
| |
| Prep.Preprocess; |
| |
| -- In verbose mode, if there is no error, report it |
| |
| if Opt.Verbose_Mode and then Err_Vars.Total_Errors_Detected = 0 then |
| Errutil.Finalize (Source_Type => "input"); |
| end if; |
| |
| -- If we had some errors, delete the output file, and report the errors, |
| |
| if Err_Vars.Total_Errors_Detected > 0 then |
| if Outfile /= Standard_Output then |
| Delete (Text_Outfile); |
| end if; |
| |
| Errutil.Finalize (Source_Type => "input"); |
| |
| -- otherwise, close the output file, and we are done. |
| |
| elsif Outfile /= Standard_Output then |
| Close (Text_Outfile); |
| end if; |
| end Gnatprep; |
| |
| ------------------------ |
| -- New_EOL_To_Outfile -- |
| ------------------------ |
| |
| procedure New_EOL_To_Outfile is |
| begin |
| New_Line (Outfile.all); |
| end New_EOL_To_Outfile; |
| |
| --------------- |
| -- Post_Scan -- |
| --------------- |
| |
| procedure Post_Scan is |
| begin |
| null; |
| end Post_Scan; |
| |
| -------------------------------------------- |
| -- Process_Command_Line_Symbol_Definition -- |
| -------------------------------------------- |
| |
| procedure Process_Command_Line_Symbol_Definition (S : String) is |
| Data : Symbol_Data; |
| Symbol : Symbol_Id; |
| |
| begin |
| -- Check the symbol definition and get the symbol and its value. |
| -- Fail if symbol definition is illegal. |
| |
| Check_Command_Line_Symbol_Definition (S, Data); |
| |
| Symbol := Index_Of (Data.Symbol); |
| |
| -- If symbol does not alrady exist, create a new entry in the mapping |
| -- table. |
| |
| if Symbol = No_Symbol then |
| Symbol_Table.Increment_Last (Mapping); |
| Symbol := Symbol_Table.Last (Mapping); |
| end if; |
| |
| Mapping.Table (Symbol) := Data; |
| end Process_Command_Line_Symbol_Definition; |
| |
| ------------------------- |
| -- Put_Char_To_Outfile -- |
| ------------------------- |
| |
| procedure Put_Char_To_Outfile (C : Character) is |
| begin |
| Put (Outfile.all, C); |
| end Put_Char_To_Outfile; |
| |
| ----------------------- |
| -- Scan_Command_Line -- |
| ----------------------- |
| |
| procedure Scan_Command_Line is |
| Switch : Character; |
| |
| begin |
| -- Parse the switches |
| |
| loop |
| begin |
| Switch := GNAT.Command_Line.Getopt ("D: b c r s u v"); |
| case Switch is |
| |
| when ASCII.NUL => |
| exit; |
| |
| when 'D' => |
| Process_Command_Line_Symbol_Definition |
| (S => GNAT.Command_Line.Parameter); |
| |
| when 'b' => |
| Opt.Blank_Deleted_Lines := True; |
| |
| when 'c' => |
| Opt.Comment_Deleted_Lines := True; |
| |
| when 'r' => |
| Source_Ref_Pragma := True; |
| |
| when 's' => |
| Opt.List_Preprocessing_Symbols := True; |
| |
| when 'u' => |
| Opt.Undefined_Symbols_Are_False := True; |
| |
| when 'v' => |
| Opt.Verbose_Mode := True; |
| |
| when others => |
| Fail ("Invalid Switch: -" & Switch); |
| end case; |
| |
| exception |
| when GNAT.Command_Line.Invalid_Switch => |
| Write_Str ("Invalid Switch: -"); |
| Write_Line (GNAT.Command_Line.Full_Switch); |
| Usage; |
| OS_Exit (1); |
| end; |
| end loop; |
| |
| -- Get the file names |
| |
| loop |
| declare |
| S : constant String := GNAT.Command_Line.Get_Argument; |
| |
| begin |
| exit when S'Length = 0; |
| |
| if Infile_Name = null then |
| Infile_Name := new String'(S); |
| elsif Outfile_Name = null then |
| Outfile_Name := new String'(S); |
| elsif Deffile_Name = null then |
| Deffile_Name := new String'(S); |
| else |
| Fail ("too many arguments specifed"); |
| end if; |
| end; |
| end loop; |
| end Scan_Command_Line; |
| |
| ----------- |
| -- Usage -- |
| ----------- |
| |
| procedure Usage is |
| begin |
| Display_Copyright; |
| Write_Line ("Usage: gnatprep [-bcrsuv] [-Dsymbol=value] " & |
| "infile outfile [deffile]"); |
| Write_Eol; |
| Write_Line (" infile Name of the input file"); |
| Write_Line (" outfile Name of the output file"); |
| Write_Line (" deffile Name of the definition file"); |
| Write_Eol; |
| Write_Line ("gnatprep switches:"); |
| Write_Line (" -b Replace preprocessor lines by blank lines"); |
| Write_Line (" -c Keep preprocessor lines as comments"); |
| Write_Line (" -D Associate symbol with value"); |
| Write_Line (" -r Generate Source_Reference pragma"); |
| Write_Line (" -s Print a sorted list of symbol names and values"); |
| Write_Line (" -u Treat undefined symbols as FALSE"); |
| Write_Line (" -v Verbose mode"); |
| Write_Eol; |
| end Usage; |
| |
| end GPrep; |