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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [ada/] [tree_io.adb] - Rev 728

Go to most recent revision | Compare with Previous | Blame | View Log

------------------------------------------------------------------------------
--                                                                          --
--                         GNAT COMPILER COMPONENTS                         --
--                                                                          --
--                              T R E E _ I O                               --
--                                                                          --
--                                 B o d y                                  --
--                                                                          --
--          Copyright (C) 1992-2009  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 3,  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.                                     --
--                                                                          --
-- As a special exception under Section 7 of GPL version 3, you are granted --
-- additional permissions described in the GCC Runtime Library Exception,   --
-- version 3.1, as published by the Free Software Foundation.               --
--                                                                          --
-- You should have received a copy of the GNU General Public License and    --
-- a copy of the GCC Runtime Library Exception along with this program;     --
-- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
-- <http://www.gnu.org/licenses/>.                                          --
--                                                                          --
-- GNAT was originally developed  by the GNAT team at  New York University. --
-- Extensive contributions were provided by Ada Core Technologies Inc.      --
--                                                                          --
------------------------------------------------------------------------------
 
with Debug;  use Debug;
with Output; use Output;
with Unchecked_Conversion;
 
package body Tree_IO is
   Debug_Flag_Tree : Boolean := False;
   --  Debug flag for debug output from tree read/write
 
   -------------------------------------------
   -- Compression Scheme Used for Tree File --
   -------------------------------------------
 
   --  We don't just write the data directly, but instead do a mild form
   --  of compression, since we expect lots of compressible zeroes and
   --  blanks. The compression scheme is as follows:
 
   --    00nnnnnn followed by nnnnnn bytes (non compressed data)
   --    01nnnnnn indicates nnnnnn binary zero bytes
   --    10nnnnnn indicates nnnnnn ASCII space bytes
   --    11nnnnnn bbbbbbbb indicates nnnnnnnn occurrences of byte bbbbbbbb
 
   --  Since we expect many zeroes in trees, and many spaces in sources,
   --  this compression should be reasonably efficient. We can put in
   --  something better later on.
 
   --  Note that this compression applies to the Write_Tree_Data and
   --  Read_Tree_Data calls, not to the calls to read and write single
   --  scalar values, which are written in memory format without any
   --  compression.
 
   C_Noncomp : constant := 2#00_000000#;
   C_Zeros   : constant := 2#01_000000#;
   C_Spaces  : constant := 2#10_000000#;
   C_Repeat  : constant := 2#11_000000#;
   --  Codes for compression sequences
 
   Max_Count : constant := 63;
   --  Maximum data length for one compression sequence
 
   --  The above compression scheme applies only to data written with the
   --  Tree_Write routine and read with Tree_Read. Data written using the
   --  Tree_Write_Char or Tree_Write_Int routines and read using the
   --  corresponding input routines is not compressed.
 
   type Int_Bytes is array (1 .. 4) of Byte;
   for Int_Bytes'Size use 32;
 
   function To_Int_Bytes is new Unchecked_Conversion (Int, Int_Bytes);
   function To_Int       is new Unchecked_Conversion (Int_Bytes, Int);
 
   ----------------------
   -- Global Variables --
   ----------------------
 
   Tree_FD : File_Descriptor;
   --  File descriptor for tree
 
   Buflen : constant Int := 8_192;
   --  Length of buffer for read and write file data
 
   Buf : array (Pos range 1 .. Buflen) of Byte;
   --  Read/write file data buffer
 
   Bufn : Nat;
   --  Number of bytes read/written from/to buffer
 
   Buft : Nat;
   --  Total number of bytes in input buffer containing valid data. Used only
   --  for input operations. There is data left to be processed in the buffer
   --  if Buft > Bufn. A value of zero for Buft means that the buffer is empty.
 
   -----------------------
   -- Local Subprograms --
   -----------------------
 
   procedure Read_Buffer;
   --  Reads data into buffer, setting Bufn appropriately
 
   function Read_Byte return Byte;
   pragma Inline (Read_Byte);
   --  Returns next byte from input file, raises Tree_Format_Error if none left
 
   procedure Write_Buffer;
   --  Writes out current buffer contents
 
   procedure Write_Byte (B : Byte);
   pragma Inline (Write_Byte);
   --  Write one byte to output buffer, checking for buffer-full condition
 
   -----------------
   -- Read_Buffer --
   -----------------
 
   procedure Read_Buffer is
   begin
      Buft := Int (Read (Tree_FD, Buf (1)'Address, Integer (Buflen)));
 
      if Buft = 0 then
         raise Tree_Format_Error;
      else
         Bufn := 0;
      end if;
   end Read_Buffer;
 
   ---------------
   -- Read_Byte --
   ---------------
 
   function Read_Byte return Byte is
   begin
      if Bufn = Buft then
         Read_Buffer;
      end if;
 
      Bufn := Bufn + 1;
      return Buf (Bufn);
   end Read_Byte;
 
   --------------------
   -- Tree_Read_Bool --
   --------------------
 
   procedure Tree_Read_Bool (B : out Boolean) is
   begin
      B := Boolean'Val (Read_Byte);
 
      if Debug_Flag_Tree then
         if B then
            Write_Str ("True");
         else
            Write_Str ("False");
         end if;
 
         Write_Eol;
      end if;
   end Tree_Read_Bool;
 
   --------------------
   -- Tree_Read_Char --
   --------------------
 
   procedure Tree_Read_Char (C : out Character) is
   begin
      C := Character'Val (Read_Byte);
 
      if Debug_Flag_Tree then
         Write_Str ("==> transmitting Character = ");
         Write_Char (C);
         Write_Eol;
      end if;
   end Tree_Read_Char;
 
   --------------------
   -- Tree_Read_Data --
   --------------------
 
   procedure Tree_Read_Data (Addr : Address; Length : Int) is
 
      type S is array (Pos) of Byte;
      --  This is a big array, for which we have to suppress the warning
 
      type SP is access all S;
 
      function To_SP is new Unchecked_Conversion (Address, SP);
 
      Data : constant SP := To_SP (Addr);
      --  Data buffer to be read as an indexable array of bytes
 
      OP : Pos := 1;
      --  Pointer to next byte of data buffer to be read into
 
      B : Byte;
      C : Byte;
      L : Int;
 
   begin
      if Debug_Flag_Tree then
         Write_Str ("==> transmitting ");
         Write_Int (Length);
         Write_Str (" data bytes");
         Write_Eol;
      end if;
 
      --  Verify data length
 
      Tree_Read_Int (L);
 
      if L /= Length then
         Write_Str ("==> transmitting, expected ");
         Write_Int (Length);
         Write_Str (" bytes, found length = ");
         Write_Int (L);
         Write_Eol;
         raise Tree_Format_Error;
      end if;
 
      --  Loop to read data
 
      while OP <= Length loop
 
         --  Get compression control character
 
         B := Read_Byte;
         C := B and 2#00_111111#;
         B := B and 2#11_000000#;
 
         --  Non-repeat case
 
         if B = C_Noncomp then
            if Debug_Flag_Tree then
               Write_Str ("==>    uncompressed:  ");
               Write_Int (Int (C));
               Write_Str (", starting at ");
               Write_Int (OP);
               Write_Eol;
            end if;
 
            for J in 1 .. C loop
               Data (OP) := Read_Byte;
               OP := OP + 1;
            end loop;
 
         --  Repeated zeroes
 
         elsif B = C_Zeros then
            if Debug_Flag_Tree then
               Write_Str ("==>    zeroes:        ");
               Write_Int (Int (C));
               Write_Str (", starting at ");
               Write_Int (OP);
               Write_Eol;
            end if;
 
            for J in 1 .. C loop
               Data (OP) := 0;
               OP := OP + 1;
            end loop;
 
         --  Repeated spaces
 
         elsif B = C_Spaces then
            if Debug_Flag_Tree then
               Write_Str ("==>    spaces:        ");
               Write_Int (Int (C));
               Write_Str (", starting at ");
               Write_Int (OP);
               Write_Eol;
            end if;
 
            for J in 1 .. C loop
               Data (OP) := Character'Pos (' ');
               OP := OP + 1;
            end loop;
 
         --  Specified repeated character
 
         else -- B = C_Repeat
            B := Read_Byte;
 
            if Debug_Flag_Tree then
               Write_Str ("==>    other char:    ");
               Write_Int (Int (C));
               Write_Str (" (");
               Write_Int (Int (B));
               Write_Char (')');
               Write_Str (", starting at ");
               Write_Int (OP);
               Write_Eol;
            end if;
 
            for J in 1 .. C loop
               Data (OP) := B;
               OP := OP + 1;
            end loop;
         end if;
      end loop;
 
      --  At end of loop, data item must be exactly filled
 
      if OP /= Length + 1 then
         raise Tree_Format_Error;
      end if;
 
   end Tree_Read_Data;
 
   --------------------------
   -- Tree_Read_Initialize --
   --------------------------
 
   procedure Tree_Read_Initialize (Desc : File_Descriptor) is
   begin
      Buft := 0;
      Bufn := 0;
      Tree_FD := Desc;
      Debug_Flag_Tree := Debug_Flag_5;
   end Tree_Read_Initialize;
 
   -------------------
   -- Tree_Read_Int --
   -------------------
 
   procedure Tree_Read_Int (N : out Int) is
      N_Bytes : Int_Bytes;
 
   begin
      for J in 1 .. 4 loop
         N_Bytes (J) := Read_Byte;
      end loop;
 
      N := To_Int (N_Bytes);
 
      if Debug_Flag_Tree then
         Write_Str ("==> transmitting Int = ");
         Write_Int (N);
         Write_Eol;
      end if;
   end Tree_Read_Int;
 
   -------------------
   -- Tree_Read_Str --
   -------------------
 
   procedure Tree_Read_Str (S : out String_Ptr) is
      N : Nat;
 
   begin
      Tree_Read_Int (N);
      S := new String (1 .. Natural (N));
      Tree_Read_Data (S.all (1)'Address, N);
   end Tree_Read_Str;
 
   -------------------------
   -- Tree_Read_Terminate --
   -------------------------
 
   procedure Tree_Read_Terminate is
   begin
      --  Must be at end of input buffer, so we should get Tree_Format_Error
      --  if we try to read one more byte, if not, we have a format error.
 
      declare
         B : Byte;
         pragma Warnings (Off, B);
 
      begin
         B := Read_Byte;
 
      exception
         when Tree_Format_Error => return;
      end;
 
      raise Tree_Format_Error;
   end Tree_Read_Terminate;
 
   ---------------------
   -- Tree_Write_Bool --
   ---------------------
 
   procedure Tree_Write_Bool (B : Boolean) is
   begin
      if Debug_Flag_Tree then
         Write_Str ("==> transmitting Boolean = ");
 
         if B then
            Write_Str ("True");
         else
            Write_Str ("False");
         end if;
 
         Write_Eol;
      end if;
 
      Write_Byte (Boolean'Pos (B));
   end Tree_Write_Bool;
 
   ---------------------
   -- Tree_Write_Char --
   ---------------------
 
   procedure Tree_Write_Char (C : Character) is
   begin
      if Debug_Flag_Tree then
         Write_Str ("==> transmitting Character = ");
         Write_Char (C);
         Write_Eol;
      end if;
 
      Write_Byte (Character'Pos (C));
   end Tree_Write_Char;
 
   ---------------------
   -- Tree_Write_Data --
   ---------------------
 
   procedure Tree_Write_Data (Addr : Address; Length : Int) is
 
      type S is array (Pos) of Byte;
      --  This is a big array, for which we have to suppress the warning
 
      type SP is access all S;
 
      function To_SP is new Unchecked_Conversion (Address, SP);
 
      Data : constant SP := To_SP (Addr);
      --  Pointer to data to be written, converted to array type
 
      IP : Pos := 1;
      --  Input buffer pointer, next byte to be processed
 
      NC : Nat range 0 .. Max_Count := 0;
      --  Number of bytes of non-compressible sequence
 
      C  : Byte;
 
      procedure Write_Non_Compressed_Sequence;
      --  Output currently collected sequence of non-compressible data
 
      -----------------------------------
      -- Write_Non_Compressed_Sequence --
      -----------------------------------
 
      procedure Write_Non_Compressed_Sequence is
      begin
         if NC > 0 then
            Write_Byte (C_Noncomp + Byte (NC));
 
            if Debug_Flag_Tree then
               Write_Str ("==>    uncompressed:  ");
               Write_Int (NC);
               Write_Str (", starting at ");
               Write_Int (IP - NC);
               Write_Eol;
            end if;
 
            for J in reverse 1 .. NC loop
               Write_Byte (Data (IP - J));
            end loop;
 
            NC := 0;
         end if;
      end Write_Non_Compressed_Sequence;
 
   --  Start of processing for Tree_Write_Data
 
   begin
      if Debug_Flag_Tree then
         Write_Str ("==> transmitting ");
         Write_Int (Length);
         Write_Str (" data bytes");
         Write_Eol;
      end if;
 
      --  We write the count at the start, so that we can check it on
      --  the corresponding read to make sure that reads and writes match
 
      Tree_Write_Int (Length);
 
      --  Conversion loop
      --    IP is index of next input character
      --    NC is number of non-compressible bytes saved up
 
      loop
         --  If input is completely processed, then we are all done
 
         if IP > Length then
            Write_Non_Compressed_Sequence;
            return;
         end if;
 
         --  Test for compressible sequence, must be at least three identical
         --  bytes in a row to be worthwhile compressing.
 
         if IP + 2 <= Length
           and then Data (IP) = Data (IP + 1)
           and then Data (IP) = Data (IP + 2)
         then
            Write_Non_Compressed_Sequence;
 
            --  Count length of new compression sequence
 
            C := 3;
            IP := IP + 3;
 
            while IP < Length
              and then Data (IP) = Data (IP - 1)
              and then C < Max_Count
            loop
               C := C + 1;
               IP := IP + 1;
            end loop;
 
            --  Output compression sequence
 
            if Data (IP - 1) = 0 then
               if Debug_Flag_Tree then
                  Write_Str ("==>    zeroes:        ");
                  Write_Int (Int (C));
                  Write_Str (", starting at ");
                  Write_Int (IP - Int (C));
                  Write_Eol;
               end if;
 
               Write_Byte (C_Zeros + C);
 
            elsif Data (IP - 1) = Character'Pos (' ') then
               if Debug_Flag_Tree then
                  Write_Str ("==>    spaces:        ");
                  Write_Int (Int (C));
                  Write_Str (", starting at ");
                  Write_Int (IP - Int (C));
                  Write_Eol;
               end if;
 
               Write_Byte (C_Spaces + C);
 
            else
               if Debug_Flag_Tree then
                  Write_Str ("==>    other char:    ");
                  Write_Int (Int (C));
                  Write_Str (" (");
                  Write_Int (Int (Data (IP - 1)));
                  Write_Char (')');
                  Write_Str (", starting at ");
                  Write_Int (IP - Int (C));
                  Write_Eol;
               end if;
 
               Write_Byte (C_Repeat + C);
               Write_Byte (Data (IP - 1));
            end if;
 
         --  No compression possible here
 
         else
            --  Output non-compressed sequence if at maximum length
 
            if NC = Max_Count then
               Write_Non_Compressed_Sequence;
            end if;
 
            NC := NC + 1;
            IP := IP + 1;
         end if;
      end loop;
 
   end Tree_Write_Data;
 
   ---------------------------
   -- Tree_Write_Initialize --
   ---------------------------
 
   procedure Tree_Write_Initialize (Desc : File_Descriptor) is
   begin
      Bufn := 0;
      Tree_FD := Desc;
      Set_Standard_Error;
      Debug_Flag_Tree := Debug_Flag_5;
   end Tree_Write_Initialize;
 
   --------------------
   -- Tree_Write_Int --
   --------------------
 
   procedure Tree_Write_Int (N : Int) is
      N_Bytes : constant Int_Bytes := To_Int_Bytes (N);
 
   begin
      if Debug_Flag_Tree then
         Write_Str ("==> transmitting Int = ");
         Write_Int (N);
         Write_Eol;
      end if;
 
      for J in 1 .. 4 loop
         Write_Byte (N_Bytes (J));
      end loop;
   end Tree_Write_Int;
 
   --------------------
   -- Tree_Write_Str --
   --------------------
 
   procedure Tree_Write_Str (S : String_Ptr) is
   begin
      Tree_Write_Int (S'Length);
      Tree_Write_Data (S (1)'Address, S'Length);
   end Tree_Write_Str;
 
   --------------------------
   -- Tree_Write_Terminate --
   --------------------------
 
   procedure Tree_Write_Terminate is
   begin
      if Bufn > 0 then
         Write_Buffer;
      end if;
   end Tree_Write_Terminate;
 
   ------------------
   -- Write_Buffer --
   ------------------
 
   procedure Write_Buffer is
   begin
      if Integer (Bufn) = Write (Tree_FD, Buf'Address, Integer (Bufn)) then
         Bufn := 0;
 
      else
         Set_Standard_Error;
         Write_Str ("fatal error: disk full");
         OS_Exit (2);
      end if;
   end Write_Buffer;
 
   ----------------
   -- Write_Byte --
   ----------------
 
   procedure Write_Byte (B : Byte) is
   begin
      Bufn := Bufn + 1;
      Buf (Bufn) := B;
 
      if Bufn = Buflen then
         Write_Buffer;
      end if;
   end Write_Byte;
 
end Tree_IO;
 

Go to most recent revision | 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.