From: JanTheKing
Subject: Macros in Lisp
Date: 
Message-ID: <1161007506.738692.206820@b28g2000cwb.googlegroups.com>
Hi,

I am new to Lisp. I want to learn creation of simple macros in Lisp
which can be used to generate dynamic functions at compile time. Can
someone help me with some simple example(s) to learn this? Thanks.

Cheers,
Jan

From: Marco Bakera
Subject: Re: Macros in Lisp
Date: 
Message-ID: <ulhvemkxq3k.fsf@ls5appsrv01.cs.uni-dortmund.de>
"JanTheKing" <········@gmail.com> writes:

> I am new to Lisp. I want to learn creation of simple macros in Lisp
> which can be used to generate dynamic functions at compile time. Can
> someone help me with some simple example(s) to learn this? Thanks.

You might have a look at http://www.gigamonkeys.com/book/. Especially
at chapter 7, 8 and those starting with "Practical".


Greetings,
Marco.
From: Pascal Bourguignon
Subject: Re: Macros in Lisp
Date: 
Message-ID: <8764ek8c00.fsf@thalassa.informatimago.com>
Marco Bakera <············@uni-dortmund.de> writes:

> "JanTheKing" <········@gmail.com> writes:
>
>> I am new to Lisp. I want to learn creation of simple macros in Lisp
>> which can be used to generate dynamic functions at compile time. Can
>> someone help me with some simple example(s) to learn this? Thanks.
>
> You might have a look at http://www.gigamonkeys.com/book/. Especially
> at chapter 7, 8 and those starting with "Practical".

But of course, NOT before having studied the first six chapters!

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

"Indentation! -- I will show you how to indent when I indent your skull!"
From: Wade Humeniuk
Subject: Re: Macros in Lisp
Date: 
Message-ID: <VwBZg.70375$E67.35985@clgrps13>
JanTheKing wrote:
> Hi,
> 
> I am new to Lisp. I want to learn creation of simple macros in Lisp
> which can be used to generate dynamic functions at compile time. Can
> someone help me with some simple example(s) to learn this? Thanks.
> 

Simple??? ....  Well

Here is some code from a C++ parser I am writing,  It will
generate a loop to lex a C++ stream (file).  An example of using the
lexer follows the lexer-loop macro.

Wade

(defmacro lexer-loop ((c stream lexer-block) &body body)
   (let ((loop (gensym)))
     `(macrolet ((c->token (char)
                   `(when (char= ,',c ,char)
                      (return-from ,',lexer-block (values ',(intern (string char)) nil))))
                 (c->loop (char &body body)
                   `(when (char= ,',c ,char) ,@body (go ,',loop)))
                 (member->loop (set &body body)
                   `(when (or ,@(mapcar (lambda (mc) `(char= ,',c ,mc)) set))
                      ,@body
                      (go ,',loop)))
                 (p->token (function &body body)
                   `(when (,function ,',c)
                      (return-from ,',lexer-block (progn ,@body))))
                 (backtrack-if-not (seq &body non-backtrack-forms)
                   (labels ((backtracker (seq)
                              (if (null seq)
                                  `(return-from ,',lexer-block
                                     (progn (loop for c in *backtrack*
                                                  do (lexback c ,',stream))
                                       ,@non-backtrack-forms))
                                (destructuring-bind (test &rest rest)
                                    seq
                                  (etypecase test
                                    (character
                                     `(when (char= ,',c ,test)
                                        (let ((,',c (lexin ,',stream nil nil)))
                                          (push ,',c *backtrack*)
                                          (when ,',c ,(backtracker rest))
                                          (lexback ','c ,',stream))))
                                    (symbol
                                     `(when (,test ,',c)
                                        (let ((,',c (lexin ,',stream nil nil)))
                                          (push ,',c *backtrack*)
                                          (when ,',c ,(backtracker rest))
                                          (lexback ','c ,',stream)))))))))
                     `(let ((*backtrack* nil))
                        (push ,',c *backtrack*)
                        ,(backtracker seq))))
                 (ctree->token (tree)
                   (labels ((build-tree (tree &optional path)
                              (if (atom tree)
                                  `(when (char= ,',c ,tree)
                                     (return-from ,',lexer-block
                                       (values ',(intern (coerce (append path (list tree)) 
'string))
                                               nil)))
                                (destructuring-bind (first &rest branches)
                                    tree
                                  `(when (char= ,',c ,first)
                                     (let ((,',c (lexin ,',stream nil nil)))
                                       (when ,',c
                                         ,@(loop for branch in branches
                                                 with new-path = (append path (list first))
                                                 collect (build-tree branch new-path)))
                                       (lexback ,',c ,',stream)
                                       (return-from ,',lexer-block
                                         (values ',(intern (coerce (append path (list 
first)) 'string))
                                                 nil))))))))
                     (build-tree tree))))
      (prog (,c)
        ,loop
        (setf ,c (lexin ,stream))
        ,@body))))

(defun top-level-lexer (stream)
   (handler-case
       (lexer-loop (c stream top-level-lexer)
         (member->loop (#\space #\tab #\newline #\cr #\ff))
         (c->loop #\# (lexdirective stream))
         (c->loop #\/ (lexcomment stream))
         (p->token start-symbol-char-p (lexback c stream) (lexsymbol stream))
         (backtrack-if-not (#\. digit-char-p) (lexnumber stream))
         (p->token digit-char-p (lexback c stream) (lexnumber stream))
         (c->token #\()
         (c->token #\))
         (c->token #\[)
         (c->token #\])
         (c->token #\{)
         (c->token #\})
         (c->token #\;)
         (c->token #\,)
         (c->token #\.)
         (ctree->token (#\: #\:))
         (ctree->token (#\+ #\+ #\=))
         (ctree->token (#\- #\- #\= #\>))
         (ctree->token (#\* #\=))
         (ctree->token (#\/ #\=))
         (ctree->token (#\% #\=))
         (ctree->token (#\> (#\> #\=) #\=))
         (ctree->token (#\< (#\< #\=) #\=))
         (ctree->token (#\& #\& #\=))
         (ctree->token (#\| #\| #\=))
         (ctree->token (#\= #\=))
         (ctree->token (#\^ #\=))
         (ctree->token (#\! #\=)))

     (end-of-file () (values nil nil))))
From: JanTheKing
Subject: Re: Macros in Lisp
Date: 
Message-ID: <1161240728.805490.125480@f16g2000cwb.googlegroups.com>
Hi Wade,

Thank you very much for sending your code. It looks good, But I am not
able to understand it...Can you please help me out?

Janesh

Wade Humeniuk wrote:
> JanTheKing wrote:
> > Hi,
> >
> > I am new to Lisp. I want to learn creation of simple macros in Lisp
> > which can be used to generate dynamic functions at compile time. Can
> > someone help me with some simple example(s) to learn this? Thanks.
> >
>
> Simple??? ....  Well
>
> Here is some code from a C++ parser I am writing,  It will
> generate a loop to lex a C++ stream (file).  An example of using the
> lexer follows the lexer-loop macro.
>
> Wade
>
> (defmacro lexer-loop ((c stream lexer-block) &body body)
>    (let ((loop (gensym)))
>      `(macrolet ((c->token (char)
>                    `(when (char= ,',c ,char)
>                       (return-from ,',lexer-block (values ',(intern (string char)) nil))))
>                  (c->loop (char &body body)
>                    `(when (char= ,',c ,char) ,@body (go ,',loop)))
>                  (member->loop (set &body body)
>                    `(when (or ,@(mapcar (lambda (mc) `(char= ,',c ,mc)) set))
>                       ,@body
>                       (go ,',loop)))
>                  (p->token (function &body body)
>                    `(when (,function ,',c)
>                       (return-from ,',lexer-block (progn ,@body))))
>                  (backtrack-if-not (seq &body non-backtrack-forms)
>                    (labels ((backtracker (seq)
>                               (if (null seq)
>                                   `(return-from ,',lexer-block
>                                      (progn (loop for c in *backtrack*
>                                                   do (lexback c ,',stream))
>                                        ,@non-backtrack-forms))
>                                 (destructuring-bind (test &rest rest)
>                                     seq
>                                   (etypecase test
>                                     (character
>                                      `(when (char= ,',c ,test)
>                                         (let ((,',c (lexin ,',stream nil nil)))
>                                           (push ,',c *backtrack*)
>                                           (when ,',c ,(backtracker rest))
>                                           (lexback ','c ,',stream))))
>                                     (symbol
>                                      `(when (,test ,',c)
>                                         (let ((,',c (lexin ,',stream nil nil)))
>                                           (push ,',c *backtrack*)
>                                           (when ,',c ,(backtracker rest))
>                                           (lexback ','c ,',stream)))))))))
>                      `(let ((*backtrack* nil))
>                         (push ,',c *backtrack*)
>                         ,(backtracker seq))))
>                  (ctree->token (tree)
>                    (labels ((build-tree (tree &optional path)
>                               (if (atom tree)
>                                   `(when (char= ,',c ,tree)
>                                      (return-from ,',lexer-block
>                                        (values ',(intern (coerce (append path (list tree))
> 'string))
>                                                nil)))
>                                 (destructuring-bind (first &rest branches)
>                                     tree
>                                   `(when (char= ,',c ,first)
>                                      (let ((,',c (lexin ,',stream nil nil)))
>                                        (when ,',c
>                                          ,@(loop for branch in branches
>                                                  with new-path = (append path (list first))
>                                                  collect (build-tree branch new-path)))
>                                        (lexback ,',c ,',stream)
>                                        (return-from ,',lexer-block
>                                          (values ',(intern (coerce (append path (list
> first)) 'string))
>                                                  nil))))))))
>                      (build-tree tree))))
>       (prog (,c)
>         ,loop
>         (setf ,c (lexin ,stream))
>         ,@body))))
>
> (defun top-level-lexer (stream)
>    (handler-case
>        (lexer-loop (c stream top-level-lexer)
>          (member->loop (#\space #\tab #\newline #\cr #\ff))
>          (c->loop #\# (lexdirective stream))
>          (c->loop #\/ (lexcomment stream))
>          (p->token start-symbol-char-p (lexback c stream) (lexsymbol stream))
>          (backtrack-if-not (#\. digit-char-p) (lexnumber stream))
>          (p->token digit-char-p (lexback c stream) (lexnumber stream))
>          (c->token #\()
>          (c->token #\))
>          (c->token #\[)
>          (c->token #\])
>          (c->token #\{)
>          (c->token #\})
>          (c->token #\;)
>          (c->token #\,)
>          (c->token #\.)
>          (ctree->token (#\: #\:))
>          (ctree->token (#\+ #\+ #\=))
>          (ctree->token (#\- #\- #\= #\>))
>          (ctree->token (#\* #\=))
>          (ctree->token (#\/ #\=))
>          (ctree->token (#\% #\=))
>          (ctree->token (#\> (#\> #\=) #\=))
>          (ctree->token (#\< (#\< #\=) #\=))
>          (ctree->token (#\& #\& #\=))
>          (ctree->token (#\| #\| #\=))
>          (ctree->token (#\= #\=))
>          (ctree->token (#\^ #\=))
>          (ctree->token (#\! #\=)))
> 
>      (end-of-file () (values nil nil))))
From: Wade Humeniuk
Subject: Re: Macros in Lisp
Date: 
Message-ID: <8AYZg.30518$P7.27390@edtnps89>
JanTheKing wrote:
> Hi Wade,
> 
> Thank you very much for sending your code. It looks good, But I am not
> able to understand it...Can you please help me out?
> 

It is literally self-explanatory, if you know macros ... and well...
other stuff.  Suffice it to say that if you macro expand the main lexer-loop
in top-level-lexer it looks like (see link under following lexer-loop)

Macro Code ================>
(lexer-loop (c stream top-level-lexer)
         (member->loop (#\space #\tab #\newline #\cr #\ff))
         (c->loop #\# (lexdirective stream))
         (c->loop #\/ (lexcomment stream))
         (p->token start-symbol-char-p (lexback c stream) (lexsymbol stream))
         (backtrack-if-not (#\. digit-char-p) (lexnumber stream))
         (p->token digit-char-p (lexback c stream) (lexnumber stream))
         (c->token #\()
         (c->token #\))
         (c->token #\[)
         (c->token #\])
         (c->token #\{)
         (c->token #\})
         (c->token #\;)
         (c->token #\,)
         (c->token #\.)
         (ctree->token (#\: #\:))
         (ctree->token (#\+ #\+ #\=))
         (ctree->token (#\- #\- #\= #\>))
         (ctree->token (#\* #\=))
         (ctree->token (#\/ #\=))
         (ctree->token (#\% #\=))
         (ctree->token (#\> (#\> #\=) #\=))
         (ctree->token (#\< (#\< #\=) #\=))
         (ctree->token (#\& #\& #\=))
         (ctree->token (#\| #\| #\=))
         (ctree->token (#\= #\=))
         (ctree->token (#\^ #\=))
         (ctree->token (#\! #\=)))

expands to==============>>>

http://www3.telus.net/public/whumeniu/expansion.lisp

<<=====================

So instead of writing all that horrible repetitive logic, that macro does
it for me.  This is not saying that lexer-loop could be improved, I see some
generalizations that could be put in that would simplify things.  But I
would not have seen them until I wrote lexer-loop in its current form and
_learned_ how to write this kind of lexer.

Wade
From: Rob Thorpe
Subject: Re: Macros in Lisp
Date: 
Message-ID: <1161262862.989466.212110@h48g2000cwc.googlegroups.com>
Wade Humeniuk wrote:
> JanTheKing wrote:
> > Hi,
> >
> > I am new to Lisp. I want to learn creation of simple macros in Lisp
> > which can be used to generate dynamic functions at compile time. Can
> > someone help me with some simple example(s) to learn this? Thanks.
> >
>
> Simple??? ....  Well
>
> Here is some code from a C++ parser I am writing,  It will
> generate a loop to lex a C++ stream (file).  An example of using the
> lexer follows the lexer-loop macro.
>

If I were you I'd split that macro over several macros and functions,
it's seriously skull-cracking as it is.
From: Wade Humeniuk
Subject: Re: Macros in Lisp
Date: 
Message-ID: <yBYZg.30519$P7.23918@edtnps89>
Rob Thorpe wrote:
> Wade Humeniuk wrote:
>> JanTheKing wrote:
>>> Hi,
>>>
>>> I am new to Lisp. I want to learn creation of simple macros in Lisp
>>> which can be used to generate dynamic functions at compile time. Can
>>> someone help me with some simple example(s) to learn this? Thanks.
>>>
>> Simple??? ....  Well
>>
>> Here is some code from a C++ parser I am writing,  It will
>> generate a loop to lex a C++ stream (file).  An example of using the
>> lexer follows the lexer-loop macro.
>>
> 
> If I were you I'd split that macro over several macros and functions,
> it's seriously skull-cracking as it is.
> 

Nah, I am a stickler for keeping the macrolet forms hidden from the outside
world.

Wade
From: Rob Thorpe
Subject: Re: Macros in Lisp
Date: 
Message-ID: <1161712031.839314.67200@k70g2000cwa.googlegroups.com>
Wade Humeniuk wrote:
> Rob Thorpe wrote:
> > Wade Humeniuk wrote:
> >> JanTheKing wrote:
> >>> Hi,
> >>>
> >>> I am new to Lisp. I want to learn creation of simple macros in Lisp
> >>> which can be used to generate dynamic functions at compile time. Can
> >>> someone help me with some simple example(s) to learn this? Thanks.
> >>>
> >> Simple??? ....  Well
> >>
> >> Here is some code from a C++ parser I am writing,  It will
> >> generate a loop to lex a C++ stream (file).  An example of using the
> >> lexer follows the lexer-loop macro.
> >>
> >
> > If I were you I'd split that macro over several macros and functions,
> > it's seriously skull-cracking as it is.
> >
>
> Nah, I am a stickler for keeping the macrolet forms hidden from the outside
> world.

I'm not saying that you shouldn't.  Just that maybe you should split
that macro into pieces.  Many by having some helper macros that expand
within it.  I think this is one situation where having macros expand
within macros is better than having one very complex macro.
From: Bill Atkins
Subject: Re: Macros in Lisp
Date: 
Message-ID: <m2hcxtsigf.fsf@jec18-18.dynamic.rpi.edu>
"Rob Thorpe" <·············@antenova.com> writes:

> Wade Humeniuk wrote:
>> Rob Thorpe wrote:
>> > Wade Humeniuk wrote:
>> >> JanTheKing wrote:
>> >>> Hi,
>> >>>
>> >>> I am new to Lisp. I want to learn creation of simple macros in Lisp
>> >>> which can be used to generate dynamic functions at compile time. Can
>> >>> someone help me with some simple example(s) to learn this? Thanks.
>> >>>
>> >> Simple??? ....  Well
>> >>
>> >> Here is some code from a C++ parser I am writing,  It will
>> >> generate a loop to lex a C++ stream (file).  An example of using the
>> >> lexer follows the lexer-loop macro.
>> >>
>> >
>> > If I were you I'd split that macro over several macros and functions,
>> > it's seriously skull-cracking as it is.
>> >
>>
>> Nah, I am a stickler for keeping the macrolet forms hidden from the outside
>> world.
>
> I'm not saying that you shouldn't.  Just that maybe you should split
> that macro into pieces.  Many by having some helper macros that expand
> within it.  I think this is one situation where having macros expand
> within macros is better than having one very complex macro.

Another option is to make use of helper functions when writing macros
(as opposed to using helper macros), which are easier to debug.
From: ········@gmail.com
Subject: Re: Macros in Lisp
Date: 
Message-ID: <1161320226.400393.102980@e3g2000cwe.googlegroups.com>
> I am new to Lisp. I want to learn creation of simple macros in Lisp
> which can be used to generate dynamic functions at compile time. Can
> someone help me with some simple example(s) to learn this? Thanks.

No to go all Kenny on you, but why on earth would anyone ask a question
like this before typing: "lisp macros" into google and instantly
finding 100 perfectly understandable explanations?!

If, after studying one or more of those you have a more specific
question, I'm sure that the community would be happy to help you out.
From: JanTheKing
Subject: Re: Macros in Lisp
Date: 
Message-ID: <1161336405.340639.89330@m73g2000cwd.googlegroups.com>
Hi,

My thanks to everyone for your help.

I did search in Google for "lisp macros" but found most of the pages to
be very complicated (atleast at my level of understanding as a
beginner). That is the reason why I sought the help of this forum. Now
I have realized that I can learn swimming not by reading swimming
manuals or by asking questions to those who know to swim - but only by
diving into water myself. I have decided to dive now. Thanks again

Cheers,
Janesh

········@gmail.com wrote:
> > I am new to Lisp. I want to learn creation of simple macros in Lisp
> > which can be used to generate dynamic functions at compile time. Can
> > someone help me with some simple example(s) to learn this? Thanks.
>
> No to go all Kenny on you, but why on earth would anyone ask a question
> like this before typing: "lisp macros" into google and instantly
> finding 100 perfectly understandable explanations?!
>
> If, after studying one or more of those you have a more specific
> question, I'm sure that the community would be happy to help you out.
From: Pascal Bourguignon
Subject: Re: Macros in Lisp
Date: 
Message-ID: <87ejt31d7l.fsf@thalassa.informatimago.com>
"JanTheKing" <········@gmail.com> writes:
> I did search in Google for "lisp macros" but found most of the pages to
> be very complicated (atleast at my level of understanding as a
> beginner). That is the reason why I sought the help of this forum. Now
> I have realized that I can learn swimming not by reading swimming
> manuals or by asking questions to those who know to swim - but only by
> diving into water myself. I have decided to dive now. Thanks again

Mind searching Google Groups and Google Code separately, and also
http://www.cliki.net/ which has pointers to interesting tutorials.

For example, on http://www.cliki.net/Online%20Tutorial
you find a link to:

 Casting SPELs in Lisp -- A (tutorial about lisp macros) Comic Book by
 Conrad Barski, M.D.


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

WARNING: This product warps space and time in its vicinity.
From: JanTheKing
Subject: Re: Macros in Lisp
Date: 
Message-ID: <1161860647.052470.162190@b28g2000cwb.googlegroups.com>
Hi Pascal,

"Casting SPELs in Lisp" is too good. Thank you very much.

Thanks to everyone for your sincere guidance.

Cheers,
Jan The King

Pascal Bourguignon wrote:
> "JanTheKing" <········@gmail.com> writes:
> > I did search in Google for "lisp macros" but found most of the pages to
> > be very complicated (atleast at my level of understanding as a
> > beginner). That is the reason why I sought the help of this forum. Now
> > I have realized that I can learn swimming not by reading swimming
> > manuals or by asking questions to those who know to swim - but only by
> > diving into water myself. I have decided to dive now. Thanks again
>
> Mind searching Google Groups and Google Code separately, and also
> http://www.cliki.net/ which has pointers to interesting tutorials.
>
> For example, on http://www.cliki.net/Online%20Tutorial
> you find a link to:
>
>  Casting SPELs in Lisp -- A (tutorial about lisp macros) Comic Book by
>  Conrad Barski, M.D.
>
>
> --
> __Pascal Bourguignon__                     http://www.informatimago.com/
> 
> WARNING: This product warps space and time in its vicinity.