diff --git a/ulisp-arm.ino b/ulisp-arm.ino index 480dd8b..c84ed29 100644 --- a/ulisp-arm.ino +++ b/ulisp-arm.ino @@ -1,5 +1,5 @@ -/* uLisp ARM 3.1 - www.ulisp.com - David Johnson-Davies - www.technoblogy.com - 20th February 2020 +/* uLisp ARM 3.2 - www.ulisp.com + David Johnson-Davies - www.technoblogy.com - 29th April 2020 Licensed under the MIT license: https://opensource.org/licenses/MIT */ @@ -11,11 +11,13 @@ const char LispLibrary[] PROGMEM = ""; // #define resetautorun #define printfreespace -#define serialmonitor // #define printgcs // #define sdcardsupport +// #define gfxsupport // #define lisplibrary #define assemblerlist +// #define lineeditor +// #define vt100 // Includes @@ -25,6 +27,22 @@ const char LispLibrary[] PROGMEM = ""; #include #include +#if defined(gfxsupport) +#include // Core graphics library +#include // Hardware-specific library for ST7735 +#define COLOR_WHITE 0xffff +#define COLOR_BLACK 0 + +// Adafruit PyBadge/PyGamer +#define TFT_CS 44 // Chip select +#define TFT_RST 46 // Display reset +#define TFT_DC 45 // Display data/command select +#define TFT_BACKLIGHT 47 // Display backlight pin +#define TFT_MOSI 41 // Data out +#define TFT_SCLK 42 // Clock out +Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST); +#endif + #if defined(sdcardsupport) #include #define SDSIZE 172 @@ -46,11 +64,12 @@ const char LispLibrary[] PROGMEM = ""; #define push(x, y) ((y) = cons((x),(y))) #define pop(y) ((y) = cdr(y)) -#define integerp(x) ((x) != NULL && ((x)->type == NUMBER || (x)->type == NUMHEX)) +#define integerp(x) ((x) != NULL && (x)->type == NUMBER) #define floatp(x) ((x) != NULL && (x)->type == FLOAT) #define symbolp(x) ((x) != NULL && (x)->type == SYMBOL) #define stringp(x) ((x) != NULL && (x)->type == STRING) #define characterp(x) ((x) != NULL && (x)->type == CHARACTER) +#define arrayp(x) ((x) != NULL && (x)->type == ARRAY) #define streamp(x) ((x) != NULL && (x)->type == STREAM) #define mark(x) (car(x) = (object *)(((uintptr_t)(car(x))) | MARKBIT)) @@ -69,24 +88,28 @@ const char LispLibrary[] PROGMEM = ""; // Constants const int TRACEMAX = 3; // Number of traced functions -enum type { ZERO=0, SYMBOL=2, CODE=4, NUMBER=6, NUMHEX=8, STREAM=10, CHARACTER=12, FLOAT=14, STRING=16, PAIR=18 }; // STRING and PAIR must be last +enum type { ZZERO=0, SYMBOL=2, CODE=4, NUMBER=6, STREAM=8, CHARACTER=10, FLOAT=12, ARRAY=14, STRING=16, PAIR=18 }; // ARRAY STRING and PAIR must be last enum token { UNUSED, BRA, KET, QUO, DOT }; -enum stream { SERIALSTREAM, I2CSTREAM, SPISTREAM, SDSTREAM }; +enum stream { SERIALSTREAM, I2CSTREAM, SPISTREAM, SDSTREAM, STRINGSTREAM, GFXSTREAM }; -enum function { NIL, TEE, NOTHING, OPTIONAL, AMPREST, LAMBDA, LET, LETSTAR, CLOSURE, SPECIAL_FORMS, QUOTE, -DEFUN, DEFVAR, SETQ, LOOP, RETURN, PUSH, POP, INCF, DECF, SETF, DOLIST, DOTIMES, TRACE, UNTRACE, -FORMILLIS, WITHSERIAL, WITHI2C, WITHSPI, WITHSDCARD, DEFCODE, TAIL_FORMS, PROGN, IF, COND, WHEN, UNLESS, -CASE, AND, OR, FUNCTIONS, NOT, NULLFN, CONS, ATOM, LISTP, CONSP, SYMBOLP, BOUNDP, SET, STREAMP, EQ, CAR, -FIRST, CDR, REST, CAAR, CADR, SECOND, CDAR, CDDR, CAAAR, CAADR, CADAR, CADDR, THIRD, CDAAR, CDADR, CDDAR, -CDDDR, LENGTH, LIST, REVERSE, NTH, ASSOC, MEMBER, APPLY, FUNCALL, APPEND, MAPC, MAPCAR, MAPCAN, ADD, -SUBTRACT, MULTIPLY, DIVIDE, MOD, ONEPLUS, ONEMINUS, ABS, RANDOM, MAXFN, MINFN, NOTEQ, NUMEQ, LESS, LESSEQ, -GREATER, GREATEREQ, PLUSP, MINUSP, ZEROP, ODDP, EVENP, INTEGERP, NUMBERP, FLOATFN, FLOATP, SIN, COS, TAN, -ASIN, ACOS, ATAN, SINH, COSH, TANH, EXP, SQRT, LOG, EXPT, CEILING, FLOOR, TRUNCATE, ROUND, CHAR, CHARCODE, -CODECHAR, CHARACTERP, STRINGP, STRINGEQ, STRINGLESS, STRINGGREATER, SORT, STRINGFN, CONCATENATE, SUBSEQ, +enum function { NIL, TEE, NOTHING, OPTIONAL, INITIALELEMENT, AMPREST, LAMBDA, LET, LETSTAR, CLOSURE, +SPECIAL_FORMS, QUOTE, DEFUN, DEFVAR, SETQ, LOOP, RETURN, PUSH, POP, INCF, DECF, SETF, DOLIST, DOTIMES, +TRACE, UNTRACE, FORMILLIS, WITHOUTPUTTOSTRING, WITHSERIAL, WITHI2C, WITHSPI, WITHSDCARD, WITHGFX, DEFCODE, +TAIL_FORMS, PROGN, IF, COND, WHEN, UNLESS, CASE, AND, OR, FUNCTIONS, NOT, NULLFN, CONS, ATOM, LISTP, +CONSP, SYMBOLP, ARRAYP, BOUNDP, SETFN, STREAMP, EQ, CAR, FIRST, CDR, REST, CAAR, CADR, SECOND, CDAR, CDDR, +CAAAR, CAADR, CADAR, CADDR, THIRD, CDAAR, CDADR, CDDAR, CDDDR, LENGTH, ARRAYDIMENSIONS, LIST, MAKEARRAY, +REVERSE, NTH, AREF, ASSOC, MEMBER, APPLY, FUNCALL, APPEND, MAPC, MAPCAR, MAPCAN, ADD, SUBTRACT, MULTIPLY, +DIVIDE, MOD, ONEPLUS, ONEMINUS, ABS, RANDOM, MAXFN, MINFN, NOTEQ, NUMEQ, LESS, LESSEQ, GREATER, GREATEREQ, +PLUSP, MINUSP, ZEROP, ODDP, EVENP, INTEGERP, NUMBERP, FLOATFN, FLOATP, SIN, COS, TAN, ASIN, ACOS, ATAN, +SINH, COSH, TANH, EXP, SQRT, LOG, EXPT, CEILING, FLOOR, TRUNCATE, ROUND, CHAR, CHARCODE, CODECHAR, +CHARACTERP, STRINGP, STRINGEQ, STRINGLESS, STRINGGREATER, SORT, STRINGFN, CONCATENATE, SUBSEQ, READFROMSTRING, PRINCTOSTRING, PRIN1TOSTRING, LOGAND, LOGIOR, LOGXOR, LOGNOT, ASH, LOGBITP, EVAL, GLOBALS, LOCALS, MAKUNBOUND, BREAK, READ, PRIN1, PRINT, PRINC, TERPRI, READBYTE, READLINE, WRITEBYTE, WRITESTRING, WRITELINE, RESTARTI2C, GC, ROOM, SAVEIMAGE, LOADIMAGE, CLS, PINMODE, DIGITALREAD, DIGITALWRITE, -ANALOGREAD, ANALOGWRITE, DELAY, MILLIS, SLEEP, NOTE, EDIT, PPRINT, PPRINTALL, REQUIRE, LISTLIBRARY, ENDFUNCTIONS }; +ANALOGREAD, ANALOGWRITE, DELAY, MILLIS, SLEEP, NOTE, EDIT, PPRINT, PPRINTALL, FORMAT, REQUIRE, +LISTLIBRARY, DRAWPIXEL, DRAWLINE, DRAWRECT, FILLRECT, DRAWCIRCLE, FILLCIRCLE, DRAWROUNDRECT, +FILLROUNDRECT, DRAWTRIANGLE, FILLTRIANGLE, DRAWCHAR, SETCURSOR, SETTEXTCOLOR, SETTEXTSIZE, SETTEXTWRAP, +FILLSCREEN, SETROTATION, INVERTDISPLAY, ENDFUNCTIONS }; // Typedefs @@ -103,6 +126,7 @@ typedef struct sobject { union { symbol_t name; int integer; + int chars; // For strings float single_float; }; }; @@ -115,8 +139,7 @@ typedef int (*intfn_ptr_type)(int w, int x, int y, int z); typedef struct { const char *string; fn_ptr_type fptr; - uint8_t min; - uint8_t max; + uint8_t minmax; } tbl_entry_t; typedef int (*gfun_t)(); @@ -129,8 +152,8 @@ typedef int PinMode; #define BUFFERSIZE 34 // Number of bits+2 #define RAMFUNC __attribute__ ((section (".ramfunctions"))) -#if defined(ARDUINO_ITSYBITSY_M0) || defined(ARDUINO_FEATHER_M0_EXPRESS) - #define WORKSPACESIZE 3072-SDSIZE /* Objects (8*bytes) */ +#if defined(ARDUINO_ITSYBITSY_M0) || defined(ARDUINO_SAMD_FEATHER_M0_EXPRESS) + #define WORKSPACESIZE 2816-SDSIZE /* Objects (8*bytes) */ #define DATAFLASHSIZE 2048000 /* 2 MBytes */ #define SYMBOLTABLESIZE 512 /* Bytes */ #define CODESIZE 128 /* Bytes */ @@ -138,33 +161,33 @@ typedef int PinMode; #define STACKDIFF 320 #elif defined(ARDUINO_GEMMA_M0) - #define WORKSPACESIZE 3072-SDSIZE /* Objects (8*bytes) */ + #define WORKSPACESIZE 2816-SDSIZE /* Objects (8*bytes) */ #define SYMBOLTABLESIZE 512 /* Bytes */ #define CODESIZE 128 /* Bytes */ #define STACKDIFF 320 -#elif defined(ARDUINO_METRO_M4) || defined(ARDUINO_ITSYBITSY_M4) || defined(ARDUINO_FEATHER_M4) +#elif defined(ARDUINO_METRO_M4) || defined(ARDUINO_ITSYBITSY_M4) || defined(ARDUINO_FEATHER_M4) || defined(ARDUINO_PYBADGE_M4) || defined(ARDUINO_PYGAMER_M4) #define WORKSPACESIZE 20480-SDSIZE /* Objects (8*bytes) */ #define DATAFLASHSIZE 2048000 /* 2 MBytes */ #define SYMBOLTABLESIZE 1024 /* Bytes */ #define CODESIZE 256 /* Bytes */ - #define STACKDIFF 320 + #define STACKDIFF 400 #elif defined(ARDUINO_GRAND_CENTRAL_M4) - #define WORKSPACESIZE 30720-SDSIZE /* Objects (8*bytes) */ + #define WORKSPACESIZE 28672-SDSIZE /* Objects (8*bytes) */ #define DATAFLASHSIZE 8192000 /* 8 MBytes */ #define SYMBOLTABLESIZE 1024 /* Bytes */ #define CODESIZE 256 /* Bytes */ - #define STACKDIFF 320 + #define STACKDIFF 400 #elif defined(ARDUINO_SAMD_MKRZERO) - #define WORKSPACESIZE 3072-SDSIZE /* Objects (8*bytes) */ + #define WORKSPACESIZE 2816-SDSIZE /* Objects (8*bytes) */ #define SYMBOLTABLESIZE 512 /* Bytes */ #define CODESIZE 128 /* Bytes */ #define STACKDIFF 840 #elif defined(ARDUINO_SAMD_ZERO) /* Put this last, otherwise overrides the Adafruit boards */ - #define WORKSPACESIZE 3072-SDSIZE /* Objects (8*bytes) */ + #define WORKSPACESIZE 2816-SDSIZE /* Objects (8*bytes) */ #define SYMBOLTABLESIZE 512 /* Bytes */ #define CODESIZE 128 /* Bytes */ #define SDCARD_SS_PIN 10 @@ -184,11 +207,11 @@ typedef int PinMode; #define STACKDIFF 1200 #elif defined(ARDUINO_NRF52840_CLUE) - #define WORKSPACESIZE 20480-SDSIZE /* Objects (8*bytes) */ + #define WORKSPACESIZE 19456-SDSIZE /* Objects (8*bytes) */ #define DATAFLASHSIZE 2048000 /* 2 MBytes */ #define SYMBOLTABLESIZE 1024 /* Bytes */ #define CODESIZE 256 /* Bytes */ - #define STACKDIFF 2048 + #define STACKDIFF 0 #elif defined(MAX32620) #define WORKSPACESIZE 24576-SDSIZE /* Objects (8*bytes) */ @@ -196,6 +219,12 @@ typedef int PinMode; #define CODESIZE 256 /* Bytes */ #define STACKDIFF 320 +#elif defined(ARDUINO_FEATHER_F405) + #define WORKSPACESIZE 11840-SDSIZE /* Objects (8*bytes) */ + #define SYMBOLTABLESIZE 1024 /* Bytes */ + #define CODESIZE 256 /* Bytes */ + #define STACKDIFF 320 + #endif object Workspace[WORKSPACESIZE] WORDALIGNED; @@ -216,7 +245,8 @@ object *GlobalEnv; object *GCStack = NULL; object *GlobalString; int GlobalStringIndex = 0; -char BreakLevel = 0; +uint8_t PrintCount = 0; +uint8_t BreakLevel = 0; char LastChar = 0; char LastPrint = 0; @@ -228,14 +258,55 @@ volatile char Flags = 0b00001; // PRINTREADABLY set by default object *tee; object *tf_progn (object *form, object *env); object *eval (object *form, object *env); -object *read (); -void repl(object *env); +object *read (gfun_t gfun); +void repl (object *env); void printobject (object *form, pfun_t pfun); char *lookupbuiltin (symbol_t name); intptr_t lookupfn (symbol_t name); int builtin (char* n); -void error (symbol_t fname, PGM_P string, object *symbol); -void error2 (symbol_t fname, PGM_P string); + +// Error handling + +void errorsub (symbol_t fname, PGM_P string) { + pfl(pserial); pfstring(PSTR("Error: "), pserial); + if (fname) { + pserial('\''); + pstring(symbolname(fname), pserial); + pfstring(PSTR("' "), pserial); + } + pfstring(string, pserial); +} + +void error (symbol_t fname, PGM_P string, object *symbol) { + errorsub(fname, string); + pfstring(PSTR(": "), pserial); printobject(symbol, pserial); + pln(pserial); + GCStack = NULL; + longjmp(exception, 1); +} + +void error2 (symbol_t fname, PGM_P string) { + errorsub(fname, string); + pln(pserial); + GCStack = NULL; + longjmp(exception, 1); +} + +// Save space as these are used multiple times +const char notanumber[] PROGMEM = "argument is not a number"; +const char notastring[] PROGMEM = "argument is not a string"; +const char notalist[] PROGMEM = "argument is not a list"; +const char notasymbol[] PROGMEM = "argument is not a symbol"; +const char notproper[] PROGMEM = "argument is not a proper list"; +const char toomanyargs[] PROGMEM = "too many arguments"; +const char toofewargs[] PROGMEM = "too few arguments"; +const char noargument[] PROGMEM = "missing argument"; +const char nostream[] PROGMEM = "missing stream argument"; +const char overflow[] PROGMEM = "arithmetic overflow"; +const char invalidarg[] PROGMEM = "invalid argument"; +const char invalidpin[] PROGMEM = "invalid pin"; +const char resultproper[] PROGMEM = "result is not a proper list"; +const char oddargs[] PROGMEM = "odd number of arguments"; // Set up workspace @@ -274,13 +345,6 @@ object *number (int n) { return ptr; } -object *numhex (int n) { - object *ptr = myalloc(); - ptr->type = NUMHEX; - ptr->integer = n; - return ptr; -} - object *makefloat (float f) { object *ptr = myalloc(); ptr->type = FLOAT; @@ -342,12 +406,17 @@ void markobject (object *obj) { unsigned int type = obj->type; mark(obj); - if (type >= PAIR || type == ZERO) { // cons + if (type >= PAIR || type == ZZERO) { // cons markobject(arg); obj = cdr(obj); goto MARK; } + if (type == ARRAY) { + obj = cdr(obj); + goto MARK; + } + if (type == STRING) { obj = cdr(obj); while (obj != NULL) { @@ -388,7 +457,7 @@ void movepointer (object *from, object *to) { for (int i=0; itype) & ~MARKBIT; - if (marked(obj) && (type >= STRING || type==ZERO)) { + if (marked(obj) && (type >= ARRAY || type==ZZERO)) { if (car(obj) == (object *)((uintptr_t)from | MARKBIT)) car(obj) = (object *)((uintptr_t)to | MARKBIT); if (cdr(obj) == from) cdr(obj) = to; @@ -407,7 +476,7 @@ void movepointer (object *from, object *to) { } } -int compactimage (object **arg) { +uintptr_t compactimage (object **arg) { markobject(tee); markobject(GlobalEnv); markobject(GCStack); @@ -523,7 +592,7 @@ void FlashBeginWrite (int blocks) { FlashWriteEnable(); digitalWrite(ssel, 0); FlashWrite(BLOCK64K); - FlashWrite(0); FlashWrite(b); FlashWrite(0); + FlashWrite(b); FlashWrite(0); FlashWrite(0); digitalWrite(ssel, 1); FlashBusy(); } @@ -591,7 +660,7 @@ int saveimage (object *arg) { if (!(arg == NULL || listp(arg))) error(SAVEIMAGE, PSTR("illegal argument"), arg); if (!FlashSetup()) error2(SAVEIMAGE, PSTR("no DataFlash found.")); // Save to DataFlash - int bytesneeded = imagesize*8 + SYMBOLTABLESIZE + 20; + int bytesneeded = 20 + SYMBOLTABLESIZE + CODESIZE + imagesize*8; if (bytesneeded > DATAFLASHSIZE) error(SAVEIMAGE, PSTR("image size too large"), number(imagesize)); uint32_t addr = 0; FlashBeginWrite((bytesneeded+65535)/65536); @@ -710,48 +779,9 @@ void autorunimage () { #endif } -// Error handling - -void errorsub (symbol_t fname, PGM_P string) { - pfl(pserial); pfstring(PSTR("Error: "), pserial); - if (fname) { - pserial('\''); - pstring(symbolname(fname), pserial); - pfstring(PSTR("' "), pserial); - } - pfstring(string, pserial); -} - -void error (symbol_t fname, PGM_P string, object *symbol) { - errorsub(fname, string); - pfstring(PSTR(": "), pserial); printobject(symbol, pserial); - pln(pserial); - GCStack = NULL; - longjmp(exception, 1); -} - -void error2 (symbol_t fname, PGM_P string) { - errorsub(fname, string); - pln(pserial); - GCStack = NULL; - longjmp(exception, 1); -} - -// Save space as these are used multiple times -const char notanumber[] PROGMEM = "argument is not a number"; -const char notastring[] PROGMEM = "argument is not a string"; -const char notalist[] PROGMEM = "argument is not a list"; -const char notasymbol[] PROGMEM = "argument is not a symbol"; -const char notproper[] PROGMEM = "argument is not a proper list"; -const char noargument[] PROGMEM = "missing argument"; -const char nostream[] PROGMEM = "missing stream argument"; -const char overflow[] PROGMEM = "arithmetic overflow"; -const char invalidpin[] PROGMEM = "invalid pin"; -const char resultproper[] PROGMEM = "result is not a proper list"; - // Tracing -boolean tracing (symbol_t name) { +bool tracing (symbol_t name) { int i = 0; while (i < TRACEMAX) { if (TraceFn[i] == name) return i+1; @@ -781,28 +811,32 @@ void untrace (symbol_t name) { // Helper functions -boolean consp (object *x) { +bool consp (object *x) { if (x == NULL) return false; unsigned int type = x->type; - return type >= PAIR || type == ZERO; + return type >= PAIR || type == ZZERO; } -boolean atom (object *x) { +bool atom (object *x) { if (x == NULL) return true; unsigned int type = x->type; - return type < PAIR && type != ZERO; + return type < PAIR && type != ZZERO; } -boolean listp (object *x) { +bool listp (object *x) { if (x == NULL) return true; unsigned int type = x->type; - return type >= PAIR || type == ZERO; + return type >= PAIR || type == ZZERO; } -boolean improperp (object *x) { +bool improperp (object *x) { if (x == NULL) return false; unsigned int type = x->type; - return type < PAIR && type != ZERO; + return type < PAIR && type != ZZERO; +} + +object *quote (object *arg) { + return cons(symbol(QUOTE), cons(arg,NULL)); } // Radix 40 encoding @@ -831,7 +865,7 @@ int pack40 (char *buffer) { return x; } -boolean valid40 (char *buffer) { +bool valid40 (char *buffer) { for (int i=0; i<6; i++) if (toradix40(buffer[i]) == -1) return false; return true; } @@ -856,7 +890,7 @@ int digitvalue (char d) { } int checkinteger (symbol_t name, object *obj) { - if (!integerp(obj)) error(name, PSTR("argument is not an integer"), obj); + if (!integerp(obj)) error(name, notanumber, obj); return obj->integer; } @@ -883,8 +917,7 @@ int issymbol (object *obj, symbol_t n) { void checkargs (symbol_t name, object *args) { int nargs = listlength(name, args); if (name >= ENDFUNCTIONS) error(0, PSTR("not valid here"), symbol(name)); - if (nargslookupmax(name)) error2(name, PSTR("has too many arguments")); + checkminmax(name, nargs); } int eq (object *arg1, object *arg2) { @@ -937,10 +970,130 @@ object *delassoc (object *key, object **alist) { return nil; } +// Array utilities + +int nextpower2 (int n) { + n--; n |= n >> 1; n |= n >> 2; n |= n >> 4; + n |= n >> 8; n |= n >> 16; n++; + return n<2 ? 2 : n; +} + +object *buildarray (int n, int s, object *def) { + int s2 = s>>1; + if (s2 == 1) { + if (n == 2) return cons(def, def); + else if (n == 1) return cons(def, NULL); + else return NULL; + } else if (n >= s2) return cons(buildarray(s2, s2, def), buildarray(n - s2, s2, def)); + else return cons(buildarray(n, s2, def), nil); +} + +object *makearray (symbol_t name, object *dims, object *def) { + int size = 1; + object *dimensions = dims; + while (dims != NULL) { + int d = car(dims)->integer; + if (d < 0) error2(MAKEARRAY, PSTR("dimension can't be negative")); + size = size * d; + dims = cdr(dims); + } + object *ptr = myalloc(); + ptr->type = ARRAY; + object *tree = nil; + if (size != 0) tree = buildarray(size, nextpower2(size), def); + ptr->cdr = cons(tree, dimensions); + return ptr; +} + +object **arrayref (object *array, int index, int size) { + int mask = nextpower2(size)>>1; + object **p = &car(cdr(array)); + while (mask) { + if ((index & mask) == 0) p = &(car(*p)); else p = &(cdr(*p)); + mask = mask>>1; + } + return p; +} + +object **getarray (symbol_t name, object *array, object *subs, object *env) { + int index = 0, size = 1, s; + object *dims = cddr(array); + while (dims != NULL && subs != NULL) { + int d = car(dims)->integer; + if (env) s = checkinteger(name, eval(car(subs), env)); else s = checkinteger(name, car(subs)); + if (s < 0 || s >= d) error(name, PSTR("subscript out of range"), car(subs)); + size = size * d; + index = index * d + s; + dims = cdr(dims); subs = cdr(subs); + } + if (dims != NULL) error2(name, PSTR("too few subscripts")); + if (subs != NULL) error2(name, PSTR("too many subscripts")); + return arrayref(array, index, size); +} + +void rslice (object *array, int size, int slice, object *dims, object *args) { + int d = first(dims)->integer; + for (int i = 0; i < d; i++) { + int index = slice * d + i; + if (cdr(dims) == NULL) { + if (args == NULL) error2(0, PSTR("initial contents don't match array type")); + object **p = arrayref(array, index, size); + *p = car(args); + } else rslice(array, size, index, cdr(dims), car(args)); + args = cdr(args); + } +} + +object *readarray (int d, object *args) { + object *list = args; + object *dims = NULL; object *head = NULL; + int size = 1; + for (int i = 0; i < d; i++) { + int l = listlength(0, list); + if (dims == NULL) { dims = cons(number(l), NULL); head = dims; } + else { cdr(dims) = cons(number(l), NULL); dims = cdr(dims); } + size = size * l; + if (list != NULL) list = car(list); + } + object *array = makearray(0, head, NULL); + rslice(array, size, 0, head, args); + return array; +} + +void pslice (object *array, int size, int slice, object *dims, pfun_t pfun) { + pfun('('); + int d = first(dims)->integer; + for (int i = 0; i < d; i++) { + if (i) pfun(' '); + int index = slice * d + i; + if (cdr(dims) == NULL) { + printobject(*arrayref(array, index, size), pfun); + } else pslice(array, size, index, cdr(dims), pfun); + } + pfun(')'); +} + +void printarray (object *array, pfun_t pfun) { + object *dimensions = cddr(array); + object *dims = dimensions; + int size = 1, n = 0; + while (dims != NULL) { size = size * car(dims)->integer; dims = cdr(dims); n++; } + pfun('#'); if (n > 1) { pint(n, pfun); pfun('A'); } + pslice(array, size, 0, dimensions, pfun); +} + // String utilities -void indent (int spaces, pfun_t pfun) { - for (int i=0; itype = STRING; + GlobalString = NULL; + GlobalStringIndex = 0; + return string; } void buildstring (char ch, int *chars, object **head) { @@ -952,12 +1105,12 @@ void buildstring (char ch, int *chars, object **head) { object *cell = myalloc(); if (*head == NULL) *head = cell; else tail->car = cell; cell->car = NULL; - cell->integer = *chars; + cell->chars = *chars; tail = cell; } else { shift = shift - 8; *chars = *chars | ch<integer = *chars; + tail->chars = *chars; if (shift == 0) *chars = 0; } } @@ -982,7 +1135,7 @@ int stringlength (object *form) { int length = 0; form = cdr(form); while (form != NULL) { - int chars = form->integer; + int chars = form->chars; for (int i=(sizeof(int)-1)*8; i>=0; i=i-8) { if (chars>>i & 0xFF) length++; } @@ -1001,7 +1154,22 @@ char nthchar (object *string, int n) { arg = car(arg); } if (arg == NULL) return 0; - return (arg->integer)>>(n*8) & 0xFF; + return (arg->chars)>>(n*8) & 0xFF; +} + +int gstr () { + if (LastChar) { + char temp = LastChar; + LastChar = 0; + return temp; + } + char c = nthchar(GlobalString, GlobalStringIndex++); + if (c != 0) return c; + return '\n'; // -1? +} + +void pstr (char c) { + buildstring(c, &GlobalStringIndex, &GlobalString); } // Lookup variable in environment @@ -1015,7 +1183,7 @@ object *value (symbol_t n, object *env) { return nil; } -boolean boundp (object *var, object *env) { +bool boundp (object *var, object *env) { symbol_t varname = var->name; if (value(varname, env) != NULL) return true; if (value(varname, GlobalEnv) != NULL) return true; @@ -1036,7 +1204,7 @@ object *closure (int tc, symbol_t name, object *state, object *function, object int trace = 0; if (name) trace = tracing(name); if (trace) { - indent(TraceDepth[trace-1]<<1, pserial); + indent(TraceDepth[trace-1]<<1, ' ', pserial); pint(TraceDepth[trace-1]++, pserial); pserial(':'); pserial(' '); pserial('('); pstring(symbolname(name), pserial); } @@ -1056,7 +1224,7 @@ object *closure (int tc, symbol_t name, object *state, object *function, object state = cdr(state); } // Add arguments to environment - boolean optional = false; + bool optional = false; while (params != NULL) { object *value; object *var = first(params); @@ -1079,7 +1247,7 @@ object *closure (int tc, symbol_t name, object *state, object *function, object if (args == NULL) { if (optional) value = nil; else { - if (name) error2(name, PSTR("has too few arguments")); + if (name) error2(name, toofewargs); else error2(0, PSTR("function has too few arguments")); } } else { value = first(args); args = cdr(args); } @@ -1090,7 +1258,7 @@ object *closure (int tc, symbol_t name, object *state, object *function, object params = cdr(params); } if (args != NULL) { - if (name) error2(name, PSTR("has too many arguments")); + if (name) error2(name, toomanyargs); else error2(0, PSTR("function has too many arguments")); } if (trace) { pserial(')'); pln(pserial); } @@ -1145,6 +1313,11 @@ object **place (symbol_t name, object *args, object *env) { } return &car(list); } + if (issymbol(function, AREF)) { + object *array = eval(second(args), env); + if (!arrayp(array)) error(AREF, PSTR("first argument is not an array"), array); + return getarray(AREF, array, cddr(args), env); + } error2(name, PSTR("illegal place")); return nil; } @@ -1152,13 +1325,13 @@ object **place (symbol_t name, object *args, object *env) { // Checked car and cdr inline object *carx (object *arg) { - if (!listp(arg)) error(0, PSTR("Can't take car"), arg); + if (!listp(arg)) error(0, PSTR("can't take car"), arg); if (arg == nil) return nil; return car(arg); } inline object *cdrx (object *arg) { - if (!listp(arg)) error(0, PSTR("Can't take cdr"), arg); + if (!listp(arg)) error(0, PSTR("can't take cdr"), arg); if (arg == nil) return nil; return cdr(arg); } @@ -1170,7 +1343,7 @@ void I2Cinit (bool enablePullup) { Wire.begin(); } -inline uint8_t I2Cread () { +inline int I2Cread () { return Wire.read(); } @@ -1203,14 +1376,14 @@ void I2Cstop (uint8_t read) { // Streams inline int spiread () { return SPI.transfer(0); } -#if defined(ARDUINO_NRF52840_CLUE) || defined(ARDUINO_GRAND_CENTRAL_M4) +#if defined(ARDUINO_NRF52840_CLUE) || defined(ARDUINO_GRAND_CENTRAL_M4) || defined(ARDUINO_PYBADGE_M4) || defined(ARDUINO_PYGAMER_M4) inline int spi1read () { return SPI1.transfer(0); } #endif #if defined(ARDUINO_SAM_DUE) inline int serial1read () { while (!Serial1.available()) testescape(); return Serial1.read(); } inline int serial2read () { while (!Serial2.available()) testescape(); return Serial2.read(); } inline int serial3read () { while (!Serial3.available()) testescape(); return Serial3.read(); } -#elif !defined(_VARIANT_BBC_MICROBIT_) +#elif !defined(_VARIANT_BBC_MICROBIT_) && !defined(ARDUINO_FEATHER_F405) inline int serial1read () { while (!Serial1.available()) testescape(); return Serial1.read(); } #endif #if defined(sdcardsupport) @@ -1226,7 +1399,7 @@ inline int SDread () { #endif void serialbegin (int address, int baud) { - #if defined(_VARIANT_BBC_MICROBIT_) + #if defined(_VARIANT_BBC_MICROBIT_) || defined(ARDUINO_FEATHER_F405) error(WITHSERIAL, PSTR("port not supported"), number(address)); #elif defined(ARDUINO_SAM_DUE) if (address == 1) Serial1.begin((long)baud*100); @@ -1244,7 +1417,7 @@ void serialend (int address) { if (address == 1) {Serial1.flush(); Serial1.end(); } else if (address == 2) {Serial2.flush(); Serial2.end(); } else if (address == 3) {Serial3.flush(); Serial3.end(); } - #elif !defined(_VARIANT_BBC_MICROBIT_) + #elif !defined(_VARIANT_BBC_MICROBIT_) && !defined(ARDUINO_FEATHER_F405) if (address == 1) {Serial1.flush(); Serial1.end(); } #endif } @@ -1260,7 +1433,7 @@ gfun_t gstreamfun (object *args) { if (streamtype == I2CSTREAM) gfun = (gfun_t)I2Cread; else if (streamtype == SPISTREAM) { if (address < 128) gfun = spiread; - #if defined(ARDUINO_NRF52840_CLUE) || defined(ARDUINO_GRAND_CENTRAL_M4) + #if defined(ARDUINO_NRF52840_CLUE) || defined(ARDUINO_GRAND_CENTRAL_M4) || defined(ARDUINO_PYBADGE_M4) || defined(ARDUINO_PYGAMER_M4) else gfun = spi1read; #endif } @@ -1270,7 +1443,7 @@ gfun_t gstreamfun (object *args) { else if (address == 1) gfun = serial1read; else if (address == 2) gfun = serial2read; else if (address == 3) gfun = serial3read; - #elif !defined(_VARIANT_BBC_MICROBIT_) + #elif !defined(_VARIANT_BBC_MICROBIT_) && !defined(ARDUINO_FEATHER_F405) else if (address == 1) gfun = serial1read; #endif } @@ -1282,7 +1455,7 @@ gfun_t gstreamfun (object *args) { } inline void spiwrite (char c) { SPI.transfer(c); } -#if defined(ARDUINO_NRF52840_CLUE) || defined(ARDUINO_GRAND_CENTRAL_M4) +#if defined(ARDUINO_NRF52840_CLUE) || defined(ARDUINO_GRAND_CENTRAL_M4) || defined(ARDUINO_PYBADGE_M4) || defined(ARDUINO_PYGAMER_M4) inline void spi1write (char c) { SPI1.transfer(c); } #endif #if defined(ARDUINO_SAM_DUE) @@ -1295,6 +1468,9 @@ inline void serial1write (char c) { Serial1.write(c); } #if defined(sdcardsupport) inline void SDwrite (char c) { SDpfile.write(c); } #endif +#if defined(gfxsupport) +inline void gfxwrite (char c) { tft.write(c); } +#endif pfun_t pstreamfun (object *args) { int streamtype = SERIALSTREAM; @@ -1307,7 +1483,7 @@ pfun_t pstreamfun (object *args) { if (streamtype == I2CSTREAM) pfun = (pfun_t)I2Cwrite; else if (streamtype == SPISTREAM) { if (address < 128) pfun = spiwrite; - #if defined(ARDUINO_NRF52840_CLUE) || defined(ARDUINO_GRAND_CENTRAL_M4) + #if defined(ARDUINO_NRF52840_CLUE) || defined(ARDUINO_GRAND_CENTRAL_M4) || defined(ARDUINO_PYBADGE_M4) || defined(ARDUINO_PYGAMER_M4) else pfun = spi1write; #endif } @@ -1317,13 +1493,19 @@ pfun_t pstreamfun (object *args) { else if (address == 1) pfun = serial1write; else if (address == 2) pfun = serial2write; else if (address == 3) pfun = serial3write; - #elif !defined(_VARIANT_BBC_MICROBIT_) + #elif !defined(_VARIANT_BBC_MICROBIT_) && !defined(ARDUINO_FEATHER_F405) else if (address == 1) pfun = serial1write; #endif } + else if (streamtype == STRINGSTREAM) { + pfun = pstr; + } #if defined(sdcardsupport) else if (streamtype == SDSTREAM) pfun = (pfun_t)SDwrite; #endif + #if defined(gfxsupport) + else if (streamtype == GFXSTREAM) pfun = (pfun_t)gfxwrite; + #endif else error2(0, PSTR("unknown stream type")); return pfun; } @@ -1473,6 +1655,159 @@ void sleep (int secs) { #endif } +// Prettyprint + +const int PPINDENT = 2; +const int PPWIDTH = 80; +const int GFXPPWIDTH = 52; // 320 pixel wide screen +int ppwidth = PPWIDTH; + +void pcount (char c) { + if (c == '\n') PrintCount++; + PrintCount++; +} + +uint8_t atomwidth (object *obj) { + PrintCount = 0; + printobject(obj, pcount); + return PrintCount; +} + +uint8_t hexwidth (object *obj) { + PrintCount = 0; + pinthex(obj->integer, pcount); + return PrintCount; +} + +boolean quoted (object *obj) { + return (consp(obj) && car(obj) != NULL && car(obj)->name == QUOTE && consp(cdr(obj)) && cddr(obj) == NULL); +} + +int subwidth (object *obj, int w) { + if (atom(obj)) return w - atomwidth(obj); + if (quoted(obj)) return subwidthlist(car(cdr(obj)), w - 1); + return subwidthlist(obj, w - 1); +} + +int subwidthlist (object *form, int w) { + while (form != NULL && w >= 0) { + if (atom(form)) return w - (2 + atomwidth(form)); + w = subwidth(car(form), w - 1); + form = cdr(form); + } + return w; +} + +void superprint (object *form, int lm, pfun_t pfun) { + if (atom(form)) { + if (symbolp(form) && form->name == NOTHING) pstring(symbolname(form->name), pfun); + else printobject(form, pfun); + } + else if (quoted(form)) { pfun('\''); superprint(car(cdr(form)), lm + 1, pfun); } + else if (subwidth(form, ppwidth - lm) >= 0) supersub(form, lm + PPINDENT, 0, pfun); + else supersub(form, lm + PPINDENT, 1, pfun); +} + +const int ppspecials = 18; +const char ppspecial[ppspecials] PROGMEM = + { DOTIMES, DOLIST, IF, SETQ, TEE, LET, LETSTAR, LAMBDA, WHEN, UNLESS, WITHI2C, WITHSERIAL, WITHSPI, WITHSDCARD, WITHGFX, WITHOUTPUTTOSTRING, FORMILLIS }; + +void supersub (object *form, int lm, int super, pfun_t pfun) { + int special = 0, separate = 1; + object *arg = car(form); + if (symbolp(arg)) { + int name = arg->name; + if (name == DEFUN || name == DEFCODE) special = 2; + else for (int i=0; iinteger; + else param[i] = (uintptr_t)arg; + args = cdr(args); + } + int w = ((intfn_ptr_type)&MyCode[entry])(param[0], param[1], param[2], param[3]); + return number(w); +} + +void putcode (object *arg, int origin, int pc) { + int code = checkinteger(DEFCODE, arg); + MyCode[origin+pc] = code & 0xff; + MyCode[origin+pc+1] = (code>>8) & 0xff; + #if defined(assemblerlist) + printhex4(pc, pserial); + printhex4(code, pserial); + #endif +} + +int assemble (int pass, int origin, object *entries, object *env, object *pcpair) { + int pc = 0; cdr(pcpair) = number(pc); + while (entries != NULL) { + object *arg = first(entries); + if (symbolp(arg)) { + if (pass == 2) { + #if defined(assemblerlist) + printhex4(pc, pserial); + pfstring(PSTR(" "), pserial); + printobject(arg, pserial); pln(pserial); + #endif + } else { + object *pair = findvalue(arg, env); + cdr(pair) = number(pc); + } + } else { + object *argval = eval(arg, env); + if (listp(argval)) { + object *arglist = argval; + while (arglist != NULL) { + if (pass == 2) { + putcode(first(arglist), origin, pc); + #if defined(assemblerlist) + if (arglist == argval) superprint(arg, 0, pserial); + pln(pserial); + #endif + } + pc = pc + 2; + cdr(pcpair) = number(pc); + arglist = cdr(arglist); + } + } else if (integerp(argval)) { + if (pass == 2) { + putcode(argval, origin, pc); + #if defined(assemblerlist) + superprint(arg, 0, pserial); pln(pserial); + #endif + } + pc = pc + 2; + cdr(pcpair) = number(pc); + } else error(DEFCODE, PSTR("illegal entry"), arg); + } + entries = cdr(entries); + } + // Round up to multiple of 4 to give code size + if (pc%4 != 0) pc = pc + 4 - pc%4; + return pc; +} + // Special forms object *sp_quote (object *args, object *env) { @@ -1509,7 +1844,7 @@ object *sp_defvar (object *args, object *env) { object *sp_setq (object *args, object *env) { object *arg = nil; while (args != NULL) { - if (cdr(args) == NULL) error2(SETQ, PSTR("odd number of parameters")); + if (cdr(args) == NULL) error2(SETQ, oddargs); object *pair = findvalue(first(args), env); arg = eval(second(args), env); cdr(pair) = arg; @@ -1555,7 +1890,7 @@ object *sp_pop (object *args, object *env) { return result; } -// Special forms incf/decf +// Accessors object *sp_incf (object *args, object *env) { checkargs(INCF, args); @@ -1628,7 +1963,7 @@ object *sp_decf (object *args, object *env) { object *sp_setf (object *args, object *env) { object *arg = nil; while (args != NULL) { - if (cdr(args) == NULL) error2(SETF, PSTR("odd number of parameters")); + if (cdr(args) == NULL) error2(SETF, oddargs); object **loc = place(SETF, first(args), env); arg = eval(second(args), env); *loc = arg; @@ -1637,6 +1972,8 @@ object *sp_setf (object *args, object *env) { return arg; } +// Other special forms + object *sp_dolist (object *args, object *env) { if (args == NULL) error2(DOLIST, noargument); object *params = first(args); @@ -1742,6 +2079,20 @@ object *sp_formillis (object *args, object *env) { return nil; } +object *sp_withoutputtostring (object *args, object *env) { + object *params = first(args); + if (params == NULL) error2(WITHOUTPUTTOSTRING, nostream); + object *var = first(params); + object *pair = cons(var, stream(STRINGSTREAM, 0)); + push(pair,env); + object *string = startstring(WITHOUTPUTTOSTRING); + object *forms = cdr(args); + eval(tf_progn(forms,env), env); + string->cdr = GlobalString; + GlobalString = NULL; + return string; +} + object *sp_withserial (object *args, object *env) { object *params = first(args); if (params == NULL) error2(WITHSERIAL, nostream); @@ -1812,7 +2163,7 @@ object *sp_withspi (object *args, object *env) { object *pair = cons(var, stream(SPISTREAM, pin + 128*address)); push(pair,env); SPIClass *spiClass = &SPI; - #if defined(ARDUINO_NRF52840_CLUE) || defined(ARDUINO_GRAND_CENTRAL_M4) + #if defined(ARDUINO_NRF52840_CLUE) || defined(ARDUINO_GRAND_CENTRAL_M4) || defined(ARDUINO_PYBADGE_M4) || defined(ARDUINO_PYGAMER_M4) if (address == 1) spiClass = &SPI1; #endif (*spiClass).begin(); @@ -1857,7 +2208,23 @@ object *sp_withsdcard (object *args, object *env) { #endif } -// ARM Assembler +object *sp_withgfx (object *args, object *env) { +#if defined(gfxsupport) + object *params = first(args); + object *var = first(params); + object *pair = cons(var, stream(GFXSTREAM, 1)); + push(pair,env); + object *forms = cdr(args); + object *result = eval(tf_progn(forms,env), env); + return result; +#else + (void) args, (void) env; + error2(WITHGFX, PSTR("not supported")); + return nil; +#endif +} + +// Assembler object *sp_defcode (object *args, object *env) { setflag(NOESC); @@ -1897,7 +2264,6 @@ object *sp_defcode (object *args, object *env) { int codesize = assemble(1, origin, cdr(args), env, pcpair); // See if it will fit - int bounds; object *globals = GlobalEnv; while (globals != NULL) { object *pair = car(globals); @@ -1958,78 +2324,6 @@ object *sp_defcode (object *args, object *env) { return var; } -object *call (int entry, int nargs, object *args, object *env) { - (void) env; - int param[4]; - for (int i=0; iinteger; - else param[i] = (uint32_t)arg; - args = cdr(args); - } - int w = ((intfn_ptr_type)&MyCode[entry])(param[0], param[1], param[2], param[3]); - return number(w); -} - -void putcode (object *arg, int origin, int pc) { - int code = checkinteger(DEFCODE, arg); - MyCode[origin+pc] = code & 0xff; - MyCode[origin+pc+1] = (code>>8) & 0xff; - #if defined(assemblerlist) - printhex4(pc, pserial); - printhex4(code, pserial); - #endif -} - -int assemble (int pass, int origin, object *entries, object *env, object *pcpair) { - int pc = 0; cdr(pcpair) = number(pc); - while (entries != NULL) { - object *arg = first(entries); - if (symbolp(arg)) { - if (pass == 2) { - #if defined(assemblerlist) - printhex4(pc, pserial); - pfstring(PSTR(" "), pserial); - printobject(arg, pserial); pln(pserial); - #endif - } else { - object *pair = findvalue(arg, env); - cdr(pair) = number(pc); - } - } else { - object *argval = eval(arg, env); - if (listp(argval)) { - object *arglist = argval; - while (arglist != NULL) { - if (pass == 2) { - putcode(first(arglist), origin, pc); - #if defined(assemblerlist) - if (arglist == argval) superprint(arg, 0, pserial); - pln(pserial); - #endif - } - pc = pc + 2; - cdr(pcpair) = number(pc); - arglist = cdr(arglist); - } - } else if (integerp(argval)) { - if (pass == 2) { - putcode(argval, origin, pc); - #if defined(assemblerlist) - superprint(arg, 0, pserial); pln(pserial); - #endif - } - pc = pc + 2; - cdr(pcpair) = number(pc); - } else error(DEFCODE, PSTR("illegal entry"), arg); - } - entries = cdr(entries); - } - // Round up to multiple of 4 to give code size - if (pc%4 != 0) pc = pc + 4 - pc%4; - return pc; -} - // Tail-recursive forms object *tf_progn (object *args, object *env) { @@ -2058,7 +2352,7 @@ object *tf_cond (object *args, object *env) { object *test = eval(first(clause), env); object *forms = cdr(clause); if (test != nil) { - if (forms == NULL) return test; else return tf_progn(forms, env); + if (forms == NULL) return quote(test); else return tf_progn(forms, env); } args = cdr(args); } @@ -2148,6 +2442,11 @@ object *fn_symbolp (object *args, object *env) { return symbolp(arg) ? tee : nil; } +object *fn_arrayp (object *args, object *env) { + (void) env; + return arrayp(first(args)) ? tee : nil; +} + object *fn_boundp (object *args, object *env) { (void) env; object *var = first(args); @@ -2155,10 +2454,10 @@ object *fn_boundp (object *args, object *env) { return boundp(var, env) ? tee : nil; } -object *fn_set (object *args, object *env) { +object *fn_setfn (object *args, object *env) { object *arg = nil; while (args != NULL) { - if (cdr(args) == NULL) error2(SET, PSTR("odd number of parameters")); + if (cdr(args) == NULL) error2(SETFN, oddargs); object *pair = findvalue(first(args), env); arg = second(args); cdr(pair) = arg; @@ -2254,8 +2553,15 @@ object *fn_length (object *args, object *env) { (void) env; object *arg = first(args); if (listp(arg)) return number(listlength(LENGTH, arg)); - if (!stringp(arg)) error(LENGTH, PSTR("argument is not a list or string"), arg); - return number(stringlength(arg)); + if (stringp(arg)) return number(stringlength(arg)); + if (arrayp(arg) && cdr(cddr(arg)) == NULL) return first(cddr(arg)); + error(LENGTH, PSTR("argument is not a list, 1d array, or string"), arg); +} + +object *fn_arraydimensions (object *args, object *env) { + object *array = first(args); + if (!arrayp(array)) error(ARRAYDIMENSIONS, PSTR("argument is not an array"), array); + return cddr(array); } object *fn_list (object *args, object *env) { @@ -2263,6 +2569,21 @@ object *fn_list (object *args, object *env) { return args; } +object *fn_makearray (object *args, object *env) { + (void) env; + object *def = nil; + object *dims = first(args); + if (dims == NULL) error2(MAKEARRAY, PSTR("dimensions can't be nil")); + else if (atom(dims)) dims = cons(dims, NULL); + if (cdr(args) != NULL) { + object *var = second(args); + if (!symbolp(var) || var->name != INITIALELEMENT) + error(MAKEARRAY, PSTR("illegal second argument"), var); + if (cddr(args) != NULL) def = third(args); + } + return makearray(MAKEARRAY, dims, def); +} + object *fn_reverse (object *args, object *env) { (void) env; object *list = first(args); @@ -2288,6 +2609,12 @@ object *fn_nth (object *args, object *env) { return nil; } +object *fn_aref (object *args, object *env) { + object *array = first(args); + if (!arrayp(array)) error(AREF, PSTR("first argument is not an array"), array); + return *getarray(AREF, array, cdr(args), 0); +} + object *fn_assoc (object *args, object *env) { (void) env; object *key = first(args); @@ -2991,8 +3318,8 @@ bool stringcompare (symbol_t name, object *args, bool lt, bool gt, bool eq) { while ((arg1 != NULL) || (arg2 != NULL)) { if (arg1 == NULL) return lt; if (arg2 == NULL) return gt; - if (arg1->integer < arg2->integer) return lt; - if (arg1->integer > arg2->integer) return gt; + if (arg1->chars < arg2->chars) return lt; + if (arg1->chars > arg2->chars) return gt; arg1 = car(arg1); arg2 = car(arg2); } @@ -3052,7 +3379,7 @@ object *fn_stringfn (object *args, object *env) { object *cell = myalloc(); cell->car = NULL; uint8_t shift = (sizeof(int)-1)*8; - cell->integer = (arg->integer)<chars = (arg->chars)<cdr = cell; } else if (type == SYMBOL) { char *s = symbolname(arg->name); @@ -3084,7 +3411,7 @@ object *fn_concatenate (object *args, object *env) { if (!stringp(obj)) error(CONCATENATE, notastring, obj); obj = cdr(obj); while (obj != NULL) { - int quad = obj->integer; + int quad = obj->chars; while (quad != 0) { char ch = quad>>((sizeof(int)-1)*8) & 0xFF; buildstring(ch, &chars, &head); @@ -3119,16 +3446,6 @@ object *fn_subseq (object *args, object *env) { return result; } -int gstr () { - if (LastChar) { - char temp = LastChar; - LastChar = 0; - return temp; - } - char c = nthchar(GlobalString, GlobalStringIndex++); - return (c != 0) ? c : '\n'; // -1? -} - object *fn_readfromstring (object *args, object *env) { (void) env; object *arg = first(args); @@ -3138,21 +3455,11 @@ object *fn_readfromstring (object *args, object *env) { return read(gstr); } -void pstr (char c) { - buildstring(c, &GlobalStringIndex, &GlobalString); -} - object *fn_princtostring (object *args, object *env) { (void) env; object *arg = first(args); - object *obj = myalloc(); - obj->type = STRING; - GlobalString = NULL; - GlobalStringIndex = 0; - char temp = Flags; - clrflag(PRINTREADABLY); - printobject(arg, pstr); - Flags = temp; + object *obj = startstring(PRINCTOSTRING); + prin1object(arg, pstr); obj->cdr = GlobalString; return obj; } @@ -3160,10 +3467,7 @@ object *fn_princtostring (object *args, object *env) { object *fn_prin1tostring (object *args, object *env) { (void) env; object *arg = first(args); - object *obj = myalloc(); - obj->type = STRING; - GlobalString = NULL; - GlobalStringIndex = 0; + object *obj = startstring(PRIN1TOSTRING); printobject(arg, pstr); obj->cdr = GlobalString; return obj; @@ -3276,7 +3580,7 @@ object *fn_print (object *args, object *env) { pfun_t pfun = pstreamfun(cdr(args)); pln(pfun); printobject(obj, pfun); - (pfun)(' '); + pfun(' '); return obj; } @@ -3284,10 +3588,7 @@ object *fn_princ (object *args, object *env) { (void) env; object *obj = first(args); pfun_t pfun = pstreamfun(cdr(args)); - char temp = Flags; - clrflag(PRINTREADABLY); - printobject(obj, pfun); - Flags = temp; + prin1object(obj, pfun); return obj; } @@ -3505,107 +3806,122 @@ object *edit (object *fun) { // Pretty printer -const int PPINDENT = 2; -const int PPWIDTH = 80; - -void pcount (char c) { - LastPrint = c; - if (c == '\n') GlobalStringIndex++; - GlobalStringIndex++; -} - -int atomwidth (object *obj) { - GlobalStringIndex = 0; - printobject(obj, pcount); - return GlobalStringIndex; -} - -boolean quoted (object *obj) { - return (consp(obj) && car(obj) != NULL && car(obj)->name == QUOTE && consp(cdr(obj)) && cddr(obj) == NULL); -} - -int subwidth (object *obj, int w) { - if (atom(obj)) return w - atomwidth(obj); - if (quoted(obj)) return subwidthlist(car(cdr(obj)), w - 1); - return subwidthlist(obj, w - 1); -} - -int subwidthlist (object *form, int w) { - while (form != NULL && w >= 0) { - if (atom(form)) return w - (2 + atomwidth(form)); - w = subwidth(car(form), w - 1); - form = cdr(form); - } - return w; -} - -void superprint (object *form, int lm, pfun_t pfun) { - if (atom(form)) { - if (symbolp(form) && form->name == NOTHING) pstring(symbolname(form->name), pfun); - else printobject(form, pfun); - } - else if (quoted(form)) { pfun('\''); superprint(car(cdr(form)), lm + 1, pfun); } - else if (subwidth(form, PPWIDTH - lm) >= 0) supersub(form, lm + PPINDENT, 0, pfun); - else supersub(form, lm + PPINDENT, 1, pfun); -} - -const int ppspecials = 16; -const char ppspecial[ppspecials] PROGMEM = - { DOTIMES, DOLIST, IF, SETQ, TEE, LET, LETSTAR, LAMBDA, WHEN, UNLESS, WITHI2C, WITHSERIAL, WITHSPI, WITHSDCARD, FORMILLIS }; - -void supersub (object *form, int lm, int super, pfun_t pfun) { - int special = 0, separate = 1; - object *arg = car(form); - if (symbolp(arg)) { - int name = arg->name; - if (name == DEFUN || name == DEFCODE) special = 2; - else for (int i=0; iname == LAMBDA) { - superprint(cons(symbol(DEFUN), cons(var, cdr(val))), 0, pserial); + superprint(cons(symbol(DEFUN), cons(var, cdr(val))), 0, pfun); } else if (consp(val) && car(val)->type == CODE) { - superprint(cons(symbol(DEFCODE), cons(var, cdr(val))), 0, pserial); + superprint(cons(symbol(DEFCODE), cons(var, cdr(val))), 0, pfun); } else { - superprint(cons(symbol(DEFVAR),cons(var,cons(cons(symbol(QUOTE),cons(val,NULL)) - ,NULL))), 0, pserial); + superprint(cons(symbol(DEFVAR), cons(var, cons(quote(val), NULL))), 0, pserial); } - pln(pserial); + pln(pfun); + testescape(); globals = cdr(globals); } + ppwidth = PPWIDTH; return symbol(NOTHING); } +// Format + +void formaterr (object *formatstr, PGM_P string, uint8_t p) { + pln(pserial); indent(4, ' ', pserial); printstring(formatstr, pserial); pln(pserial); + indent(p+5, ' ', pserial); pserial('^'); + errorsub(FORMAT, string); + pln(pserial); + GCStack = NULL; + longjmp(exception, 1); +} + +object *fn_format (object *args, object *env) { + (void) env; + pfun_t pfun = pserial; + object *output = first(args); + object *obj; + if (output == nil) { obj = startstring(FORMAT); pfun = pstr; } + else if (output != tee) pfun = pstreamfun(args); + object *formatstr = second(args); + if (!stringp(formatstr)) error(FORMAT, notastring, formatstr); + object *save = NULL; + args = cddr(args); + int len = stringlength(formatstr); + uint8_t n = 0, width = 0, w, bra = 0; + char pad = ' '; + bool tilde = false, comma, quote; + while (n < len) { + char ch = nthchar(formatstr, n); + char ch2 = ch & ~0x20; // force to upper case + if (tilde) { + if (comma && quote) { pad = ch; comma = false, quote = false; } + else if (ch == '\'') { + if (comma) quote = true; + else formaterr(formatstr, PSTR("quote not valid"), n); + } + else if (ch == '~') { pfun('~'); tilde = false; } + else if (ch >= '0' && ch <= '9') width = width*10 + ch - '0'; + else if (ch == ',') comma = true; + else if (ch == '%') { pln(pfun); tilde = false; } + else if (ch == '&') { pfl(pfun); tilde = false; } + else if (ch == '{') { + if (save != NULL) formaterr(formatstr, PSTR("can't nest ~{"), n); + if (args == NULL) formaterr(formatstr, noargument, n); + if (!listp(first(args))) formaterr(formatstr, notalist, n); + save = args; args = first(args); bra = n; tilde = false; + } + else if (ch == '}') { + if (save == NULL) formaterr(formatstr, PSTR("no matching ~{"), n); + if (args == NULL) { args = cdr(save); save = NULL; } else n = bra; + tilde = false; + } + else if (ch2 == 'A' || ch2 == 'S' || ch2 == 'D' || ch2 == 'G' || ch2 == 'X') { + if (args == NULL) formaterr(formatstr, noargument, n); + object *arg = first(args); args = cdr(args); + uint8_t aw = atomwidth(arg); + if (width < aw) w = 0; else w = width-aw; + tilde = false; + if (ch2 == 'A') { prin1object(arg, pfun); indent(w, pad, pfun); } + else if (ch2 == 'S') { printobject(arg, pfun); indent(w, pad, pfun); } + else if (ch2 == 'D' || ch2 == 'G') { indent(w, pad, pfun); prin1object(arg, pfun); } + else if (ch2 == 'X' && integerp(arg)) { + uint8_t hw = hexwidth(arg); if (width < hw) w = 0; else w = width-hw; + indent(w, pad, pfun); pinthex(arg->integer, pfun); + } else if (ch2 == 'X') { indent(w, pad, pfun); prin1object(arg, pfun); } + tilde = false; + } else formaterr(formatstr, PSTR("invalid directive"), n); + } else { + if (ch == '~') { tilde = true; pad = ' '; width = 0; comma = false; quote = false; } + else pfun(ch); + } + n++; + } + if (output == nil) { obj->cdr = GlobalString; return obj; } + else return nil; +} + // LispLibrary object *fn_require (object *args, object *env) { @@ -3646,6 +3962,196 @@ object *fn_listlibrary (object *args, object *env) { return symbol(NOTHING); } +// Graphics functions + +object *fn_drawpixel (object *args, object *env) { +#if defined(gfxsupport) + (void) env; + uint16_t colour = COLOR_WHITE; + if (cddr(args) != NULL) colour = checkinteger(DRAWPIXEL, third(args)); + tft.drawPixel(checkinteger(DRAWPIXEL, first(args)), checkinteger(DRAWPIXEL, second(args)), colour); + return nil; +#endif +} + +object *fn_drawline (object *args, object *env) { +#if defined(gfxsupport) + (void) env; + uint16_t params[4], colour = COLOR_WHITE; + for (int i=0; i<4; i++) { params[i] = checkinteger(DRAWLINE, car(args)); args = cdr(args); } + if (args != NULL) colour = checkinteger(DRAWLINE, car(args)); + tft.drawLine(params[0], params[1], params[2], params[3], colour); + return nil; +#endif +} + +object *fn_drawrect (object *args, object *env) { +#if defined(gfxsupport) + (void) env; + uint16_t params[4], colour = COLOR_WHITE; + for (int i=0; i<4; i++) { params[i] = checkinteger(DRAWRECT, car(args)); args = cdr(args); } + if (args != NULL) colour = checkinteger(DRAWRECT, car(args)); + tft.drawRect(params[0], params[1], params[2], params[3], colour); + return nil; +#endif +} + +object *fn_fillrect (object *args, object *env) { +#if defined(gfxsupport) + (void) env; + uint16_t params[4], colour = COLOR_WHITE; + for (int i=0; i<4; i++) { params[i] = checkinteger(FILLRECT, car(args)); args = cdr(args); } + if (args != NULL) colour = checkinteger(FILLRECT, car(args)); + tft.fillRect(params[0], params[1], params[2], params[3], colour); + return nil; +#endif +} + +object *fn_drawcircle (object *args, object *env) { +#if defined(gfxsupport) + (void) env; + uint16_t params[3], colour = COLOR_WHITE; + for (int i=0; i<3; i++) { params[i] = checkinteger(DRAWCIRCLE, car(args)); args = cdr(args); } + if (args != NULL) colour = checkinteger(DRAWCIRCLE, car(args)); + tft.drawCircle(params[0], params[1], params[2], colour); + return nil; +#endif +} + +object *fn_fillcircle (object *args, object *env) { +#if defined(gfxsupport) + (void) env; + uint16_t params[3], colour = COLOR_WHITE; + for (int i=0; i<3; i++) { params[i] = checkinteger(FILLCIRCLE, car(args)); args = cdr(args); } + if (args != NULL) colour = checkinteger(FILLCIRCLE, car(args)); + tft.fillCircle(params[0], params[1], params[2], colour); + return nil; +#endif +} + +object *fn_drawroundrect (object *args, object *env) { +#if defined(gfxsupport) + (void) env; + uint16_t params[5], colour = COLOR_WHITE; + for (int i=0; i<5; i++) { params[i] = checkinteger(DRAWROUNDRECT, car(args)); args = cdr(args); } + if (args != NULL) colour = checkinteger(DRAWROUNDRECT, car(args)); + tft.drawRoundRect(params[0], params[1], params[2], params[3], params[4], colour); + return nil; +#endif +} + +object *fn_fillroundrect (object *args, object *env) { +#if defined(gfxsupport) + (void) env; + uint16_t params[5], colour = COLOR_WHITE; + for (int i=0; i<5; i++) { params[i] = checkinteger(FILLROUNDRECT, car(args)); args = cdr(args); } + if (args != NULL) colour = checkinteger(FILLROUNDRECT, car(args)); + tft.fillRoundRect(params[0], params[1], params[2], params[3], params[4], colour); + return nil; +#endif +} + +object *fn_drawtriangle (object *args, object *env) { +#if defined(gfxsupport) + (void) env; + uint16_t params[6], colour = COLOR_WHITE; + for (int i=0; i<6; i++) { params[i] = checkinteger(DRAWTRIANGLE, car(args)); args = cdr(args); } + if (args != NULL) colour = checkinteger(DRAWTRIANGLE, car(args)); + tft.drawTriangle(params[0], params[1], params[2], params[3], params[4], params[5], colour); + return nil; +#endif +} + +object *fn_filltriangle (object *args, object *env) { +#if defined(gfxsupport) + (void) env; + uint16_t params[6], colour = COLOR_WHITE; + for (int i=0; i<6; i++) { params[i] = checkinteger(FILLTRIANGLE, car(args)); args = cdr(args); } + if (args != NULL) colour = checkinteger(FILLTRIANGLE, car(args)); + tft.fillTriangle(params[0], params[1], params[2], params[3], params[4], params[5], colour); + return nil; +#endif +} + +object *fn_drawchar (object *args, object *env) { +#if defined(gfxsupport) + (void) env; + uint16_t colour = COLOR_WHITE, bg = COLOR_BLACK, size = 1; + object *more = cdr(cddr(args)); + if (more != NULL) { + colour = checkinteger(DRAWCHAR, car(more)); + more = cdr(more); + if (more != NULL) { + bg = checkinteger(DRAWCHAR, car(more)); + more = cdr(more); + if (more != NULL) size = checkinteger(DRAWCHAR, car(more)); + } + } + tft.drawChar(checkinteger(DRAWCHAR, first(args)), checkinteger(DRAWCHAR, second(args)), checkchar(DRAWCHAR, third(args)), + colour, bg, size); + return nil; +#endif +} + +object *fn_setcursor (object *args, object *env) { +#if defined(gfxsupport) + (void) env; + tft.setCursor(checkinteger(SETCURSOR, first(args)), checkinteger(SETCURSOR, second(args))); + return nil; +#endif +} + +object *fn_settextcolor (object *args, object *env) { +#if defined(gfxsupport) + (void) env; + if (cdr(args) != NULL) tft.setTextColor(checkinteger(SETTEXTCOLOR, first(args)), checkinteger(SETTEXTCOLOR, second(args))); + else tft.setTextColor(checkinteger(SETTEXTCOLOR, first(args))); + return nil; +#endif +} + +object *fn_settextsize (object *args, object *env) { +#if defined(gfxsupport) + (void) env; + tft.setTextSize(checkinteger(SETTEXTSIZE, first(args))); + return nil; +#endif +} + +object *fn_settextwrap (object *args, object *env) { +#if defined(gfxsupport) + (void) env; + tft.setTextWrap(first(args) != NULL); + return nil; +#endif +} + +object *fn_fillscreen (object *args, object *env) { +#if defined(gfxsupport) + (void) env; + uint16_t colour = COLOR_BLACK; + if (args != NULL) colour = checkinteger(FILLSCREEN, first(args)); + tft.fillScreen(colour); + return nil; +#endif +} + +object *fn_setrotation (object *args, object *env) { +#if defined(gfxsupport) + (void) env; + tft.setRotation(checkinteger(SETROTATION, first(args))); + return nil; +#endif +} + +object *fn_invertdisplay (object *args, object *env) { +#if defined(gfxsupport) + (void) env; + tft.invertDisplay(first(args) != NULL); + return nil; +#endif +} + // Insert your own function definitions here // Built-in procedure names - stored in PROGMEM @@ -3654,366 +4160,419 @@ const char string0[] PROGMEM = "nil"; const char string1[] PROGMEM = "t"; const char string2[] PROGMEM = "nothing"; const char string3[] PROGMEM = "&optional"; -const char string4[] PROGMEM = "&rest"; -const char string5[] PROGMEM = "lambda"; -const char string6[] PROGMEM = "let"; -const char string7[] PROGMEM = "let*"; -const char string8[] PROGMEM = "closure"; -const char string9[] PROGMEM = "special_forms"; -const char string10[] PROGMEM = "quote"; -const char string11[] PROGMEM = "defun"; -const char string12[] PROGMEM = "defvar"; -const char string13[] PROGMEM = "setq"; -const char string14[] PROGMEM = "loop"; -const char string15[] PROGMEM = "return"; -const char string16[] PROGMEM = "push"; -const char string17[] PROGMEM = "pop"; -const char string18[] PROGMEM = "incf"; -const char string19[] PROGMEM = "decf"; -const char string20[] PROGMEM = "setf"; -const char string21[] PROGMEM = "dolist"; -const char string22[] PROGMEM = "dotimes"; -const char string23[] PROGMEM = "trace"; -const char string24[] PROGMEM = "untrace"; -const char string25[] PROGMEM = "for-millis"; -const char string26[] PROGMEM = "with-serial"; -const char string27[] PROGMEM = "with-i2c"; -const char string28[] PROGMEM = "with-spi"; -const char string29[] PROGMEM = "with-sd-card"; -const char string30[] PROGMEM = "defcode"; -const char string31[] PROGMEM = "tail_forms"; -const char string32[] PROGMEM = "progn"; -const char string33[] PROGMEM = "if"; -const char string34[] PROGMEM = "cond"; -const char string35[] PROGMEM = "when"; -const char string36[] PROGMEM = "unless"; -const char string37[] PROGMEM = "case"; -const char string38[] PROGMEM = "and"; -const char string39[] PROGMEM = "or"; -const char string40[] PROGMEM = "functions"; -const char string41[] PROGMEM = "not"; -const char string42[] PROGMEM = "null"; -const char string43[] PROGMEM = "cons"; -const char string44[] PROGMEM = "atom"; -const char string45[] PROGMEM = "listp"; -const char string46[] PROGMEM = "consp"; -const char string47[] PROGMEM = "symbolp"; -const char string48[] PROGMEM = "boundp"; -const char string49[] PROGMEM = "set"; -const char string50[] PROGMEM = "streamp"; -const char string51[] PROGMEM = "eq"; -const char string52[] PROGMEM = "car"; -const char string53[] PROGMEM = "first"; -const char string54[] PROGMEM = "cdr"; -const char string55[] PROGMEM = "rest"; -const char string56[] PROGMEM = "caar"; -const char string57[] PROGMEM = "cadr"; -const char string58[] PROGMEM = "second"; -const char string59[] PROGMEM = "cdar"; -const char string60[] PROGMEM = "cddr"; -const char string61[] PROGMEM = "caaar"; -const char string62[] PROGMEM = "caadr"; -const char string63[] PROGMEM = "cadar"; -const char string64[] PROGMEM = "caddr"; -const char string65[] PROGMEM = "third"; -const char string66[] PROGMEM = "cdaar"; -const char string67[] PROGMEM = "cdadr"; -const char string68[] PROGMEM = "cddar"; -const char string69[] PROGMEM = "cdddr"; -const char string70[] PROGMEM = "length"; -const char string71[] PROGMEM = "list"; -const char string72[] PROGMEM = "reverse"; -const char string73[] PROGMEM = "nth"; -const char string74[] PROGMEM = "assoc"; -const char string75[] PROGMEM = "member"; -const char string76[] PROGMEM = "apply"; -const char string77[] PROGMEM = "funcall"; -const char string78[] PROGMEM = "append"; -const char string79[] PROGMEM = "mapc"; -const char string80[] PROGMEM = "mapcar"; -const char string81[] PROGMEM = "mapcan"; -const char string82[] PROGMEM = "+"; -const char string83[] PROGMEM = "-"; -const char string84[] PROGMEM = "*"; -const char string85[] PROGMEM = "/"; -const char string86[] PROGMEM = "mod"; -const char string87[] PROGMEM = "1+"; -const char string88[] PROGMEM = "1-"; -const char string89[] PROGMEM = "abs"; -const char string90[] PROGMEM = "random"; -const char string91[] PROGMEM = "max"; -const char string92[] PROGMEM = "min"; -const char string93[] PROGMEM = "/="; -const char string94[] PROGMEM = "="; -const char string95[] PROGMEM = "<"; -const char string96[] PROGMEM = "<="; -const char string97[] PROGMEM = ">"; -const char string98[] PROGMEM = ">="; -const char string99[] PROGMEM = "plusp"; -const char string100[] PROGMEM = "minusp"; -const char string101[] PROGMEM = "zerop"; -const char string102[] PROGMEM = "oddp"; -const char string103[] PROGMEM = "evenp"; -const char string104[] PROGMEM = "integerp"; -const char string105[] PROGMEM = "numberp"; -const char string106[] PROGMEM = "float"; -const char string107[] PROGMEM = "floatp"; -const char string108[] PROGMEM = "sin"; -const char string109[] PROGMEM = "cos"; -const char string110[] PROGMEM = "tan"; -const char string111[] PROGMEM = "asin"; -const char string112[] PROGMEM = "acos"; -const char string113[] PROGMEM = "atan"; -const char string114[] PROGMEM = "sinh"; -const char string115[] PROGMEM = "cosh"; -const char string116[] PROGMEM = "tanh"; -const char string117[] PROGMEM = "exp"; -const char string118[] PROGMEM = "sqrt"; -const char string119[] PROGMEM = "log"; -const char string120[] PROGMEM = "expt"; -const char string121[] PROGMEM = "ceiling"; -const char string122[] PROGMEM = "floor"; -const char string123[] PROGMEM = "truncate"; -const char string124[] PROGMEM = "round"; -const char string125[] PROGMEM = "char"; -const char string126[] PROGMEM = "char-code"; -const char string127[] PROGMEM = "code-char"; -const char string128[] PROGMEM = "characterp"; -const char string129[] PROGMEM = "stringp"; -const char string130[] PROGMEM = "string="; -const char string131[] PROGMEM = "string<"; -const char string132[] PROGMEM = "string>"; -const char string133[] PROGMEM = "sort"; -const char string134[] PROGMEM = "string"; -const char string135[] PROGMEM = "concatenate"; -const char string136[] PROGMEM = "subseq"; -const char string137[] PROGMEM = "read-from-string"; -const char string138[] PROGMEM = "princ-to-string"; -const char string139[] PROGMEM = "prin1-to-string"; -const char string140[] PROGMEM = "logand"; -const char string141[] PROGMEM = "logior"; -const char string142[] PROGMEM = "logxor"; -const char string143[] PROGMEM = "lognot"; -const char string144[] PROGMEM = "ash"; -const char string145[] PROGMEM = "logbitp"; -const char string146[] PROGMEM = "eval"; -const char string147[] PROGMEM = "globals"; -const char string148[] PROGMEM = "locals"; -const char string149[] PROGMEM = "makunbound"; -const char string150[] PROGMEM = "break"; -const char string151[] PROGMEM = "read"; -const char string152[] PROGMEM = "prin1"; -const char string153[] PROGMEM = "print"; -const char string154[] PROGMEM = "princ"; -const char string155[] PROGMEM = "terpri"; -const char string156[] PROGMEM = "read-byte"; -const char string157[] PROGMEM = "read-line"; -const char string158[] PROGMEM = "write-byte"; -const char string159[] PROGMEM = "write-string"; -const char string160[] PROGMEM = "write-line"; -const char string161[] PROGMEM = "restart-i2c"; -const char string162[] PROGMEM = "gc"; -const char string163[] PROGMEM = "room"; -const char string164[] PROGMEM = "save-image"; -const char string165[] PROGMEM = "load-image"; -const char string166[] PROGMEM = "cls"; -const char string167[] PROGMEM = "pinmode"; -const char string168[] PROGMEM = "digitalread"; -const char string169[] PROGMEM = "digitalwrite"; -const char string170[] PROGMEM = "analogread"; -const char string171[] PROGMEM = "analogwrite"; -const char string172[] PROGMEM = "delay"; -const char string173[] PROGMEM = "millis"; -const char string174[] PROGMEM = "sleep"; -const char string175[] PROGMEM = "note"; -const char string176[] PROGMEM = "edit"; -const char string177[] PROGMEM = "pprint"; -const char string178[] PROGMEM = "pprintall"; -const char string179[] PROGMEM = "require"; -const char string180[] PROGMEM = "list-library"; +const char string4[] PROGMEM = ":initial-element"; +const char string5[] PROGMEM = "&rest"; +const char string6[] PROGMEM = "lambda"; +const char string7[] PROGMEM = "let"; +const char string8[] PROGMEM = "let*"; +const char string9[] PROGMEM = "closure"; +const char string10[] PROGMEM = ""; +const char string11[] PROGMEM = "quote"; +const char string12[] PROGMEM = "defun"; +const char string13[] PROGMEM = "defvar"; +const char string14[] PROGMEM = "setq"; +const char string15[] PROGMEM = "loop"; +const char string16[] PROGMEM = "return"; +const char string17[] PROGMEM = "push"; +const char string18[] PROGMEM = "pop"; +const char string19[] PROGMEM = "incf"; +const char string20[] PROGMEM = "decf"; +const char string21[] PROGMEM = "setf"; +const char string22[] PROGMEM = "dolist"; +const char string23[] PROGMEM = "dotimes"; +const char string24[] PROGMEM = "trace"; +const char string25[] PROGMEM = "untrace"; +const char string26[] PROGMEM = "for-millis"; +const char string27[] PROGMEM = "with-output-to-string"; +const char string28[] PROGMEM = "with-serial"; +const char string29[] PROGMEM = "with-i2c"; +const char string30[] PROGMEM = "with-spi"; +const char string31[] PROGMEM = "with-sd-card"; +const char string32[] PROGMEM = "with-gfx"; +const char string33[] PROGMEM = "defcode"; +const char string34[] PROGMEM = ""; +const char string35[] PROGMEM = "progn"; +const char string36[] PROGMEM = "if"; +const char string37[] PROGMEM = "cond"; +const char string38[] PROGMEM = "when"; +const char string39[] PROGMEM = "unless"; +const char string40[] PROGMEM = "case"; +const char string41[] PROGMEM = "and"; +const char string42[] PROGMEM = "or"; +const char string43[] PROGMEM = ""; +const char string44[] PROGMEM = "not"; +const char string45[] PROGMEM = "null"; +const char string46[] PROGMEM = "cons"; +const char string47[] PROGMEM = "atom"; +const char string48[] PROGMEM = "listp"; +const char string49[] PROGMEM = "consp"; +const char string50[] PROGMEM = "symbolp"; +const char string51[] PROGMEM = "arrayp"; +const char string52[] PROGMEM = "boundp"; +const char string53[] PROGMEM = "setfn"; +const char string54[] PROGMEM = "streamp"; +const char string55[] PROGMEM = "eq"; +const char string56[] PROGMEM = "car"; +const char string57[] PROGMEM = "first"; +const char string58[] PROGMEM = "cdr"; +const char string59[] PROGMEM = "rest"; +const char string60[] PROGMEM = "caar"; +const char string61[] PROGMEM = "cadr"; +const char string62[] PROGMEM = "second"; +const char string63[] PROGMEM = "cdar"; +const char string64[] PROGMEM = "cddr"; +const char string65[] PROGMEM = "caaar"; +const char string66[] PROGMEM = "caadr"; +const char string67[] PROGMEM = "cadar"; +const char string68[] PROGMEM = "caddr"; +const char string69[] PROGMEM = "third"; +const char string70[] PROGMEM = "cdaar"; +const char string71[] PROGMEM = "cdadr"; +const char string72[] PROGMEM = "cddar"; +const char string73[] PROGMEM = "cdddr"; +const char string74[] PROGMEM = "length"; +const char string75[] PROGMEM = "array-dimensions"; +const char string76[] PROGMEM = "list"; +const char string77[] PROGMEM = "make-array"; +const char string78[] PROGMEM = "reverse"; +const char string79[] PROGMEM = "nth"; +const char string80[] PROGMEM = "aref"; +const char string81[] PROGMEM = "assoc"; +const char string82[] PROGMEM = "member"; +const char string83[] PROGMEM = "apply"; +const char string84[] PROGMEM = "funcall"; +const char string85[] PROGMEM = "append"; +const char string86[] PROGMEM = "mapc"; +const char string87[] PROGMEM = "mapcar"; +const char string88[] PROGMEM = "mapcan"; +const char string89[] PROGMEM = "+"; +const char string90[] PROGMEM = "-"; +const char string91[] PROGMEM = "*"; +const char string92[] PROGMEM = "/"; +const char string93[] PROGMEM = "mod"; +const char string94[] PROGMEM = "1+"; +const char string95[] PROGMEM = "1-"; +const char string96[] PROGMEM = "abs"; +const char string97[] PROGMEM = "random"; +const char string98[] PROGMEM = "max"; +const char string99[] PROGMEM = "min"; +const char string100[] PROGMEM = "/="; +const char string101[] PROGMEM = "="; +const char string102[] PROGMEM = "<"; +const char string103[] PROGMEM = "<="; +const char string104[] PROGMEM = ">"; +const char string105[] PROGMEM = ">="; +const char string106[] PROGMEM = "plusp"; +const char string107[] PROGMEM = "minusp"; +const char string108[] PROGMEM = "zerop"; +const char string109[] PROGMEM = "oddp"; +const char string110[] PROGMEM = "evenp"; +const char string111[] PROGMEM = "integerp"; +const char string112[] PROGMEM = "numberp"; +const char string113[] PROGMEM = "float"; +const char string114[] PROGMEM = "floatp"; +const char string115[] PROGMEM = "sin"; +const char string116[] PROGMEM = "cos"; +const char string117[] PROGMEM = "tan"; +const char string118[] PROGMEM = "asin"; +const char string119[] PROGMEM = "acos"; +const char string120[] PROGMEM = "atan"; +const char string121[] PROGMEM = "sinh"; +const char string122[] PROGMEM = "cosh"; +const char string123[] PROGMEM = "tanh"; +const char string124[] PROGMEM = "exp"; +const char string125[] PROGMEM = "sqrt"; +const char string126[] PROGMEM = "log"; +const char string127[] PROGMEM = "expt"; +const char string128[] PROGMEM = "ceiling"; +const char string129[] PROGMEM = "floor"; +const char string130[] PROGMEM = "truncate"; +const char string131[] PROGMEM = "round"; +const char string132[] PROGMEM = "char"; +const char string133[] PROGMEM = "char-code"; +const char string134[] PROGMEM = "code-char"; +const char string135[] PROGMEM = "characterp"; +const char string136[] PROGMEM = "stringp"; +const char string137[] PROGMEM = "string="; +const char string138[] PROGMEM = "string<"; +const char string139[] PROGMEM = "string>"; +const char string140[] PROGMEM = "sort"; +const char string141[] PROGMEM = "string"; +const char string142[] PROGMEM = "concatenate"; +const char string143[] PROGMEM = "subseq"; +const char string144[] PROGMEM = "read-from-string"; +const char string145[] PROGMEM = "princ-to-string"; +const char string146[] PROGMEM = "prin1-to-string"; +const char string147[] PROGMEM = "logand"; +const char string148[] PROGMEM = "logior"; +const char string149[] PROGMEM = "logxor"; +const char string150[] PROGMEM = "lognot"; +const char string151[] PROGMEM = "ash"; +const char string152[] PROGMEM = "logbitp"; +const char string153[] PROGMEM = "eval"; +const char string154[] PROGMEM = "globals"; +const char string155[] PROGMEM = "locals"; +const char string156[] PROGMEM = "makunbound"; +const char string157[] PROGMEM = "break"; +const char string158[] PROGMEM = "read"; +const char string159[] PROGMEM = "prin1"; +const char string160[] PROGMEM = "print"; +const char string161[] PROGMEM = "princ"; +const char string162[] PROGMEM = "terpri"; +const char string163[] PROGMEM = "read-byte"; +const char string164[] PROGMEM = "read-line"; +const char string165[] PROGMEM = "write-byte"; +const char string166[] PROGMEM = "write-string"; +const char string167[] PROGMEM = "write-line"; +const char string168[] PROGMEM = "restart-i2c"; +const char string169[] PROGMEM = "gc"; +const char string170[] PROGMEM = "room"; +const char string171[] PROGMEM = "save-image"; +const char string172[] PROGMEM = "load-image"; +const char string173[] PROGMEM = "cls"; +const char string174[] PROGMEM = "pinmode"; +const char string175[] PROGMEM = "digitalread"; +const char string176[] PROGMEM = "digitalwrite"; +const char string177[] PROGMEM = "analogread"; +const char string178[] PROGMEM = "analogwrite"; +const char string179[] PROGMEM = "delay"; +const char string180[] PROGMEM = "millis"; +const char string181[] PROGMEM = "sleep"; +const char string182[] PROGMEM = "note"; +const char string183[] PROGMEM = "edit"; +const char string184[] PROGMEM = "pprint"; +const char string185[] PROGMEM = "pprintall"; +const char string186[] PROGMEM = "format"; +const char string187[] PROGMEM = "require"; +const char string188[] PROGMEM = "list-library"; +const char string189[] PROGMEM = "draw-pixel"; +const char string190[] PROGMEM = "draw-line"; +const char string191[] PROGMEM = "draw-rect"; +const char string192[] PROGMEM = "fill-rect"; +const char string193[] PROGMEM = "draw-circle"; +const char string194[] PROGMEM = "fill-circle"; +const char string195[] PROGMEM = "draw-round-rect"; +const char string196[] PROGMEM = "fill-round-rect"; +const char string197[] PROGMEM = "draw-triangle"; +const char string198[] PROGMEM = "fill-triangle"; +const char string199[] PROGMEM = "draw-char"; +const char string200[] PROGMEM = "set-cursor"; +const char string201[] PROGMEM = "set-text-color"; +const char string202[] PROGMEM = "set-text-size"; +const char string203[] PROGMEM = "set-text-wrap"; +const char string204[] PROGMEM = "fill-screen"; +const char string205[] PROGMEM = "set-rotation"; +const char string206[] PROGMEM = "invert-display"; +// Third parameter is no. of arguments; 1st hex digit is min, 2nd hex digit is max, 0xF is unlimited const tbl_entry_t lookup_table[] PROGMEM = { - { string0, NULL, 0, 0 }, - { string1, NULL, 0, 0 }, - { string2, NULL, 0, 0 }, - { string3, NULL, 0, 0 }, - { string4, NULL, 0, 0 }, - { string5, NULL, 0, 127 }, - { string6, NULL, 0, 127 }, - { string7, NULL, 0, 127 }, - { string8, NULL, 0, 127 }, - { string9, NULL, NIL, NIL }, - { string10, sp_quote, 1, 1 }, - { string11, sp_defun, 2, 127 }, - { string12, sp_defvar, 1, 2 }, - { string13, sp_setq, 2, 126 }, - { string14, sp_loop, 0, 127 }, - { string15, sp_return, 0, 127 }, - { string16, sp_push, 2, 2 }, - { string17, sp_pop, 1, 1 }, - { string18, sp_incf, 1, 2 }, - { string19, sp_decf, 1, 2 }, - { string20, sp_setf, 2, 126 }, - { string21, sp_dolist, 1, 127 }, - { string22, sp_dotimes, 1, 127 }, - { string23, sp_trace, 0, 1 }, - { string24, sp_untrace, 0, 1 }, - { string25, sp_formillis, 1, 127 }, - { string26, sp_withserial, 1, 127 }, - { string27, sp_withi2c, 1, 127 }, - { string28, sp_withspi, 1, 127 }, - { string29, sp_withsdcard, 2, 127 }, - { string30, sp_defcode, 0, 127 }, - { string31, NULL, NIL, NIL }, - { string32, tf_progn, 0, 127 }, - { string33, tf_if, 2, 3 }, - { string34, tf_cond, 0, 127 }, - { string35, tf_when, 1, 127 }, - { string36, tf_unless, 1, 127 }, - { string37, tf_case, 1, 127 }, - { string38, tf_and, 0, 127 }, - { string39, tf_or, 0, 127 }, - { string40, NULL, NIL, NIL }, - { string41, fn_not, 1, 1 }, - { string42, fn_not, 1, 1 }, - { string43, fn_cons, 2, 2 }, - { string44, fn_atom, 1, 1 }, - { string45, fn_listp, 1, 1 }, - { string46, fn_consp, 1, 1 }, - { string47, fn_symbolp, 1, 1 }, - { string48, fn_boundp, 1, 1 }, - { string49, fn_set, 2, 126 }, - { string50, fn_streamp, 1, 1 }, - { string51, fn_eq, 2, 2 }, - { string52, fn_car, 1, 1 }, - { string53, fn_car, 1, 1 }, - { string54, fn_cdr, 1, 1 }, - { string55, fn_cdr, 1, 1 }, - { string56, fn_caar, 1, 1 }, - { string57, fn_cadr, 1, 1 }, - { string58, fn_cadr, 1, 1 }, - { string59, fn_cdar, 1, 1 }, - { string60, fn_cddr, 1, 1 }, - { string61, fn_caaar, 1, 1 }, - { string62, fn_caadr, 1, 1 }, - { string63, fn_cadar, 1, 1 }, - { string64, fn_caddr, 1, 1 }, - { string65, fn_caddr, 1, 1 }, - { string66, fn_cdaar, 1, 1 }, - { string67, fn_cdadr, 1, 1 }, - { string68, fn_cddar, 1, 1 }, - { string69, fn_cdddr, 1, 1 }, - { string70, fn_length, 1, 1 }, - { string71, fn_list, 0, 127 }, - { string72, fn_reverse, 1, 1 }, - { string73, fn_nth, 2, 2 }, - { string74, fn_assoc, 2, 2 }, - { string75, fn_member, 2, 2 }, - { string76, fn_apply, 2, 127 }, - { string77, fn_funcall, 1, 127 }, - { string78, fn_append, 0, 127 }, - { string79, fn_mapc, 2, 127 }, - { string80, fn_mapcar, 2, 127 }, - { string81, fn_mapcan, 2, 127 }, - { string82, fn_add, 0, 127 }, - { string83, fn_subtract, 1, 127 }, - { string84, fn_multiply, 0, 127 }, - { string85, fn_divide, 1, 127 }, - { string86, fn_mod, 2, 2 }, - { string87, fn_oneplus, 1, 1 }, - { string88, fn_oneminus, 1, 1 }, - { string89, fn_abs, 1, 1 }, - { string90, fn_random, 1, 1 }, - { string91, fn_maxfn, 1, 127 }, - { string92, fn_minfn, 1, 127 }, - { string93, fn_noteq, 1, 127 }, - { string94, fn_numeq, 1, 127 }, - { string95, fn_less, 1, 127 }, - { string96, fn_lesseq, 1, 127 }, - { string97, fn_greater, 1, 127 }, - { string98, fn_greatereq, 1, 127 }, - { string99, fn_plusp, 1, 1 }, - { string100, fn_minusp, 1, 1 }, - { string101, fn_zerop, 1, 1 }, - { string102, fn_oddp, 1, 1 }, - { string103, fn_evenp, 1, 1 }, - { string104, fn_integerp, 1, 1 }, - { string105, fn_numberp, 1, 1 }, - { string106, fn_floatfn, 1, 1 }, - { string107, fn_floatp, 1, 1 }, - { string108, fn_sin, 1, 1 }, - { string109, fn_cos, 1, 1 }, - { string110, fn_tan, 1, 1 }, - { string111, fn_asin, 1, 1 }, - { string112, fn_acos, 1, 1 }, - { string113, fn_atan, 1, 2 }, - { string114, fn_sinh, 1, 1 }, - { string115, fn_cosh, 1, 1 }, - { string116, fn_tanh, 1, 1 }, - { string117, fn_exp, 1, 1 }, - { string118, fn_sqrt, 1, 1 }, - { string119, fn_log, 1, 2 }, - { string120, fn_expt, 2, 2 }, - { string121, fn_ceiling, 1, 2 }, - { string122, fn_floor, 1, 2 }, - { string123, fn_truncate, 1, 2 }, - { string124, fn_round, 1, 2 }, - { string125, fn_char, 2, 2 }, - { string126, fn_charcode, 1, 1 }, - { string127, fn_codechar, 1, 1 }, - { string128, fn_characterp, 1, 1 }, - { string129, fn_stringp, 1, 1 }, - { string130, fn_stringeq, 2, 2 }, - { string131, fn_stringless, 2, 2 }, - { string132, fn_stringgreater, 2, 2 }, - { string133, fn_sort, 2, 2 }, - { string134, fn_stringfn, 1, 1 }, - { string135, fn_concatenate, 1, 127 }, - { string136, fn_subseq, 2, 3 }, - { string137, fn_readfromstring, 1, 1 }, - { string138, fn_princtostring, 1, 1 }, - { string139, fn_prin1tostring, 1, 1 }, - { string140, fn_logand, 0, 127 }, - { string141, fn_logior, 0, 127 }, - { string142, fn_logxor, 0, 127 }, - { string143, fn_lognot, 1, 1 }, - { string144, fn_ash, 2, 2 }, - { string145, fn_logbitp, 2, 2 }, - { string146, fn_eval, 1, 1 }, - { string147, fn_globals, 0, 0 }, - { string148, fn_locals, 0, 0 }, - { string149, fn_makunbound, 1, 1 }, - { string150, fn_break, 0, 0 }, - { string151, fn_read, 0, 1 }, - { string152, fn_prin1, 1, 2 }, - { string153, fn_print, 1, 2 }, - { string154, fn_princ, 1, 2 }, - { string155, fn_terpri, 0, 1 }, - { string156, fn_readbyte, 0, 2 }, - { string157, fn_readline, 0, 1 }, - { string158, fn_writebyte, 1, 2 }, - { string159, fn_writestring, 1, 2 }, - { string160, fn_writeline, 1, 2 }, - { string161, fn_restarti2c, 1, 2 }, - { string162, fn_gc, 0, 0 }, - { string163, fn_room, 0, 0 }, - { string164, fn_saveimage, 0, 1 }, - { string165, fn_loadimage, 0, 1 }, - { string166, fn_cls, 0, 0 }, - { string167, fn_pinmode, 2, 2 }, - { string168, fn_digitalread, 1, 1 }, - { string169, fn_digitalwrite, 2, 2 }, - { string170, fn_analogread, 1, 1 }, - { string171, fn_analogwrite, 2, 2 }, - { string172, fn_delay, 1, 1 }, - { string173, fn_millis, 0, 0 }, - { string174, fn_sleep, 1, 1 }, - { string175, fn_note, 0, 3 }, - { string176, fn_edit, 1, 1 }, - { string177, fn_pprint, 1, 2 }, - { string178, fn_pprintall, 0, 0 }, - { string179, fn_require, 1, 1 }, - { string180, fn_listlibrary, 0, 0 }, + { string0, NULL, 0x00 }, + { string1, NULL, 0x00 }, + { string2, NULL, 0x00 }, + { string3, NULL, 0x00 }, + { string4, NULL, 0x00 }, + { string5, NULL, 0x00 }, + { string6, NULL, 0x0F }, + { string7, NULL, 0x0F }, + { string8, NULL, 0x0F }, + { string9, NULL, 0x0F }, + { string10, NULL, 0x00 }, + { string11, sp_quote, 0x11 }, + { string12, sp_defun, 0x2F }, + { string13, sp_defvar, 0x12 }, + { string14, sp_setq, 0x2F }, + { string15, sp_loop, 0x0F }, + { string16, sp_return, 0x0F }, + { string17, sp_push, 0x22 }, + { string18, sp_pop, 0x11 }, + { string19, sp_incf, 0x12 }, + { string20, sp_decf, 0x12 }, + { string21, sp_setf, 0x2F }, + { string22, sp_dolist, 0x1F }, + { string23, sp_dotimes, 0x1F }, + { string24, sp_trace, 0x01 }, + { string25, sp_untrace, 0x01 }, + { string26, sp_formillis, 0x1F }, + { string27, sp_withoutputtostring, 0x1F }, + { string28, sp_withserial, 0x1F }, + { string29, sp_withi2c, 0x1F }, + { string30, sp_withspi, 0x1F }, + { string31, sp_withsdcard, 0x2F }, + { string32, sp_withgfx, 0x1F }, + { string33, sp_defcode, 0x0F }, + { string34, NULL, 0x00 }, + { string35, tf_progn, 0x0F }, + { string36, tf_if, 0x23 }, + { string37, tf_cond, 0x0F }, + { string38, tf_when, 0x1F }, + { string39, tf_unless, 0x1F }, + { string40, tf_case, 0x1F }, + { string41, tf_and, 0x0F }, + { string42, tf_or, 0x0F }, + { string43, NULL, 0x00 }, + { string44, fn_not, 0x11 }, + { string45, fn_not, 0x11 }, + { string46, fn_cons, 0x22 }, + { string47, fn_atom, 0x11 }, + { string48, fn_listp, 0x11 }, + { string49, fn_consp, 0x11 }, + { string50, fn_symbolp, 0x11 }, + { string51, fn_arrayp, 0x11 }, + { string52, fn_boundp, 0x11 }, + { string53, fn_setfn, 0x2F }, + { string54, fn_streamp, 0x11 }, + { string55, fn_eq, 0x22 }, + { string56, fn_car, 0x11 }, + { string57, fn_car, 0x11 }, + { string58, fn_cdr, 0x11 }, + { string59, fn_cdr, 0x11 }, + { string60, fn_caar, 0x11 }, + { string61, fn_cadr, 0x11 }, + { string62, fn_cadr, 0x11 }, + { string63, fn_cdar, 0x11 }, + { string64, fn_cddr, 0x11 }, + { string65, fn_caaar, 0x11 }, + { string66, fn_caadr, 0x11 }, + { string67, fn_cadar, 0x11 }, + { string68, fn_caddr, 0x11 }, + { string69, fn_caddr, 0x11 }, + { string70, fn_cdaar, 0x11 }, + { string71, fn_cdadr, 0x11 }, + { string72, fn_cddar, 0x11 }, + { string73, fn_cdddr, 0x11 }, + { string74, fn_length, 0x11 }, + { string75, fn_arraydimensions, 0x11 }, + { string76, fn_list, 0x0F }, + { string77, fn_makearray, 0x13 }, + { string78, fn_reverse, 0x11 }, + { string79, fn_nth, 0x22 }, + { string80, fn_aref, 0x2F }, + { string81, fn_assoc, 0x22 }, + { string82, fn_member, 0x22 }, + { string83, fn_apply, 0x2F }, + { string84, fn_funcall, 0x1F }, + { string85, fn_append, 0x0F }, + { string86, fn_mapc, 0x2F }, + { string87, fn_mapcar, 0x2F }, + { string88, fn_mapcan, 0x2F }, + { string89, fn_add, 0x0F }, + { string90, fn_subtract, 0x1F }, + { string91, fn_multiply, 0x0F }, + { string92, fn_divide, 0x1F }, + { string93, fn_mod, 0x22 }, + { string94, fn_oneplus, 0x11 }, + { string95, fn_oneminus, 0x11 }, + { string96, fn_abs, 0x11 }, + { string97, fn_random, 0x11 }, + { string98, fn_maxfn, 0x1F }, + { string99, fn_minfn, 0x1F }, + { string100, fn_noteq, 0x1F }, + { string101, fn_numeq, 0x1F }, + { string102, fn_less, 0x1F }, + { string103, fn_lesseq, 0x1F }, + { string104, fn_greater, 0x1F }, + { string105, fn_greatereq, 0x1F }, + { string106, fn_plusp, 0x11 }, + { string107, fn_minusp, 0x11 }, + { string108, fn_zerop, 0x11 }, + { string109, fn_oddp, 0x11 }, + { string110, fn_evenp, 0x11 }, + { string111, fn_integerp, 0x11 }, + { string112, fn_numberp, 0x11 }, + { string113, fn_floatfn, 0x11 }, + { string114, fn_floatp, 0x11 }, + { string115, fn_sin, 0x11 }, + { string116, fn_cos, 0x11 }, + { string117, fn_tan, 0x11 }, + { string118, fn_asin, 0x11 }, + { string119, fn_acos, 0x11 }, + { string120, fn_atan, 0x12 }, + { string121, fn_sinh, 0x11 }, + { string122, fn_cosh, 0x11 }, + { string123, fn_tanh, 0x11 }, + { string124, fn_exp, 0x11 }, + { string125, fn_sqrt, 0x11 }, + { string126, fn_log, 0x12 }, + { string127, fn_expt, 0x22 }, + { string128, fn_ceiling, 0x12 }, + { string129, fn_floor, 0x12 }, + { string130, fn_truncate, 0x12 }, + { string131, fn_round, 0x12 }, + { string132, fn_char, 0x22 }, + { string133, fn_charcode, 0x11 }, + { string134, fn_codechar, 0x11 }, + { string135, fn_characterp, 0x11 }, + { string136, fn_stringp, 0x11 }, + { string137, fn_stringeq, 0x22 }, + { string138, fn_stringless, 0x22 }, + { string139, fn_stringgreater, 0x22 }, + { string140, fn_sort, 0x22 }, + { string141, fn_stringfn, 0x11 }, + { string142, fn_concatenate, 0x1F }, + { string143, fn_subseq, 0x23 }, + { string144, fn_readfromstring, 0x11 }, + { string145, fn_princtostring, 0x11 }, + { string146, fn_prin1tostring, 0x11 }, + { string147, fn_logand, 0x0F }, + { string148, fn_logior, 0x0F }, + { string149, fn_logxor, 0x0F }, + { string150, fn_lognot, 0x11 }, + { string151, fn_ash, 0x22 }, + { string152, fn_logbitp, 0x22 }, + { string153, fn_eval, 0x11 }, + { string154, fn_globals, 0x00 }, + { string155, fn_locals, 0x00 }, + { string156, fn_makunbound, 0x11 }, + { string157, fn_break, 0x00 }, + { string158, fn_read, 0x01 }, + { string159, fn_prin1, 0x12 }, + { string160, fn_print, 0x12 }, + { string161, fn_princ, 0x12 }, + { string162, fn_terpri, 0x01 }, + { string163, fn_readbyte, 0x02 }, + { string164, fn_readline, 0x01 }, + { string165, fn_writebyte, 0x12 }, + { string166, fn_writestring, 0x12 }, + { string167, fn_writeline, 0x12 }, + { string168, fn_restarti2c, 0x12 }, + { string169, fn_gc, 0x00 }, + { string170, fn_room, 0x00 }, + { string171, fn_saveimage, 0x01 }, + { string172, fn_loadimage, 0x01 }, + { string173, fn_cls, 0x00 }, + { string174, fn_pinmode, 0x22 }, + { string175, fn_digitalread, 0x11 }, + { string176, fn_digitalwrite, 0x22 }, + { string177, fn_analogread, 0x11 }, + { string178, fn_analogwrite, 0x22 }, + { string179, fn_delay, 0x11 }, + { string180, fn_millis, 0x00 }, + { string181, fn_sleep, 0x11 }, + { string182, fn_note, 0x03 }, + { string183, fn_edit, 0x11 }, + { string184, fn_pprint, 0x12 }, + { string185, fn_pprintall, 0x01 }, + { string186, fn_format, 0x2F }, + { string187, fn_require, 0x11 }, + { string188, fn_listlibrary, 0x00 }, + { string189, fn_drawpixel, 0x23 }, + { string190, fn_drawline, 0x45 }, + { string191, fn_drawrect, 0x45 }, + { string192, fn_fillrect, 0x45 }, + { string193, fn_drawcircle, 0x34 }, + { string194, fn_fillcircle, 0x34 }, + { string195, fn_drawroundrect, 0x56 }, + { string196, fn_fillroundrect, 0x56 }, + { string197, fn_drawtriangle, 0x67 }, + { string198, fn_filltriangle, 0x67 }, + { string199, fn_drawchar, 0x36 }, + { string200, fn_setcursor, 0x22 }, + { string201, fn_settextcolor, 0x12 }, + { string202, fn_settextsize, 0x11 }, + { string203, fn_settextwrap, 0x11 }, + { string204, fn_fillscreen, 0x01 }, + { string205, fn_setrotation, 0x11 }, + { string206, fn_invertdisplay, 0x11 }, }; // Table lookup functions @@ -4045,12 +4604,10 @@ intptr_t lookupfn (symbol_t name) { return (intptr_t)lookup_table[name].fptr; } -uint8_t lookupmin (symbol_t name) { - return lookup_table[name].min; -} - -uint8_t lookupmax (symbol_t name) { - return lookup_table[name].max; +void checkminmax (symbol_t name, int nargs) { + uint8_t minmax = lookup_table[name].minmax; + if (nargs<(minmax >> 4)) error2(name, toofewargs); + if ((minmax & 0x0f) != 0x0f && nargs>(minmax & 0x0f)) error2(name, toomanyargs); } char *lookupbuiltin (symbol_t name) { @@ -4088,14 +4645,12 @@ object *eval (object *form, object *env) { int TC=0; EVAL: // Enough space? - // Serial.println((uint32_t)sp); + // Serial.println((uint32_t)sp - (uint32_t)&end); if (((uint32_t)sp - (uint32_t)&end) < STACKDIFF) error2(0, PSTR("Stack overflow")); if (Freespace <= WORKSPACESIZE>>4) gc(form, env); // Escape if (tstflag(ESCAPE)) { clrflag(ESCAPE); error2(0, PSTR("Escape!"));} - #if defined (serialmonitor) if (!tstflag(NOESC)) testescape(); - #endif if (form == NULL) return nil; @@ -4103,7 +4658,6 @@ object *eval (object *form, object *env) { if (symbolp(form)) { symbol_t name = form->name; - if (name == NIL) error2(0, PSTR("Error 1")); // return nil; object *pair = value(name, env); if (pair != NULL) return cdr(pair); pair = value(name, GlobalEnv); @@ -4113,7 +4667,7 @@ object *eval (object *form, object *env) { } if (form->type == CODE) error2(0, PSTR("can't evaluate CODE header")); - + // It's a list object *function = car(form); object *args = cdr(form); @@ -4128,6 +4682,7 @@ object *eval (object *form, object *env) { if ((name == LET) || (name == LETSTAR)) { int TCstart = TC; object *assigns = first(args); + if (!listp(assigns)) error(name, PSTR("first argument is not a list"), assigns); object *forms = cdr(args); object *newenv = env; push(newenv, GCStack); @@ -4168,7 +4723,7 @@ object *eval (object *form, object *env) { goto EVAL; } - if (name < SPECIAL_FORMS) error2((int)function, PSTR("can't be used as a function")); + if (name < SPECIAL_FORMS) error2((uintptr_t)function, PSTR("can't be used as a function")); } // Evaluate the parameters - result in head @@ -4194,8 +4749,7 @@ object *eval (object *form, object *env) { if (symbolp(function)) { symbol_t name = function->name; if (name >= ENDFUNCTIONS) error(0, PSTR("not valid here"), fname); - if (nargslookupmax(name)) error2(name, PSTR("has too many arguments")); + checkminmax(name, nargs); object *result = ((fn_ptr_type)lookupfn(name))(args, env); pop(GCStack); return result; @@ -4209,7 +4763,7 @@ object *eval (object *form, object *env) { int trace = tracing(fname->name); if (trace) { object *result = eval(form, env); - indent((--(TraceDepth[trace-1]))<<1, pserial); + indent((--(TraceDepth[trace-1]))<<1, ' ', pserial); pint(TraceDepth[trace-1], pserial); pserial(':'); pserial(' '); printobject(fname, pserial); pfstring(PSTR(" returned "), pserial); @@ -4231,8 +4785,8 @@ object *eval (object *form, object *env) { if (car(function)->type == CODE) { int n = listlength(DEFCODE, second(function)); - if (nargsname, PSTR("has too few arguments")); - if (nargs>n) error2(fname->name, PSTR("has too many arguments")); + if (nargsname, toofewargs); + if (nargs>n) error2(fname->name, toomanyargs); uint32_t entry = startblock(car(function)) + 1; pop(GCStack); return call(entry, n, args, env); @@ -4278,7 +4832,7 @@ void printstring (object *form, pfun_t pfun) { if (tstflag(PRINTREADABLY)) pfun('"'); form = cdr(form); while (form != NULL) { - int chars = form->integer; + int chars = form->chars; for (int i=(sizeof(int)-1)*8; i>=0; i=i-8) { char ch = chars>>i & 0xFF; if (tstflag(PRINTREADABLY) && (ch == '"' || ch == '\\')) pfun('\\'); @@ -4320,7 +4874,6 @@ void pinthex (uint32_t i, pfun_t pfun) { #else uint32_t p = 0x10000000; #endif - pfun('#'); pfun('x'); for (uint32_t d=p; d>0; d=d/16) { uint32_t j = i/d; if (j!=0 || lead || d==1) { pfun((j<10) ? j+'0' : j+'W'); lead=1;} @@ -4342,7 +4895,7 @@ void pmantissa (float f, pfun_t pfun) { int sig = floor(log10(f)); int mul = pow(10, 5 - sig); int i = round(f * mul); - boolean point = false; + bool point = false; if (i == 1000000) { i = 100000; sig++; } if (sig < 0) { pfun('0'); pfun('.'); point = true; @@ -4394,7 +4947,7 @@ void pfl (pfun_t pfun) { if (LastPrint != '\n') pfun('\n'); } -void printobject (object *form, pfun_t pfun){ +void printobject (object *form, pfun_t pfun) { if (form == NULL) pfstring(PSTR("nil"), pfun); else if (listp(form) && issymbol(car(form), CLOSURE)) pfstring(PSTR(""), pfun); else if (listp(form)) { @@ -4411,12 +4964,12 @@ void printobject (object *form, pfun_t pfun){ printobject(form, pfun); } pfun(')'); - } else if (form->type == NUMHEX) pinthex(form->integer, pfun); - else if (integerp(form)) pint(form->integer, pfun); + } else if (integerp(form)) pint(form->integer, pfun); else if (floatp(form)) pfloat(form->single_float, pfun); else if (symbolp(form)) { if (form->name != NOTHING) pstring(symbolname(form->name), pfun); } - else if (characterp(form)) pcharacter(form->integer, pfun); + else if (characterp(form)) pcharacter(form->chars, pfun); else if (stringp(form)) printstring(form, pfun); + else if (arrayp(form)) printarray(form, pfun); else if (form->type == CODE) pfstring(PSTR("code"), pfun); else if (streamp(form)) { pfun('<'); @@ -4431,6 +4984,13 @@ void printobject (object *form, pfun_t pfun){ error2(0, PSTR("Error in print")); } +void prin1object (object *form, pfun_t pfun) { + char temp = Flags; + clrflag(PRINTREADABLY); + printobject(form, pfun); + Flags = temp; +} + // Read functions int glibrary () { @@ -4452,21 +5012,122 @@ void loadfromlibrary (object *env) { } } +// For line editor +const int TerminalWidth = 80; +volatile int WritePtr = 0, ReadPtr = 0; +const int KybdBufSize = 333; // 42*8 - 3 +char KybdBuf[KybdBufSize]; +volatile uint8_t KybdAvailable = 0; + +// Parenthesis highlighting +void esc (int p, char c) { + Serial.write('\e'); Serial.write('['); + Serial.write((char)('0'+ p/100)); + Serial.write((char)('0'+ (p/10) % 10)); + Serial.write((char)('0'+ p % 10)); + Serial.write(c); +} + +void hilight (char c) { + Serial.write('\e'); Serial.write('['); Serial.write(c); Serial.write('m'); +} + +void Highlight (int p, int wp, uint8_t invert) { + wp = wp + 2; // Prompt +#if defined (printfreespace) + int f = Freespace; + while (f) { wp++; f=f/10; } +#endif + int line = wp/TerminalWidth; + int col = wp%TerminalWidth; + int targetline = (wp - p)/TerminalWidth; + int targetcol = (wp - p)%TerminalWidth; + int up = line-targetline, left = col-targetcol; + if (p) { + if (up) esc(up, 'A'); + if (col > targetcol) esc(left, 'D'); else esc(-left, 'C'); + if (invert) hilight('7'); + Serial.write('('); Serial.write('\b'); + // Go back + if (up) esc(up, 'B'); // Down + if (col > targetcol) esc(left, 'C'); else esc(-left, 'D'); + Serial.write('\b'); Serial.write(')'); + if (invert) hilight('0'); + } +} + +void processkey (char c) { + if (c == 27) { setflag(ESCAPE); return; } // Escape key +#if defined(vt100) + static int parenthesis = 0, wp = 0; + // Undo previous parenthesis highlight + Highlight(parenthesis, wp, 0); + parenthesis = 0; +#endif + // Edit buffer + if (c == '\n' || c == '\r') { + pserial('\n'); + KybdAvailable = 1; + ReadPtr = 0; + return; + } + if (c == 8 || c == 0x7f) { // Backspace key + if (WritePtr > 0) { + WritePtr--; + Serial.write(8); Serial.write(' '); Serial.write(8); + if (WritePtr) c = KybdBuf[WritePtr-1]; + } + } else if (WritePtr < KybdBufSize) { + KybdBuf[WritePtr++] = c; + Serial.write(c); + } +#if defined(vt100) + // Do new parenthesis highlight + if (c == ')') { + int search = WritePtr-1, level = 0; + while (search >= 0 && parenthesis == 0) { + c = KybdBuf[search--]; + if (c == ')') level++; + if (c == '(') { + level--; + if (level == 0) {parenthesis = WritePtr-search-1; wp = WritePtr; } + } + } + Highlight(parenthesis, wp, 1); + } +#endif + return; +} + int gserial () { if (LastChar) { char temp = LastChar; LastChar = 0; return temp; } +#if defined(lineeditor) + while (!KybdAvailable) { + while (!Serial.available()); + char temp = Serial.read(); + processkey(temp); + } + if (ReadPtr != WritePtr) return KybdBuf[ReadPtr++]; + KybdAvailable = 0; + WritePtr = 0; + return '\n'; +#else while (!Serial.available()); char temp = Serial.read(); if (temp != '\n') pserial(temp); return temp; +#endif } +#define issp(x) (x == ' ' || x == '\n' || x == '\r' || x == '\t') + object *nextitem (gfun_t gfun) { int ch = gfun(); - while(isspace(ch)) ch = gfun(); + while(issp(ch)) ch = gfun(); if (ch == ';') { while(ch != '(') ch = gfun(); @@ -4486,7 +5147,7 @@ object *nextitem (gfun_t gfun) { char *buffer = SymbolTop; int bufmax = maxbuffer(buffer); // Max index unsigned int result = 0; - boolean isfloat = false; + bool isfloat = false; float fresult = 0.0; if (ch == '+') { @@ -4501,11 +5162,17 @@ object *nextitem (gfun_t gfun) { ch = gfun(); if (ch == ' ') return (object *)DOT; isfloat = true; - } else if (ch == '#') { + } + + // Parse reader macros + else if (ch == '#') { ch = gfun(); char ch2 = ch & ~0x20; // force to upper case - if (ch == '\\') base = 0; // character - else if (ch == '|') { + if (ch == '\\') { // Character + base = 0; ch = gfun(); + if (issp(ch) || ch == ')' || ch == '(') return character(ch); + else LastChar = ch; + } else if (ch == '|') { do { while (gfun() != '|'); } while (gfun() != '#'); return nextitem(gfun); @@ -4518,17 +5185,20 @@ object *nextitem (gfun_t gfun) { object *result = eval(read(gfun), NULL); clrflag(NOESC); return result; - } else error2(0, PSTR("illegal character after #")); + } + else if (ch == '(') { LastChar = ch; return readarray(1, read(gfun)); } + else if (ch >= '1' && ch <= '9' && (gfun() & ~0x20) == 'A') return readarray(ch - '0', read(gfun)); + else error2(0, PSTR("illegal character after #")); ch = gfun(); } int valid; // 0=undecided, -1=invalid, +1=valid if (ch == '.') valid = 0; else if (digitvalue(ch) ((unsigned int)INT_MAX+(1-sign)/2)) return makefloat((float)result*sign); - if (base == 16) return numhex(result*sign); else return number(result*sign); + return number(result*sign); } else if (base == 0) { if (index == 1) return character(buffer[0]); const char* p = ControlCodes; char c = 0; @@ -4569,7 +5239,7 @@ object *nextitem (gfun_t gfun) { if (strcasecmp(buffer, p) == 0) return character(c); p = p + strlen(p) + 1; c++; } - error2(0, PSTR("Unknown character")); + error2(0, PSTR("unknown character")); } int x = builtin(buffer); @@ -4615,6 +5285,16 @@ object *read (gfun_t gfun) { // Setup +void initgfx () { +#if defined(gfxsupport) + tft.initR(INITR_BLACKTAB); + tft.setRotation(1); + pinMode(TFT_BACKLIGHT, OUTPUT); + digitalWrite(TFT_BACKLIGHT, HIGH); + tft.fillScreen(ST77XX_BLACK); +#endif +} + void initenv () { GlobalEnv = NULL; tee = symbol(TEE); @@ -4627,7 +5307,8 @@ void setup () { initworkspace(); initenv(); initsleep(); - pfstring(PSTR("uLisp 3.1 "), pserial); pln(pserial); + initgfx(); + pfstring(PSTR("uLisp 3.2 "), pserial); pln(pserial); } // Read/Evaluate/Print loop