--- old/CHANGELOG	Fri Jul 15 19:31:15 2005
+++ CHANGELOG	Wed Aug 10 15:26:18 2005
@@ -4,3 +4,25 @@
 2005-07-15: 1.1: General cleanup and refcount bug fix in builtin.c.
 newscope() now calls throwoom so callers merely need return(0).
 New strings are initialized to null bytes.
+
+2005-07-18: 1.2: Removed dprint from preload.lisp.
+Added freelist/reuse of objects, making dropobj() an O(1) operation.
+
+2005-08-10: 1.3: Fixed missing incref in sub().
+Fixed missing call to throwoom from cons_tostring.
+Changed dont-expand to dont-macro-expand in preload.lisp for clarity.
+Added reverse/append, reverse, append and load-file to preload.lisp.
+Added cars, cdrs, cadrs, cadar, let*, +, -, *, and / to preload.lisp.
+Fixed macro definitions of map and unless in preload.lisp.
+Implemented reader.c in preload.lisp and simplified reader.c greatly.
+The repl no longer prints the result of the evaluation if it is false.
+scope.c's undefined_error is now allocated at runtime.
+Fixed missing decref(str) in string_to_integer.
+Changed string_tostring to the new string quoting character (" not |).
+Added string_length function.
+Added new_string function and renamed newstring to real_new_string.
+Fixed missing throwoom() in real_new_string.
+Removed extraneous lines in catch.
+Alway decref exception and exceptionvalue in throw (they can't be NULL).
+Removed extraneous lines in newobj.c.
+Fixed missing throwoom() in new_word.
--- old/Makefile	Mon Jul 18 20:22:02 2005
+++ Makefile	Mon Jul 18 20:26:08 2005
@@ -4,13 +4,14 @@
 #CFLAGS+=-g -DDEBUG
 SRCS=builtin.c cons.c float.c func.c integer.c main.c nil.c quote.c rawfunc.c reader.c scope.c stream.c string.c throw.c util.c word.c
 BUILDDIR=obj/
-VERSION=1.2
+VERSION=1.3
 DISTFILES=CHANGELOG Makefile lisp.h $(SRCS) preload.lisp
 
 $(BUILDDIR)mikelisp : $(SRCS:%.c=$(BUILDDIR)%.o) lisp.h
 	$(CC) $(CFLAGS) -o $@ $(SRCS:%.c=$(BUILDDIR)%.o)
 
 $(BUILDDIR)%.o : %.c lisp.h
+	@mkdir -p $(BUILDDIR)
 	$(CC) $(CFLAGS) -c -o $@ $<
 
 clean :
--- old/lisp.h	Mon Jul 18 20:22:02 2005
+++ lisp.h	Mon Jul 25 17:01:04 2005
@@ -1,4 +1,4 @@
-/* lisp.h   by Michael Thorpe   2005-07-18 */
+/* lisp.h   by Michael Thorpe   2005-07-25 */
 
 #ifndef OBJ_H
 #define OBJ_H
@@ -145,14 +145,16 @@
  *    -2 = io-error
  * other = character read/written
  */
+#ifdef DEBUG
 obj *writeobj(obj *stream,obj *o);
+#endif
 int real_sgetc(obj *stream);
 int real_speekc(obj *stream);
 int real_sputc(obj *stream,int c);
 int stream_init();
 
 /* string.c */
-obj *newstring(const char *data,unsigned long len);
+obj *real_new_string(const char *data,unsigned long len);
 int string_init();
 
 /* throw.c */
--- old/builtin.c	Fri Jul 15 19:29:50 2005
+++ builtin.c	Wed Aug 10 14:43:47 2005
@@ -1,4 +1,4 @@
-/* builtin.c   by Michael Thorpe   2005-07-15 */
+/* builtin.c   by Michael Thorpe   2005-08-10 */
 
 #include <ctype.h>
 #include <limits.h>
@@ -403,7 +403,7 @@
 	if(r) {
 		r->value.i=result;
 		if(overflow)
-			return(throw(overflowerror,r));
+			return(throw(incref(overflowerror),r));
 	}
 	return(r);
 }
--- old/cons.c	Fri Jul 15 19:29:50 2005
+++ cons.c	Wed Aug 10 14:45:44 2005
@@ -1,4 +1,4 @@
-/* cons.c   by Michael Thorpe   2005-07-14 */
+/* cons.c   by Michael Thorpe   2005-08-10 */
 
 #include <stdlib.h>
 #include <string.h>
@@ -60,7 +60,7 @@
 	a=(obj **)malloc((i+1)*sizeof(obj *));
 	if(!a) {
 		decref(in);
-		return(0);
+		return(throwoom());
 	}
 	l=1; /*  2 (for the open/close parens)
 	        -1 (for the "extra" space char on item 0) */
@@ -90,7 +90,7 @@
 		n++;
 		halfopen=1;
 	}
-	out=newstring(0,l);
+	out=real_new_string(0,l);
 	if(!out)
 		goto fail;
 	s=out->value.s.data;
--- old/float.c	Thu Dec  4 20:34:06 2003
+++ float.c	Mon Jul 25 17:02:03 2005
@@ -1,4 +1,4 @@
-/* float.c   by Michael Thorpe   2003-05-26 */
+/* float.c   by Michael Thorpe   2005-07-25 */
 
 #include <stdio.h>
 #include "lisp.h"
@@ -12,7 +12,7 @@
 	if(i==-1 || i>sizeof(buf))
 		return(throwrangecheck(in));
 	decref(in);
-	out=newstring(buf,i);
+	out=real_new_string(buf,i);
 	return(out);
 }
 
--- old/func.c	Mon Jul 11 11:42:38 2005
+++ func.c	Wed Aug 10 14:46:33 2005
@@ -1,4 +1,4 @@
-/* func.c   by Michael Thorpe   2005-07-11 */
+/* func.c   by Michael Thorpe   2005-08-10 */
 
 #include <string.h>
 #include "lisp.h"
@@ -29,24 +29,23 @@
 
 static obj *applyfunc(scope *s,obj *func,obj *args) {
 	obj *prog;
-	scope *t;
 
 	decscoperef(s);
-	t=newscope(incscoperef(globalscope));
-	if(!t) {
+	s=newscope(incscoperef(globalscope));
+	if(!s) {
 		decref(func);
 		decref(args);
 		return(0);
 	}
-	if(bindlist(t,func->value.func.args,args)) {
-		decscoperef(t);
+	if(bindlist(s,func->value.func.args,args)) {
+		decscoperef(s);
 		decref(args);
 		return(throwargumenterror(func));
 	}
 	prog=incref(func->value.func.prog);
 	decref(func);
 	decref(args);
-	return(evaluate(t,prog));
+	return(evaluate(s,prog));
 }
 
 static obj *func_tostring(obj *in) {
@@ -57,7 +56,7 @@
 	if(args) {
 		func=(in->value.func.prog->type->tostring)(incref(in->value.func.prog));
 		if(func) {
-			out=newstring(0,8+args->value.s.len+1+func->value.s.len+1);
+			out=real_new_string(0,8+args->value.s.len+1+func->value.s.len+1);
 			if(out) {
 				memcpy(out->value.s.data,"(lambda ",8);
 				memcpy(out->value.s.data+8,args->value.s.data,args->value.s.len);
--- old/integer.c	Mon Jul 18 20:22:02 2005
+++ integer.c	Mon Jul 25 17:03:00 2005
@@ -1,4 +1,4 @@
-/* integer.c   by Michael Thorpe   2005-07-18 */
+/* integer.c   by Michael Thorpe   2005-07-25 */
 
 #include <stdio.h>
 #include "lisp.h"
@@ -12,7 +12,7 @@
 	if(i==-1 || i>sizeof(buf))
 		return(throwrangecheck(in));
 	decref(in);
-	out=newstring(buf,i);
+	out=real_new_string(buf,i);
 	return(out);
 }
 
--- old/main.c	Mon Jul 18 20:22:02 2005
+++ main.c	Mon Jul 25 16:11:19 2005
@@ -1,4 +1,4 @@
-/* main.c   by Michael Thorpe   2005-07-18 */
+/* main.c   by Michael Thorpe   2005-07-25 */
 
 #include <stdio.h>
 #include "lisp.h"
@@ -50,7 +50,9 @@
 }
 
 int main() {
+#ifdef DEBUG
 	obj *o;
+#endif
 
 	if(scope_init()
 	|| builtin_init()
@@ -64,13 +66,16 @@
 		return(1);
 	}
 	if(tryit()) {
-		fprintf(stderr,"\ngot bad return value from tryit!\nEXCEPTION: ");
+		fprintf(stderr,"\ngot bad return value from tryit!\n");
+#ifdef DEBUG
+		fprintf(stderr,"EXCEPTION: ");
 		o=writeobj(incref(stderrobj),incref(exception));
 		decref(o);
 		fprintf(stderr,"\nEXCEPTION-VALUE: ");
 		o=writeobj(incref(stderrobj),incref(exceptionvalue));
 		decref(o);
 		fprintf(stderr,"\n");
+#endif
 		return(1);
 	}
 	decscoperef(globalscope);
--- old/nil.c	Mon Jul 18 20:22:02 2005
+++ nil.c	Mon Jul 25 17:03:08 2005
@@ -1,10 +1,10 @@
-/* nil.c   by Michael Thorpe   2005-07-18 */
+/* nil.c   by Michael Thorpe   2005-07-25 */
 
 #include "lisp.h"
 
 static obj *nil_tostring(obj *in) {
 	decref(in);
-	return(newstring("nil",3));
+	return(real_new_string("nil",3));
 }
 
 objtype nil_objtype={
--- old/quote.c	Tue Jul 12 16:38:32 2005
+++ quote.c	Mon Jul 25 17:03:15 2005
@@ -1,4 +1,4 @@
-/* quote.c   by Michael Thorpe   2005-07-12 */
+/* quote.c   by Michael Thorpe   2005-07-25 */
 
 #include <string.h>
 #include "lisp.h"
@@ -22,7 +22,7 @@
 	s=(in->value.o->type->tostring)(incref(in->value.o));
 	decref(in);
 	if(s) {
-		out=newstring(0,s->value.s.len+1);
+		out=real_new_string(0,s->value.s.len+1);
 		if(out) {
 			out->value.s.data[0]='\'';
 			memcpy(out->value.s.data+1,s->value.s.data,s->value.s.len);
--- old/rawfunc.c	Tue Jul 12 15:59:55 2005
+++ rawfunc.c	Mon Jul 25 17:03:23 2005
@@ -1,4 +1,4 @@
-/* rawfunc.c   by Michael Thorpe   2005-07-12 */
+/* rawfunc.c   by Michael Thorpe   2005-07-25 */
 
 #include <stdio.h>
 #include "lisp.h"
@@ -62,7 +62,7 @@
 	if(i==-1 || i>sizeof(buf))
 		return(throwrangecheck(in));
 	decref(in);
-	out=newstring(buf,i);
+	out=real_new_string(buf,i);
 	return(out);
 }
 
--- old/reader.c	Fri Jul 15 19:29:50 2005
+++ reader.c	Wed Aug 10 14:57:57 2005
@@ -1,10 +1,10 @@
-/* reader.c   by Michael Thorpe   2005-07-15 */
+/* reader.c   by Michael Thorpe   2005-08-10 */
 
 #include <ctype.h>
 #include <stdlib.h>
 #include "lisp.h"
 
-static obj *close_paren,*dot_word,*list_word,*no_object,*reader_error,*unquote_word;
+static obj *close_paren,*dot_word,*reader_error;
 
 static obj *macro_tick(obj *stream) {
 	obj *o;
@@ -115,29 +115,6 @@
 	return(incref(close_paren));
 }
 
-static obj *macro_comma(obj *stream) {
-	obj *cons,*foo;
-
-	foo=read_object(stream);
-	if(!foo) {
-		if(real_eqv(exception,eoferror))
-			return(throw(incref(reader_error),stream));
-		decref(stream);
-		return(0);
-	}
-	decref(stream);
-	cons=newlist(2);
-	if(!cons) {
-		decref(foo);
-		return(0);
-	}
-	decref(CAR(cons));
-	CAR(cons)=incref(unquote_word);
-	decref(CADR(cons));
-	CADR(cons)=foo;
-	return(cons);
-}
-
 static obj *macro_semicolon(obj *stream) {
 	int c;
 
@@ -150,92 +127,15 @@
 			return(throw(incref(ioerror),stream));
 		case '\n':
 		case '\r':
-			decref(stream);
-			return(incref(no_object));
-		}
-	}
-}
-
-static obj *quasiquote(obj *arg) {
-	obj *new,*old,*result,*tmp;
-
-	if(arg->type==&nil_objtype)
-		return(arg);
-	if(arg->type != &cons_objtype) {
-		result=newobj(&quote_objtype);
-		if(!result) {
-			decref(arg);
-			return(0);
-		}
-		result->value.o=arg;
-		return(result);
-	}
-	if(CAR(arg)==unquote_word && CDR(arg)->type==&cons_objtype && CDDR(arg)==&nilobj) {
-		result=incref(CADR(arg));
-		decref(arg);
-		return(result);
-	}
-	result=newlist(2);
-	if(!result) {
-		decref(arg);
-		return(0);
-	}
-	decref(CAR(result));
-	CAR(result)=incref(list_word);
-	new=CDR(result);
-	old=arg;
-	while(1) {
-/*
- * At this point:
- *   new is !0
- *   old and new are pointing to the same place on their respective lists
- */
-		tmp=quasiquote(incref(CAR(old)));
-		if(!tmp) {
-			decref(result);
-			decref(arg);
-			return(0);
+			return(read_object(stream));
 		}
-		decref(CAR(new));
-		CAR(new)=tmp;
-		old=CDR(old);
-		if(old->type != &cons_objtype)
-			break;
-		tmp=newlist(1);
-		if(!tmp) {
-			decref(result);
-			decref(arg);
-			return(0);
-		}
-		decref(CDR(new));
-		CDR(new)=tmp;
-		new=CDR(new);
 	}
-	tmp=quasiquote(incref(old));
-	if(!tmp) {
-		decref(result);
-		decref(arg);
-		return(0);
-	}
-	decref(CDR(new));
-	CDR(new)=tmp;
-	decref(arg);
-	return(result);
-}
-
-static obj *macro_backtick(obj *stream) {
-	obj *foo;
-
-	foo=read_object(stream);
-	if(!foo)
-		return(0);
-	return(quasiquote(foo));
 }
 
 #define MAX_STRING 8192
 static char string_buf[MAX_STRING+1];
 
-static obj *macro_verticalbar(obj *stream) {
+static obj *macro_doublequote(obj *stream) {
 	int c,i=0,seenbackslash=0;
 
 	while(1) {
@@ -248,10 +148,10 @@
 			seenbackslash=!seenbackslash;
 			if(seenbackslash)
 				continue;
-		} else if('|'==c) {
+		} else if('"'==c) {
 			if(!seenbackslash) {
 				decref(stream);
-				return(newstring(string_buf,i));
+				return(real_new_string(string_buf,i));
 			}
 			seenbackslash=0;
 		}
@@ -264,16 +164,9 @@
 #define MAX_TOKEN 128
 static char reader_buf[MAX_TOKEN+1];
 
-#define ES_NORMAL 0
-#define ES_SINGLE 1
-#define ES_MULTIPLE 2
-#define ES_MULTIPLESINGLE 3
-
-/* This should be static */
 obj *read_object(obj *stream) {
 	obj *o;
 	int c,buflen=0,isnum=0;
-	int escapestate=ES_NORMAL;
 	char *tmp;
 
 	if(stream->type != &stream_objtype)
@@ -281,55 +174,35 @@
 	while(1) {
 		c=real_speekc(stream);
 		if(c==-1) {
-			if(escapestate==ES_NORMAL && buflen)
+			if(buflen)
 				break;
 			return(throw(incref(eoferror),stream));
 		}
 		if(!isascii(c))
 			return(throw(incref(reader_error),stream));
 		if(isspace(c)) {
-			if(escapestate==ES_NORMAL) {
-				if(buflen)
-					break;
-				else {
-					real_sgetc(stream);
-					continue;
-				}
-			}
-		}
-		/* Terminating macro characters */
-		if(escapestate==ES_NORMAL && (c=='\'' || c=='(' || c==')' || c==',' || c==';' || c=='`' || c=='|')) {
 			if(buflen)
 				break;
-			real_sgetc(stream);
-			incref(stream);
-			switch(c) {
-			case '\'': o=macro_tick(stream); break;
-			case '(': o=macro_openparen(stream); break;
-			case ')': o=macro_closeparen(stream); break;
-			case ',': o=macro_comma(stream); break;
-			case ';': o=macro_semicolon(stream); break;
-			case '`': o=macro_backtick(stream); break;
-			case '|': o=macro_verticalbar(stream); break;
-			default: o=0; /* This is just to shut gcc up */
-			}
-			if(o && real_eqv(o,no_object)) {
-				decref(o);
+			else {
+				real_sgetc(stream);
 				continue;
 			}
-			decref(stream);
-			return(o);
 		}
+		if(buflen && (c=='"' || c=='\'' || c=='(' || c==')' || c==';'))
+			break;
 		real_sgetc(stream);
-		if(c=='\\' && !(escapestate&ES_SINGLE)) {
-			escapestate |= ES_SINGLE;
-			continue;
-		}
-		if(c=='"' && !(escapestate&ES_SINGLE)) {
-			escapestate ^= ES_MULTIPLE;
-			continue;
+		switch(c) {
+		case '"':
+			return(macro_doublequote(stream));
+		case '\'':
+			return(macro_tick(stream));
+		case '(':
+			return(macro_openparen(stream));
+		case ')':
+			return(macro_closeparen(stream));
+		case ';':
+			return(macro_semicolon(stream));
 		}
-/* Is everything else a constituent character? */
 		if((!buflen || (buflen==1 && reader_buf[0]=='-')) && isdigit(c))
 			isnum=1;
 		if(isnum && !isdigit(c))
@@ -337,7 +210,6 @@
 		reader_buf[buflen++]=c;
 		if(buflen==MAX_TOKEN+1)
 			return(throw(incref(reader_error),stream));
-		escapestate &= ~ES_SINGLE;
 	}
 	decref(stream);
 	if(isnum) {
@@ -356,13 +228,10 @@
 int reader_init() {
 	if(!(close_paren=newword(")",1))
 	|| !(dot_word=newword(".",1))
-	|| !(list_word=newword("list",4))
-	|| !(no_object=newword("no-object",9))
 	|| store_builtin_ns1("read-object",read_object)
-	|| !(reader_error=newword("reader_error",12))
-	|| !(unquote_word=newword("unquote",7)))
+	|| !(reader_error=newword("reader-error",12)))
 		return(1);
-	INC_KNOWN_OBJECTS(6);
+	INC_KNOWN_OBJECTS(3);
 	return(0);
 }
 
--- old/scope.c	Mon Jul 18 20:22:02 2005
+++ scope.c	Wed Aug 10 14:58:55 2005
@@ -1,4 +1,4 @@
-/* scope.c   by Michael Thorpe   2005-07-18 */
+/* scope.c   by Michael Thorpe   2005-08-10 */
 
 #include <stdlib.h>
 #include <string.h>
@@ -19,7 +19,7 @@
 static scope topscope={1,0,0};
 scope *globalscope=0;
 
-static obj undefined_error={&word_objtype,{refcount:1},{s:{"undefined",9}}};
+static obj *undefined_error;
 
 /* real_lookup doesn't decref/incref anything */
 static entry *real_lookup(scope *scope,obj *name) {
@@ -100,7 +100,7 @@
 	e=real_lookup(scope,name);
 	if(!e) {
 		decscoperef(scope);
-		return(throw(incref(&undefined_error),name));
+		return(throw(incref(undefined_error),name));
 	}
 	decref(name);
 	val=incref(e->value);
@@ -164,9 +164,11 @@
 
 int scope_init() {
 	if(!(globalscope=newscope(incscoperef(&topscope)))
+	|| !(undefined_error=newword("undefined",9))
 	|| store_builtin_s2("#define",define)
 	|| store_builtin_s2("#define-local",define_local))
 		return(1);
+	INC_KNOWN_OBJECTS(1);
 	return(0);
 }
 
--- old/stream.c	Fri Jul 15 19:29:50 2005
+++ stream.c	Mon Jul 25 17:03:39 2005
@@ -1,4 +1,4 @@
-/* stream.c   by Michael Thorpe   2005-07-14 */
+/* stream.c   by Michael Thorpe   2005-07-25 */
 
 #include <limits.h>
 #include <stdio.h>
@@ -192,7 +192,7 @@
 	if(i==-1 || i>=sizeof(buf))
 		return(throwrangecheck(in));
 	decref(in);
-	out=newstring(buf,i);
+	out=real_new_string(buf,i);
 	return(out);
 }
 
@@ -222,6 +222,7 @@
 	return(string);
 }
 
+#ifdef DEBUG
 obj *writeobj(obj *stream,obj *o) {
 	obj *s;
 
@@ -232,6 +233,7 @@
 	}
 	return(write_string(stream,s));
 }
+#endif
 
 int real_sgetc(obj *stream) {
 	int c;
@@ -273,8 +275,7 @@
 	|| store_builtin_ns1("read-char",sgetc)
 	|| store_builtin_ns1("peek-char",speekc)
 	|| store_builtin_ns2("write-char",sputc)
-	|| store_builtin_ns2("write-string",write_string)
-	|| store_builtin_ns2("write-object",writeobj))
+	|| store_builtin_ns2("write-string",write_string))
 		return(1);
 	in->value.stream.readable=1;
 	in->value.stream.writable=0;
--- old/string.c	Fri Jul 15 19:29:50 2005
+++ string.c	Wed Aug 10 15:04:03 2005
@@ -1,5 +1,6 @@
-/* string.c   by Michael Thorpe   2005-07-14 */
+/* string.c   by Michael Thorpe   2005-08-10 */
 
+#include <assert.h>
 #include <limits.h>
 #include <stdlib.h>
 #include <string.h>
@@ -79,6 +80,7 @@
 		return(throwtypeerror(str));
 	if(l==LONG_MIN || l==LONG_MAX)
 		return(throwrangecheck(str));
+	decref(str);
 	i=newobj(&integer_objtype);
 	if(i)
 		i->value.i=l;
@@ -101,25 +103,45 @@
 
 	for(i=j=0;i<in->value.s.len;i++) {
 		switch(in->value.s.data[i]) {
-		case '\0': case '\\': case '|': j++; break;
+		case '\0': case '\\': case '"': j++; break;
 		}
 	}
-	o=newstring(0,in->value.s.len+2+j);
+	o=real_new_string(0,in->value.s.len+2+j);
 	if(!o)
 		return(throwoom());
-	o->value.s.data[0]='|';
+	o->value.s.data[0]='"';
 	for(i=0,j=1;i<in->value.s.len;i++) {
 		switch(in->value.s.data[i]) {
-		case '\0': case '\\': case '|': o->value.s.data[j++]='\\'; break;
+		case '\0':
+			o->value.s.data[j++]='\\';
+			o->value.s.data[j++]='0';
+			break;
+		case '\\':
+		case '"':
+			o->value.s.data[j++]='\\';
+		default:
+			o->value.s.data[j++]=in->value.s.data[i];
+			break;
 		}
-		o->value.s.data[j++]=in->value.s.data[i];
 	}
-	o->value.s.data[j++]='|';
-	o->value.s.len=j;
+	o->value.s.data[j++]='"';
+	assert(o->value.s.len==j);
 	decref(in);
 	return(o);
 }
 
+static obj *string_length(obj *str) {
+	obj *l;
+
+	if(str->type != &string_objtype)
+		return(throwtypeerror(str));
+	l=newobj(&integer_objtype);
+	if(l)
+		l->value.i=str->value.s.len;
+	decref(str);
+	return(l);
+}
+
 static obj *substring(obj *str,obj *offobj,obj *lenobj) {
 	obj *substr;
 	unsigned long off,len;
@@ -160,18 +182,18 @@
 		decref(str);
 		return(throwrangecheck(incref(&nilobj)));
 	}
-	substr=newstring(str->value.s.data+off,len);
+	substr=real_new_string(str->value.s.data+off,len);
 	decref(str);
 	return(substr);
 }
 
-obj *newstring(const char *data,unsigned long len) {
+obj *real_new_string(const char *data,unsigned long len) {
 	obj *o;
 	char *s;
 
 	s=(char *)malloc(len);
 	if(!s)
-		return(0);
+		return(throwoom());
 	o=newobj(&string_objtype);
 	if(!o) {
 		free(s);
@@ -186,11 +208,25 @@
 	return(o);
 }
 
+static obj *new_string(obj *o) {
+	obj *r;
+
+	if(o->type != &integer_objtype)
+		return(throwtypeerror(o));
+	if(o->value.i<0)
+		return(throwrangecheck(o));
+	r=real_new_string(0,o->value.i);
+	decref(o);
+	return(r);
+}
+
 int string_init() {
 	if(store_builtin_ns2("get-char",get_char)
+	|| store_builtin_ns1("new-string",new_string)
 	|| store_builtin_ns3("put-char",put_char)
 	|| store_builtin_ns1("string->integer",string_to_integer)
 	|| store_builtin_ns1("string->symbol",string_to_symbol)
+	|| store_builtin_ns1("string-length",string_length)
 	|| store_builtin_ns3("substring",substring))
 		return(1);
 	return(0);
--- old/throw.c	Wed Jul 13 15:54:20 2005
+++ throw.c	Wed Aug 10 15:05:30 2005
@@ -1,4 +1,4 @@
-/* throw.c   by Michael Thorpe   2005-07-13 */
+/* throw.c   by Michael Thorpe   2005-08-10 */
 
 #include "lisp.h"
 
@@ -41,9 +41,6 @@
 		}
 		decref(tmp);
 		return(evaluate(s,handler));
-		decscoperef(s);
-		decref(handler);
-		return(0);
 	}
 	decref(type);
 	decscoperef(s);
@@ -52,10 +49,8 @@
 }
 
 obj *throw(obj *type,obj *value) {
-	if(exception)
-		decref(exception);
-	if(exceptionvalue)
-		decref(exceptionvalue);
+	decref(exception);
+	decref(exceptionvalue);
 	exception=type;
 	exceptionvalue=value;
 	return(0);
--- old/util.c	Mon Jul 18 20:22:02 2005
+++ util.c	Wed Aug 10 15:06:00 2005
@@ -1,4 +1,4 @@
-/* util.c   by Michael Thorpe   2005-07-18 */
+/* util.c   by Michael Thorpe   2005-08-10 */
 
 #include <stdlib.h>
 #include <string.h>
@@ -99,8 +99,6 @@
 	firstobj=o;
 #endif
 	return(o);
-	if(o->type->dropobj)
-		(o->type->dropobj)(o);
 }
 
 int register_objtype(objtype *type) {
--- old/word.c	Fri Jul 15 19:29:50 2005
+++ word.c	Wed Aug 10 15:07:22 2005
@@ -1,4 +1,4 @@
-/* word.c   by Michael Thorpe   2005-07-14 */
+/* word.c   by Michael Thorpe   2005-08-10 */
 
 #include <stdlib.h>
 #include <string.h>
@@ -15,7 +15,7 @@
 static obj *word_tostring(obj *in) {
 	obj *out;
 
-	out=newstring(in->value.s.data,in->value.s.len);
+	out=real_new_string(in->value.s.data,in->value.s.len);
 	decref(in);
 	return(out);
 }
@@ -26,7 +26,7 @@
 
 	s=(char *)malloc(len);
 	if(!s)
-		return(0);
+		return(throwoom());
 	o=newobj(&word_objtype);
 	if(!o) {
 		free(s);
--- old/preload.lisp	Mon Jul 18 20:23:24 2005
+++ preload.lisp	Wed Aug 10 15:11:33 2005
@@ -1,3 +1,5 @@
+; preload.lisp   by Michael Thorpe   2005-08-10
+
 (#define '#f (= 1 2))
 (#define '#t (= 1 1))
 (#define 'pair? (#lambda '(o) '(eqv? 'cons (object-type o))))
@@ -20,8 +22,7 @@
 			'#f)))
 
 (#define 'macroexpansions '())
-(#define 'dont-expand '(dont expand))
-; Should this be rewritten to handle tail recursion?
+(#define 'dont-macro-expand '(dont . macro-expand))
 (#define 'macro-expand
 	(#lambda '(o)
 		'(#ifelse (pair? o)
@@ -33,7 +34,7 @@
 							(#prog2of2
 								(#define-local 'cdr-o (cdr o))
 								'(#define-local 'expansion (macro . cdr-o)))
-							'(#ifelse (eq? expansion dont-expand)
+							'(#ifelse (eq? expansion dont-macro-expand)
 								'#f
 								'(#define-local 'o (macro-expand expansion))))
 						'#f))
@@ -84,7 +85,7 @@
 		'(list '#loop (quote (macro-expand (cons 'progn body))))))
 (#macro-define 'map
 	(#lambda '(mapper . args)
-		'(list '#map (quote (macro-expand body)) . args)))
+		'(list '#map (quote (macro-expand mapper)) . args)))
 (#macro-define 'subscope
 	(#lambda 'body
 		'(list '#subscope (quote (macro-expand (cons 'progn body))))))
@@ -101,6 +102,38 @@
 ;;; From this point on we're operating on our own repl (minus the printing) ;;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
+(define (write-newline file)
+	(write-char file 10))
+(define (write-object file obj)
+	(write-string file (->string obj)))
+(define (dprint o)
+	(write-object #standard-out o)
+	(write-newline #standard-out))
+
+(macro-define (+ . aaa)
+	(ifelse (pair? (cdr aaa))
+		(ifelse (pair? (cdr (cdr aaa)))
+			(list '+ (car aaa) (cons '+ (cdr aaa)))
+			dont-macro-expand)
+		(car aaa)))
+(macro-define (- . aaa)
+	(ifelse (pair? (cdr aaa))
+		(ifelse (pair? (cdr (cdr aaa)))
+			(list '- (car aaa) (cons '+ (cdr aaa)))
+			dont-macro-expand)
+		(car aaa)))
+(macro-define (* . aaa)
+	(ifelse (pair? (cdr aaa))
+		(ifelse (pair? (cdr (cdr aaa)))
+			(list '* (car aaa) (cons '* (cdr aaa)))
+			dont-macro-expand)
+		(car aaa)))
+(macro-define (/ . aaa)
+	(ifelse (pair? (cdr aaa))
+		(ifelse (pair? (cdr (cdr aaa)))
+			(list '/ (car aaa) (cons '* (cdr aaa)))
+			dont-macro-expand)
+		(car aaa)))
 (macro-define (and a . b)
 	(ifelse b
 		(list 'ifelse a (cons 'and b) #f)
@@ -110,6 +143,12 @@
 	(list 'ifelse bool
 		(cons 'progn progs)
 		#f))
+(macro-define (let* bindings . body)
+	(ifelse bindings
+		(list 'progn
+			(list 'define-local (caar bindings) (cons 'progn (cdar bindings)))
+			(cons 'let* (cons (cdr bindings) body)))
+		(cons 'progn body)))
 (macro-define (next-loop) (list 'throw ''next-loop #f))
 (macro-define (not a) (list 'ifelse a #f #t))
 (macro-define (or a . b)
@@ -118,24 +157,249 @@
 			(list 'define-local 'a a)
 			(list 'ifelse 'a 'a (cons 'or b)))
 		a))
-(macro-define (unless bool . progs)
+(macro-define (unless bool . body)
 	(list 'ifelse bool
 		#f
-		(cons 'progn progs)))
+		(cons 'progn body)))
 (macro-define (while cond . body)
 	(list 'loop
 		(list 'ifelse cond
 			(cons 'progn body)
 			(list 'throw ''exit-loop #f))))
 
-(define (write-newline file)
-	(write-char file 10))
+(define (cadar o)
+	(car (cdr (car o))))
+
+(define (reverse/append straight newtail)
+	(while straight
+		(define-local newtail (cons (car straight) newtail))
+		(define-local straight (cdr straight)))
+	newtail)
+(define (reverse straight)
+	(reverse/append straight '()))
+(define (append oldlist newtail)
+	(reverse (reverse/append oldlist newtail)))
+
+(define (cars arg) ; ((1 2) (3 4)) => (1 3)
+	(define-local stack '())
+	(while arg
+		(define-local stack (cons (caar arg) stack))
+		(define-local arg (cdr arg)))
+	(reverse stack))
+(define (cdrs arg) ; ((1 2) (3 4)) => ((2) (4))
+	(define-local stack '())
+	(while arg
+		(define-local stack (cons (cdar arg) stack))
+		(define-local arg (cdr arg)))
+	(reverse stack))
+(define (cadrs arg) ; ((1 2) (3 4)) => (2 4)
+	(define-local stack '())
+	(while arg
+		(define-local stack (cons (cadar arg) stack))
+		(define-local arg (cdr arg)))
+	(reverse stack))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Now we reimplement the reader and read-object ;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; This object is placed in the CAR of a cons to indicate that quasiquote
+; should replace the cons with the CDR of the cons (but not quoted).
+; For example, if read-object is about to read:
+;   ,bar
+; it will call macro-comma, which calls read-object, gets bar, and returns:
+;   ('(unquote . identifier) . bar)
+; which will get translated by quasiquote into:
+;   bar
+; If read-object is called where the stream starts with:
+;   `(foo ,bar baz)
+; then the backtick will be read and quasiquote called.  Quasiquote will
+; call read-object, which will return:
+;   (foo ('(unquote . identifier) . bar) baz)
+; Then quasiquote will do its thing and return:
+;   (list 'foo bar 'baz)
+;
+(define unquote-identifier '(unquote . identifier))
+
+(define character-macros '())
+(define (define-character-macro char macro)
+	(define character-macros (cons (cons char macro) character-macros)))
+
+(define (expand-string oldstring)
+	(define-local newstring (new-string (+ 512 (string-length oldstring))))
+	(define-local i 0)
+	(while (< i (string-length oldstring))
+		(put-char newstring i (get-char oldstring i)))
+	newstring)
+
+(define (macro-singlequote stream)
+	(catch 'end-of-file
+		(quote (read-object stream))
+		(throw 'reader-error stream)))
+(define-character-macro 39 macro-singlequote)
+
+; FIXME: We should use peek-char so the stream will point to the offending
+; token if it's not a close parenthesis
+(define (submacro-dot stream)
+	(catch 'end-of-file
+		(progn
+			(define-local o (read-object stream))
+			(ifelse (not (eqv? ') (read-object stream)))
+				(throw 'reader-error stream)
+				o))
+		(throw 'reader-error stream)))
+
+(define (macro-openparen stream)
+	(define-local reverse-list '())
+	(define-local new-list '())
+	(catch 'end-of-file
+		(loop
+			(define-local o (read-object stream))
+			(ifelse (eqv? o '))
+				(exit-loop)
+				(ifelse (eqv? o '.)
+					(ifelse reverse-list
+						(progn
+							(define-local new-list (submacro-dot stream))
+							(exit-loop))
+						(throw 'reader-error stream))
+					(define-local reverse-list (cons o reverse-list)))))
+		(throw 'reader-error stream))
+	(while reverse-list
+		(define-local new-list (cons (car reverse-list) new-list))
+		(define-local reverse-list (cdr reverse-list)))
+	new-list)
+(define-character-macro 40 macro-openparen)
+
+(define (macro-closeparen stream)
+	'))
+(define-character-macro 41 macro-closeparen)
+
+(define (macro-comma stream)
+	(catch 'end-of-file
+		(cons unquote-identifier (read-object stream))
+		(throw 'reader-error stream)))
+(define-character-macro 44 macro-comma)
+
+(define (macro-semicolon stream)
+	(define-local c 0)
+	(while (and (<> c 10) (<> c 13))
+		(define-local c (read-char stream)))
+	(read-object stream))
+(define-character-macro 59 macro-semicolon)
+
+; FIXME: quasiquote should be rewritten to handle things like:
+;   `(foo bar . ,(baz quux))
+; Which needs to be translated into:
+;   (cons 'foo (cons 'bar (baz quux)))
+;
+; The old version which handles:
+;   `(foo . ,bar)
+; (i.e., not a cons as the unquoted object in the final cdr) is:
+;(define (quasiquote obj)
+;	(ifelse obj
+;		(ifelse (pair? obj)
+;			(ifelse (eq? unquote-identifier (car obj))
+;				(cdr obj)
+;				(progn
+;					(define-local stack '(list))
+;					(define-local newtail '())
+;					(while obj
+;						(if (eq? unquote-identifier (car obj))
+;							(define-local newtail (cdr obj))
+;							(exit-loop))
+;						(define-local stack (cons (quasiquote (car obj)) stack))
+;						(define-local obj (cdr obj)))
+;					(reverse/append stack newtail)))
+;			(quote obj))
+;		obj))
+;
+(define (quasiquote obj)
+	(ifelse obj
+		(ifelse (pair? obj)
+			(ifelse (eq? unquote-identifier (car obj))
+				(cdr obj)
+				(cons 'list (map (quasiquote #object) obj)))
+			(quote obj))
+		obj))
+
+(define (macro-backtick stream)
+	(quasiquote
+		(catch 'end-of-file
+			(read-object stream)
+			(throw 'reader-error stream))))
+(define-character-macro 96 macro-backtick)
+
+(define (macro-doublequote stream)
+	(define-local string (new-string 512))
+	(define-local i 0)
+	(define-local c 0)
+	(loop
+		(if (= i (string-length string))
+			(define-local string (expand-string string)))
+		(define-local c
+			(catch 'end-of-file
+				(read-char stream)
+				(throw 'reader-error stream)))
+		(if (= c 34) ; 34 = ASCII double quote
+			(exit-loop))
+		(if (= c 92) ; 92 = ASCII backslash
+			(define-local c 
+				(catch 'end-of-file
+					(read-char stream)
+					(throw 'reader-error stream))))
+		(put-char string i c)
+		(define-local i (+ i 1)))
+	(substring string 0 i))
+(define-character-macro 34 macro-doublequote)
+
+(define (read-token stream c)
+	(define-local buffer (new-string 512))
+	(define-local i 0)
+	(loop
+		(if (= i (string-length buffer))
+			(define-local buffer (expand-string buffer)))
+		(put-char buffer i c)
+		(define-local i (+ i 1))
+		(catch 'end-of-file
+			(define-local c (peek-char stream))
+			(exit-loop))
+		(if (isspace c)
+			(exit-loop))
+		(unless (isascii c)
+			(exit-loop))
+		(if (get character-macros c)
+			(exit-loop))
+		(define-local c (read-char stream)))
+	(define buffer (substring buffer 0 i))
+	(catch 'type-error
+		(string->integer buffer)
+		(string->symbol buffer)))
+
+(define (read-object stream)
+	(define-local c 32) ; 32 = ASCII space
+	(while (isspace c)
+		(define-local c (read-char stream)))
+	(unless (isascii c)
+		(throw 'reader-error stream))
+	(define macro (get character-macros c))
+	(ifelse macro
+		(macro stream)
+		(read-token stream c)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; And here's our repl ;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define (load-file filename)
+	(evaluate-file (open-file filename "r")))
+
 (define (show-error error errorvalue)
 	(write-newline #standard-out)
-	(write-string #standard-out |EXCEPTION: |)
+	(write-string #standard-out "EXCEPTION: ")
 	(write-object #standard-out error)
 	(write-newline #standard-out)
-	(write-string #standard-out |EXCEPTION-VALUE: |)
+	(write-string #standard-out "EXCEPTION-VALUE: ")
 	(write-object #standard-out errorvalue)
 	(write-newline #standard-out))
 (define (read-eval-print in out prompt)
@@ -149,7 +413,7 @@
 			(catch #f
 				(evaluate (macro-expand scratchspace))
 				(progn (show-error #exception #exceptionvalue) (ifelse prompt (next-loop) (exit-loop)))))
-		(if prompt
+		(if (and prompt scratchspace)
 			(write-object out scratchspace)
 			(write-newline out))))
-(read-eval-print #standard-in #standard-out (ifelse (isatty #standard-in) |mikelisp> | #f))
+(read-eval-print #standard-in #standard-out (ifelse (isatty #standard-in) "mikelisp> " #f))
