OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / ada / xoscons.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                          GNAT SYSTEM UTILITIES                           --
4 --                                                                          --
5 --                              X O S C O N S                               --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --            Copyright (C) 2008, Free Software Foundation, Inc.            --
10 --                                                                          --
11 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
12 -- terms of the  GNU General Public License as published  by the Free Soft- --
13 -- ware  Foundation;  either version 3,  or (at your option) any later ver- --
14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
17 -- for  more details.  You should have  received  a copy of the GNU General --
18 -- Public License  distributed with GNAT; see file COPYING3.  If not, go to --
19 -- http://www.gnu.org/licenses for a complete copy of the license.          --
20 --                                                                          --
21 -- GNAT was originally developed  by the GNAT team at  New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
23 --                                                                          --
24 ------------------------------------------------------------------------------
25
26 --  This program generates the spec of System.OS_Constants (s-oscons.ads).
27
28 --  It works in conjunction with a C template file which must be pre-processed
29 --  and compiled using the cross compiler. Two input files are used:
30 --    - the preprocessed C file: s-oscons-tmplt.i
31 --    - the generated assembly file: s-oscons-tmplt.s
32
33 --  The contents of s-oscons.ads is written on standard output.
34
35 with Ada.Characters.Handling; use Ada.Characters.Handling;
36 with Ada.Exceptions;          use Ada.Exceptions;
37 with Ada.Strings.Fixed;       use Ada.Strings.Fixed;
38 with Ada.Text_IO;             use Ada.Text_IO;
39 with Ada.Streams.Stream_IO;   use Ada.Streams.Stream_IO;
40
41 pragma Warnings (Off);
42 --  System.Unsigned_Types is an internal GNAT unit
43 with System.Unsigned_Types;   use System.Unsigned_Types;
44 pragma Warnings (On);
45
46 with GNAT.Table;
47
48 with XUtil;                   use XUtil;
49
50 procedure XOSCons is
51
52    use ASCII;
53    use Ada.Strings;
54
55    Unit_Name : constant String := "s-oscons";
56    Tmpl_Name : constant String := Unit_Name & "-tmplt";
57
58    -------------------------------------------------
59    -- Information retrieved from assembly listing --
60    -------------------------------------------------
61
62    --  We need to deal with integer values that can be signed or unsigned,
63    --  so we need to cater for the maximum range of both cases.
64
65    type String_Access is access all String;
66    --  Note: we can't use GNAT.Strings for this definition, since that unit
67    --  is not available in older base compilers.
68
69    type Int_Value_Type is record
70       Positive  : Boolean;
71       Abs_Value : Long_Unsigned := 0;
72    end record;
73
74    type Asm_Info_Kind is
75      (CND,     --  Constant (decimal)
76       CNS,     --  Constant (freeform string)
77       TXT);    --  Literal text
78    --  Recognized markers found in assembly file. These markers are produced
79    --  by the same-named macros from the C template.
80
81    type Asm_Info (Kind : Asm_Info_Kind := TXT) is record
82       Line_Number   : Integer;
83       --  Line number in C source file
84
85       Constant_Name : String_Access;
86       --  Name of constant to be defined
87
88       Value_Len     : Natural := 0;
89       --  Length of text representation of constant's value
90
91       Text_Value    : String_Access;
92       --  Value for CNS constant
93
94       Int_Value     : Int_Value_Type;
95       --  Value for CND constant
96
97       Comment       : String_Access;
98       --  Additional descriptive comment for constant, or free-form text (TXT)
99    end record;
100
101    package Asm_Infos is new GNAT.Table (
102       Table_Component_Type => Asm_Info,
103       Table_Index_Type     => Integer,
104       Table_Low_Bound      => 1,
105       Table_Initial        => 100,
106       Table_Increment      => 10);
107
108    Max_Constant_Name_Len  : Natural := 0;
109    Max_Constant_Value_Len : Natural := 0;
110    --  Longest name and longest value lengths
111
112    procedure Output_Info (OFile : Sfile; Info_Index : Integer);
113    --  Output information from the indicated asm info line
114
115    procedure Parse_Asm_Line (Line : String);
116    --  Parse one information line from the assembly source
117
118    function Contains_Template_Name (S : String) return Boolean;
119    --  True if S contains Tmpl_Name, possibly with different casing
120
121    function Spaces (Count : Integer) return String;
122    --  If Count is positive, return a string of Count spaces, else return an
123    --  empty string.
124
125    ----------------------------
126    -- Contains_Template_Name --
127    ----------------------------
128
129    function Contains_Template_Name (S : String) return Boolean is
130    begin
131       return Index (Source => To_Lower (S), Pattern => Tmpl_Name) > 0;
132    end Contains_Template_Name;
133
134    -----------------
135    -- Output_Info --
136    -----------------
137
138    procedure Output_Info (OFile : Sfile; Info_Index : Integer) is
139       Info : Asm_Info renames Asm_Infos.Table (Info_Index);
140
141       procedure Put (S : String);
142
143       ---------
144       -- Put --
145       ---------
146
147       procedure Put (S : String) is
148       begin
149          Put (OFile, S);
150       end Put;
151
152    begin
153       if Info.Kind /= TXT then
154          --  TXT case is handled by the common code below
155
156          Put ("   ");
157          Put (Info.Constant_Name.all);
158          Put (Spaces (Max_Constant_Name_Len - Info.Constant_Name'Length));
159
160          Put (" : constant := ");
161
162          if Info.Kind = CND then
163             if not Info.Int_Value.Positive then
164                Put ("-");
165             end if;
166             Put (Trim (Info.Int_Value.Abs_Value'Img, Side => Left));
167          else
168             Put (Info.Text_Value.all);
169          end if;
170
171          Put (";");
172
173          if Info.Comment'Length > 0 then
174             Put (Spaces (Max_Constant_Value_Len - Info.Value_Len));
175             Put (" --  ");
176          end if;
177       end if;
178
179       Put (Info.Comment.all);
180       New_Line (OFile);
181    end Output_Info;
182
183    --------------------
184    -- Parse_Asm_Line --
185    --------------------
186
187    procedure Parse_Asm_Line (Line : String) is
188       Index1, Index2 : Integer := Line'First;
189
190       function Field_Alloc return String_Access;
191       --  Allocate and return a copy of Line (Index1 .. Index2 - 1)
192
193       procedure Find_Colon (Index : in out Integer);
194       --  Increment Index until the next colon in Line
195
196       function Parse_Int (S : String) return Int_Value_Type;
197       --  Parse a decimal number, preceded by an optional '$' or '#' character,
198       --  and return its value.
199
200       -----------------
201       -- Field_Alloc --
202       -----------------
203
204       function Field_Alloc return String_Access is
205       begin
206          return new String'(Line (Index1 .. Index2 - 1));
207       end Field_Alloc;
208
209       ----------------
210       -- Find_Colon --
211       ----------------
212
213       procedure Find_Colon (Index : in out Integer) is
214       begin
215          loop
216             Index := Index + 1;
217             exit when Index > Line'Last or else Line (Index) = ':';
218          end loop;
219       end Find_Colon;
220
221       ---------------
222       -- Parse_Int --
223       ---------------
224
225       function Parse_Int (S : String) return Int_Value_Type is
226          First    : Integer := S'First;
227          Positive : Boolean;
228       begin
229          --  On some platforms, immediate integer values are prefixed with
230          --  a $ or # character in assembly output.
231
232          if S (First) = '$'
233            or else S (First) = '#'
234          then
235             First := First + 1;
236          end if;
237
238          if S (First) = '-' then
239             Positive := False;
240             First    := First + 1;
241          else
242             Positive := True;
243          end if;
244
245          return (Positive  => Positive,
246                  Abs_Value => Long_Unsigned'Value (S (First .. S'Last)));
247
248       exception
249          when E : others =>
250             Put_Line (Standard_Error, "can't parse decimal value: " & S);
251             raise;
252       end Parse_Int;
253
254    --  Start of processing for Parse_Asm_Line
255
256    begin
257       Find_Colon (Index2);
258
259       declare
260          Info : Asm_Info (Kind => Asm_Info_Kind'Value
261                                     (Line (Line'First .. Index2 - 1)));
262       begin
263          Index1 := Index2 + 1;
264          Find_Colon (Index2);
265
266          Info.Line_Number :=
267            Integer (Parse_Int (Line (Index1 .. Index2 - 1)).Abs_Value);
268
269          case Info.Kind is
270             when CND | CNS =>
271                Index1 := Index2 + 1;
272                Find_Colon (Index2);
273
274                Info.Constant_Name := Field_Alloc;
275                if Info.Constant_Name'Length > Max_Constant_Name_Len then
276                   Max_Constant_Name_Len := Info.Constant_Name'Length;
277                end if;
278
279                Index1 := Index2 + 1;
280                Find_Colon (Index2);
281
282                if Info.Kind = CND then
283                   Info.Int_Value := Parse_Int (Line (Index1 .. Index2 - 1));
284                   Info.Value_Len := Index2 - Index1 - 1;
285                else
286                   Info.Text_Value := Field_Alloc;
287                   Info.Value_Len  := Info.Text_Value'Length;
288                end if;
289
290             when others =>
291                null;
292          end case;
293
294          Index1 := Index2 + 1;
295          Index2 := Line'Last + 1;
296          Info.Comment := Field_Alloc;
297
298          if Info.Kind = TXT then
299             Info.Text_Value := Info.Comment;
300
301          --  Update Max_Constant_Value_Len, but only if this constant has
302          --  a comment (else the value is allowed to be longer).
303
304          elsif Info.Comment'Length > 0 then
305             if Info.Value_Len > Max_Constant_Value_Len then
306                Max_Constant_Value_Len := Info.Value_Len;
307             end if;
308          end if;
309
310          Asm_Infos.Append (Info);
311       end;
312    exception
313       when E : others =>
314          Put_Line (Standard_Error,
315            "can't parse " & Line);
316          Put_Line (Standard_Error,
317            "exception raised: " & Exception_Information (E));
318    end Parse_Asm_Line;
319
320    ------------
321    -- Spaces --
322    ------------
323
324    function Spaces (Count : Integer) return String is
325    begin
326       if Count <= 0 then
327          return "";
328       else
329          return (1 .. Count => ' ');
330       end if;
331    end Spaces;
332
333    --  Local declarations
334
335    Asm_File_Name  : constant String := Tmpl_Name & ".s";
336    Tmpl_File_Name : constant String := Tmpl_Name & ".i";
337    Ada_File_Name  : constant String := Unit_Name & ".ads";
338
339    Asm_File  : Ada.Text_IO.File_Type;
340    Tmpl_File : Ada.Text_IO.File_Type;
341    OFile     : Sfile;
342
343    Line : String (1 .. 256);
344    Last : Integer;
345    --  Line being processed
346
347    Current_Line : Integer;
348    Current_Info : Integer;
349    In_Comment   : Boolean;
350    In_Template  : Boolean;
351
352 --  Start of processing for XOSCons
353
354 begin
355    --  Load values from assembly file
356
357    Open (Asm_File, In_File, Asm_File_Name);
358
359    while not End_Of_File (Asm_File) loop
360       Get_Line (Asm_File, Line, Last);
361       if Last > 2 and then Line (1 .. 2) = "->" then
362          Parse_Asm_Line (Line (3 .. Last));
363       end if;
364    end loop;
365
366    Close (Asm_File);
367
368    --  Load C template and output definitions
369
370    Open (Tmpl_File, In_File, Tmpl_File_Name);
371    Create (OFile, Out_File, Ada_File_Name);
372
373    Current_Line := 0;
374    Current_Info := Asm_Infos.First;
375    In_Comment   := False;
376
377    while not End_Of_File (Tmpl_File) loop
378       <<Get_One_Line>>
379       Get_Line (Tmpl_File, Line, Last);
380
381       if Last >= 2 and then Line (1 .. 2) = "# " then
382          declare
383             Index : Integer := 3;
384          begin
385             while Index <= Last and then Line (Index) in '0' .. '9' loop
386                Index := Index + 1;
387             end loop;
388
389             if Contains_Template_Name (Line (Index + 1 .. Last)) then
390                Current_Line := Integer'Value (Line (3 .. Index - 1));
391                In_Template  := True;
392                goto Get_One_Line;
393             else
394                In_Template := False;
395             end if;
396          end;
397
398       elsif In_Template then
399          if In_Comment then
400             if Line (1 .. Last) = "*/" then
401                In_Comment := False;
402             else
403                Put_Line (OFile, Line (1 .. Last));
404             end if;
405
406          elsif Line (1 .. Last) = "/*" then
407             In_Comment := True;
408
409          elsif Asm_Infos.Table (Current_Info).Line_Number = Current_Line then
410             Output_Info (OFile, Current_Info);
411             Current_Info := Current_Info + 1;
412          end if;
413          Current_Line := Current_Line + 1;
414       end if;
415    end loop;
416
417    Close (Tmpl_File);
418
419 end XOSCons;