From: Ludovic Brenta on
Natacha Kerensikova writes on comp.lang.ada:
> On Aug 12, 9:59 pm, Ludovic Brenta <ludo...(a)ludovic-brenta.org> wrote:
>> In reality, an S-Expression (a "cons pair" in Lisp parlance) can indeed
>> not have three elements; the notation (a b c) is, really, shorthand for
>> (a (b c)); I was keen to implement that in my parser.  See
>>
>> http://en.wikipedia.org/wiki/S-expression#Definition
>
> According to that page, cons pairs are noted with an extra dot, like
> (x . y), right? So (a b c) would be (a . (b . (c . nil))), right?
> Then my example would be:
> (tcp-connect . ((host . (foo.example . nil)) . ((port . (80 . nil)) .
> nil)))

Correct. The dot notation is from Lisp; (x . y) really denotes a cons
pair while (x y) is shorthand for (x . (y . nil)).

However, (y . nil) doesn't really make any sense; since y is an atom,
you don't need to wrap it in a cons pair, so just y is sufficient (you
only need a way to distinguish cons pairs from atoms and say that atoms
don't have a car and cdr but only a value; that's what the Atom
discriminant is for in my implementation). Replacing (y . nil) with
just y, your example then becomes:

(tcp-connect . ((host . foo.example) . (port . 80)))

which is exactly what my parser builds in memory: 4 cons pairs, 5 atoms.
The other notations:

(tcp-connect ((host foo.example) (port 80)))

and

(tcp-connect (host foo.example) (port 80))

are shorthand for that.

--
Ludovic Brenta.
From: Randy Brukardt on
"Dmitry A. Kazakov" <mailbox(a)dmitry-kazakov.de> wrote in message
news:1spow9sibnv6l.ci558lff75c8$.dlg(a)40tude.net...
> On Wed, 11 Aug 2010 18:18:48 -0500, Randy Brukardt wrote:
>
>> "Dmitry A. Kazakov" <mailbox(a)dmitry-kazakov.de> wrote in message
>> news:iv3qwjogornz$.1s8kq0yfl2wxl.dlg(a)40tude.net...
>> ...
>>> Conversion mess is what we already have right now. The point is that "+"
>>> is
>>> well-defined and meaningful for octets, but it is not closed in there.
>>> Why
>>>
>>> function "**" (Left : T; Right : Natural) return T;
>>> function S'Pos(Arg : S'Base) return universal_integer;
>>> ...
>>>
>>> are OK and "+" is not?
>>
>> The first has the same operand and result type (the power operand is
>> something else and not really part of the operator IMHO).
>
> What is the difference between "**" and "+"? It must be a language one,
> because semantically sum of octets is not an octet.

Octets don't have a sum, "sum of octets" is meaningless. It's like talking
about the "sum of sand". They're just buckets. (By "octet" here I mean the
same concept that Ada calls Stream_Elements, other than with a fixed size.)

>> The second is the
>> long winded name for a conversion operator - it implies no semantic
>> change.
>> I'm arguing that operations like S'Pos would be better having a common
>> name
>> like "#" rather than a host of specialized names.
>
> Huh, and these must be a type conversions too:
>
> function S'Exponent (X : T) return universal_integer;
> S'Length
> A'Length (N)
> ...

Nope, these have semantics. Of course, the boundary is a gray area.

....
>>> 1. What is this else?
>>
>> Huh? This doesn't parse.
>
> The above looks like math to me. You take octet arguments and compute some
> results using arithmetic operations.

The octets are converted to some other type that has math. There is no
built-in relationship between the octet and the type with the math; it has
to be explicitly defined.

....
> I see. No, that is a wrong way IMO. The right one is interfaces. If you
> want S be like T, derive S from T. If you don't like the implementation of
> T, inherit only the interface of. You should never have a need in explicit
> type conversions in a properly designed program.

That way lies madness. You would have to give types properties that they
have no reason to have (like "sum of octets"). And if you do that, you now
have a lot more chances for error (such as adding octets that are used to
hold character values and not integers). Octets are by their nature an
untyped bucket with no semantics; there has to be a conversion operation
(like "#" above or S'Read in Ada) to some type with semantics for it to be
meaningful.

>> That's the point: in Ada, type conversions are *not* functions, they're a
>> built-in gizmo [including some attributed]; by naming them "#" we would
>> allow unifying them with functions.
>
> I would prefer to eliminate them altogether. Conversions are always bad.

I strongly disagree. Some things are best modeled with little or no explicit
semantics (such as a raw stream), and you must have conversions to get to
real semantics. Indeed, *not* having using conversions in that case is
misleading; you're applying improper semantics to the operation.

Randy.


From: Jeffrey R. Carter on
On 08/12/2010 12:59 PM, Ludovic Brenta wrote:
>
> If I understand your quasi-BNF correctly, an S-Expression in your
> grammar can have only one or two, but not three elements. This
> contradicts the "(TCP-something (host abc) (port 42) )" example, which
> has three elements.

No, {} means zero or more, so an S-expression can have one or more elements.

Kerensikova (or is it Port�?) provided a more detailed grammar (using the
trailing '*' from regexps rather than {}) with some additional options.

> http://en.wikipedia.org/wiki/S-expression#Definition

But maybe we're both wrong.

--
Jeff Carter
"What I wouldn't give for a large sock with horse manure in it."
Annie Hall
42
From: Shark8 on
Natacha,

I took a bit of a stab at writing an SExpression handler, note that
it's not a parser [text-file -> SExpression] but rather what (I think)
you were terming in-memory. It has stream-support so you can directly
save/load an SExpression's structure & contents and it should be easy
to make it "parenthesis preservative" in the parser if you so desire.

I [semi-]plan on making a child-package for the parser "package
SExpression.Text" or somesuch for storing/loading the SExpressions
from text [that is, parsing them].

---------------------------------------------
-- SExpression.ads
---------------------------------------------

With
Ada.Streams,
Ada.Streams.Stream_IO;


Package SExpression is

Type Byte is mod 2**8;
For Byte'Size use 8;

Type Binary_Data_Type is Array( Positive Range <> ) Of Byte;
Pragma Pack(Binary_Data_Type);

Type Node_Data_Type is ( Binary_Data, String_Data, Number_Data );
Type Node_Type( Data_Type : Node_Data_Type ) is private;
Procedure Create( Node: out Node_Type; Data: in
String );
Procedure Create( Node: out Node_Type; Data: in
Binary_Data_Type );
Procedure Create( Node: out Node_Type; Data: in
Long_Integer );

Type List_Type;
Type SExpression_Type(List_Size : Natural) is private;
Function Is_List ( SExp : in SExpression_Type) Return Boolean;
Function Create ( Node : Node_Type ) Return SExpression_Type;
Procedure Append ( SExp : in out SExpression_Type; Node :
Node_Type );
Procedure Append ( Front: in out SExpression_Type;
Back : in SExpression_Type );
Procedure Prepend( SExp : in out SExpression_Type; Node :
Node_Type );
Procedure Prepend( Front: in SExpression_Type;
Back : in out SExpression_Type );

Type List_Type is Array(Positive Range <>) of
Not Null Access SExpression_Type;

Procedure Create( SExp : out SExpression_Type; List : in
List_Type );

Package Stream is
Use Ada.Streams;

Procedure Write_Bin ( Stream: Not Null Access
Root_Stream_Type'Class;
Item : in Binary_Data_Type );
Procedure Read_Bin ( Stream: Not Null Access
Root_Stream_Type'Class;
Item : out Binary_Data_Type );

Procedure Write_Node( Stream: Not Null Access
Root_Stream_Type'Class;
Item : in Node_Type );
Procedure Read_Node ( Stream: Not Null Access
Root_Stream_Type'Class;
Item : out Node_Type );

Procedure Write_Sexp( Stream: Not Null Access
Root_Stream_Type'Class;
Item : in SExpression_Type );
Procedure Read_SExp ( Stream: Not Null Access
Root_Stream_Type'Class;
Item : out SExpression_Type );

Procedure Write_List( Stream: Not Null Access
Root_Stream_Type'Class;
Item : in List_Type );
Procedure Read_List ( Stream: Not Null Access
Root_Stream_Type'Class;
Item : out List_Type );

end Stream;


private


Type Node_Type( Data_Type : Node_Data_Type ) is Record
case Data_Type is
when Binary_Data => B : Access Binary_Data_Type;
when String_Data => S : Access String;
when Number_Data => N : Long_Integer;
end case;
end record;

For Node_Type'Write use Stream.Write_Node;
For Node_Type'Read use Stream.Read_Node;

Type SExpression_Type(List_Size : Natural) is Record
case List_Size is
when 0 => Data: Not Null Access Node_Type;
when others => List: List_Type(1..List_Size);
end case;
end record;

For SExpression_Type'Read use Stream.Read_SExp;
For SExpression_Type'Write use Stream.Write_SExp;

For List_Type'Read use Stream.Read_List;
For List_Type'Write use Stream.Write_List;

For Binary_Data_Type'Read use Stream.Read_Bin;
For Binary_Data_Type'Write use Stream.Write_Bin;
end SExpression;

---------------------------------------------
-- SExpression.adb
---------------------------------------------

Package body SExpression is

-- Internal Node-Creation Functions.
Function Make_Node( Data: String ) Return Node_Type is
begin
Return Result: Node_Type( Data_Type => String_Data ) do
Result.S:= New String'(Data);
end Return;
end Make_Node;

Function Make_Node( Data: Binary_Data_Type ) Return Node_Type is
begin
Return Result: Node_Type( Data_Type => Binary_Data ) do
Result.B:= New Binary_Data_Type'(Data);
end Return;
end Make_Node;

Function Make_Node( Data: Long_Integer ) Return Node_Type is
begin
Return Result: Node_Type( Data_Type => Number_Data ) do
Result.N:= Data;
end Return;
end Make_Node;


-- Public Node-Creation Procedures {wraps node-creation functions}
Procedure Create ( Node: out Node_Type; Data: in String ) is
begin
Node:= Make_Node(Data);
end Create;

Procedure Create ( Node: out Node_Type; Data: in Binary_Data_Type )
is
begin
Node:= Make_Node( Data );
end Create;

Procedure Create ( Node: out Node_Type; Data: in Long_Integer ) is
begin
Node:= Make_Node(Data);
end Create;

Pragma Inline( Create );

Function Is_List(SExp : in SExpression_Type) Return Boolean is
begin
Return SExp.List_Size > 0;
end Is_List;
Pragma Inline(Is_List);

Function Create( List : in List_Type ) Return SExpression_Type is
begin
Return Result: SExpression_Type( List_Size => List'Length ) do
Result.List:= List;
end return;
end Create;

Procedure Create( SExp : out SExpression_Type; List : in
List_Type ) is
begin
SExp:= Create( List );
end Create;

Function Create( Node : Node_Type ) Return SExpression_Type is
begin
Return Result : SExpression_Type( List_Size => 0 ) do
Result.Data:= New Node_Type'( Node );
end return;
end Create;

Procedure Append ( SExp : in out SExpression_Type; Node :
Node_Type ) is
begin
if Is_List(SExp) then
SExp:= Create( Sexp.List & New
SExpression_Type'(Create(Node)) );
else
SExp:= Create( New
SExpression_Type'(Create(SExp.Data.All))
& New SExpression_Type'(Create(Node))
);
end if;
end Append;

Procedure Prepend( SExp : in out SExpression_Type; Node :
Node_Type ) is
begin
if Is_List(SExp) then
SExp:= Create( New SExpression_Type'(Create(Node)) &
Sexp.List);
else
SExp:= Create( New SExpression_Type'(Create(Node))
& New SExpression_Type'(Create(SExp.Data.All))
);
end if;
end Prepend;

Procedure Append ( Front: in out SExpression_Type;
Back : in SExpression_Type ) is
begin
if Is_List(Back) then
Front:= Create( Front.List & Back.List);
else
Append( SExp => Front, Node => Back.Data.All );
end if;
end Append;

Procedure Prepend( Front: in SExpression_Type;
Back : in out SExpression_Type ) is
begin
if Is_List(Front) then
Back:= Create( Front.List & Back.List);
else
Prepend( SExp => Back, Node => Front.Data.All );
end if;
end Prepend;

package body Stream is
Procedure Write_Bin ( Stream: Not Null Access
Root_Stream_Type'Class;
Item : in Binary_Data_Type ) is
begin
Positive'Write( Stream, Item'Length );
For Index in Item'Range loop
Byte'Write( Stream, Item(Index) );
end loop;
end Write_Bin;

Procedure Read_Bin ( Stream: Not Null Access
Root_Stream_Type'Class;
Item : out Binary_Data_Type ) is

Function Get_Elements( Length: Positive ) Return
Binary_Data_Type is
begin
Return Result: Binary_Data_Type(1..Length) do
For Index in Result'Range loop
Byte'Read( Stream, Result(Index) );
end loop;
end Return;
end Get_Elements;

Length: Positive;
begin
Positive'Read( Stream, Length );
Item:= Get_Elements( Length );
end Read_Bin;


Procedure Write_Node( Stream: Not Null Access
Root_Stream_Type'Class;
Item : in Node_Type ) is
begin
Node_Data_Type'Write( Stream, Item.Data_Type );

Case Item.Data_Type is
When Binary_Data => Binary_Data_Type'Write( Stream,
Item.B.All );
When String_Data => String'Write( Stream, Item.S.All );
When Number_Data => Long_Integer'Write( Stream, Item.N );
end Case;
end Write_Node;

Procedure Read_Node ( Stream: Not Null Access
Root_Stream_Type'Class;
Item : out Node_Type ) is
Data_Type : Node_Data_Type;
begin
Node_Data_Type'Read( Stream, Data_Type );

Case Data_Type is
When Binary_Data =>
Item.B:= New Binary_Data_Type'( 1..0 => <> );
Declare
Binary_Temp : Access Binary_Data_Type:=
New Binary_Data_Type'( 1..0 => 16#FF# );
Begin
Binary_Data_Type'Read( Stream, Binary_Temp.All );
Item:= Make_Node( Data => Binary_Temp.All );
End;
When String_Data =>
declare
String_Temp : Access String:= New String'("");
begin
String'Read( Stream, String_Temp.All);
Item:= Make_Node( Data => String_Temp.All );
end;
When Number_Data =>
declare
Temp : Long_Integer;
begin
Long_Integer'Read( Stream, Temp );
Item:= Make_Node( Temp );
end;
end Case;
end Read_Node;




Procedure Write_SExp( Stream: Not Null Access
Root_Stream_Type'Class;
Item : in SExpression_Type ) is
begin
Natural'Write( Stream, Item.List_Size );
if Item.List_Size = 0 then
Node_Type'Write( Stream, Item.Data.All );
else
List_Type'Write( Stream, Item.List );
end if;
end Write_SExp;

Procedure Read_SExp ( Stream: Not Null Access
Root_Stream_Type'Class;
Item : out SExpression_Type ) is
List_Size : Natural;
begin
Natural'Read( Stream, List_Size );
if List_Size = 0 then
Declare
Temp : Access Node_Type:= New
Node_Type'( Make_Node(0) );
Begin
Node_Type'Read( Stream, Temp.All );
Item:= Create( Temp.All );
End;
else
Declare
Dummy: Aliased SExpression_Type:=
Create(Make_Node(0));
Temp : List_Type:= (1..List_Size =>
Dummy'Unchecked_Access );
Begin
List_Type'Read( Stream, Temp );
Item:= Create( Temp );
End;
end if;
end Read_SExp;


Procedure Write_List( Stream: Not Null Access
Root_Stream_Type'Class;
Item : in List_Type ) is
begin
Positive'Write(Stream, Item'Length);
For Index in Item'Range loop
SExpression_Type'Write( Stream, Item(Index).All );
end loop;
end Write_List;

Procedure Read_List ( Stream: Not Null Access
Root_Stream_Type'Class;
Item : out List_Type ) is

Function Get_Elements( Length: Positive ) Return List_Type is
Working : Access SExpression_Type;
begin
Working:= New SExpression_Type'( Create(Make_Node(0)) );
Return Result: List_Type(1..Length) do
For Index in Result'Range loop
SExpression_Type'Read( Stream, Working.All );
Result(Index):= New
SExpression_Type'( Working.All );
end loop;
end Return;
end Get_Elements;

Length : Positive;
begin
Positive'Read(Stream, Length);
Item:= Get_Elements( Length );
end Read_List;


end Stream;

end SExpression;
From: Shark8 on
Reading about the Cons-es I figure I should show how the constructs I
made can be made exactly equivalent to a series of Cons-pairs.
Unless I'm completely misunderstanding/misinterpreting the Lisp idea
of a list being an item or an item followed by a list.

Function Construct_Cons_Pair( Head, Tail : in Node_Type )
Return SExpression_Type is
begin
Return Result: SExpression_Type (List_Size => 2) do
Result.List(1):= New SExpression_Type'( Create(Head) );
Result.List(2):= New SExpression_Type'( Create(Tail) );
end return;
end Construct_Cons_Pair;

Function Construct_Cons_Pair( Head : in Node_Type;
Tail : in SExpression_Type)
Return SExpression_Type is
begin
Case Tail.List_Size is
When 0 => Return Construct_Cons_Pair( Head,
Tail.Data.All );
When 1 => Return Construct_Cons_Pair( Head,
Tail.List(1).All );
When Others =>
Return Result: SExpression_Type (List_Size => 2) do
Result.List(1):= New SExpression_Type'( Create(Head) );
Result.List(2):= New SExpression_Type'( Tail );
end return;
end case;
end Construct_Cons_Pair;


Function Is_Cons_Pair_Construct( S: in SExpression_Type ) Return
Boolean is
-- Perhaps this would be better named Is_Lisp_Construct....
begin
Return ((S.List_Size = 2) And Then
((Not Is_List(S.List(1).All)) And
Is_Cons_Pair_Construct( S.List(2).All )))
OR S.List_Size = 0;
end Is_Cons_Pair_Construct;

Maybe I should make a Construct_Cons_Pair( Head : in SExpression_Type;
Tail : in Node_Type) for orthogonality's sake... but that would go
against the Lisp-way.
First  |  Prev  |  Next  |  Last
Pages: 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
Prev: GPRbuild compatibility
Next: Irony?