shithub: femtolisp

Download patch

ref: b76bbe37247399331e39bfbbef8724bb2520065d
parent: 0d5cb7352392ec64f47029db38de6d12707b82ef
author: JeffBezanson <[email protected]>
date: Mon Jul 14 21:20:52 EDT 2008

changing environment representation to contiguous values

eliminating built-in label form



--- a/femtolisp/ast/out.lsp
+++ b/femtolisp/ast/out.lsp
@@ -1,3 +1,1 @@
-1201386230.6766149997711182
-(r-expressions (r-call library MASS) (r-call dyn.load "starp.so") (<- ppcommand (lambda (...) (let nil (r-block (r-call .Call "ppcommand" (r-call list r-dotdotdot)))))) (<- ppvcommand (lambda (va) (let nil (r-block (r-call .Call "ppcommand" va))))) (<- ppinvoke ppcommand) (<- pploadconfig (lambda (fileName) (let nil (r-block (r-call .Call "pploadconfig" fileName))))) (<- ppconnect (lambda (numProcs machines) (let ((machines nil) (numProcs nil)) (r-block (when (missing numProcs) (<- numProcs nil)) (when (missing machines) (<- machines nil)) (r-call .Call "ppconnect" (r-call list numProcs machines)))))) (<- ppgetlogpath (lambda nil (let nil (r-block (r-call .Call "ppgetlogpath"))))) (<- ppgetlog (lambda nil (let nil (r-block (r-call .Call "ppgetlog"))))) (<- ppshowdashboard (lambda nil (let nil (r-block (r-call .Call "ppshowdashboard"))))) (<- pphidedashboard (lambda nil (let nil (r-block (r-call .Call "pphidedashboard"))))) (<- revealargs (lambda (dots) (let nil (r-block (r-call .Call "_revealArgs" dots))))) (<- listargs (lambda (...) (let nil (r-block (r-call revealargs (r-call get "...")))))) (<- ppping (lambda nil (let nil (r-block (r-call ppcommand "ppping"))))) (<- ppver (lambda nil (let nil (r-block (r-call ppcommand "pp_ver"))))) (<- STARPDIST "../../../linkdist") (<- STARPPLATFORM "ia32_linux") (r-call .Call "_setstarpdist" STARPDIST) (r-call .Call "_setstarpplat" STARPPLATFORM) (r-call pploadconfig (r-call paste STARPDIST "/config/starpd.properties" (*named* sep ""))) (<- dimdis (lambda (v) (let nil (r-block (if (r-call == (r-call r-index (r-call class v) 1) "dlayoutn") (return (r-call as.numeric (r-call r-index (r-call class v) 2)))) (if (r-call ! (r-call is.null v)) (r-block (for i (r-call : (r-call length v) 1) (if (r-call > (r-call r-aref v i) 1) (return i)))) (r-block (return 1))) (return (r-call length v)))))) (<- is.scalar (lambda (x) (let nil (r-block (&& (|\|\|| (r-call == (r-call mode x) "numeric") (r-call == (r-call mode x) "complex")) (r-call is.null (r-call (r-call .Primitive "dim") x)) (r-call == (r-call length x) 1)))))) (<- p 1) (r-block (ref= #:g0 (r-call c "dlayout" "numeric")) (<- p (r-call class p #:g0)) #:g0) (<- darray (lambda (id shape distribution isreal) (let ((d nil) (distribution nil) (shape nil)) (r-block (<- shape (r-call as.array shape)) (<- distribution (r-call + distribution 1)) (r-block (ref= #:g1 (r-call append "dlayoutn" (r-call toString distribution) (r-call class shape))) (<- shape (r-call class shape #:g1)) #:g1) (<- d (r-call list (*named* id id) (*named* shape shape) (*named* isreal isreal) (*named* logical *r-false*) nil nil)) (r-block (<- d (r-call class d "darray")) "darray") d)))) (<- darraydist (lambda (da) (let nil (r-block (r-call as.numeric (r-call r-aref (r-call class (r-call r-aref da (index-in-strlist shape (r-call attr da "names")))) 2)))))) (<- is.darray (lambda (x) (let nil (r-block (r-call == (r-call r-index (r-call class x) 1) "darray"))))) (<- is.nd (lambda (x) (let nil (r-block (r-call != (r-call length (r-call dim x)) 2))))) (<- is.darraynd (lambda (x) (let nil (r-block (&& (r-call is.darray x) (r-call is.nd x)))))) (<- is.dlayout (lambda (x) (let nil (r-block (r-call any (r-call == (r-call class x) "dlayout")))))) (<- vdim (lambda (x) (let nil (r-block (if (r-call is.vector x) (r-call length x) (r-call dim x)))))) (<- |[[.dlayoutn| (<- |[.dlayoutn| (lambda (dl n) (let ((didi nil) (r nil) (dd nil)) (r-block (<- dd (r-call as.numeric (r-call r-aref (r-call class dl) 2))) (if (r-call == (r-call length n) 1) (r-block (if (r-call == n dd) (r-call * (r-call r-index (r-call as.vector dl) n) p) (r-call r-index (r-call as.vector dl) n))) (r-block (<- r (r-call r-index (r-call as.numeric dl) n)) (<- didi (r-call dimdis r)) (for i (r-call : 1 (r-call length n)) (r-block (if (r-call == (r-call r-aref n i) dd) (r-block (<- didi i) (break))))) (r-block (ref= #:g2 (r-call append "dlayoutn" (r-call toString didi) (r-call class r))) (<- r (r-call class r #:g2)) #:g2) (return r)))))))) (<- print.darray (lambda (d ...) (let ((shs nil) (sh nil)) (r-block (<- sh (r-call as.
\ No newline at end of file
-1201386230.8069550991058350
+'(r-expressions (r-call library MASS) (r-call dyn.load "starp.so") (<- ppcommand (lambda (...) (let nil (r-block (r-call .Call "ppcommand" (r-call list r-dotdotdot)))))) (<- ppvcommand (lambda (va) (let nil (r-block (r-call .Call "ppcommand" va))))) (<- ppinvoke ppcommand) (<- pploadconfig (lambda (fileName) (let nil (r-block (r-call .Call "pploadconfig" fileName))))) (<- ppconnect (lambda (numProcs machines) (let ((machines nil) (numProcs nil)) (r-block (when (missing numProcs) (<- numProcs nil)) (when (missing machines) (<- machines nil)) (r-call .Call "ppconnect" (r-call list numProcs machines)))))) (<- ppgetlogpath (lambda nil (let nil (r-block (r-call .Call "ppgetlogpath"))))) (<- ppgetlog (lambda nil (let nil (r-block (r-call .Call "ppgetlog"))))) (<- ppshowdashboard (lambda nil (let nil (r-block (r-call .Call "ppshowdashboard"))))) (<- pphidedashboard (lambda nil (let nil (r-block (r-call .Call "pphidedashboard"))))) (<- revealargs (lambda (dots) (let nil (r-block (r-call .Call "_revealArgs" dots))))) (<- listargs (lambda (...) (let nil (r-block (r-call revealargs (r-call get "...")))))) (<- ppping (lambda nil (let nil (r-block (r-call ppcommand "ppping"))))) (<- ppver (lambda nil (let nil (r-block (r-call ppcommand "pp_ver"))))) (<- STARPDIST "../../../linkdist") (<- STARPPLATFORM "ia32_linux") (r-call .Call "_setstarpdist" STARPDIST) (r-call .Call "_setstarpplat" STARPPLATFORM) (r-call pploadconfig (r-call paste STARPDIST "/config/starpd.properties" (*named* sep ""))) (<- dimdis (lambda (v) (let nil (r-block (if (r-call == (r-call r-index (r-call class v) 1) "dlayoutn") (return (r-call as.numeric (r-call r-index (r-call class v) 2)))) (if (r-call ! (r-call is.null v)) (r-block (for i (r-call : (r-call length v) 1) (if (r-call > (r-call r-aref v i) 1) (return i)))) (r-block (return 1))) (return (r-call length v)))))) (<- is.scalar (lambda (x) (let nil (r-block (&& (|\|\|| (r-call == (r-call mode x) "numeric") (r-call == (r-call mode x) "complex")) (r-call is.null (r-call (r-call .Primitive "dim") x)) (r-call == (r-call length x) 1)))))) (<- p 1) (r-block (ref= #:g0 (r-call c "dlayout" "numeric")) (<- p (r-call class p #:g0)) #:g0) (<- darray (lambda (id shape distribution isreal) (let ((d nil) (distribution nil) (shape nil)) (r-block (<- shape (r-call as.array shape)) (<- distribution (r-call + distribution 1)) (r-block (ref= #:g1 (r-call append "dlayoutn" (r-call toString distribution) (r-call class shape))) (<- shape (r-call class shape #:g1)) #:g1) (<- d (r-call list (*named* id id) (*named* shape shape) (*named* isreal isreal) (*named* logical *r-false*) nil nil)) (r-block (<- d (r-call class d "darray")) "darray") d)))) (<- darraydist (lambda (da) (let nil (r-block (r-call as.numeric (r-call r-aref (r-call class (r-call r-aref da (index-in-strlist shape (r-call attr da "names")))) 2)))))) (<- is.darray (lambda (x) (let nil (r-block (r-call == (r-call r-index (r-call class x) 1) "darray"))))) (<- is.nd (lambda (x) (let nil (r-block (r-call != (r-call length (r-call dim x)) 2))))) (<- is.darraynd (lambda (x) (let nil (r-block (&& (r-call is.darray x) (r-call is.nd x)))))) (<- is.dlayout (lambda (x) (let nil (r-block (r-call any (r-call == (r-call class x) "dlayout")))))) (<- vdim (lambda (x) (let nil (r-block (if (r-call is.vector x) (r-call length x) (r-call dim x)))))) (<- |[[.dlayoutn| (<- |[.dlayoutn| (lambda (dl n) (let ((didi nil) (r nil) (dd nil)) (r-block (<- dd (r-call as.numeric (r-call r-aref (r-call class dl) 2))) (if (r-call == (r-call length n) 1) (r-block (if (r-call == n dd) (r-call * (r-call r-index (r-call as.vector dl) n) p) (r-call r-index (r-call as.vector dl) n))) (r-block (<- r (r-call r-index (r-call as.numeric dl) n)) (<- didi (r-call dimdis r)) (for i (r-call : 1 (r-call length n)) (r-block (if (r-call == (r-call r-aref n i) dd) (r-block (<- didi i) (break))))) (r-block (ref= #:g2 (r-call append "dlayoutn" (r-call toString didi) (r-call class r))) (<- r (r-call class r #:g2)) #:g2) (return r)))))))) (<- print.darray (lambda (d ...) (let ((shs nil) (sh nil)) (r-block (<- sh (r-call as
\ No newline at end of file
--- a/femtolisp/attic/trash.c
+++ b/femtolisp/attic/trash.c
@@ -115,3 +115,15 @@
  inv_error:
     lerror(DivideError, "/: division by zero");
 }
+
+static void printstack(value_t *penv, uint32_t envsz)
+{
+    int i;
+    printf("env=%d, size=%d\n", penv - &Stack[0], envsz);
+    for(i=0; i < SP; i++) {
+        printf("%d: ", i);
+        print(stdout, Stack[i], 0);
+        printf("\n");
+    }
+    printf("\n");
+}
--- a/femtolisp/flisp.c
+++ b/femtolisp/flisp.c
@@ -68,7 +68,7 @@
 #include "flisp.h"
 
 static char *builtin_names[] =
-    { "quote", "cond", "if", "and", "or", "while", "lambda", "label",
+    { "quote", "cond", "if", "and", "or", "while", "lambda",
       "trycatch", "progn",
 
       "eq", "atom", "not", "symbolp", "numberp", "boundp", "consp",
@@ -84,13 +84,13 @@
 value_t Stack[N_STACK];
 u_int32_t SP = 0;
 
-value_t NIL, T, LAMBDA, LABEL, QUOTE, VECTOR, IF, TRYCATCH;
+value_t NIL, T, LAMBDA, QUOTE, VECTOR, IF, TRYCATCH;
 value_t BACKQUOTE, COMMA, COMMAAT, COMMADOT;
 value_t IOError, ParseError, TypeError, ArgError, UnboundError, MemoryError;
 value_t DivideError, BoundsError, Error;
 value_t conssym, symbolsym, fixnumsym, vectorsym, builtinsym;
 
-static value_t eval_sexpr(value_t e, value_t *penv, int tail, u_int32_t envend);
+static value_t eval_sexpr(value_t e, value_t *penv, int tail);
 static value_t *alloc_words(int n);
 static value_t relocate(value_t v);
 static void do_print(FILE *f, value_t v, int princ);
@@ -608,13 +608,13 @@
     return NIL;
 }
 
-#define eval(e)         ((tag(e)<0x2) ? (e) : eval_sexpr((e),penv,0,envend))
-#define topeval(e, env) ((tag(e)<0x2) ? (e) : eval_sexpr((e),env,1,SP))
+#define eval(e)         ((tag(e)<0x2) ? (e) : eval_sexpr((e),penv,0))
+#define topeval(e, env) ((tag(e)<0x2) ? (e) : eval_sexpr((e),env,1))
 #define tail_eval(xpr) do { SP = saveSP;  \
     if (tag(xpr)<0x2) { return (xpr); } \
     else { e=(xpr); goto eval_top; } } while (0)
 
-static value_t do_trycatch(value_t expr, value_t *penv, u_int32_t envend)
+static value_t do_trycatch(value_t expr, value_t *penv)
 {
     value_t v;
 
@@ -639,26 +639,27 @@
 /* stack setup on entry:
   n     n+1   ...
  +-----+-----+-----+-----+-----+-----+-----+-----+
- | SYM | VAL | SYM | VAL | CLO |     |     |     |
+ | LL  | VAL | VAL | CLO |     |     |     |     |
  +-----+-----+-----+-----+-----+-----+-----+-----+
-  ^                             ^                      ^
-  |                             |                      |
-  penv                          envend                 SP (who knows where)
+  ^                                                   ^
+  |                                                   |
+  penv                                                SP (who knows where)
 
- sym is an argument name and val is its binding. CLO is a closed-up
- environment vector (which can be empty, i.e. NIL).
- CLO is always there, but there might be zero SYM/VAL pairs.
+ where LL is the lambda list, CLO is a closed-up environment vector
+ (which can be empty, i.e. NIL). An environment vector is just a copy
+ of the stack from LL through CLO.
+ There might be zero values, in which case LL is NIL.
 
  if tail==1, you are allowed (indeed encouraged) to overwrite this
  environment, otherwise you have to put any new environment on the top
  of the stack.
 */
-static value_t eval_sexpr(value_t e, value_t *penv, int tail, u_int32_t envend)
+static value_t eval_sexpr(value_t e, value_t *penv, int tail)
 {
-    value_t f, v, asym, *pv, *argsyms, *body, *lenv, *argenv;
+    value_t f, v, *pv, *argsyms, *body, *lenv;
     cons_t *c;
     symbol_t *sym;
-    u_int32_t saveSP;
+    u_int32_t saveSP, envsz;
     int i, nargs, noeval=0;
     fixnum_t s;
     cvalue_t *cv;
@@ -669,15 +670,18 @@
         sym = (symbol_t*)ptr(e);
         if (sym->syntax == TAG_CONST) return sym->binding;
         while (1) {
-            if (tag(*penv) == TAG_BUILTIN)
-                penv = &vector_elt(*penv, 0);
-            if (*penv == e)
-                return penv[1];
-            else if (*penv == NIL)
+            v = *penv++;
+            while (iscons(v)) {
+                if (car_(v)==e) return *penv;
+                v = cdr_(v); penv++;
+            }
+            if (v == e) return *penv;  // dotted list
+            if (v != NIL) penv++;
+            if (*penv == NIL)
                 break;
-            penv+=2;
+            penv = &vector_elt(*penv, 0);
         }
-        if ((v = sym->binding) == UNBOUND)   // 3. global env
+        if ((v = sym->binding) == UNBOUND)
             raise(list2(UnboundError, e));
         return v;
     }
@@ -696,7 +700,7 @@
         else
             noeval = 2;
     }
-    else f = eval_sexpr(v, penv, 0, envend);
+    else f = eval(v);
     v = Stack[saveSP];
     if (tag(f) == TAG_BUILTIN) {
         // handle builtin function
@@ -718,25 +722,30 @@
             break;
         case F_LAMBDA:
             // build a closure (lambda args body . env)
-            if (issymbol(*penv) && *penv != NIL) {
+            if (*penv != NIL) {
                 // save temporary environment to the heap
-                // find out how much space we need
-                nargs = ((int)(&Stack[envend] - penv - 1));
                 lenv = penv;
-                pv = alloc_words(nargs + 2);
+                //envsz = saveSP - (penv - &Stack[0]);
+                envsz = 2;
+                v = *penv;
+                while (iscons(v)) {
+                    envsz++;
+                    v = cdr_(v);
+                }
+                if (v != NIL) envsz++;
+                pv = alloc_words(envsz + 1);
                 PUSH(tagptr(pv, TAG_BUILTIN));
-                pv[0] = (nargs+1)<<2;
+                pv[0] = envsz<<2;
                 pv++;
-                while (nargs--)
+                while (envsz--)
                     *pv++ = *penv++;
-                // final element points to existing cloenv
-                *pv = Stack[envend-1];
                 // environment representation changed; install
                 // the new representation so everybody can see it
-                *lenv = Stack[SP-1];
+                lenv[0] = NIL;
+                lenv[1] = Stack[SP-1];
             }
             else {
-                PUSH(*penv); // env has already been captured; share
+                PUSH(penv[1]); // env has already been captured; share
             }
             c = (cons_t*)ptr(v=cons_reserve(3));
             c->car = LAMBDA;
@@ -746,22 +755,6 @@
             c->car = car(cdr_(Stack[saveSP])); //body
             c->cdr = Stack[SP-1]; //env
             break;
-        case F_LABEL:
-            // the syntax of label is (label name (lambda args body))
-            // nothing else is guaranteed to work
-            PUSH(car(Stack[saveSP]));
-            PUSH(car(cdr_(Stack[saveSP])));
-            body = &Stack[SP-1];
-            *body = eval(*body);  // evaluate lambda
-            pv = alloc_words(4);
-            pv[0] = 3<<2;  // vector size 3
-            // add [name fn] to front of function's environment
-            pv[1] = Stack[SP-2]; // name
-            pv[2] = v = *body;   // lambda
-            f = cdr(cdr(v));
-            pv[3] = cdr(f);
-            cdr_(f) = tagptr(pv, TAG_BUILTIN);
-            break;
         case F_IF:
             v = car(Stack[saveSP]);
             if (eval(v) != NIL)
@@ -843,7 +836,7 @@
             }
             break;
         case F_TRYCATCH:
-            v = do_trycatch(car(Stack[saveSP]), penv, envend);
+            v = do_trycatch(car(Stack[saveSP]), penv);
             break;
 
         // ordinary functions
@@ -851,15 +844,24 @@
             argcount("set", nargs, 2);
             e = Stack[SP-2];
             while (1) {
-                if (tag(*penv) == TAG_BUILTIN)
-                    penv = &vector_elt(*penv, 0);
-                if (*penv == e) {
-                    penv[1] = Stack[SP-1];
-                    SP=saveSP; return penv[1];
+                v = *penv++;
+                while (iscons(v)) {
+                    if (car_(v)==e) {
+                        *penv = Stack[SP-1];
+                        SP=saveSP;
+                        return *penv;
+                    }
+                    v = cdr_(v); penv++;
                 }
-                else if (*penv == NIL)
+                if (v == e) {
+                    *penv = Stack[SP-1];
+                    SP=saveSP;
+                    return *penv;
+                }
+                if (v != NIL) penv++;
+                if (*penv == NIL)
                     break;
-                penv+=2;
+                penv = &vector_elt(*penv, 0);
             }
             sym = tosymbol(e, "set");
             v = Stack[SP-1];
@@ -1132,13 +1134,17 @@
             v = Stack[SP-1];
             if (tag(v)<0x2) { SP=saveSP; return v; }
             if (tail) {
-                *penv = NIL;
-                envend = SP = (u_int32_t)(penv-&Stack[0]) + 1;
-                e=v; goto eval_top;
+                penv[0] = NIL;
+                penv[1] = NIL;
+                //envsz = 0;
+                SP = (u_int32_t)(penv-&Stack[0]) + 2;
+                e=v;
+                goto eval_top;
             }
             else {
                 PUSH(NIL);
-                v = eval_sexpr(v, &Stack[SP-1], 1, SP);
+                PUSH(NIL);
+                v = eval_sexpr(v, &Stack[SP-2], 1);
             }
             break;
         case F_RAISE:
@@ -1184,70 +1190,80 @@
     }
  apply_lambda:
     if (iscons(f)) {
-        // apply lambda or macro expression
-        PUSH(cdr(cdr_(f)));
-        PUSH(car_(cdr_(f)));
+        // apply lambda expression
+        f = cdr_(f);
+        PUSH(f);
+        PUSH(car(f)); // arglist
         argsyms = &Stack[SP-1];
-        argenv = &Stack[SP];  // argument environment starts now
         // build a calling environment for the lambda
         // the environment is the argument binds on top of the captured
         // environment
-        while (iscons(v)) {
-            // bind args
-            if (!iscons(*argsyms)) {
-                if (*argsyms == NIL)
-                    lerror(ArgError, "apply: too many arguments");
-                break;
+        if (noeval) {
+            while (iscons(v)) {
+                // bind args
+                if (!iscons(*argsyms)) {
+                    if (*argsyms == NIL)
+                        lerror(ArgError, "apply: too many arguments");
+                    break;
+                }
+                PUSH(car_(v));
+                *argsyms = cdr_(*argsyms);
+                v = cdr_(v);
             }
-            asym = car_(*argsyms);
-            if (asym==NIL || !issymbol(asym))
-                lerror(ArgError, "apply: invalid formal argument");
-            v = car_(v);
-            if (!noeval) {
-                v = eval(v);
-            }
-            PUSH(asym);
-            PUSH(v);
-            *argsyms = cdr_(*argsyms);
-            v = Stack[saveSP] = cdr_(Stack[saveSP]);
+            if (*argsyms != NIL && issymbol(*argsyms))
+                PUSH(v);
         }
-        if (*argsyms != NIL) {
-            if (issymbol(*argsyms)) {
-                PUSH(*argsyms);
-                PUSH(Stack[saveSP]);
-                if (!noeval) {
-                    // this version uses collective allocation. about 7-10%
-                    // faster for lists with > 2 elements, but uses more
-                    // stack space
-                    i = SP;
-                    while (iscons(Stack[saveSP])) {
-                        PUSH(eval(car_(Stack[saveSP])));
-                        Stack[saveSP] = cdr_(Stack[saveSP]);
+        else {
+            while (iscons(v)) {
+                // bind args
+                if (!iscons(*argsyms)) {
+                    if (*argsyms == NIL)
+                        lerror(ArgError, "apply: too many arguments");
+                    break;
+                }
+                v = eval(car_(v));
+                PUSH(v);
+                *argsyms = cdr_(*argsyms);
+                v = Stack[saveSP] = cdr_(Stack[saveSP]);
+            }
+            if (*argsyms != NIL && issymbol(*argsyms)) {
+                PUSH(NIL);
+                // this version uses collective allocation. about 7-10%
+                // faster for lists with > 2 elements, but uses more
+                // stack space
+                i = SP;
+                while (iscons(Stack[saveSP])) {
+                    v = car_(Stack[saveSP]);
+                    v = eval(v);
+                    PUSH(v);
+                    Stack[saveSP] = cdr_(Stack[saveSP]);
+                }
+                nargs = SP-i;
+                if (nargs) {
+                    Stack[i-1] = cons_reserve(nargs);
+                    c = (cons_t*)ptr(Stack[i-1]);
+                    for(; i < (int)SP; i++) {
+                        c->car = Stack[i];
+                        c->cdr = tagptr(c+1, TAG_CONS);
+                        c++;
                     }
-                    nargs = SP-i;
-                    if (nargs) {
-                        Stack[i-1] = cons_reserve(nargs);
-                        c = (cons_t*)ptr(Stack[i-1]);
-                        for(; i < (int)SP; i++) {
-                            c->car = Stack[i];
-                            c->cdr = tagptr(c+1, TAG_CONS);
-                            c++;
-                        }
-                        (c-1)->cdr = Stack[saveSP];
-                        POPN(nargs);
-                    }
+                    (c-1)->cdr = Stack[saveSP];
+                    POPN(nargs);
                 }
             }
-            else if (iscons(*argsyms)) {
-                lerror(ArgError, "apply: too few arguments");
-            }
         }
-        PUSH(cdr(Stack[saveSP+1])); // add cloenv to new environment
-        e = car_(Stack[saveSP+1]);
+        if (iscons(*argsyms)) {
+            lerror(ArgError, "apply: too few arguments");
+        }
+        *argsyms = car_(Stack[saveSP+1]);
+        f = cdr_(Stack[saveSP+1]);
+        PUSH(cdr(f));
+        e = car_(f);
+
         // macro: evaluate expansion in the calling environment
         if (noeval == 2) {
             if (tag(e)<0x2) ;
-            else e = eval_sexpr(e, argenv, 1, SP);
+            else e = eval_sexpr(e, argsyms, 1);
             SP = saveSP;
             if (tag(e)<0x2) return(e);
             noeval = 0;
@@ -1258,14 +1274,15 @@
             if (tail) {
                 noeval = 0;
                 // ok to overwrite environment
-                nargs = (int)(&Stack[SP] - argenv);
-                for(i=0; i < nargs; i++)
-                    penv[i] = argenv[i];
-                envend = SP = (u_int32_t)((penv+nargs) - &Stack[0]);
+                s = SP - saveSP - 2;
+                for(i=0; i < s; i++)
+                    penv[i] = argsyms[i];
+                SP = (u_int32_t)((penv+s) - &Stack[0]);
+                //envsz = s;
                 goto eval_top;
             }
             else {
-                v = eval_sexpr(e, argenv, 1, SP);
+                v = eval_sexpr(e, argsyms, 1);
                 SP = saveSP;
                 return v;
             }
@@ -1296,7 +1313,6 @@
     NIL = symbol("nil"); setc(NIL, NIL);
     T   = symbol("T");   setc(T,   T);
     LAMBDA = symbol("lambda");
-    LABEL = symbol("label");
     QUOTE = symbol("quote");
     VECTOR = symbol("vector");
     TRYCATCH = symbol("trycatch");
@@ -1351,7 +1367,8 @@
     value_t v;
     u_int32_t saveSP = SP;
     PUSH(NIL);
-    v = topeval(expr, &Stack[SP-1]);
+    PUSH(NIL);
+    v = topeval(expr, &Stack[SP-2]);
     SP = saveSP;
     return v;
 }
--- a/femtolisp/flisp.h
+++ b/femtolisp/flisp.h
@@ -77,7 +77,7 @@
 
 enum {
     // special forms
-    F_QUOTE=0, F_COND, F_IF, F_AND, F_OR, F_WHILE, F_LAMBDA, F_LABEL,
+    F_QUOTE=0, F_COND, F_IF, F_AND, F_OR, F_WHILE, F_LAMBDA,
     F_TRYCATCH, F_PROGN,
     // functions
     F_EQ, F_ATOM, F_NOT, F_SYMBOLP, F_NUMBERP, F_BOUNDP, F_CONSP,
--- a/femtolisp/perf.lsp
+++ b/femtolisp/perf.lsp
@@ -15,3 +15,7 @@
 (princ "mexpand: ")
 (time (dotimes (n 5000) (macroexpand '(dotimes (i 100) body1 body2))))
 
+(path.cwd "ast")
+(princ "p-lambda: ")
+(load "rpasses.lsp")
+(path.cwd "..")
--- a/femtolisp/system.lsp
+++ b/femtolisp/system.lsp
@@ -20,6 +20,9 @@
               (list 'set-syntax (list 'quote name)
                     (list 'lambda args (f-body body)))))
 
+(defmacro label (name fn)
+  (list (list 'lambda (cons name nil) (list 'setq name fn)) nil))
+
 ; support both CL defun and Scheme-style define
 (defmacro defun (name args . body)
   (list 'setq name (list 'lambda args (f-body body))))