Thursday, April 04, 2013

Building a Lisp Interpreter from Scratch -- Part 2: Core Forms

Before looking at the object model of pLisp, we turn our attention to the core forms in our interpreter. Core forms are the primitive expressions that need to be handled by the interpreter; they cannot be palmed off to the libraries, where they could be implemented in pLisp itself.

Here's a list of the core forms. Quite a few of them are there because of necessity (see above), while some of them are more for convenience, i.e, life as we know it would not end if they were absent. Also, if you want to do anything practical, say arithmetic, strings, arrays, and so on, and not end up with an interpreter that just manipulates symbols, you need things like +, -, ARRAY-GET, and ARRAY-SET (not to mention PRINT for output).

1. EQ tests for equality of content.
2. QUOTE, BACKQUOTE, COMMAandCOMMA-ATare not the operators' real symbols; they are indicated so to avoid confusion with punctuation (ditto for GT, but this has more to do with my laziness in working with HTML tags).
3. PROGN can actually be implemented as a macro using a series of LAMBDAs; I just went with a native implementation. Macros involving LAMBDAs are used for implementing WHILE and LET, however (the LET macro uses the MAP function in turn):

(defmacro while (condition &rest body)

`(((lambda (f) (set f (lambda ()

(if ,condition

(progn ,@body (f)))))) '())))

(defun map (f lst)

(if (null lst)

nil

(cons (f (car lst)) (map f (cdr lst)))))

(defmacro let (specs &rest body)

`((lambda ,(map car specs) ,@body) ,@(map cadr specs)))

4. The other comparison operators are implemented using macros.

5. LISTP can be implemented as a macro as well, through ATOM.

6. Strings are implemented as arrays, the corresponding GETand SETare again taken care of by macros.

Astute readers may be wondering by now what kind of a bastard Lisp they're looking at. I initially started out with Common Lisp in mind (though building pLisp as a Lisp-1), then made a detour into Scheme -- mainly for the continuations -- before I decided to persist with the veneer of CL (maybe not just the veneer; the macro system is more or less full CL; I didn't venture into Scheme syntax rules territory at all). Anyway, to a large extent, one dialect of Lisp can be made to look like another by liberal and injudicious usage of macros, so it doesn't matter that much for our purposes, I guess.