From: bufie
Subject: another simple defmacro question
Date: 
Message-ID: <ltSXc.103456$TI1.34207@attbi_s52>
Hi again,

I know I'm missing something simple here, but I've tried a bunch of stuff
and it just doesn't work...

My application needs to read a list of constants at compile time from a
file.  I came up with this macro:

(defmacro my-file-to-string-list (fname)
  (let ((stringlist)
           (tmpstr))
    (with-open-file (infile fname :direction :input)
      (loop
        (setq tmpstr (read-line infile nil nil))
        (unless tmpstr
          (return))
        (push tmpstr stringlist)
         ))
    (setq stringlist (nreverse stringlist))
    stringlist
    ))

When I call this using
(setq mystrings (my-file-to-string-list myfilename))

I get an error that the first line of the file is invalid as a function
(it's apparently considering the opening paren of the list as a function
call).  I know there must be something simple here (if I change the defmacro
to defun it will work, but doesn't get evaluated at load time or compile
time), and I think I've solved this (or seen it solved) before, but I'm just
not seeing it this time...

help, please!

thanks!

bufie

From: Barry Margolin
Subject: Re: another simple defmacro question
Date: 
Message-ID: <barmar-89F101.23294727082004@comcast.dca.giganews.com>
In article <······················@attbi_s52>,
 "bufie" <·····@spamneggs.com> wrote:

> Hi again,
> 
> I know I'm missing something simple here, but I've tried a bunch of stuff
> and it just doesn't work...
> 
> My application needs to read a list of constants at compile time from a
> file.  I came up with this macro:
> 
> (defmacro my-file-to-string-list (fname)
>   (let ((stringlist)
>            (tmpstr))
>     (with-open-file (infile fname :direction :input)
>       (loop
>         (setq tmpstr (read-line infile nil nil))
>         (unless tmpstr
>           (return))
>         (push tmpstr stringlist)
>          ))
>     (setq stringlist (nreverse stringlist))
>     stringlist
>     ))
> 
> When I call this using
> (setq mystrings (my-file-to-string-list myfilename))
> 
> I get an error that the first line of the file is invalid as a function
> (it's apparently considering the opening paren of the list as a function
> call).  I know there must be something simple here (if I change the defmacro
> to defun it will work, but doesn't get evaluated at load time or compile
> time), and I think I've solved this (or seen it solved) before, but I'm just
> not seeing it this time...

Macros are expected to expand into *code*, not data.  The code for a 
literal list of strings is (quote ("string1" "string2" ...)), but you're 
expanding into ("string1" "string2" ...).  Your macro should end with:

  ',stringlist

And would you *please* stop putting close parens on lines by themselves?  
It's not how we do things around here.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: bufie
Subject: Re: another simple defmacro question
Date: 
Message-ID: <kpTXc.246755$eM2.43840@attbi_s51>
Hi Barry,

"Barry Margolin" <······@alum.mit.edu> wrote in message
·································@comcast.dca.giganews.com...
> In article <······················@attbi_s52>,
>  "bufie" <·····@spamneggs.com> wrote:
>
> > (defmacro my-file-to-string-list (fname)
> >   (let ((stringlist)
> >            (tmpstr))
> >     (with-open-file (infile fname :direction :input)
> >       (loop
> >         (setq tmpstr (read-line infile nil nil))
> >         (unless tmpstr
> >           (return))
> >         (push tmpstr stringlist)
> >          ))
> >     (setq stringlist (nreverse stringlist))
> >     stringlist))

[snip]

> Macros are expected to expand into *code*, not data.  The code for a
> literal list of strings is (quote ("string1" "string2" ...)), but you're
> expanding into ("string1" "string2" ...).  Your macro should end with:
>
>   ',stringlist

I had tried this, but since I didn't have a backquote anywhere in the macro
it didn't work.  However, I just added one at the beginning of the last line
so it now looks like this:
`',stringlist

and it all seems to work now.  Thanks very much for your help!

> And would you *please* stop putting close parens on lines by themselves?
> It's not how we do things around here.

will do.  Sorry about that!

Thanks again!

bufie
From: Peter Lewerin
Subject: Re: another simple defmacro question
Date: 
Message-ID: <b72f3640.0408272358.b6b444b@posting.google.com>
"bufie" <·····@spamneggs.com> wrote

> My application needs to read a list of constants at compile time from a
> file.  I came up with this macro:

Someone else will most likely help you write the macro.  I just
wondered if you wouldn't do better to COMPILE-FILE the file with the
list of constants?

    (COMPILE-FILE fname :LOAD T)
From: bufie
Subject: Re: another simple defmacro question
Date: 
Message-ID: <yHSXc.57962$9d6.23697@attbi_s54>
Sorry to immediately follow up to my own post, but I just tried one more
thing that seems to work.  If I change the call to

(setq mystrings (macroexpand '(my-file-to-string-list myfilename)))

the variable mystrings gets set to a list of strings corresponding to the
lines in the file.  Is this the right approach to do this, or is there a
better way?

thanks for your help!

bufie

"bufie" <·····@spamneggs.com> wrote in message
···························@attbi_s52...
> Hi again,
>
> I know I'm missing something simple here, but I've tried a bunch of stuff
> and it just doesn't work...
>
> My application needs to read a list of constants at compile time from a
> file.  I came up with this macro:
>
> (defmacro my-file-to-string-list (fname)
>   (let ((stringlist)
>            (tmpstr))
>     (with-open-file (infile fname :direction :input)
>       (loop
>         (setq tmpstr (read-line infile nil nil))
>         (unless tmpstr
>           (return))
>         (push tmpstr stringlist)
>          ))
>     (setq stringlist (nreverse stringlist))
>     stringlist
>     ))
>
> When I call this using
> (setq mystrings (my-file-to-string-list myfilename))
>
> I get an error that the first line of the file is invalid as a function
> (it's apparently considering the opening paren of the list as a function
> call).  I know there must be something simple here (if I change the
defmacro
> to defun it will work, but doesn't get evaluated at load time or compile
> time), and I think I've solved this (or seen it solved) before, but I'm
just
> not seeing it this time...
>
> help, please!
>
> thanks!
>
> bufie
>
>
From: bufie
Subject: Re: another simple defmacro question
Date: 
Message-ID: <s2TXc.246630$eM2.16300@attbi_s51>
Ok, I was wrong...  This solution doesn't expand at compile time after
all -- I thought it would, but it still looks for the file with the text
strings in it...

It seems there's got to be a way to do this so that the constants will be
defined in the compiled code...

thanks in advance for any help you can provide!

bufie

"bufie" <·····@spamneggs.com> wrote in message
··························@attbi_s54...
> Sorry to immediately follow up to my own post, but I just tried one more
> thing that seems to work.  If I change the call to
>
> (setq mystrings (macroexpand '(my-file-to-string-list myfilename)))
>
> the variable mystrings gets set to a list of strings corresponding to the
> lines in the file.  Is this the right approach to do this, or is there a
> better way?
>
> thanks for your help!
>
> bufie
>
> "bufie" <·····@spamneggs.com> wrote in message
> ···························@attbi_s52...
> > Hi again,
> >
> > I know I'm missing something simple here, but I've tried a bunch of
stuff
> > and it just doesn't work...
> >
> > My application needs to read a list of constants at compile time from a
> > file.  I came up with this macro:
> >
> > (defmacro my-file-to-string-list (fname)
> >   (let ((stringlist)
> >            (tmpstr))
> >     (with-open-file (infile fname :direction :input)
> >       (loop
> >         (setq tmpstr (read-line infile nil nil))
> >         (unless tmpstr
> >           (return))
> >         (push tmpstr stringlist)
> >          ))
> >     (setq stringlist (nreverse stringlist))
> >     stringlist
> >     ))
> >
> > When I call this using
> > (setq mystrings (my-file-to-string-list myfilename))
> >
> > I get an error that the first line of the file is invalid as a function
> > (it's apparently considering the opening paren of the list as a function
> > call).  I know there must be something simple here (if I change the
> defmacro
> > to defun it will work, but doesn't get evaluated at load time or compile
> > time), and I think I've solved this (or seen it solved) before, but I'm
> just
> > not seeing it this time...
> >
> > help, please!
> >
> > thanks!
> >
> > bufie
> >
> >
>
>
From: Jeff
Subject: Re: another simple defmacro question
Date: 
Message-ID: <QHSXc.321833$a24.317660@attbi_s03>
bufie wrote:

> My application needs to read a list of constants at compile time from
> a file.  I came up with this macro:

There is no need for this to be a macro. You can just make a simple
defun to do this. As long as the SETQ is at the toplevel, it will
happen at compile time.

Jeff
From: Barry Margolin
Subject: Re: another simple defmacro question
Date: 
Message-ID: <barmar-5640C8.23263927082004@comcast.dca.giganews.com>
In article <·······················@attbi_s03>,
 "Jeff" <···@nospam.insightbb.com> wrote:

> bufie wrote:
> 
> > My application needs to read a list of constants at compile time from
> > a file.  I came up with this macro:
> 
> There is no need for this to be a macro. You can just make a simple
> defun to do this. As long as the SETQ is at the toplevel, it will
> happen at compile time.

No it won't, it generate code to call the function at load time.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: Joost Kremers
Subject: Re: another simple defmacro question
Date: 
Message-ID: <slrncj0rka.8u.joostkremers@j.kremers4.news.arnhem.chello.nl>
bufie wrote:
[snip macro]
> I get an error that the first line of the file is invalid as a function

yes, because macros return code, which is then evaluated. you have the
macro return a list, and that list will be evaluated as if it were code.

for evaluation at compilation time, CL provides EVAL-WHEN.

-- 
Joost Kremers                                      ············@yahoo.com
Selbst in die Unterwelt dringt durch Spalten Licht
EN:SiS(9)
From: Pascal Costanza
Subject: Re: another simple defmacro question
Date: 
Message-ID: <cgq58e$gku$1@newsreader3.netcologne.de>
bufie wrote:

> Hi again,
> 
> I know I'm missing something simple here, but I've tried a bunch of stuff
> and it just doesn't work...
> 
> My application needs to read a list of constants at compile time from a
> file.

I am not 100% sure if this will work, but here is what I came up with 
(untested!):

(defvar *mystrings*)

(eval-when (:compile-toplevel)
   (setq *mystrings*
         (with-open-file (infile fname :direction :input)
           (loop for tmpstr = (read-line infile nil nil)
                 while tmpstr
                 collect tmpstr))))


However, I think Peter Lewerin's suggestion is the better idea. If you 
can manage to have the constants defined in that infile just be a Lisp 
constant then you should be done:

(defconstant +mystrings+ (list "foo" "bar" "baz"))


Pascal

-- 
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
From: Thomas A. Russ
Subject: Re: another simple defmacro question
Date: 
Message-ID: <ymipt58cu61.fsf@sevak.isi.edu>
"bufie" <·····@spamneggs.com> writes:

> 
> Hi again,
> 
> I know I'm missing something simple here, but I've tried a bunch of stuff
> and it just doesn't work...
> 
> My application needs to read a list of constants at compile time from a
> file.  I came up with this macro:

This is not a job for a macro.

This is a job for EVAL-WHEN.

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Thomas A. Russ
Subject: Re: another simple defmacro question
Date: 
Message-ID: <ymioeksctvw.fsf@sevak.isi.edu>
"bufie" <·····@spamneggs.com> writes:

Not at all connected with your original problem, but you can
exploit the full power of LOOP to greatly simplify this part
of the code:

>   (let ((stringlist)
>            (tmpstr))
>     (with-open-file (infile fname :direction :input)
>       (loop
>         (setq tmpstr (read-line infile nil nil))
>         (unless tmpstr
>           (return))
>         (push tmpstr stringlist)
>          ))
>     (setq stringlist (nreverse stringlist))
>     stringlist
>     ))

It can be transformed into:

   (with-open-file (infile fname :direction :input)
      (loop for tmpstr = (read-line infile nil nil)
            while tmpstr
            collect tmpstr))

This moves the variable "tmpstr" into the loop itself
and dispenses with "stringlist" entirely, since it isn't
needed.  The LOOP "collect" form efficiently adds elements
to the end of the list, and that is what is returned by
the form.

(I kept your variable names, but I would usually call
 "tmpstr" "line" instead...)

-- 
Thomas A. Russ,  USC/Information Sciences Institute