From: Dr. Roy
Subject: Tiny Lisp written in C
Date: 
Message-ID: <10844@cit-vax.Caltech.Edu>
I have become entranced with AutoLisp, the lisp variant
that goes along with the AutoCad drafting program, and I
would like to make a lisp dialect for my own software.

Specifically, there would be a lisp interpeter which can
be hooked into my set of C functions which actually do the
work.

Does anyone know of a public domain lisp interpreter, written
in a high-level language, preferably C, which can control
an application like this?

Roy Williams
Caltech
···@willow.caltech.edu

From: Robert Steven Glickstein
Subject: ELI (was Re: Tiny Lisp written in C)
Date: 
Message-ID: <YYV1zny00VsnA0cUtp@andrew.cmu.edu>
> Excerpts from ext.nn.comp.lang.c: 30-May-89 Tiny Lisp written in C Dr.
> ···@willow.Caltech.E (483)

> Does anyone know of a public domain lisp interpreter, written
> in a high-level language, preferably C, which can control
> an application like this?

And now for the monthly ELI posting.

I am the author of the Andrew System embedded lisp from CMU (called ELI
[Embedded Lisp Interpreter]).  It is written in very portable C and is
available on the X11R3 distribution which can be ftp'd from
expo.lcs.mit.edu (Internet: 18.30.0.212) in the file
"/contrib/eli-dist.tar".  It implements an "extended subset" of Common
Lisp, and is currently in use as a filtering language for the Andrew
Message System.  It is a fairly stable if not utterly robust package,
but when you buy into ELI, you will also be among the first to know
about its upcoming successor, ELSIE (the "Embedded Lisp [Scheme]
Interpreter, 'ELSIE'"), which will be even smaller and faster than ELI
and which will not be an "extended subset" of anything; it will be a
proper superset of the Revised^4 Report on Scheme, complete with a Lisp
compatability module and tons of other wonderful features such as
dynamic loading and user-defined types.  If you are interested in
discussing ELI or ELSIE, or indeed any other part of the Andrew system,
please check out comp.soft-sys.andrew or subscribe to the mailing list
"info-andrew" by sending mail to ····················@andrew.cmu.edu". 
If you are unable to ftp from expo.lcs.mit.edu, send me mail and I can
mail you the ELI distribution.  Let me know if I can send anyone any
more information.


                             ==============
                             Bob Glickstein
                           ITC Database Group
                      Information Technology Center
                       Carnegie Mellon University
                             Pittsburgh, PA
                             ==============
From: Robert Steven Glickstein
Subject: Oops Re: ELI (was Re: Tiny Lisp written in C)
Date: 
Message-ID: <oYV49Pe00VsnA0qEc2@andrew.cmu.edu>
> Excerpts from ext.nn.comp.lang.c: 31-May-89 ELI (was Re: Tiny Lisp
> writ.. Robert S. ··········@and (1936)

> I am the author of the Andrew System embedded lisp from CMU (called ELI
> [Embedded Lisp Interpreter]).  It is written in very portable C and is
> available on the X11R3 distribution which can be ftp'd from
> expo.lcs.mit.edu (Internet: 18.30.0.212) in the file
"/contrib/eli-dist.tar".

Oops.  I should have said that X11R3 (which includes Andrew, which
includes ELI) can be ftp'd from expo, or you can get ELI all by itself,
also from expo.  The ELI-only distribution is in /contrib/eli-dist.tar;
X11R3 is elsewhere on the same system.  Also, the ELI sources were
posted on comp.soft-sys.andrew a while ago, and if anyone archives that,
you can get it from there.


                             ==============
                             Bob Glickstein
                           ITC Database Group
                      Information Technology Center
                       Carnegie Mellon University
                             Pittsburgh, PA
                             ==============
From: Niels Mayer
Subject: Re: ELI (was Re: Tiny Lisp written in C)
Date: 
Message-ID: <3450@hplabsz.HPL.HP.COM>
I recently checked out the new version of ELI on expo.lcs.mit.edu by Bob
Glickstein to find out whether any of the bugs I have found had been fixed.
They weren't unfortunately.... here's some previous postiungs I've made
about ELI bugs, just so that you can know to avoid these problems with ELI.

ELI is a nifty package, and I'm not trying to denigrate BobG's work. I just
wanted to inform y'all of existing bugs in ELI before y'all go off and
waste your precious time tracking down anomalous behavior in ELI.

------- Forwarded Messages

To: ···········@andrew.cmu.edu
Subject: BGLISP/ELI -- question, contribution, bugs, and "features"
Organization: Hewlett-Packard Labs, Software Technology Lab, Palo Alto, CA.
X-Mailer: mh6.6
Date: Tue, 22 Nov 88 01:08:07 PST
Message-ID: <·············@hplnpm>
From: Niels P. Mayer <·····@hplnpm>


Here are some bugs I've found using ELI/bglisp as released in the X11r3
tape (under contrib/toolkits/andrew/overhead/eli/). I'm running on a
HP9000s350 under HPUX 6.2.

An aside -- Are any of you out there using FLAMES and/or ELI/bglisp in
your applications? I'd love to hear what sort of mail processing you're
doing with FLAMES, and what kinds of user-customizable applications you've
dreamed up using ELI. Also, I'd like to hear reports of ELI's reliability,
scalability, speed, etc. Me? I'm using ELI to build a "widget interpreter"
using the HP Xwidgets. The widget iterpreter will be part of a hybrid
lisp/c development platform for a highly customizable CSCW/mail system that
I'm prototyping.  It will NOT be based on AMS/FLAMES, though I might steal
EZ for displaying/editing multimedia messages.

Oh, and I also have added a few useful primitives to ELI -- lisp interfaces
to the unix subroutines popen(3S), pclose(3S), fopen(3S), fclose(3S),
fgets(3S), fputs(3S), and fscanf(3S). Anybody want these?

And finally, here's da bugs -- anybody got a fix?

- ------------------------------------------------------------------------------
(1) I found this bug in "let", while tracking down a misfeature in "do"
(see (2) below):

(setq a 666)
(progn
  (printf "before let a = %S\n" a)
  (let ((a 3))
    (progn
      (printf "in let, before setq, a = %S\n" a)
      (setq a 5)
      (printf "in let, after setq, a =  %S\n" a)
      )
    )
  (printf "after let, a = %S\n" a)
  )

Evaling the above two expressions gives the following results.

> BGLisp> (666)
> BGLisp> before let a = 666
> in let, before setq, a = 3
> in let, after setq, a =  3
> after let, a = 5
> (T)

In other words, the setq within the let is being bound to the "a" outside
of the scope of the let. This pretty much makes "let" and "let*" useless 
for creating local variables, since you can never change their values.

- ------------------------------------------------------------------------------

(2) The reason why I tried out what "let" was doing is because a simple
test program I was writing using "do" was failing for totally unexpected
reasons. The documentation for the "do" and "do*" functions indicates that
local variables of "do" retain their initializer values while in the do
loop unless a step value is given. Although this goes against all usages of
"do" that I've come across in the other dialects of lisp i've used, I
figured I could get by with a construct like the following in order
to allow variables declared in "do"'s varlist to act as local temporary
variables (as if declared in a "let" block just outside of the "do"):

(do
  ((i 0 i)) 	
  (<test> <return>)
  <body>
  )

Unfortunately, we see the same error here as we did in "let" above, namely
that if I try to do a (setq i 2) in <body>, I won't be setting the i that
was locally bound in "do". Within the scope of "do", variable i will always
stay at 0.

Ok, fine, so I figured that bglisp's "do" local variables insist on getting
set and altered through the <init> and <step> expressions in the varlist.
So I tried putting the local variables that need to be setq'd inside a
"let" that wraps the "do":

(let ((j 0))
  (do
   ((i 0 (+ i 1)))
   ((equal j 100) j)
   (progn
     (setq j i)
     (printf "%S\n" j))
   ))

The result is of course an infinite loop, with bglisp printing out "0\n"
until I ^C it. The reason for the behaviour is mentioned in (1) above.
Granted, the above is a contrived example that needn't be written the way
it is to achieve the desired effect. It is really just a simplification of
a problem I was having with a more complicated procedure that required the
ability to set and use local variables within the <body> of the "do".

- ------------------------------------------------------------------------------

(3) The following is probably less of a "bug" and more of a "feature" of
bglisp, eli. However, it will certainly cause much confusion for those that
know some of the well-known dialects of lisp such as common lisp, maclisp,
franzlisp, gnuemacs-lisp, etc:

All the lisps I've come across that take a <body> expression, such as "do",
"let", "cond", "defun", etc, allow <body> to be a sequence of expressions.
In bglisp/eli forces you to wrap any such sequence of expressions in a
progn as in the example above. Is this perhaps because bglisp is derived
from Gosling's mocklisp?

- -- Niels "tomorrow -- we'll work on closures and continuations! :-)" Mayer.


------- Message 2

To: Robert Steven Glickstein <·····@andrew.cmu.edu>
Subject: Eli Bug?
Organization: Hewlett-Packard Labs, Software Technology Lab, Palo Alto, CA.
X-Mailer: mh6.6
Date: Sun, 27 Nov 88 18:39:48 PST
Message-ID: <··············@hplnpm>
From: Niels P. Mayer <·····@hplnpm>


I've gotten part of my "widget interpreter" (WINTERP) working using Eli,
and I think I may have found some memory allocation problems caused by
reading or evaling long strings.

to reproduce the problem, try the following:

create a file "foo.l" containing
(setq a
"1234567890....."
)

where "1234567890....." is really a >512 character string.

Startup bglisp and do 
(read "foo.l")

Follow that by some other operation like
(+ 1 1)

On my system in bglisp, it will print out some character right after the
CRLF following (+ 1 1), for example:

BGLisp> (read "foo.l")
("12345678901234567890123456789012345678901234567890123456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
7890123456789012345678901234567890123456789012345678901234567890123456789012345
6789012345678901234561234567890123456789012345678901234567890123456789012345678
9012345678901234567890123456789012345678901234567890123456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
7890123456789012345678901234567890123456")
BGLisp> (+ 1 1)
9
BGLisp> 2

In this case, a spurious "9" was printed out, indicating that something
strange is going on.

In bglisp, this problem doesn't seem to cause any core dumps, and it's hard
for me to say what data is getting corrupted. However, in my widget
interpreter, the problem isn't so benign, since I always get a core dump
the next time an X Event is processed, or the next time WINTERP accepts a
socket connection from a widget interpreter client (lisp input to ELI in
WINTERP comes from a socket...). After many hours of tracking down false
leads in my server/client code, I finally arrived upon the problem caused
by long strings being loaded.

Any ideas on what's going wrong?

Also, do you have any suggestions for fixing the let/setq bug mentioned
in my info-andrew note?

Given the proper guidance, I'd be willing to help fix bugs in Eli.
I'm knee-deep in the code as is, and I need to fix the let/setq
problem before I start writing any serious applications with the widget
interpreter.

Thanks,

- -- Niels.

------- Comment on Above Message by Niels Mayer:

The above bug is caused by a LEX limitation:

from the lex manpage:

>      WARNINGS
>
>           The token buffer in the program built by  lex  is  of  fixed
>           length,
> 
>                   yytext[YYLMAX]
> 
>           where YYLMAX is defined to be 200 characters.   Overflow  of
>           this array is not detected in the lex.yy.c program.

The value of "200" seems to correspond to the breakpoint in tokenlength
around which I was noticing strange behaviour, and indeed, in elil.c i find
>	# define YYLMAX 200

A workaround to the problem of reading in long strings is to use strcat

instead of 
	"veryveryverylongstring......"
use
	(strcat "very" "very" "very" "long" "string" "...")

------- Message 3

Date: Sat,  8 Apr 89 01:07:38 -0500 (CDT)
From: Bill Janssen <························@mcc.com>
To: ················@andrew.cmu.edu, ···········@andrew.cmu.edu
Subject: bug in eli "and"

[from the help entry for eli-functions:]

> The following standard Common LISP primitives are supported in eli.  They
> should work exactly as they're supposed to work in Common LISP, and hence are
> not explained here.  Consult a Common LISP manual for an explanation:

The "and" function in eli is documented to work as CommonLisp "and" does, but it
doesn't.

CL:    (and t "foo") => "foo"

ELI:   (and t "foo") => t

I imagine this is also true for "or".

Bill

------- Message 4

Date: Sat,  8 Apr 89 01:12:17 -0500 (CDT)
From: Bill Janssen <························@mcc.com>
To: ················@andrew.cmu.edu, ···········@andrew.cmu.edu
Subject: bug in eli "cond"

"cond" is documented to work like the "cond" in CommonLisp, but it doesn't.

CL:   (cond ((boundp 'a) (+ 2 3) (+ 3 4)) (t nil)) => nil

ELI:  (cond ((boundp 'a) (+ 2 3) (+ 3 4)) (t nil)) => *error*

where "*error*" indicates that the interpreter doesn't like the syntax of the
first cond clause.

Bill

------- Message 5

Date: Sat,  8 Apr 89 01:16:07 -0500 (CDT)
From: Bill Janssen <························@mcc.com>
To: ················@andrew.cmu.edu, ···········@andrew.cmu.edu
Subject: bug in ELI "let" and "let*"

The ELI functions "let" and "let*" are documented to work as their CommonLisp
version do.  They don't.  In CommonLisp, both let and let* establish an
implicit progn, so that a number of forms can be evaluated sequentially in the
body of the let.  The value of the last form evaluated is returned as the value
of the let.  ELI only allows one form in its "let".

Bill

------- End of Forwarded Messages
From: Niels Mayer
Subject: ELI vs XLISP // ELSIE vs XSCHEME (was ELI (was Re: Tiny Lisp written in C))
Date: 
Message-ID: <3451@hplabsz.HPL.HP.COM>
Does anyone have some opinions on how ELI compares to XLISP for the purpose
of embedding an interpretive customization and extension language within a
mostly C-implemented application? Also, how will ELSIE compare to XSCHEME
as an embedded language inside an application?

My initial experiments show that a  application written with XLISP has a
smaller runtime image than one written in ELI. Furthermore, the ELI process
seems to grow without bound on certain forms of lisp computations, namely,
extensive string processing and highly recursive functions.

For example, when I run the ackermann function (tak 18 12 6) in ELI/bglisp,
the process will grow without bound until I run out of swap space. Running
smaller ackermann values will allow the computation to complete, but
generally, the process will grow from an original size of about 150 kBytes
to 4 megabytes (!).

The same ackermann fn running in XLISP has the process size stay at under
230 kBytes from start to finish. Furthermore, XLISP seems to be able to run
the smaller ackermann fn much more quickly than ELI/bglisp (that is, the
ackermann call that would run under ELI/bglisp w/o running out of memory).
(Much of the slowdown can be attributed to swapping that monster blisp
process.)

I haven't looked at the internals of XLISP enough (yet) to understand why
it is more memory- and time- efficient than ELI. It seems to use the "fixed
size memory" model of lisp, in which the lisp heap stays at a fixed size
and garbage collections occur when more space is needed.

Perhaps the problem in ELI/bglisp is that it only tries to garbage collect
every time it hits the top-level evaluator. That can be a problem if you're
running a function that runs a long time and conses up alot of stuff (or
just creates a large lisp stack due to recursion).  

Any further comments on size/efficiency comparisons between ELI and XLISP
would be appreciated.

-- Niels

PS: For people wondering about the code sizes mentioned above, I'm running
on an HP9000s370 (33Mhz 68030) running HPUX 6.5 (un*x).
From: Robert Steven Glickstein
Subject: Re: ELI vs XLISP // ELSIE vs XSCHEME (was ELI (was Re: Tiny Lisp written in C))
Date: 
Message-ID: <kYY2see00VsnALRFZO@andrew.cmu.edu>
> Excerpts from ext.in.info-andrew: 8-Jun-89 ELI vs XLISP // ELSIE vs XS..
> Niels ·····@hplabs.hp.co (2051)

> Does anyone have some opinions on how ELI compares to XLISP for the
> purpose
> of embedding an interpretive customization and extension language within
> a
> mostly C-implemented application?

I have almost no experience with XLisp embedding, so I can't properly
answer this question, but I do acknowledge several problems with ELI,
most of which stem from the fact that in its initial design and
throughout 75% of its writing, it was not intended as a general-purpose
embedded language.  It is to correct the many deficiencies of ELI that
the writing of ELSIE has been undertaken (a prototype version is within
a week of completion).

> Also, how will ELSIE compare to XSCHEME
> as an embedded language inside an application?

Hopefully much better than ELI compares to XLisp.  As I understand it,
@rumor{work on XScheme is not progressing very far, as the author is
concentrating on improving the more mature XLisp.}  The features
intended for the release version of ELSIE certainly exceed the
capabilities of XScheme.

> My initial experiments show that a  application written with XLISP has a
> smaller runtime image than one written in ELI. Furthermore, the ELI
> process
> seems to grow without bound on certain forms of lisp computations,
> namely,
> extensive string processing and highly recursive functions.

Mea maxima culpa.

> For example, when I run the ackermann function (tak 18 12 6) in
> ELI/bglisp,
> the process will grow without bound until I run out of swap space.
> Running
> smaller ackermann values will allow the computation to complete, but
> generally, the process will grow from an original size of about 150
> kBytes
> to 4 megabytes (!).

Yikes!  My pride is thoroughly swallowed.

> [...] Perhaps the problem in ELI/bglisp is that it only tries to garbage
> collect
> every time it hits the top-level evaluator. That can be a problem if
> you're
> running a function that runs a long time and conses up alot of stuff (or
> just creates a large lisp stack due to recursion).  

Absolutely right.  A bad hack at the last minute to compensate for my
decision against the "stop, mark-and-copy" form of garbage collecting
led to this problem.  ELSIE (which, like ELI, also does on-the-fly
GC'ing) overcomes this by deallocating objects the instant they can be
proven unneeded.  This, combined with ELSIE's properly-tail-recursive
evaluator (which ELI does not have) should virtually eliminate the size
problem.

> Any further comments on size/efficiency comparisons between ELI and XLISP
> would be appreciated.

Well, as I acknowledged above, ELI is a dog, albeit a more
well-documented library than XLisp.  ELSIE is my attempt to atone for
the sins committed during my undergrad days.  Although ELSIE will be
interpreted rather than compiled, it should be orders of magnitude
faster and smaller than ELI.

-Bob Glickstein