Lisp Interpreter for mbed LPC1768

Dependencies:   mbed

Lisp Interpreter

(Marc Adler Lisp Interpreter, malisp)

mbed LPC1768 port by Takehisa Oneta (ohneta@gmail.com)

Revision:
0:e9a7a38d9ad3
Child:
1:a2955606adef
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/malisp.cpp	Sun Apr 17 11:59:13 2016 +0000
@@ -0,0 +1,1065 @@
+#include "mbed.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include "malisp.h"
+#include "mbed_functions.h"
+
+extern Serial pc;
+extern DigitalOut led1;
+extern DigitalOut led2;
+extern DigitalOut led3;
+extern DigitalOut led4;
+extern char *lisplib;
+
+int _stack = 5000;
+
+LIST *TRU;
+LIST *g_alist;      // 連想リスト
+LIST *g_oblist;     // list of Lisp Functions
+
+char progon;
+
+//FILE *fd;     // input file descriptor
+FILE_MINE   fd;
+
+int32_t  getc_mine_buffer_pt = 0;
+int      getc_mine_buffer[8];
+uint32_t lisplib_counter = 0;
+
+//----------------------------------------------------------------
+//int getc_mine(FILE *fd)
+int getc_mine(FILE_MINE fd)
+{
+    if (getc_mine_buffer_pt > 0) {
+        int c = getc_mine_buffer[getc_mine_buffer_pt];
+        getc_mine_buffer_pt--;
+        if (getc_mine_buffer_pt < 0) {
+            getc_mine_buffer_pt = 0;
+        }
+        return c;
+    }
+
+    //return getc(fd);
+    
+    int c = 0;
+    if (fd == FILE_SERIAL) {
+        c = pc.getc();
+        //pc.putc(c);
+ 
+    } else if (fd == FILE_STRING) {
+
+        if (lisplib_counter > strlen(lisplib)) {
+            c = EOF;     // EOF
+        } else {
+            c = *(lisplib + lisplib_counter);
+            lisplib_counter++;
+        }
+    }
+    
+    return c;
+}
+
+//void ungetc_mine(int c, FILE *fd)
+void ungetc_mine(int c, FILE_MINE fd)
+{
+    getc_mine_buffer_pt++;
+    getc_mine_buffer[getc_mine_buffer_pt] = c;
+}
+
+//----------------------------------------------------------------
+// main program
+//----------------------------------------------------------------
+
+void malisp_main()
+{
+    initialize();
+    pc.printf("\nMarc Adler's LISP Interpreter. (mbed port and expansion by ohneta)\n");
+    load_library();
+
+    pc.printf("[FREE-MEM: %d bytes]\n", _getFreeMemorySize());
+
+    {
+        fd = FILE_SERIAL;
+        getc_mine_buffer_pt = 0;
+        interpret_malisp();
+    }
+}
+
+void interpret_malisp()
+{
+    LIST *p = NULL;
+    LIST *q = NULL;
+    int c;
+
+    while (EOF != (c = gettok())) {
+        if (c == ERR) {
+            continue;
+        }
+
+        switch (c) {
+            case LPAREN:
+                getc_mine(fd);   // span the paren
+                q = makelist();
+                p = eval(q, g_alist);
+                break;
+
+            case LETTER:
+                p = cdr(car(getid()));
+                break;
+        }
+
+        if (fd == FILE_SERIAL) {
+            pc.printf("\n");
+            pc.printf("value => ");
+            if (p == NULL) {
+                pc.printf("nil");
+            } else {
+                lisp_print(cons(p, NULL));
+                //lisp_print(p);
+            }
+            pc.printf("\n");
+        }
+    }
+}
+
+//----------------------------------------------------------------
+// initialization procedures
+//----------------------------------------------------------------
+
+void initialize()
+{
+    init("'", QUOTE);
+    init("car", FCAR);
+    init("cond", COND);
+    init("cdr", FCDR);
+    init("defun", DEFUN);
+    init("cons",FCONS);
+    init("nil", NILL);
+    init("atom",FATOM);
+    init("prog",PROG);
+    init("eq",  FEQ);
+    init("go",  GO);
+    init("setq",FSETQ);
+    init("return",RETRN);
+    init("print",PRINT);
+    init("read", FREAD);
+    init("rplaca",FREPLACA);
+    init("rplacd",FREPLACD);
+    init("apply", FAPPLY);
+    init("eval",  FEVAL);
+    init("and", FAND);
+    init("or", FOR);
+    init("not", FNOT);
+    init("plus",  PLUS);
+    init("zerop", ZEROP);
+    init("diff",  DIFF);
+    init("greaterp", GREATERP);
+    init("times", TIMES);
+    init("lessp", LESSP);
+    init("add1",  ADD1);
+    init("sub1",  SUB1);
+    init("quot",  QUOTIENT);
+    TRU = cons(init("t",T), NULL);
+    init("numberp",NUMBERP);
+    rplact(TRU, SATOM);
+    init("null",  NUL);
+    init("funcall",FUNCALL);
+
+    // for mbed functions
+    init("info", FINFO);
+    init("freemem", FFREEMEM);
+    init("wait", FWAIT);
+    init("dout", FDOUT);
+    init("din",  FDIN);
+    init("aout", FAOUT);
+    init("ain",  FAIN);
+    init("pwmout", PWMOUT);
+
+    g_oblist = g_alist;
+}
+
+LIST *init(char *name, int t)
+{
+    LIST *p;
+
+    p = install(name, 1);
+    rplact(p, t);
+    return p;
+}
+
+//----------------------------------------------------------------
+// create the executable list form of a LISP program
+//----------------------------------------------------------------
+
+LIST *makelist()
+{
+    LIST *p;
+
+    switch (gettok()) {
+        case LPAREN:
+            getc_mine(fd);  // span the paren ?????
+            p = makelist();
+            p = cons(p, makelist());
+            rplact(p, LST);
+            return p;
+
+        case LETTER:
+            p = getid();
+            return cons(p, makelist());
+
+        case INQUOTE:
+            p = getid();
+            p = cons(p, makelist());
+            rplaca(p, cons(car(p), cons(car(cdr(p)), NULL)));
+            rplacd(p, cdr(cdr(p)));
+            return p;
+
+        case DIGIT:
+            p = getnum();
+            return cons(p, makelist());
+
+        case RPAREN:
+            getc_mine(fd);  // span rparen ??????
+            return NULL;
+    }
+
+    return NULL;
+}
+
+
+// isp_print - walks along the list structure printing atoms
+void lisp_print(LIST *p)
+{
+    if (p != NULL) {
+        if (type(p) == RATOM) {
+            pc.printf("%f ", p->u.num);
+        } else if (type(p) == IATOM) {
+            pc.printf("%d ", (int) p->u.num);
+        } else if (type(p) == SATOM) {
+            pc.printf("%s ", getname(car(p)));
+        } else if (type(car(p)) == LST) {
+            pc.printf("%c", '(');
+            lisp_print(car(p));
+            pc.printf("%c", ')');
+            lisp_print(cdr(p));
+        } else if (type(p) == LST) {
+            lisp_print(car(p));
+            lisp_print(cdr(p));
+        } else {
+            pc.printf("******** can't print it out *******\n");
+        }
+    }
+}
+
+//----------------------------------------------------------------
+// evaluate a LISP function
+//----------------------------------------------------------------
+
+LIST *eval(LIST *x, LIST *alist)
+{
+    LIST *p, *q;
+    int savt, t;
+
+    if (x == NULL) {
+        return NULL;
+    }
+    t = type(x);
+    if (t == VARI) {
+        return assoc(alist, getname(car(x)));
+    }
+    if (t == IATOM || t == RATOM) {
+        return x;
+    }
+    if (t == LABL) {
+        return NULL;
+    }
+
+    switch (type(car(x))) {
+        case T:
+            return TRU;
+
+        case NILL:
+            return NULL;
+
+        case QUOTE:
+            var_to_atom(car(cdr(x)));
+            return car(cdr(x));
+
+        case FCAR:
+            return car(eval(cdr(x), alist));
+
+        case FCDR:
+            return cdr(eval(cdr(x), alist));
+
+        case FATOM:
+            return atom(eval(cdr(x), alist));
+
+        case FEQ:
+            return eq(eval(car(cdr(x)),alist), eval(cdr(cdr(x)),alist));
+
+        case NUL:
+            return eq(eval(car(cdr(x)), alist), NULL);
+
+        case FCONS:
+            return cons(eval(car(cdr(x)),alist), eval(cdr(cdr(x)), alist));
+
+        case FLIST:
+            return _list(x);
+
+        case COND:
+            return evalcond(cdr(x), alist);
+
+        case FSETQ:
+            p = eval(cdr(cdr(x)), alist);
+            rplacd(getvar(alist, getname(car(car(cdr(x))))), p);
+            return p;
+
+        case DEFUN:
+            rplact(car(car(cdr(x))), FUSER);
+            rplacd(car(car(cdr(x))), cdr(cdr(x)));
+            var_to_user(cdr(cdr(cdr(x))));
+            if (fd == FILE_SERIAL) {
+                pc.printf("%s\n", getname(car(car(cdr(x)))));
+            }
+            return NULL;
+
+        case FUSER:
+            p = cdr(car(car(x)));   // p is statement list
+            return eval(car(cdr(p)), pairargs(car(p), evalargs(cdr(x),alist), alist, FALSE));
+
+        case FAPPLY:
+        case FUNCALL:
+            p = eval(car(cdr(x)), alist);   // func name
+            if (isfunc(savt = type(car(p)))) {
+                p = cons(p, cdr(cdr(x)));
+                if (savt == FUSER) {
+                    rplact(car(p), FUSER);
+                }
+                q = eval(p, alist);
+                rplact(car(p), savt);
+                return q;
+            } else
+                return NULL;
+
+        case FEVAL:
+            p = eval(cdr(x), alist);
+            if (type(p) == SATOM) {
+                return assoc(alist, getname(car(p)));
+            }
+            return eval(p, alist);
+
+        case PRINT:
+            lisp_print(eval(car(cdr(x)), alist));
+            pc.printf("\n");
+            return NULL;
+
+        case FREAD:
+            return makelist();
+
+        case FAND:
+            return _and(x);
+        case FOR:
+            return _or(x);
+        case FNOT:
+            return _not(x);
+
+        case PLUS:
+        case DIFF:
+        case TIMES:
+        case QUOTIENT:
+        case GREATERP:
+        case LESSP:
+            return arith(car(x), eval(car(cdr(x)), alist), eval(cdr(cdr(x)), alist));
+
+        case ADD1:
+        case SUB1:
+            return arith(car(x), eval(car(cdr(x)), alist), NULL);
+
+        case ZEROP:
+            p = eval(car(cdr(x)), alist);
+            return  (p->u.num == 0) ? TRU : NULL;
+
+        case NUMBERP:
+            savt = type(eval(car(cdr(x)), alist));
+            return (savt==IATOM || savt==RATOM) ? TRU : NULL;
+
+        case PROG:
+            return evalprog(x, alist);
+
+        case GO:
+            return cdr(car(car(cdr(x))));
+
+        case RETRN:
+            progon = FALSE;
+            return eval(cdr(x), alist);
+
+        case LST:
+            if (cdr(x) == NULL) {
+                return eval(car(x), alist);
+            }
+            return cons(eval(car(x),alist),eval(cdr(x),alist));
+
+        case VARI:
+            return assoc(alist, getname(car(car(x))));
+
+        case IATOM:
+        case RATOM:
+            return car(x);
+
+
+
+        // mbed expand
+        case FINFO:
+        {
+/*
+pc.printf("alist --\n");
+            work_garbageCollect(g_alist);
+pc.printf("oblist --\n");
+            work_garbageCollect(g_oblist);
+*/
+//pc.printf("alist --\n");
+//debug(g_alist);
+pc.printf("\noblist --\n");
+debug(g_oblist);
+
+            return NULL;
+        }
+        case FFREEMEM:
+        {
+            LIST * p = memfreesize();
+            if (p != NULL) {
+                p->gcbit = GARBAGE;
+            }
+            return p;
+        }
+        case FWAIT:
+        {
+            LIST * p = mbed_wait(eval(car(cdr(x)), alist));
+            if (p != NULL) {
+                p->gcbit = GARBAGE;
+            }
+            return p;
+        }
+        case FDOUT:
+            return mbed_digitalout(eval(car(cdr(x)), alist), eval(cdr(cdr(x)), alist));
+        case FDIN:
+            return mbed_digitalin(eval(car(cdr(x)), alist), eval(cdr(cdr(x)), alist));
+        case FAOUT:
+            return mbed_analogout(eval(car(cdr(x)), alist), eval(cdr(cdr(x)), alist));
+        case FAIN:
+            return mbed_analogin(eval(car(cdr(x)), alist));
+        case PWMOUT:
+            return mbed_pwmout(eval(car(cdr(x)), alist), eval(car(cdr(cdr(x))), alist), eval(cdr(cdr(cdr(x))), alist));
+    }
+    
+    return NULL;
+}
+
+
+LIST *evalcond(LIST *expr, LIST *alist)
+{
+    if (expr == NULL) {
+        return NULL;
+    }
+
+    if (eval(car(car(expr)), alist) != NULL) {      // expr was true
+        return eval(car(cdr(car(expr))), alist);    // return result
+    }
+
+    return evalcond(cdr(expr), alist);        // eval rest of args
+}
+
+
+LIST *evalprog(LIST *p, LIST *alist)
+{
+    LIST *x = NULL;
+
+    // set up parameters as locals
+    alist = pairargs(car(cdr(p)), cons(NULL, NULL), alist, TRUE);
+    progon = TRUE;
+    p = cdr(cdr(p));     /* p now points to the statement list */
+    find_labels(p);  /* set up all labels in the prog */
+
+    while (p != NULL && progon) {
+        x = eval(car(p), alist);
+        if (type(car(car(p))) == GO) {
+            p = x;       /* GO returned the next statement to go to */
+        } else {
+            p = cdr(p);  /* just follow regular chain of statements */
+
+        }
+    }
+
+    progon = TRUE;   /* in case of nested progs */
+    return x;
+}
+
+// pairargs - installs parameters in the alist, and sets the value to be the value of the corresponding argument.
+LIST *pairargs(LIST *params, LIST *args, LIST *alist, int prog)
+{
+    if (params == NULL) {  // no more args to be evaluated
+        return alist;
+    }
+
+    LIST *p = cons(NULL, car(args));  // value of param is corresponding arg
+    p->u.pname = getname(car(car(params)));
+    rplact(p, VARI);
+    if (prog) {
+        return cons(p, pairargs(cdr(params), cons(NULL,NULL), alist, prog));
+    }
+
+    return cons(p, pairargs(cdr(params), cdr(args),   alist, prog));
+}
+
+LIST *evalargs(LIST *arglist, LIST *alist)
+{
+    if (arglist == NULL) {
+        return NULL;
+    }
+
+    return cons(eval(car(arglist),alist), evalargs(cdr(arglist), alist));
+}
+
+LIST *assoc( LIST *alist, char *name)
+{
+    return cdr(getvar(alist, name));
+}
+
+LIST *getvar(LIST *alist, char *name)
+{
+    return lookup(alist, name);
+}
+
+// arith - performs arithmetic on numeric items
+LIST *arith(LIST *op, LIST *x, LIST *y)
+{
+    LIST *p;
+    float res = 0;
+    int t = type(op);
+
+    if (t == LESSP) {
+        return (x->u.num < y->u.num) ? TRU : NULL;
+    }
+    if (t == GREATERP) {
+        return (x->u.num > y->u.num) ? TRU : NULL;
+    }
+
+    switch (t) {
+        case PLUS:
+            res = x->u.num + y->u.num;
+            break;
+        case DIFF:
+            res = x->u.num - y->u.num;
+            break;
+        case TIMES:
+            res = x->u.num * y->u.num;
+            break;
+        case QUOTIENT:
+            res = x->u.num / y->u.num;
+            break;
+        case ADD1:
+            res = x->u.num + 1;
+            break;
+        case SUB1:
+            res = x->u.num - 1;
+            break;
+    }
+
+    p = cons(NULL, NULL);
+
+// @TODO: tがADD1かSUB1の場合、yは必ずNULLなので、 type(y)を実行するとエラーだと思うんだが...
+/*
+    if (    (type(x) == IATOM) &&
+            (type(y) == IATOM) ||
+                (t == ADD1) || (t == SUB1)  )
+        ) {
+*/
+    if ((type(x) == IATOM) && ((t == ADD1) || (t == SUB1))) {
+        p->u.num = (int)res;
+        rplact(p, IATOM);
+    } else {
+        p->u.num = res;
+        rplact(p, RATOM);
+    }
+    
+    return p;
+}
+
+//----------------------------------------------------------------
+// input functions
+//----------------------------------------------------------------
+
+// advance - skips white space in input file
+int advance()
+{
+    int c;
+#if 0
+    while (((c = getc_mine(fd)) != EOF) && (strchr(" \t\n", c) != NULL));
+#else
+    while (1) {
+        c = getc_mine(fd);
+        if (c == EOF) {
+            break;
+        }
+        if (strchr(" \t\n\r", c) == NULL) {
+            break;
+        }
+    }
+#endif
+    ungetc_mine(c, fd);
+//pc.printf("%c", c);
+
+    return c;
+}
+
+LIST *lookup(LIST *head, char *name)
+{
+    LIST *p;
+
+#if 0
+    for (p = head; p != NULL && strcmp(name, getname(car(p))); p = cdr(p)) {
+        ;
+    }
+#else
+    p = head;
+    while (p != NULL) {
+        if (strcmp(name, getname(car(p))) == 0) {
+            break;
+        }
+        p = cdr(p);
+    }
+#endif
+
+    return ((p == NULL) ? NULL : car(p));
+}
+
+LIST *install(char *name, int nameConstKind = 0)
+{
+    LIST *p;
+
+    p = cons(NULL, NULL);
+#if 0
+    strcpy(p->u.pname = (char *)emalloc(strlen(name) + 1), name);
+#else
+if (nameConstKind == 0) {    
+    p->u.pname = (char *)emalloc(strlen(name) + 1);
+    strcpy(p->u.pname, name);
+} else {
+    p->u.pname = name;
+}
+#endif
+    rplact(p, VARI);
+    g_alist = cons(p, g_alist);
+
+    return p;
+}
+
+LIST *getnum()
+{
+    LIST *p;
+    float sum, n;
+    int c;
+
+    sum = 0.0;
+    p = cons(NULL, NULL);
+    rplact(p, IATOM);
+
+    while (isdigit(c = getc_mine(fd))) {
+        sum = sum * 10 + c - '0';
+    }
+
+    if (c == '.') {  /* the number is real */
+        n = 10;
+        rplact(p, RATOM);
+        //while (isdigit(c = getc(fd))) {
+        while (isdigit(c = getc_mine(fd))) {
+                sum += (c - '0')/n;
+            n *= 10;
+        }
+    }
+
+    ungetc_mine(c, fd);
+    p->u.num = sum;
+
+    return p;
+}
+
+LIST *getid()
+{
+    LIST *p;
+
+    char inbuf[120];
+    char *s = inbuf;
+    LIST *idptr;
+
+    int c = getc_mine(fd);
+    *s = c;
+    s++;
+    if (c != '\'') {
+        while(1) {
+            c = getc_mine(fd);
+            if (!isalnum(c)) {
+                ungetc_mine(c, fd);
+                break;
+            }
+            *s = c;
+            s++;
+        }
+    }
+    *s = '\0';
+
+    if ((idptr = lookup(g_oblist, inbuf)) == NULL) {    // not a LISP function
+        if ((idptr = lookup(g_alist, inbuf)) == NULL) { // id not declared yet
+            idptr = install(inbuf, 0);                     // install it in g_alist (alist)
+        }
+    }
+    p = cons(idptr, NULL);
+    rplact(p, type(idptr));
+
+    return p;
+}
+
+int gettok()
+{
+    int c;
+ 
+    while ((c = advance()) == ';') {    // saw a comment
+        while (1) {
+            c = getc_mine(fd);
+            if ((c == EOF) || (c == '\n')) { // EOF or CR
+                break;
+            }
+        }
+    }
+
+    if (isalpha(c)) {
+        return LETTER;
+    }
+    if (isdigit(c)) {
+        return DIGIT;
+    }
+    switch (c) {
+        case '(':
+            return LPAREN;
+        case ')':
+            return RPAREN;
+        case '\'':
+            return INQUOTE;
+        case EOF:
+            return EOF;
+    }
+    
+    return ERR;
+}
+
+//----------------------------------------------------------------
+// LISP primitive functions
+//----------------------------------------------------------------
+
+// new - gets a new node from the free storage
+LIST *new_malisp()
+{
+    LIST *p = (struct LIST *)emalloc(sizeof(LIST));
+    p->gcbit = RUNNING;
+
+    return p;
+}
+
+int type(LIST *p)
+{
+    return p->htype;
+}
+
+char* getname(LIST *p)
+{
+    return (p == NULL) ? NULL : p->u.pname;
+}
+
+// pのcar部をqに置き換える
+void rplaca(LIST *p, LIST *q)
+{
+    p->left = q;
+}
+
+// pのcdr部をqに置き換える
+void rplacd(LIST *p, LIST *q)
+{
+    p->right = q;
+}
+
+// pのタイプ(htype)をtに置き換える
+void rplact(LIST *p, int t)
+{
+    p->htype = t;
+}
+
+LIST *car(LIST *p)
+{
+    return (p == NULL) ? NULL : p->left;
+}
+
+LIST *cdr(LIST *p)
+{
+    return (p == NULL) ? NULL : p->right;
+}
+
+LIST *cons(LIST *p, LIST *q)
+{
+    LIST *x = new_malisp();
+
+/*
+// for debug
+{
+    static int num = 0;
+    x->gcbit = (num << 16) | x->gcbit;
+pc.printf("cons-num(%08x): %d\n", x->gcbit, num);
+
+    num++;
+}
+*/
+    rplaca(x, p);
+    rplacd(x, q);
+    rplact(x, LST);
+
+    return x;
+}
+
+LIST *eq(LIST *x, LIST *y)
+{
+    if (x == NULL || y == NULL) {
+        if (x == y) {
+            return TRU;
+        }
+    } else if (type(x) == SATOM && type(y) == SATOM && car(x) == car(y)) {
+        return TRU;
+    }
+
+    return NULL;
+}
+
+LIST *atom(LIST *x)
+{
+    int typ;
+
+    if (x == NULL || (typ = type(x)) == IATOM || typ == RATOM || typ == SATOM) {
+        return TRU;
+    }
+
+    return NULL;
+}
+
+//----------------------------------------------------------------
+// logical connectives - and, or, not
+
+LIST *_and(LIST *x)
+{
+    LIST *p;
+    for (p = cdr(x); p != NULL; p = cdr(p)) {
+        if (eval(car(p), NULL) == NULL) {
+            return NULL;
+        }
+    }
+
+    return TRU;
+}
+
+LIST *_or(LIST *x)
+{
+    LIST *p;
+    for (p = cdr(x); p != NULL; p = cdr(p)) {
+        if (eval(car(p), NULL) != NULL) {
+            return TRU;
+        }
+    }
+
+    return NULL;
+}
+
+LIST *_not(LIST *x)
+{
+    return (eval(cdr(x), NULL) == NULL) ? TRU : NULL;
+}
+
+// other primitives
+
+LIST *_list(LIST *x)
+{
+    LIST *res, *p;
+
+    for (res = NULL, p = cdr(x);  p != NULL;  p = cdr(p)) {
+        res = cons(res, car(p));
+    }
+
+    return res;
+}
+
+
+void var_to_user(LIST *p)
+{
+    if (p == NULL) {
+        return;
+    }
+
+    if (type(p) == VARI) {
+        if (type(car(p)) == FUSER) {
+            rplact(p, FUSER);
+        }
+    } else if (type(p) == LST) {
+        var_to_user(car(p));
+        var_to_user(cdr(p));
+    }
+}
+
+void var_to_atom(LIST *p)
+{
+    int t;
+
+    if (p != NULL) {
+        if (((t = type(p)) != LST && !isfunc(t)) || t == FUSER) {
+            rplact(p, SATOM);
+        } else {
+            var_to_atom(car(p));   var_to_atom(cdr(p));
+        }
+    }
+}
+
+// find_labels - change the type of all labels in a PROG to LABL
+void find_labels(LIST *p)
+{
+    for ( ;  p != NULL;  p = cdr(p)) {
+        if (type(car(p)) == VARI) {
+            rplact(car(p), LABL);           // change the type to LABL
+            rplacd(car(car(p)), cdr(p));    // label points to next statement
+        }
+    }
+}
+
+//----------------------------------------------------------------
+// garbage collection
+//----------------------------------------------------------------
+
+void work_garbageCollect(LIST *p)
+{
+    int cnt = 0;
+    while (p != NULL) {
+
+        int t = type(p);
+
+        pc.printf("[%d] ", cnt);
+        pc.printf("(%d) ", t);
+        if ((t == IATOM) || (t == RATOM)) {
+            pc.printf("[%f ] : ", p->u.num);
+        } else if (t == SATOM) {
+            pc.printf("[%s ] : ", p->u.pname);
+        } else {
+            pc.printf(" : ");
+        }
+
+        pc.printf("%d : ", (p->gcbit >> 16) & 0xff);    // num
+        pc.printf("%d \n", (p->gcbit & 0xff));          // bit (USED/RUNNING)
+        
+        p = cdr(p);
+        cnt++;
+    }
+}
+
+//  marktree - recursively marks all used items in a list
+void marktree(LIST *p)
+{
+    if (p != NULL) {
+        if (type(p) == LST) {
+            marktree(car(p));
+            marktree(cdr(p));
+        }
+        p->gcbit = USED;
+    }
+}
+
+/*********************** storage allocator *****************/
+
+void *emalloc(size_t size)
+{
+    void *s;
+
+    if ((s = malloc(size)) == NULL) {
+        pc.printf("OUT OF MEMORY !! : crashed !! \n");
+        exit(0);
+    }
+
+    return s;
+}
+
+// routine to load the library of lisp functions in
+void load_library(void)
+{
+#if 0
+    char libpath[1024];
+    strcpy(libpath, getenv("HOME"));
+    strcat(libpath, "/lisplib");
+    
+    if ((fd = fopen(libpath, "r")) !=  NULL) {
+        interpret_malisp();
+        fclose(fd);
+        
+        pc.printf("loaded lisplib from %s\n", libpath);
+    }
+    interpret_malisp();
+    
+    fd = stdin;
+#else
+
+    fd = FILE_STRING;
+    interpret_malisp();
+    pc.printf("loaded lisplib from flash\n");
+
+    fd = FILE_SERIAL;
+
+#endif
+}
+
+// isfunc - returns YES if type t is a user-function or a lisp primitive
+int isfunc(int t)
+{
+    return
+        (   t==FUSER || t==ADD1 || t==SUB1 || t==PLUS || t==DIFF || t==TIMES ||
+            t==QUOTIENT || t==LESSP || t==GREATERP || t==ZEROP || t==NUMBERP ||
+            t==FCAR || t==FCDR || t==FCONS || t==FREAD || t==PRINT || t==FNOT||
+            t==FAND || t==FOR  || t==FEVAL || t==FEQ || t==FATOM ||
+
+            // mbed extends
+            t == FFREEMEM || t == FWAIT || t == FDOUT || t == FDIN ||
+            t == FAOUT || t == FAIN || t == PWMOUT
+        );
+}
+
+void debug(LIST *p)
+{
+    pc.printf("DEBUG ---\n");
+    debug2(p);
+    pc.printf("\n");
+}
+
+void debug2(LIST *p)
+{
+  int t;
+
+  if (p != NULL) {
+    if ((t = type(p)) == LST) {
+        pc.printf("(");
+        debug2(car(p));
+        debug2(cdr(p));
+        pc.printf(")");
+    } else if (t == RATOM) {
+        pc.printf("RATOM %f ", p->u.num);
+    } else if (t == IATOM) {
+        pc.printf("IATOM %d ", (int) p->u.num);
+    } else if (t == SATOM) {
+        pc.printf("SATOM %s ", getname(car(p)));
+    } else {
+        pc.printf("FUNC %d ", type(p));
+    }
+  }
+}