comp.lang.ada
 help / color / mirror / Atom feed
* Ann: Little tutorial about streams
@ 2011-02-28 17:00 mockturtle
  2011-02-28 20:32 ` Ludovic Brenta
  2011-03-01  3:48 ` Randy Brukardt
  0 siblings, 2 replies; 10+ messages in thread
From: mockturtle @ 2011-02-28 17:00 UTC (permalink / raw)


Dear.all,
remembering my initial difficulties with streams (I self-taught Ada, using few tutorials and lots of experiments before landing to the RM), I decided to write a page (my first one, so be patient :-) of the Wikibook with a little stream tutorial

http://en.wikibooks.org/w/index.php?title=Ada_Programming/Input_Output/Stream_Tutorial

As said in the page, the goal is to give to the reader an intuitive idea about how streams work so, in order to not hide the forest with too many leaves, some of the finest details have been omitted.  A subpage of the above page has a fairly complex example that is not complete yet, but I plan to complete it soon. 

The page is not linked yet with the book body.  I was thinking to add a link to it in the "Input Output" page as soon as the subpage with the example is in a good state.

Any feedback [especially positive one :-) :-) :-) :-)] is appreciated.



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Ann: Little tutorial about streams
  2011-02-28 17:00 Ann: Little tutorial about streams mockturtle
@ 2011-02-28 20:32 ` Ludovic Brenta
  2011-03-01  3:48 ` Randy Brukardt
  1 sibling, 0 replies; 10+ messages in thread
From: Ludovic Brenta @ 2011-02-28 20:32 UTC (permalink / raw)


mockturtle writes:
> Dear.all,

> remembering my initial difficulties with streams (I self-taught Ada,
> using few tutorials and lots of experiments before landing to the RM),
> I decided to write a page (my first one, so be patient :-) of the
> Wikibook with a little stream tutorial
>
> http://en.wikibooks.org/w/index.php?title=Ada_Programming/Input_Output/Stream_Tutorial
>
> As said in the page, the goal is to give to the reader an intuitive
> idea about how streams work so, in order to not hide the forest with
> too many leaves, some of the finest details have been omitted.  A
> subpage of the above page has a fairly complex example that is not
> complete yet, but I plan to complete it soon.
>
> The page is not linked yet with the book body.  I was thinking to add
> a link to it in the "Input Output" page as soon as the subpage with
> the example is in a good state.
>
> Any feedback [especially positive one :-) :-) :-) :-)] is appreciated.

Your page is great.  How's that for positive criticism :)

I've made a couple edits which you are, of course, free to revert.  I
(think I) have generally improved the style of the prose but not changed
the basic structure of the tutorial.

Now I have specific suggestions for further improvement:

* Between the sections "Abstract streams" and "Serialization functions",
  it would be nice to have a section on "Predefined concrete streams"
  discussing, in particular Ada.Text_IO.Text_Stream, so that beginners
  can start writing to the console using streams.

* In the section about Ada.Text_IO.Text_Streams, explain that this is
  much faster than Ada.Text_IO and why (hint: ARM A.10.4, A.12.2(7))

* Your first example of a serialization function, procedure
  Example.Print, seems too complicated.  But that may be on purpose, so
  I have not changed it.  Here is a simpler implementation:

  package body Example is
     procedure Print (Stream : not null access Ada.Streams.Root_Stream_Type'Class;
                      Item   : in  Int) 
     is
        -- Convert Item to String (with no trailing space)
        Value  : String := Trim(Int'Image(Item), Left);
        
        -- Convert Value'Length to String (with no trailing space)
        Len    : String := Trim(Integer'Image(Value'Length), Left);
     begin 
        String'Write (Stream, Len & 'i' & Value);
     end Print;
  end Example;

Thank you for taking the initiative writing this nice tutorial.  I think
it really helps lower the bar for novices.

-- 
Ludovic Brenta.



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Little tutorial about streams
  2011-02-28 17:00 Ann: Little tutorial about streams mockturtle
  2011-02-28 20:32 ` Ludovic Brenta
@ 2011-03-01  3:48 ` Randy Brukardt
  2011-03-01  9:54   ` AdaMagica
  2011-03-01 10:16   ` Dmitry A. Kazakov
  1 sibling, 2 replies; 10+ messages in thread
From: Randy Brukardt @ 2011-03-01  3:48 UTC (permalink / raw)


"mockturtle" <framefritti@gmail.com> wrote in message 
news:f8e7ccbf-a966-4568-9f0d-8e9e38f37dc6@glegroupsg2000goo.googlegroups.com...
>Dear.all,
>remembering my initial difficulties with streams (I self-taught Ada, using 
>few tutorials and lots of experiments before >landing to the RM), I decided 
>to write a page (my first one, so be patient :-) of the Wikibook with a 
>little stream >tutorial
>
>http://en.wikibooks.org/w/index.php?title=Ada_Programming/Input_Output/Stream_Tutorial

Looks generally good.

The little table under "Serialization functions" seems confusing, since it 
uses "composite" for Input and Output. But of course you can use Read and 
Write for "composite" types. It seems the intent is to be more informal 
(since "simple" is used rather than "elementary", which is good as there are 
no elementary class-wide types); may I suggest that the other entries use 
"complex" rather than "composite"? (Or some word meaning the same, if the 
confusion with "complex" numbers is a concern.)

In the text under "Write attribute", we have:

Clearly, the default implementation, being dependent on the machine and 
compiler, can be useful only if the data is written and read by programs 
compiled with the same compiler. If the data, for example, is to be sent 
across the network and read by a program written in another language, 
running on an unknown architecture, it is important for the programmer to 
control the format of the data sent over the wire. Because of this exigence, 
Ada allows the programmer to override S'Write (and the other stream-related 
functions described in the following), using an attribute definition clause 
(RM 13.3):

I had to get a dictionary to figure out what the word "exigence" means. 
Probably best to use a simpler word here; no need to make a tutorial harder 
to read than needed. I'd probably use "requirement" or "need" instead. (I 
didn't edit this as I think it is important for the author to consider their 
intention; I may have missed it altogether.)

It might make sense to mention that you can also specify these subprograms 
with an aspect clause in Ada 2012 (and indeed this will be preferred for 
most uses to the older attribute definition clause). But perhaps that's out 
of bounds here.

Finally, there might be some value to mentioning the use of 
Generic_Dispatching_Constructor to build user-defined class-wide Input 
routines. But maybe that is too advanced of a topic??

                             Randy.






^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Little tutorial about streams
  2011-03-01  3:48 ` Randy Brukardt
@ 2011-03-01  9:54   ` AdaMagica
  2011-03-01 10:16   ` Dmitry A. Kazakov
  1 sibling, 0 replies; 10+ messages in thread
From: AdaMagica @ 2011-03-01  9:54 UTC (permalink / raw)


On 1 Mrz., 04:48, "Randy Brukardt" <ra...@rrsoftware.com> wrote:
> The little table under "Serialization functions" seems confusing, since it
> uses "composite" for Input and Output. But of course you can use Read and
> Write for "composite" types. It seems the intent is to be more informal
> (since "simple" is used rather than "elementary", which is good as there are
> no elementary class-wide types); may I suggest that the other entries use
> "complex" rather than "composite"? (Or some word meaning the same, if the
> confusion with "complex" numbers is a concern.)

I would propose "definite" for "simple" and "indefinite" for
"composed".

For definite types, the bounds and discriminants are known, so need
not be put on the stream (Read/Write).

For indefinite types, the bounds and discriminants are needed to
construct the object, so they have to be put into the stream (Input/
Output).



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Little tutorial about streams
  2011-03-01  3:48 ` Randy Brukardt
  2011-03-01  9:54   ` AdaMagica
@ 2011-03-01 10:16   ` Dmitry A. Kazakov
  2011-03-01 13:56     ` Simon Wright
  1 sibling, 1 reply; 10+ messages in thread
From: Dmitry A. Kazakov @ 2011-03-01 10:16 UTC (permalink / raw)


On Mon, 28 Feb 2011 21:48:19 -0600, Randy Brukardt wrote:

> Clearly, the default implementation, being dependent on the machine and 
> compiler, can be useful only if the data is written and read by programs 
> compiled with the same compiler. If the data, for example, is to be sent 
> across the network and read by a program written in another language, 
> running on an unknown architecture, it is important for the programmer to 
> control the format of the data sent over the wire. Because of this exigence, 
> Ada allows the programmer to override S'Write (and the other stream-related 
> functions described in the following), using an attribute definition clause 
> (RM 13.3):

You can also mention chain code as a technique to implement S'Read/Write in
a platform independent way.

Of course one problem remains: the type of the stream I/O unit. A good
candidate might be Character'Read/Write. That should work in most cases.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Little tutorial about streams
  2011-03-01 10:16   ` Dmitry A. Kazakov
@ 2011-03-01 13:56     ` Simon Wright
  2011-03-01 14:38       ` Dmitry A. Kazakov
  0 siblings, 1 reply; 10+ messages in thread
From: Simon Wright @ 2011-03-01 13:56 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:

> You can also mention chain code as a technique to implement
> S'Read/Write in a platform independent way.

?

Wikipedia says "A chain code is a lossless compression algorithm for
monochrome images."



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Little tutorial about streams
  2011-03-01 13:56     ` Simon Wright
@ 2011-03-01 14:38       ` Dmitry A. Kazakov
  2011-03-04 20:58         ` mockturtle
  0 siblings, 1 reply; 10+ messages in thread
From: Dmitry A. Kazakov @ 2011-03-01 14:38 UTC (permalink / raw)


On Tue, 01 Mar 2011 13:56:40 +0000, Simon Wright wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> 
>> You can also mention chain code as a technique to implement
>> S'Read/Write in a platform independent way.
>
> ?
> 
> Wikipedia says "A chain code is a lossless compression algorithm for
> monochrome images."

I guess this is because chain codes were initially deployed for encoding
pixels and directions (left, top-left etc) in image processing. But chain
code is useful for any encoding of variable-length data without an explicit
length count. E.g. UTF-8 is a chain code. 

Naturals of any length can be portably encoded using chain code like this:

0 = 16#00#
1 = 16#01#
127= 16#7F#
128= 16#80# 16#01# 
129= 16#81# 16#01#
... 

(assuming that octets are atomic). The high order bit when 0 indicates end
of the chain. The lower order bits encode the value.

Signed integer is encoded as above multiplied by 2 using the lowest bit for
the sign.

Floating point numbers are encoded as integer fraction (normalized,
multiplied by 2**p) followed by the integer normalized exponent - p. p is
the required precision.

Enumerations are encoded as E'Pos.

Strings are as the length and the body. (Nobody uses wide-strings of course
(:-)).

That basically is.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Little tutorial about streams
  2011-03-01 14:38       ` Dmitry A. Kazakov
@ 2011-03-04 20:58         ` mockturtle
  2011-03-05  1:08           ` Shark8
  2011-03-05  1:35           ` Randy Brukardt
  0 siblings, 2 replies; 10+ messages in thread
From: mockturtle @ 2011-03-04 20:58 UTC (permalink / raw)


Dear all,
I'm back.  First of all, thank you to everyone for your comments.  Let me do a cumulative answer. I am afraid that this will make this post a bit long.

----

> ---- on Feb 28 2011 Ludovic Brenta wrote
>
>  Your page is great.  How's that for positive criticism :)

It is great. :-)

> ---- on Feb 28 2011 Ludovic Brenta wrote
>
> I've made a couple edits which you are, of course, free to revert.  I
> (think I) have generally improved the style of the prose but not changed
> the basic structure of the tutorial.

Thank you, I'll check, but I am sure that they are OK.  English is not my native language and, although I feel quite confident with it, style improvements are welcome.

> ---- on Feb 28 2011 Ludovic Brenta wrote
>
> Between the sections "Abstract streams" and "Serialization functions",
> it would be nice to have a section on "Predefined concrete streams"
> discussing, in particular Ada.Text_IO.Text_Stream, so that beginners
> can start writing to the console using streams.

Thank you for the suggestion.  I will add the new section as soon as I can.

> ---- on Feb 28 2011 Ludovic Brenta wrote
>
> Your first example of a serialization function, procedure
> Example.Print, seems too complicated.  But that may be on purpose,
> ...

No, it was not on purpose.  I reused an old code and I did not notice that I could simplify it.


> ---- on Mar 1 2011 Randy Brukardt wrote
>
> The little table under "Serialization functions" seems confusing, since it 
> uses "composite" for Input and Output. But of course you can use Read and 
> Write for "composite" types.
> ...

> ---- on Mar 1 2011 AdaMagica wrote
>
> I would propose "definite" for "simple" and "indefinite" for
> "composed".

To be honest, I do not like that choice of names too.  I could not think anything better when I was writing it, so I went for the "least bad" choice, making a mental note to think something better.  I'll take  your suggestions into account.

> ---- on Mar 1 2011 Randy Brukardt wrote
>
> I had to get a dictionary to figure out what the 
> word "exigence" means. Probably best to use a simpler 
> word here; no need to make a tutorial harder to read 
> than needed. 
> ...

Juk! I could call this a "false false friend"... In Italian "esigenza" is a very common word and this made me to slip to "exigence"...  I'll change it.

> ---- on Mar 1 2011 Randy Brukardt wrote
>
> It might make sense to mention that you can also specify these subprograms 
> with an aspect clause in Ada 2012 

I did not know about this.  Do you have a reference?




> ---- on Mar 1 2011 Dmitry A. Kazakov wrote
>
> You can also mention chain code as a technique to 
> implement S'Read/Write in a platform independent way.

Thank you for your suggestion.  One motivation for chosing the format used in the example was that I wanted to have something that could be printed on screen (also to debug the code before publishing it).

----

Here, I hope I did not forget anyone.  Thank you again for your feedback.

Riccardo



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Little tutorial about streams
  2011-03-04 20:58         ` mockturtle
@ 2011-03-05  1:08           ` Shark8
  2011-03-05  1:35           ` Randy Brukardt
  1 sibling, 0 replies; 10+ messages in thread
From: Shark8 @ 2011-03-05  1:08 UTC (permalink / raw)


I was debating on whether or not to submit to you a little 'toy' LISP
interpreter I've started. I've only got the reading and writing here,
no eval or special-forms like 'if', but since they're Stream-based it
might be appropriate.


---------------------------------
-- Lisp Interpreter in Ada.
-- By Joey Fish

---------------
-- LISP.ADS  --
---------------
With
Ada.Containers.Indefinite_Vectors,
Ada.Streams;

Package LISP is

 
-----------------------------------------------------------------------
   --	In LISP a List is defined as either a single element or an	--
   --	element followed by a lisr; as a consequence of this
definition	--
   --	there is no such thing as an "Empty List."			--
 
-----------------------------------------------------------------------


   Type List is Private;
   -- ToDo: Add primitive functions for list construction/
manipulation.
   -- ToDo: Add primitive functions for determining if it is an
executable list.

Private
   -- Alias Ads.Streams.Root_Stream_Type for ease of use.
   SubType Stream_Root is Ada.Streams.Root_Stream_Type;

   -- Element_Type describes the possible types of an Atom
   --	Note: Empty_Type is the NULL-element.
   Type Element_Type is
     ( Empty_Type, Boolean_Type, Integer_Type, Real_Type,
String_Type );

   -- Type Atom is a record containing the type and value of an
element.
   Type Atom( Element : Element_Type:= Empty_Type ) is record
      Case Element is
         When Empty_Type	=> Null;
         When Boolean_Type	=> Boolean_Value : Boolean:= False;
         When Integer_Type	=> Integer_Value : Integer:= 0;
         When Real_Type		=> Real_Value	 : Float  := 0.0;
         When String_Type	=> Is_Name	 : Boolean:= False;
				   String_Value	 : Not Null Access String;
      End Case;
   end record;

   Procedure Write_Atom( Stream	: Not Null Access Stream_Root'Class;
			 Item	: In Atom
                       );

   For Atom'Write Use Write_Atom;

   Type Atom_Array is Array (Positive Range <>) of Atom;
   Type Elementry_List( Terminal : Boolean:= True ) is record
      Head : Atom:=		( Element => Empty_Type );
      Case Terminal is
	When False => Tail : Not Null Access Elementry_List;
	When True  => Null;
      End Case;
   end record;

   Procedure Append( Head : In Out Elementry_List; Tail : In
Elementry_List );
   Function  Convert( List : Elementry_List ) Return Atom_Array;
   Function  Convert( List : Atom_Array ) Return Elementry_List;

   Procedure Write_EList( Stream	: Not Null Access Stream_Root'Class;
			  Item		: In Elementry_List
                       );
   Procedure Read_EList( Stream	: Not Null Access Stream_Root'Class;
			 Item	: Out Elementry_List
                       );


   For Elementry_List'Read  Use Read_EList;
   For Elementry_List'Write Use Write_EList;

   Type List_Element_Type is ( Atom_Element, EList_Type,
Recursive_List );
   Type List_Element( Element : List_Element_Type:= Atom_Element ) is
record
      Case Element is
	When Atom_Element	=> Atom_Data	: Atom;
	When EList_Type		=> EList_Data	: Elementry_List;
	When Recursive_List	=> RList_Data	: Not Null Access List;
      end case;
   end record;
   Function As_List( Input : in List_Element ) Return List;

   Package Elements is New Ada.Containers.Indefinite_Vectors
	( Index_Type => Positive, Element_Type => List_Element );

   Type List is Tagged record
      Data : Elements.Vector:= Elements.Empty_Vector;
   end record;

   Procedure Write_List( Stream	: Not Null Access Stream_Root'Class;
			  Item	: In List
                       );
   Procedure Read_List( Stream	: Not Null Access Stream_Root'Class;
			 Item	: Out List
                       );

   For List'Read  Use Read_List;
   For List'Write Use Write_List;


End LISP;

---------------
-- LISP.ADB  --
---------------

With
Ada.Strings.Fixed;

Package Body LISP is

   FALSE_Text	: Constant String:= Boolean'Image( False );
   TRUE_Text	: Constant String:= Boolean'Image( True  );
   NULL_Text	: Constant String:= "NULL";

   Function Trim_Image( Input : In Float ) Return String is
      Use Ada.Strings, Ada.Strings.Fixed;
   Begin
      Return Result: String:=
        Trim( Side => Left, Source => Float'Image( Input ) );
   End Trim_Image;


   ------------------
   --  WRITE_ATOM  --
   ------------------
   Procedure Write_Atom(	Stream	: Not Null Access Stream_Root'Class;
				Item	: In Atom ) is
      Text : Access String;
   begin
      Case Item.Element is
	 When Empty_Type	=>
		Text:= New String'( NULL_Text );
         When Boolean_Type	=>
		Text:= New String'( Boolean'Image(Item.Boolean_Value) );
         When Integer_Type	=>
		Text:= New String'( Integer'Image(Item.Integer_Value) );
         When Real_Type		=>
		Text:= New String'( Float'Image( Item.Real_Value ) );
         When String_Type	=>
            If Not Item.Is_Name then
		Text:= New String'( '"' & Item.String_Value.All & '"' );
            else
		Text:= New String'( Item.String_Value.All );
            end if;
      End Case;
      String'Write(	Stream, Text.All	);
   end Write_Atom;


   --------------
   --  Append  --
   --------------
   Procedure Append( Head : In Out Elementry_List; Tail : In
Elementry_List ) is
   begin
      If Head.Terminal then
         Declare
            Result : Elementry_List:= Elementry_List'( Terminal =>
False,
		Head => Head.Head, Tail => New Elementry_List'(Tail) );
            For Result'Address Use Head'Address;
         Begin		-- Here the initialization of Result changes the value
            Null;	-- of Head because they are overlaid; further, we
are
         End;		-- guarenteed that the sizes are both the same because
      else		-- Elementry_List is a simple varient record and cannot
         Declare	-- be extended because it is not a tagged-type.
            This : Access Elementry_List:= Head.Tail;
         Begin
            While Not This.Terminal loop	-- If Head is not terminal
then
               This:= This.Tail;		-- we must traverse the list
            end loop;				-- until the end to append Tail.
            Append( This.All, Tail );
         End;
      end if;
   end Append;

   Function  Convert( List : Elementry_List ) Return Atom_Array is

      Function Get_Element( Item : Elementry_List ) Return Atom_Array
is
      begin
         if Item.Terminal then
            Return Result : Atom_Array:= ( 1 => Item.Head );
         else
            Return Result : Atom_Array:= Atom_Array'( 1 => Item.Head )
		& Get_Element( Item.Tail.All );
         end if;
      end Get_Element;

   begin
      Return Get_Element( List );
   end Convert;

   Function Create( Input : Atom ) Return Elementry_List is
   begin
      Return Result: Elementry_List:= ( Terminal => True, Head =>
Input );
   end;


   Function  Convert( List : Atom_Array ) Return Elementry_List is
   begin
      if List'Length = 0 then
         Raise Program_Error;
      end if;

      Declare
	Working : Elementry_List:= Create( Input => List(List'First) );
      Begin
	For Index in Positive'Succ(List'First)..List'Last loop
            Append( Head => Working, Tail => Create( List(Index) ) );
	end loop;
       Return Working;
      End;
   end Convert;


   ---------------------------------------------------
   --  Elementry_List's  'Read & 'Write Attributes  --
   ---------------------------------------------------

   Procedure Write_EList( Stream	: Not Null Access Stream_Root'Class;
			  Item		: In Elementry_List
                       ) is

   begin
      Character'Write( Stream, '(' );		-- When saving to a Stream
every
      Declare					-- elementry-list begins with an
         This : Elementry_List:= Item;		-- opening parenthisis,
followed
      Begin					-- by list of Atoms (whitespace
         List:					-- separated), terminated by a
         loop					-- closing parenthisis.
            Atom'Write( Stream, This.Head );
            Exit List When This.Terminal;
            This:= This.Tail.All;
            Character'Write( Stream, ',' );
         end loop List;
         Character'Write( Stream, ')' );
      End;
   end Write_EList;

   Procedure Read_EList( Stream	: Not Null Access Stream_Root'Class;
			 Item	: Out Elementry_List
                        ) is
      Function Parse_Atom( S : String ) Return Atom is
         Function Get_Type_Indicator(Input : String) Return
Element_Type is
            SubType Digit is Character Range '0'..'9';
         begin
            Case Input(Input'First) is		-- A floating-point numeric is
               When Digit =>			-- distinguished from an integer
                  For Index in Input'Range loop	-- by the decimal
point or the
                     Case Input(Index) is	-- exponent notation.
                        When 'e' | 'E' | '.' => Return Real_Type;
                        When Others => null;
                     End case;
                  end loop;
                  Return Integer_Type;
               When Others =>
                  if Input = NULL_Text then	-- NULL, TRUE, & FALSE are
texts
                     Return Empty_Type;		-- which are not String_Type.
                  elsif Input = TRUE_Text or Input = FALSE_Text then
                     Return Boolean_Type;
                  else				-- Everything else, however, is
                     Return String_Type;	-- either a String_Type or a
                  end if;			-- name. Strings start w/ '"'.
            end case;
         end Get_Type_Indicator;

       Use Ada.Strings, Ada.Strings.Fixed;			-- Parse_Atom
         Input : String:= Ada.Strings.Fixed.Trim( S, Both );	-- starts
here.
      begin
         Return Result : Atom(Get_Type_Indicator(Input)) do
            Case Result.Element is
            When Empty_Type	=> Null;
            When String_Type	=>
               Result.Is_Name:= Input(Input'First) = '"';
               if Not Result.Is_Name then
               Result.String_Value:= New String'(
		  Input(Positive'Succ(Input'First)..Positive'Pred(Input'Last))
						);
               else
                  Result.String_Value:= New String'(Input);
               end if;
            When Integer_Type	=> Result.Integer_Value:=
Integer'Value(Input);
            When Real_Type	=> Result.Real_Value:= Float'Value(Input);
            When Boolean_Type	=> Result.Boolean_Value:= Input =
TRUE_Text;
            End case;
         End Return;
      end Parse_Atom;

         WhiteSpace : Constant Array(Character) Of Boolean:=
           ( ASCII.VT | ASCII.HT | ASCII.LF | ASCII.CR | ' ' => True,
             Others => False );

	Type Index_Vector is Array (Positive Range <>) of Positive;
	Seperators	: Not Null Access Index_Vector:=
					New Index_Vector'( 2..1 => 1 );
	Working		: Not Null Access String:= New String'( "" );
	C		: Character;
	Result		: Elementry_List;
	In_String	: Boolean:= False;
	Is_Terminated	: Boolean:= False;

   begin
      Loop
	Character'Read( Stream, C );
	Case C is
	 When '"'	=>	In_String:= Not In_String;
				Is_Terminated:= False;
         When ')'	=>	Exit When Not In_String;
         When Others	=>
	    If WhiteSpace(C) then
		if Is_Terminated then
			GoTo Bypass;
		else
			Is_Terminated:= True;
		end if;
	    else
		Is_Terminated:= False;
	    end if;
	End Case;
	Working:= New String'( Working.All & C );	-- We update "working."
	if WhiteSpace(C) then			-- and delimit with whitespace.
	   Seperators:= New Index_Vector'( Seperators.All & Working'Last );
	end if;
	<<Bypass>>
	Null;
      End Loop;

	-- We simulate a terminating space by appending one more
	-- than the last index to Seperators.
	Seperators:= New Index_Vector'(Seperators.All & (Working'Last+1));

      Declare
	-- We use one more than Working'First to ignore the '(' that starts
	-- this list, just like we terminated the string just before
	-- copying the trailing ')' into Working.
	Start : Positive:= Working'First+1;
	Stop  : Positive;
      Begin
	for Index in Seperators'Range loop	-- Here is where we create an
	    Stop:= Seperators( Index )-1;	-- atom from every interval we
	    Append(Result,			-- recorded in "seperators".
		(Terminal => True, Head => Parse_Atom(Working(Start..Stop)))
		  );
	    Start:= Seperators( Index )+1;
	end loop;
      End;
					-- And we return everything we
      Item:= Result.Tail.All;		-- previously appended to result.
   end Read_EList;

   ---------------
   --  As_List  --
   ---------------
   Function As_List( Input : in List_Element ) Return List is
   Begin
      Return Result : List do
         Case Input.Element is
            When Atom_Element	=> Result.Data.Append( New_Item =>
Input );
            When Recursive_List	=> Result:= Input.RList_Data.All;
            When EList_Type	=>
               Declare
		Data : Elementry_List:= Input.EList_Data;
               Begin
		loop
		   Result.Data.Append( New_Item => (Atom_Element, Data.Head) );
		   Exit When Data.Terminal;
		   Data:= Data.Tail.All;
		end loop;
               End;
         End Case;
      End Return;
   End As_List;



   Procedure Write_List( Stream	: Not Null Access Stream_Root'Class;
			  Item	: In List
                       ) is
      SubType ELIST is Elementry_List;
   begin
      Character'Write( Stream, '(' );
      Declare
         Procedure Process_Data( Position : Elements.Cursor ) is
            Item : List_Element Renames Elements.Element( Position );
         begin
            Case Item.Element is
            When Atom_Element	=> Atom'Write( Stream, Item.Atom_Data );
            When EList_Type	=> ELIST'Write(Stream, Item.EList_Data);
            When Recursive_List	=> List'Write( Stream,
Item.RList_Data.All );
            end case;
         end Process_Data;
      Begin
         Item.Data.Iterate( Process_Data'Access );
      End;
      Character'Write( Stream, ')' );
   end Write_List;

   Procedure Read_List( Stream	: Not Null Access Stream_Root'Class;
			 Item	: Out List
                      ) is
   begin
      null;
   end Read_List;


End LISP;



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Little tutorial about streams
  2011-03-04 20:58         ` mockturtle
  2011-03-05  1:08           ` Shark8
@ 2011-03-05  1:35           ` Randy Brukardt
  1 sibling, 0 replies; 10+ messages in thread
From: Randy Brukardt @ 2011-03-05  1:35 UTC (permalink / raw)


"mockturtle" <framefritti@gmail.com> wrote in message 
news:fba7e41d-288d-419a-ae55-86c2fd954903@glegroupsg2000goo.googlegroups.com...
> Dear all,
> I'm back.  First of all, thank you to everyone for your comments.  Let me 
> do a cumulative answer. I am afraid that this will make this post a bit 
> long.
...
>> ---- on Mar 1 2011 Randy Brukardt wrote
>>
>> It might make sense to mention that you can also specify these 
>> subprograms
>> with an aspect clause in Ada 2012
>
> I did not know about this.  Do you have a reference?

The draft standard and Rationale are the best references. But the rationale 
isn't close to done at this point (I've only seen a draft of Chapter 1 to 
date) and isn't public anyway. The current draft of the standard gives the 
syntax (see http://www.ada-auth.org/standards/ada12.html for the whole 
draft; specifically see 
http://www.ada-auth.org/standards/12rm/html/RM-13-3-1.html for the aspect 
syntax). The next draft will have essentially all of the details (probably 
available in April).

Anyway, the basic idea is that aspect clauses can be given as part of 
declarations. The "definition" is not resolved or evaluated until the entity 
declared by the declaration is frozen (formally until the end of the 
enclosing declaration list), so these are automatically "forward" 
references. For instance, you could have:

    type A_Type is ....
        with Read => My_Read,
               Write => My_Write;

   procedure My_Read (Stream : not null access 
Ada.Streams.Root_Stream_Type'Class;
                                     Item : out A_Type);

   procedure My_Write (Stream : not null access 
Ada.Streams.Root_Stream_Type'Class;
                                     Item : in A_Type);

This notation is most valuable for subprograms (since it sidesteps the 
problems of overloading that cause problems for pragmas and attribute 
definition clauses), but it is general and works on almost any declaration. 
(There are a few obscure things that are technically declarations -- like 
goto labels -- that don't allow aspect clauses.)

Just one of the good things coming in Ada 2012.

                                  Randy.





^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2011-03-05  1:35 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-02-28 17:00 Ann: Little tutorial about streams mockturtle
2011-02-28 20:32 ` Ludovic Brenta
2011-03-01  3:48 ` Randy Brukardt
2011-03-01  9:54   ` AdaMagica
2011-03-01 10:16   ` Dmitry A. Kazakov
2011-03-01 13:56     ` Simon Wright
2011-03-01 14:38       ` Dmitry A. Kazakov
2011-03-04 20:58         ` mockturtle
2011-03-05  1:08           ` Shark8
2011-03-05  1:35           ` Randy Brukardt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox