From: Frank Goenninger DG1SBG
Subject: Translating parse result into instances
Date: 
Message-ID: <lzabs8g5ny.fsf@pcsde001.de.goenninger.net>
I have a - hm, what? - a "stream" of data as follows:

("model" (("id" "FRGO"))
 ("polygon" (("color" "+RED+") ("class" "GNC-QUAD"))
  ("points" (("n" "4"))
   ("point" NIL ("x" NIL "0") ("y" NIL "0") ("z" NIL "0"))
   ("point" NIL ("x" NIL "100") ("y" NIL "0") ("z" NIL "0"))
   ("point" NIL ("x" NIL "100") ("y" NIL "-100") ("z" NIL "0"))
   ("point" NIL ("x" NIL "0") ("y" NIL "-100") ("z" NIL "0"))))
 ("polygon" (("color" "+BLUE+") ("class" "GNC-QUAD"))
  ("points" (("n" "4"))
   ("point" NIL ("x" NIL "50") ("y" NIL "0") ("z" NIL "5"))
   ("point" NIL ("x" NIL "100") ("y" NIL "60") ("z" NIL "5"))
   ("point" NIL ("x" NIL "100") ("y" NIL "-60") ("z" NIL "50"))
   ("point" NIL ("x" NIL "50") ("y" NIL "-100") ("z" NIL "50"))))
 ("polygon" (("color" "+GREEN+") ("class" "GNC-QUAD"))
  ("points" (("n" "4"))
   ("point" NIL ("x" NIL "-50") ("y" NIL "10") ("z" NIL "30"))
   ("point" NIL ("x" NIL "150") ("y" NIL "60") ("z" NIL "5"))
   ("point" NIL ("x" NIL "150") ("y" NIL "-60") ("z" NIL "50"))
   ("point" NIL ("x" NIL "-50") ("y" NIL "-100") ("z" NIL "50")))))

I need to create a Model instance with ID slot being bound to
:frgo. Next I want to create Polygon instances ... You get the idea. 

New one for me, really. What if this goes to some few hundreds of
polygons... So I am looking not for complete code just for a few 
pointers/hints which route to go. Loop? Mapcar combined with a large 
cond or so?

Thx!! 

Cheers
  Frank

-- 

  Frank Goenninger

  frgo(at)mac(dot)com

  "Don't ask me! I haven't been reading comp.lang.lisp long enough to 
  really know ..."

From: Ari Johnson
Subject: Re: Translating parse result into instances
Date: 
Message-ID: <m2ps1439bu.fsf@nibbler.theari.com>
Frank Goenninger DG1SBG <·············@nomail.org> writes:

> I need to create a Model instance with ID slot being bound to
> :frgo. Next I want to create Polygon instances ... You get the idea. 

> New one for me, really. What if this goes to some few hundreds of
> polygons... So I am looking not for complete code just for a few 
> pointers/hints which route to go. Loop? Mapcar combined with a large 
> cond or so?

This is what my idea looks like.  You could replace some parts with
MAPCAR if you wanted to do so.  Note that this is clearly not
complete, but is a good start toward what you want to accomplish and
is extensible to handle other types of data if you want to do so.

I don't know why you ask what would happen if it went to several
hundred polygons.  It'll use more memory, proportionate to the number
of polygons, of course, but the code below is O(n) so you shouldn't
worry about things blowing up before you run out of memory.



(defclass model ()
  ((id :initarg id :accessor id)
   (elements :initarg elements :initform '() :accessor elements)))

(defclass polygon ()
  ((color :initarg color :accessor color)
   (class :initarg class :accessor class)
   (points :initarg points :initform '() :accessor points)))

(defclass point ()
  ((data :initarg data :accessor data)))

(defmacro string-case (key &body forms)
  `(cond ,@(mapcar (lambda (form)
                     (if (eq (car form) t)
                         `(t ,@(cdr form))
                         `((string= ,key ,(car form))
                           ,@(cdr form))))
                   forms)))

(defun parse-model (data)
  (string-case (car data)
    ("model" (%parse-model% data))
    (t (error "Unknown model type ~S" (car data)))))

(defun %parse-model% (data)
  (destructuring-bind (type attributes &rest elements)
      data
    (let ((model (make-instance 'model)))
      (loop :for attribute :in attributes
         :do (string-case (car attribute)
               ("id" (setf (id model) (cadr attribute)))
               (t (error "Unknown model attribute ~S" (car attribute)))))
      (let ((parsed-elements '()))
        (loop :for element :in elements
           :do (push (parse-element element) parsed-elements))
        (setf (elements model) (nreverse parsed-elements)))
      model)))

(defun parse-element (data)
  (string-case (car data)
    ("polygon" (%parse-polygon% data))
    (t (error "Unknown element type ~S" (car data)))))

(defun %parse-polygon% (data)
  (destructuring-bind (type attributes structure)
      data
    (let ((polygon (make-instance 'polygon)))
      (loop :for attribute :in attributes
         :do (string-case (car attribute)
               ("color" (setf (color polygon) (cadr attribute)))
               ("class" (setf (class polygon) (cadr attribute)))
               (t (error "Unknown polygon attribute ~S" (car attribute)))))
      (destructuring-bind (structure-type structure-attributes &rest elements)
          structure
        (string-case structure-type
          ("points"
           (let ((npoints nil)
                 (points '()))
             (loop :for attribute :in structure-attributes
                :do (string-case (car attribute)
                      ("n" (setf npoints (parse-integer (cadr attribute))))
                      (t (error "Unknown points structure attribute ~S"
                                (car attribute)))))
             (unless npoints
               (warn "Points structure lacks \"n\" attribute"))
             (loop :for point :in elements
                :do (push (parse-point point) points))
             (when npoints
               (unless (= npoints (length points))
                 (warn "Points structure has incorrect \"n\" attribute")))
             (setf (points polygon) (nreverse points))))
          (t (error "Unknown structure type ~S" structure-type))))
      polygon)))

(defun parse-point (data)
  data)
From: Frank Goenninger DG1SBG
Subject: Re: Translating parse result into instances
Date: 
Message-ID: <lz642vgwn2.fsf@de.goenninger.net>
Ari Johnson <·········@gmail.com> writes:

[complete code given by Ari snipped]

wow - thx! I have to digest this now ... Thanks!!!

Frank
-- 

  Frank Goenninger

  frgo(at)mac(dot)com

  "Don't ask me! I haven't been reading comp.lang.lisp long enough to 
  really know ..."
From: Pillsy
Subject: Re: Translating parse result into instances
Date: 
Message-ID: <1188570210.099282.239220@w3g2000hsg.googlegroups.com>
On Aug 30, 3:53 pm, Frank Goenninger DG1SBG <·············@nomail.org>
wrote:

> I have a - hm, what? - a "stream" of data as follows:

I went a bit crazy with this, and for some reason coded up a complete
solution. Since you don't actually want a complete solution, I'll just
say that one way to things like this is to destructure each like this:

(COMMAND . ARGS)

where COMMAND is the initial string, and ARGS are everything else.
Then use command as a key to some data structure which contains a
bunch of closures which you then I used an EQUALP hashtable, but list
structures could work as well. Each closure then destructures ARGS in
the right way, and does what you need to do in terms of making
instances.

I've found this technique is also good for parsing DSLs when you're
doing macrology (and in a way, it defines a DSL here, too), and with a
few tastefully chosen macros and functions, you can make a DSL for
expressing simple parsers that's concise and easy to modify.

This macro implements one part of the parser. You ought to be able to
extrapolate the rest of the implementation from it:

(defmacro define-parser (command (&rest lambda-list) &body body)
  (check-type command string)
  (let ((args (gensym)))
    `(progn
       (register-parser ,command
			#'(lambda (&rest ,args)
			    (destructuring-bind ,lambda-list
				,args
			      ,@body))))))

Cheers,
Pillsy
From: Frank Goenninger DG1SBG
Subject: Re: Translating parse result into instances
Date: 
Message-ID: <lzwsvbfh40.fsf@de.goenninger.net>
Pillsy <·········@gmail.com> writes:

> On Aug 30, 3:53 pm, Frank Goenninger DG1SBG <·············@nomail.org>
> wrote:
>
>> I have a - hm, what? - a "stream" of data as follows:
>
> I went a bit crazy with this, and for some reason coded up a complete
> solution. Since you don't actually want a complete solution, I'll just
> say that one way to things like this is to destructure each like this:
>
> (COMMAND . ARGS)
>
> where COMMAND is the initial string, and ARGS are everything else.
> Then use command as a key to some data structure which contains a
> bunch of closures which you then I used an EQUALP hashtable, but list
> structures could work as well. Each closure then destructures ARGS in
> the right way, and does what you need to do in terms of making
> instances.
>
> I've found this technique is also good for parsing DSLs when you're
> doing macrology (and in a way, it defines a DSL here, too), and with a
> few tastefully chosen macros and functions, you can make a DSL for
> expressing simple parsers that's concise and easy to modify.
>
> This macro implements one part of the parser. You ought to be able to
> extrapolate the rest of the implementation from it:
>
> (defmacro define-parser (command (&rest lambda-list) &body body)
>   (check-type command string)
>   (let ((args (gensym)))
>     `(progn
>        (register-parser ,command
> 			#'(lambda (&rest ,args)
> 			    (destructuring-bind ,lambda-list
> 				,args
> 			      ,@body))))))
>
> Cheers,
> Pillsy

ooookkkaaaayyyyy - now there's enough food for thought to cover the
weekend's spare hours for Lisp hacking ;-) I also found that Peter's
PCL with the MP3 parser is giving some hints going in the same
direction as you do with the define-parser macro.

Thanks a *lot* for showing and sharing!

Best
   Frank

-- 

  Frank Goenninger

  frgo(at)mac(dot)com

  "Don't ask me! I haven't been reading comp.lang.lisp long enough to 
  really know ..."
From: Ken Tilton
Subject: Re: Translating parse result into instances
Date: 
Message-ID: <1BUBi.9$NE7.2@newsfe12.lga>
Is this homework?! This looks like homework!

Frank Goenninger DG1SBG wrote:
> I have a - hm, what? - a "stream" of data as follows:
> 
> ("model" (("id" "FRGO"))
>  ("polygon" (("color" "+RED+") ("class" "GNC-QUAD"))
>   ("points" (("n" "4"))
>    ("point" NIL ("x" NIL "0") ("y" NIL "0") ("z" NIL "0"))
>    ("point" NIL ("x" NIL "100") ("y" NIL "0") ("z" NIL "0"))
>    ("point" NIL ("x" NIL "100") ("y" NIL "-100") ("z" NIL "0"))
>    ("point" NIL ("x" NIL "0") ("y" NIL "-100") ("z" NIL "0"))))
>  ("polygon" (("color" "+BLUE+") ("class" "GNC-QUAD"))
>   ("points" (("n" "4"))
>    ("point" NIL ("x" NIL "50") ("y" NIL "0") ("z" NIL "5"))
>    ("point" NIL ("x" NIL "100") ("y" NIL "60") ("z" NIL "5"))
>    ("point" NIL ("x" NIL "100") ("y" NIL "-60") ("z" NIL "50"))
>    ("point" NIL ("x" NIL "50") ("y" NIL "-100") ("z" NIL "50"))))
>  ("polygon" (("color" "+GREEN+") ("class" "GNC-QUAD"))
>   ("points" (("n" "4"))
>    ("point" NIL ("x" NIL "-50") ("y" NIL "10") ("z" NIL "30"))
>    ("point" NIL ("x" NIL "150") ("y" NIL "60") ("z" NIL "5"))
>    ("point" NIL ("x" NIL "150") ("y" NIL "-60") ("z" NIL "50"))
>    ("point" NIL ("x" NIL "-50") ("y" NIL "-100") ("z" NIL "50")))))
> 
> I need to create a Model instance with ID slot being bound to
> :frgo. Next I want to create Polygon instances ... You get the idea. 
> 
> New one for me, really. What if this goes to some few hundreds of
> polygons... 

Maude has the most RAM. Otherwise... look at your data, and think 
"destructuring-bind". You have:

   (class slots parts)

You can worry about destructuring slots if you get that far.

Parts will have the same structure, so at long last you have an excuse 
to use recursion! (I just wanted to goad some fool into posting an 
iterative solution.)

Functions are good at recursion. so...

(defun build-model (model-spec)
     (destructuring-bind (class slots parts) spec
        ...left as an exercise...))

I hope your teacher reads this NG!

kenny

ps. You'll need APPLY and (intern slot-name :keyword) to pull off the 
make-instance, and the foresight to make the initargs for the slot the 
same as the expected input slot names. kt


-- 
http://www.theoryyalgebra.com/

"We are what we pretend to be." -Kurt Vonnegut
From: Frank Goenninger DG1SBG
Subject: Re: Translating parse result into instances
Date: 
Message-ID: <lz1wdjgw4b.fsf@de.goenninger.net>
Ken Tilton <···········@optonline.net> writes:

> Is this homework?! This looks like homework!

Huh? Wow, now I am wondering if you really think of me as posting
homework here without mentioning it or if you really wanted to say
"How come he's asking so simple a question ?"...

Well, just to be clear - this is *not* homework. And I actually was
looking for the basic scheme of a solution ... Parsing is new for me
in Lisp - though strictly it's just some sort of mapping / destructuring,
of course.

The "layered destructuring" Ari showed is just sweet because I can
extend it easily.

Regarding what it's for:
I am saving polygons of Cello Widgets to a file - So I can provide
other themes just by changing polygons of widgets. I even can generate
polygon info with a vector graphics tool... And let this do a real
designer. She's working on the XML file which the tool is able to
read and writes a new file which I am reading then in.

So I can concentrate on the Lisp part and let others do what I am
certainly not that good at.

Looked like a simple solution. And it is - no?

Frank
From: Ken Tilton
Subject: Re: Translating parse result into instances
Date: 
Message-ID: <qP2Ci.274$ph.231@newsfe12.lga>
Frank Goenninger DG1SBG wrote:
> Ken Tilton <···········@optonline.net> writes:
> 
> 
>>Is this homework?! This looks like homework!
> 
> 
> Huh? Wow, now I am wondering if you really think of me as posting
> homework here without mentioning it or if you really wanted to say
> "How come he's asking so simple a question ?"...

Omigod! You never seem to guess "... or Kenny is joking again".*

Frank, we have been working together on Cello for about ten years now, 
during which I have learned about and almost contracted with your 
multi-billion dollar consulting firm -- I think I know you are not in 
college!!!!!

> 
> Well, just to be clear - this is *not* homework. And I actually was
> looking for the basic scheme of a solution ... Parsing is new for me
> in Lisp - though strictly it's just some sort of mapping / destructuring,
> of course.
> 
> The "layered destructuring" Ari showed is just sweet because I can
> extend it easily.

I am sorry you did not like the help I offered. That's the last time I 
ever help you!!!!**

> 
> Regarding what it's for:
> I am saving polygons of Cello Widgets to a file - So I can provide
> other themes just by changing polygons of widgets. I even can generate
> polygon info with a vector graphics tool... And let this do a real
> designer. She's working on the XML file which the tool is able to
> read and writes a new file which I am reading then in.

Skins? Good lord, man, what are you up to?!

> 
> So I can concentrate on the Lisp part and let others do what I am
> certainly not that good at.
> 
> Looked like a simple solution. And it is - no?

Sounds like I did not talk you into using Tk widgets. :)

kt

* I guess I should be grateful someone around here takes me seriously.

** Kidding! :)

-- 
http://www.theoryyalgebra.com/

"We are what we pretend to be." -Kurt Vonnegut
From: Frank Goenninger DG1SBG
Subject: Re: Translating parse result into instances
Date: 
Message-ID: <lzodgmg2x8.fsf@de.goenninger.net>
Ken Tilton <···········@optonline.net> writes:

> Frank Goenninger DG1SBG wrote:
>> Ken Tilton <···········@optonline.net> writes:
>>
>>
>>>Is this homework?! This looks like homework!
>>
>>
>> Huh? Wow, now I am wondering if you really think of me as posting
>> homework here without mentioning it or if you really wanted to say
>> "How come he's asking so simple a question ?"...
>
> Omigod! You never seem to guess "... or Kenny is joking again".*

Ha! I got you! Hey, Kenny, of course I never actually thought you'd
say this to be meant that way - I had to do it: Just that line of you
made a good lough this morning here ... ;-) !

>
> Frank, we have been working together on Cello for about ten years now,
> during which I have learned about and almost contracted with your
> multi-billion dollar consulting firm -- I think I know you are not in
> college!!!!!

Yeah, yeah - I know you know. But it simply was too damned easy to
react as I did - so I did.

>
> I am sorry you did not like the help I offered. That's the last time I
> ever help you!!!!**
>

Well, I didn'z say I don't like the "look there" hint :-) It's still
in the pipeline for being thought about. Oh yeah, all that
"Multi-billion business" stuff is giving me headaches these
days - leaving no room for the fun part (Cello Widgets)...

>>
>> Regarding what it's for:
>> I am saving polygons of Cello Widgets to a file - So I can provide
>> other themes just by changing polygons of widgets. I even can generate
>> polygon info with a vector graphics tool... And let this do a real
>> designer. She's working on the XML file which the tool is able to
>> read and writes a new file which I am reading then in.
>
> Skins? Good lord, man, what are you up to?!

Something beautiful I hope!

> Sounds like I did not talk you into using Tk widgets. :)

Ah no - too much into Cello already. Sorry, now that I have seen the
light I won't go back to the dark powers! :-)

>
> kt
>
> * I guess I should be grateful someone around here takes me
> seriously.

Don't mess with your accepted image here on c.l.l. - You could be
misunderstood ...

>
> ** Kidding! :)

:-)