Prev: GPRbuild compatibility
Next: Irony?
From: Ludovic Brenta on 12 Aug 2010 16:45 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 12 Aug 2010 16:56 "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 12 Aug 2010 18:25 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 12 Aug 2010 19:26 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 12 Aug 2010 22:31
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. |