On Thursday, November 27, 2014 11:22:55 AM UTC-6, Kaz Kylheku wrote:
> On 2014-11-27, luser droog <
luser...@gmail.com> wrote:
> > I've posted my baby lisp for review over in comp.lang.lisp.
> >
> >
https://groups.google.com/d/topic/comp.lang.lisp/mpRg2BwGgdo/discussion
> >
> > But the C may be too heavy for the average reader there.
> > So I'd appreciate a look (and words) from some C people too.
>
> Here are some real comments, instead of nitpicking about your style,
> whcih is basically consistent and clear, once the reader accepts it.
Much obliged. This is what I had hoped for.
>
> The code is entirely transparent to me,
Each time I read this, I get flashes from David Lynch's Dune.
The scene where the Emperor meets the Guild Navigator in his
enormous elephant tank and he says "You are transparent.
I see through you."
Spooky.
>and I don't care about implicit int;
> it's a deprecated language feature, but everyone has understood it since
> K&R published the first edition of their book in 1978.
>
> Ease of notation is very important, at least until the point that you have a
> working Lisp compiler. Until that point, you're writing a lot of code inside
> the interpreter, which is painful unless you "bend" the C language somehow.
> When you have a compiler going, you can write code in Lisp, and it can spit out
> C (or assembly or whatever). The generated C then no longer has to be readable,
> but before then, it helps you to have a notation you can live with.
>
> Your program is of little practical use because you're denoting objects by
> integers, which index into a single array, so the entire heap has to be in a
> flat space. As a language, it's probably worse than any Lisp that has ever
> existed, including the early work by John McCarthy's group.
That is a severe limitation in the design I've chosen. But, but...
Hm. Can't think of an excuse. It can be changed. Bits from the address
could index an array of base-pointers, to split data across multiple
arrays. And it can be made to allocate chunks with malloc and coalesce
adjacent chunks if the union is still addressable by the remaining
address bits.
But the decisions went kind of like this: implicit int functions will
look more like the published spec, thus easier to verify; so the object
must be encapsulated in an int to achieve this. If the tag data comes
off of the bottom of the int, then the remaining bits can hold a signed
value, so long as right-shifting preserves signedness, hence the assert.
While not necessarily golfing this to the max, brevity was a goal.
The ultimate goal being to fit the entire interpreter comfortably,
needing no comments, on just a few pages. "Paper" portable.
>
> You have neglected to implement a garbage collector and your cons function just
> runs beyond the allocated range, always grabbing brand new memory:
>
> cons(x,y){int z;R z=n-m,*n++=x,*n++=y,z<<2;}
Totally right. Allocation and bounds checking. Yes, it would/will need
garbage collection before it will be useful for an application.
I was so excited that SETQ was working that I want to show the world!
>
> You have dropped to a nonportable memory scheme involving catching segfaults
> and using sbrk. This is not compatible with the use of anything else in
> the image, like C libraries that use malloc. Eventually your heap will
> crash into something, like mmap'ed library. No language today can afford
> to be designed to be this hostile against integration.
That. Yeah. Totally not portable. But, it's so cool. Just take the memory
and run: no "malloc overhead", like a car with no firewall I suppose.
I started doing this with tiny interpreters like
http://codegolf.stackexchange.com/questions/19151/build-interpreter-for-non-existent-language/19240#19240
http://codegolf.stackexchange.com/questions/16476/implement-the-universal-machine-emulator/18694#18694
and then it became a habit. It's pretty miraculous that printf wasn't
giving me problems.
>
> Your Lisp dialect is not robust. Though you detect type mismatches, you
> sweep them under the carpet. For instance, I noticed right off the bat that
> if x is not a cons then (rplaca x y) silently does nothing and returns zero,
> instead of raising an exception. Though it's good that the program doesn't
> crash in this situation, ignoring a problem isn't much better; someone
> trying to write a complicated program will pull their hair out debugging
> without any help.
>
> Implementing a Lisp without a plan for implementing exceptions from the get go
> is a nonstarter.
Hm. My first go-to idea would be setjmp/longjmp.
But it could also be a propagated error code.
My inca interpreter does one, and xpost does the other.
Is there a third way?
>
> I just noticed that your eq function is broken. eq is implementation
> equality in Lisp, and so rather than:
>
> eq(x,y){R atomp(x)&&atomp(y)?x==y:0;}
>
> it should really just be:
>
> eq(x,y){R x==y;} /* compare that the bits in x are the same as y */
>
> consider what happens if your eq is invoked like this:
>
> eq(a,a)
>
> and a is not an atom? It will return 0, incorrectly reporting that a is not eq
> to itself, which is the "hello world" base case for eq!
Indeed yes. I've been having that very bug.
The first DEFUN example from the micro-manual is
(DEFUN NULL(X)(EQ X NIL))
which has not been working.
>
> By the way, have a look at the Lisp500 project ("Lisp in 500 lines of C"), if
> you can still find it. It's something similar to yours.
I did stumble upon that, searching comp.lang.lisp for "DEFUN".
https://web.archive.org/web/20070317222332/http://www.modeemi.fi/~chery/lisp500/
If you thought mine had too many comments, it's your lucky lucky day.
I've made very little sense out of it so far, but I do consider it
inspirational.