blob: 015f9644e7ec4f38a36333ee959a4f88863d0aed [file] [log] [blame]
------------------------------------------------------------------------------
-- --
-- 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;