From 6024b0056fc329b76a0ce729e0830de25527aa27 Mon Sep 17 00:00:00 2001 From: cuu Date: Tue, 18 Mar 2025 15:13:21 +0800 Subject: [PATCH] add uLisp patch --- Code/uLisp/README.md | 68 + Code/uLisp/uLisp.patch | 9831 ++++++++++++++++++++++++++++++++ wiki/arduino_uLisp_compile.png | Bin 0 -> 201195 bytes 3 files changed, 9899 insertions(+) create mode 100644 Code/uLisp/README.md create mode 100644 Code/uLisp/uLisp.patch create mode 100644 wiki/arduino_uLisp_compile.png diff --git a/Code/uLisp/README.md b/Code/uLisp/README.md new file mode 100644 index 0000000..638cba4 --- /dev/null +++ b/Code/uLisp/README.md @@ -0,0 +1,68 @@ +# How to compile uLisp + +uLisp for PicoCalc use [arduino ide](https://www.arduino.cc/en/software) to develop. + +## Install arduino-pico + +Open up the Arduino IDE and go to File->Preferences. + +In the dialog that pops up, enter the following URL in the "Additional Boards Manager URLs" field: + +https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json + +![image](https://user-images.githubusercontent.com/11875/111917251-3c57f400-8a3c-11eb-8120-810a8328ab3f.png) + +Hit OK to close the dialog. + +Go to Tools->Boards->Board Manager in the IDE + +Type "pico" in the search box and select "Add": + +![image](https://user-images.githubusercontent.com/11875/111917223-12063680-8a3c-11eb-8884-4f32b8f0feb1.png) + + +Original document reference: https://github.com/earlephilhower/arduino-pico/blob/master/README.md + +## Patch code +``` +git clone https://github.com/technoblogy/ulisp-arm.git + +cd uLisp-arm + +git reset --hard 97e61151dfb236311089abd3e89029e367613f70 + +git apply uLisp.patch +``` + +Install **TFT_eSPI 2.5.34** in arduino ide and patch it + +``` +cp patches/Setup60_RP2040_ILI9488.h ~/Arduino/libraries/TFT_eSPI/User_Setups/Setup60_RP2040_ILI9488.h +``` + +Add a new include +``` +#include +``` +and comment out +``` +#include +``` +in `~/Arduino/libraries/TFT_eSPI/User_Setup_Select.h` + +## Compile and upload + +In arduino ide ,config board and other arguments + +Put pico in BOOTSEL mode by pressing BOOTSEL key and power on it + +Hit the upload button in arduino ide + +Here is the screenshot for reference: + +![ulisp arduino](https://github.com/clockworkpi/PicoCalc/blob/master/wiki/arduino_uLisp_compile.png) + + + + + diff --git a/Code/uLisp/uLisp.patch b/Code/uLisp/uLisp.patch new file mode 100644 index 0000000..c700403 --- /dev/null +++ b/Code/uLisp/uLisp.patch @@ -0,0 +1,9831 @@ +diff --git a/Directory.ino b/Directory.ino +new file mode 100644 +index 0000000..eb84696 +--- /dev/null ++++ b/Directory.ino +@@ -0,0 +1,71 @@ ++/* ++ * http://forum.ulisp.com/t/showing-the-files-on-an-sdcard/1266/4 ++ SD Card Extension ++ Put it in a file Directory.ino in the same folder as the uLisp source file for your platform. ++Uncomment #define extensions at the start of the main uLisp source file. ++Compile and upload uLisp. ++ ++*/ ++ ++object *fn_directory (object *args, object *env) { ++ ++#if defined(sdcardsupport) ++ (void) env; ++ object *result = cons(NULL, NULL); ++ ++ #if defined(ARDUINO_RASPBERRY_PI_PICO) ++ #if defined(CPI_PICOCALC) ++ if(!SD.begin(SDCARD_SS_PIN,(uint32_t) SPI_HALF_SPEED, SPI)){ ++ //if(!SD.begin(SDCARD_SS_PIN,tft.getSPIinstance())){ ++ error2(PSTR("problem init SD card")); ++ return cdr(result); ++ } ++ #else ++ SD.begin(SDCARD_SS_PIN,(uint32_t) SPI_HALF_SPEED, SPI1); ++ #endif ++ #else ++ SD.begin(SDCARD_SS_PIN); ++ #endif ++ File root = SD.open("/"); ++ if (!root) error2(PSTR("problem reading from SD card")); ++ object *ptr = result; ++ while (true) { ++ File entry = root.openNextFile(); ++ if (!entry) break; ++ ++ object *filename = lispstring((char*)entry.name()); ++ cdr(ptr) = cons(filename, NULL); ++ ptr = cdr(ptr); ++ }; ++ root.close(); ++ return cdr(result); ++ #else ++ return NULL; ++ #endif ++} ++ ++// Symbol names ++const char stringdirectory[] PROGMEM = "directory"; ++ ++// Documentation strings ++const char docdirectory[] PROGMEM = "(directory)\n" ++"Reads the directory at the top level of an SD card and returns\n" ++"a list of the filenames."; ++ ++// Symbol lookup table ++const tbl_entry_t lookup_table2[] PROGMEM = { ++ { stringdirectory, fn_directory, 0200, docdirectory }, ++}; ++ ++// Table cross-reference functions ++ ++tbl_entry_t *tables[] = {lookup_table, lookup_table2}; ++const unsigned int tablesizes[] = { arraysize(lookup_table), arraysize(lookup_table2) }; ++ ++const tbl_entry_t *table (int n) { ++ return tables[n]; ++} ++ ++unsigned int tablesize (int n) { ++ return tablesizes[n]; ++} +diff --git a/patches/Setup60_RP2040_ILI9488.h b/patches/Setup60_RP2040_ILI9488.h +new file mode 100755 +index 0000000..c5e16f5 +--- /dev/null ++++ b/patches/Setup60_RP2040_ILI9488.h +@@ -0,0 +1,200 @@ ++// USER DEFINED SETTINGS ++// Set driver type, fonts to be loaded, pins used and SPI control method etc ++// ++// See the User_Setup_Select.h file if you wish to be able to define multiple ++// setups and then easily select which setup file is used by the compiler. ++// ++// If this file is edited correctly then all the library example sketches should ++// run without the need to make any more changes for a particular hardware setup! ++// Note that some sketches are designed for a particular TFT pixel width/height ++ ++#define USER_SETUP_ID 60 ++// ################################################################################## ++// ++// Section 1. Call up the right driver file and any options for it ++// ++// ################################################################################## ++ ++// Tell the library to use 8 bit parallel mode (otherwise SPI is assumed) ++//#define TFT_PARALLEL_8_BIT ++ ++// Display type - only define if RPi display ++//#define RPI_DISPLAY_TYPE // 20MHz maximum SPI ++ ++// Only define one driver, the other ones must be commented out ++// #define ILI9341_DRIVER ++//#define ST7735_DRIVER // Define additional parameters below for this display ++//#define ILI9163_DRIVER // Define additional parameters below for this display ++//#define S6D02A1_DRIVER ++//#define RPI_ILI9486_DRIVER // 20MHz maximum SPI ++//#define HX8357D_DRIVER ++//#define ILI9481_DRIVER ++//#define ILI9486_DRIVER ++#define ILI9488_DRIVER // WARNING: Do not connect ILI9488 display SDO to MISO if other devices share the SPI bus (TFT SDO does NOT tristate when CS is high) ++// #define ST7789_DRIVER // Full configuration option, define additional parameters below for this display ++// #define ST7789_2_DRIVER // Minimal configuration option, define additional parameters below for this display ++//#define R61581_DRIVER ++//#define RM68140_DRIVER ++//#define ST7796_DRIVER ++//#define SSD1963_480_DRIVER ++//#define SSD1963_800_DRIVER ++//#define SSD1963_800ALT_DRIVER ++//#define ILI9225_DRIVER ++ ++// Some displays support SPI reads via the MISO pin, other displays have a single ++// bi-directional SDA pin and the library will try to read this via the MOSI line. ++// To use the SDA line for reading data from the TFT uncomment the following line: ++ ++// #define TFT_SDA_READ // This option is for ESP32 ONLY, tested with ST7789 display only ++ ++// For ST7735, ST7789 and ILI9341 ONLY, define the colour order IF the blue and red are swapped on your display ++// Try ONE option at a time to find the correct colour order for your display ++ ++// #define TFT_RGB_ORDER TFT_RGB // Colour order Red-Green-Blue ++#define TFT_RGB_ORDER TFT_BGR // Colour order Blue-Green-Red ++ ++// For ST7789, ST7735 and ILI9163 ONLY, define the pixel width and height in portrait orientation ++// #define TFT_WIDTH 80 ++// #define TFT_WIDTH 128 ++// #define TFT_WIDTH 240 // ST7789 240 x 240 and 240 x 320 ++// #define TFT_HEIGHT 160 ++// #define TFT_HEIGHT 128 ++// #define TFT_HEIGHT 240 // ST7789 240 x 240 ++// #define TFT_HEIGHT 320 // ST7789 240 x 320 ++// For ST7735 ONLY, define the type of display, originally this was based on the ++// colour of the tab on the screen protector film but this is not always true, so try ++// out the different options below if the screen does not display graphics correctly, ++// e.g. colours wrong, mirror images, or tray pixels at the edges. ++// Comment out ALL BUT ONE of these options for a ST7735 display driver, save this ++// this User_Setup file, then rebuild and upload the sketch to the board again: ++ ++// #define ST7735_INITB ++// #define ST7735_GREENTAB ++// #define ST7735_GREENTAB2 ++// #define ST7735_GREENTAB3 ++// #define ST7735_GREENTAB128 // For 128 x 128 display ++// #define ST7735_GREENTAB160x80 // For 160 x 80 display (BGR, inverted, 26 offset) ++// #define ST7735_REDTAB ++// #define ST7735_BLACKTAB ++// #define ST7735_REDTAB160x80 // For 160 x 80 display with 24 pixel offset ++ ++// If colours are inverted (white shows as black) then uncomment one of the next ++// 2 lines try both options, one of the options should correct the inversion. ++ ++// #define TFT_INVERSION_ON ++// #define TFT_INVERSION_OFF ++ ++ ++// ################################################################################## ++// ++// Section 2. Define the pins that are used to interface with the display here ++// ++// ################################################################################## ++ ++// If a backlight control signal is available then define the TFT_BL pin in Section 2 ++// below. The backlight will be turned ON when tft.begin() is called, but the library ++// needs to know if the LEDs are ON with the pin HIGH or LOW. If the LEDs are to be ++// driven with a PWM signal or turned OFF/ON then this must be handled by the user ++// sketch. e.g. with digitalWrite(TFT_BL, LOW); ++ ++// #define TFT_BL 32 // LED back-light control pin ++// #define TFT_BACKLIGHT_ON HIGH // Level to turn ON back-light (HIGH or LOW) ++ ++// We must use hardware SPI, a minimum of 3 GPIO pins is needed. ++// Typical setup for the RP2040 is : ++// ++// Display SDO/MISO to RP2040 pin D0 (or leave disconnected if not reading TFT) ++// Display LED to RP2040 pin 3V3 or 5V ++// Display SCK to RP2040 pin D2 ++// Display SDI/MOSI to RP2040 pin D3 ++// Display DC (RS/AO)to RP2040 pin D18 (can use another pin if desired) ++// Display RESET to RP2040 pin D19 (can use another pin if desired) ++// Display CS to RP2040 pin D20 (can use another pin if desired, or GND, see below) ++// Display GND to RP2040 pin GND (0V) ++// Display VCC to RP2040 5V or 3.3V (5v if display has a 5V to 3.3V regulator fitted) ++// ++// The DC (Data Command) pin may be labelled AO or RS (Register Select) ++// ++// With some displays such as the ILI9341 the TFT CS pin can be connected to GND if no more ++// SPI devices (e.g. an SD Card) are connected, in this case comment out the #define TFT_CS ++// line below so it is NOT defined. Other displays such at the ST7735 require the TFT CS pin ++// to be toggled during setup, so in these cases the TFT_CS line must be defined and connected. ++ ++// For the Pico use these #define lines ++// #define TFT_MISO 0 ++// #define TFT_MOSI 3 ++// #define TFT_SCLK 2 ++// #define TFT_CS 20 // Chip select control pin ++// #define TFT_DC 18 // Data Command control pin ++// #define TFT_RST 19 // Reset pin (could connect to Arduino RESET pin) ++//#define TFT_BL // LED back-light ++ ++#define TFT_MISO 12 ++#define TFT_MOSI 11 ++#define TFT_SCLK 10 ++#define TFT_CS 13 // Not connected ++#define TFT_DC 14 ++#define TFT_RST 15 // Connect reset to ensure display initialises ++//#define TFT_BL 13 // LED back-light ++//#define TFT_BACKLIGHT_ON HIGH // Level to turn ON back-light (HIGH or LOW) ++ ++//#define TOUCH_CS 16 ++ ++ ++//#define TOUCH_CS 21 // Chip select pin (T_CS) of touch screen ++ ++// ################################################################################## ++// ++// Section 3. Define the fonts that are to be used here ++// ++// ################################################################################## ++ ++// Comment out the #defines below with // to stop that font being loaded ++// The ESP8366 and ESP32 have plenty of memory so commenting out fonts is not ++// normally necessary. If all fonts are loaded the extra FLASH space required is ++// about 17Kbytes. To save FLASH space only enable the fonts you need! ++ ++#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH ++//#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters ++//#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters ++//#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm ++//#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-. ++//#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-. ++//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT ++//#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts ++ ++// Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded ++// this will save ~20kbytes of FLASH ++//#define SMOOTH_FONT ++ ++ ++// ################################################################################## ++// ++// Section 4. Other options ++// ++// ################################################################################## ++ ++// For the RP2040 processor define the SPI port channel used, default is 0 ++#define TFT_SPI_PORT 1 // Set to 0 if SPI0 pins are used, or 1 if spi1 pins used ++ ++// Define the SPI clock frequency, this affects the graphics rendering speed. Too ++// fast and the TFT driver will not keep up and display corruption appears. ++// With an ILI9341 display 40MHz works OK, 80MHz sometimes fails ++// With a ST7735 display more than 27MHz may not work (spurious pixels and lines) ++// With an ILI9163 display 27 MHz works OK. ++ ++// #define SPI_FREQUENCY 1000000 ++// #define SPI_FREQUENCY 5000000 ++// #define SPI_FREQUENCY 10000000 ++// #define SPI_FREQUENCY 20000000 ++// #define SPI_FREQUENCY 32000000 ++// #define SPI_FREQUENCY 70000000 ++#define SPI_FREQUENCY 25000000 ++ ++// Optional reduced SPI frequency for reading TFT ++// #define SPI_READ_FREQUENCY 20000000 ++//#define SPI_READ_FREQUENCY 2000000 ++ ++// The XPT2046 requires a lower SPI clock rate of 2.5MHz so we define that here: ++#define SPI_TOUCH_FREQUENCY 2500000 ++ +diff --git a/ulisp-arm-comments.ino b/ulisp-arm-comments.ino +deleted file mode 100644 +index 0e87e20..0000000 +--- a/ulisp-arm-comments.ino ++++ /dev/null +@@ -1,8779 +0,0 @@ +-/* uLisp ARM Release 4.4b - www.ulisp.com +- David Johnson-Davies - www.technoblogy.com - 3rd April 2023 +- +- Licensed under the MIT license: https://opensource.org/licenses/MIT +-*/ +- +-// Lisp Library +-const char LispLibrary[] PROGMEM = ""; +- +-// Compile options +- +-// #define resetautorun +-#define printfreespace +-// #define printgcs +-// #define sdcardsupport +-// #define gfxsupport +-// #define lisplibrary +-#define assemblerlist +-// #define lineeditor +-// #define vt100 +-// #define extensions +- +-// Includes +- +-// #include "LispLibrary.h" +-#include +-#include +-#include +-#include +- +-#if defined(sdcardsupport) +-#include +-#define SDSIZE 91 +-#else +-#define SDSIZE 0 +-#endif +- +-// Platform specific settings +- +-#define WORDALIGNED __attribute__((aligned (4))) +-#define BUFFERSIZE 36 // Number of bits+4 +-#define RAMFUNC __attribute__ ((section (".ramfunctions"))) +-#define MEMBANK +- +-#if defined(ARDUINO_GEMMA_M0) || defined(ARDUINO_SEEED_XIAO_M0) || defined(ARDUINO_QTPY_M0) +- #define WORKSPACESIZE (2816-SDSIZE) /* Objects (8*bytes) */ +- #define EEPROMFLASH +- #define FLASHSIZE 32768 /* Bytes */ +- #define CODESIZE 128 /* Bytes */ +- #define STACKDIFF 320 +- #define CPU_ATSAMD21 +- +-#elif defined(ARDUINO_ITSYBITSY_M0) || defined(ARDUINO_SAMD_FEATHER_M0_EXPRESS) +- #define WORKSPACESIZE (2816-SDSIZE) /* Objects (8*bytes) */ +- #define DATAFLASH +- #define FLASHSIZE 2048000 /* 2 MBytes */ +- #define CODESIZE 128 /* Bytes */ +- #define SDCARD_SS_PIN 4 +- #define STACKDIFF 320 +- #define CPU_ATSAMD21 +- +-#elif defined(ADAFRUIT_FEATHER_M0) /* Feather M0 without DataFlash */ +- #define WORKSPACESIZE (2816-SDSIZE) /* Objects (8*bytes) */ +- #define EEPROMFLASH +- #define FLASHSIZE 32768 /* Bytes */ +- #define CODESIZE 128 /* Bytes */ +- #define SDCARD_SS_PIN 4 +- #define STACKDIFF 320 +- #define CPU_ATSAMD21 +- +-#elif defined(ARDUINO_METRO_M4) || defined(ARDUINO_ITSYBITSY_M4) || defined(ARDUINO_FEATHER_M4) +- #define WORKSPACESIZE (20608-SDSIZE) /* Objects (8*bytes) */ +- #define DATAFLASH +- #define FLASHSIZE 2048000 /* 2 MBytes */ +- #define CODESIZE 256 /* Bytes */ +- #define SDCARD_SS_PIN 10 +- #define STACKDIFF 400 +- #define CPU_ATSAMD51 +- +-#elif defined(ARDUINO_PYBADGE_M4) || defined(ARDUINO_PYGAMER_M4) +- #define WORKSPACESIZE (20608-SDSIZE) /* Objects (8*bytes) */ +- #define DATAFLASH +- #define FLASHSIZE 2048000 /* 2 MBytes */ +- #define CODESIZE 256 /* Bytes */ +- #define SDCARD_SS_PIN 10 +- #define STACKDIFF 400 +- #define CPU_ATSAMD51 +- #if defined(gfxsupport) +- const int COLOR_WHITE = 0xffff, COLOR_BLACK = 0, TFT_BACKLIGHT = 47; +- #include // Core graphics library +- #include // Hardware-specific library for ST7735 +- Adafruit_ST7735 tft = Adafruit_ST7735(44, 45, 41, 42, 46); +- #endif +- +-#elif defined(ARDUINO_WIO_TERMINAL) +- #define WORKSPACESIZE (20480-SDSIZE) /* Objects (8*bytes) */ +- #define DATAFLASH +- #define FLASHSIZE 2048000 /* 2 MBytes */ +- #define CODESIZE 256 /* Bytes */ +- #define STACKDIFF 400 +- #define CPU_ATSAMD51 +- #define EXTERNAL_FLASH_USE_QSPI +- #if defined(gfxsupport) +- const int COLOR_WHITE = 0xffff, COLOR_BLACK = 0; +- #include // Hardware-specific library +- TFT_eSPI tft = TFT_eSPI(); +- #endif +- +-#elif defined(ARDUINO_GRAND_CENTRAL_M4) +- #define WORKSPACESIZE (28800-SDSIZE) /* Objects (8*bytes) */ +- #define DATAFLASH +- #define FLASHSIZE 8192000 /* 8 MBytes */ +- #define CODESIZE 256 /* Bytes */ +- #define STACKDIFF 400 +- #define CPU_ATSAMD51 +- +-#elif defined(ARDUINO_SAMD_MKRZERO) +- #define WORKSPACESIZE (2640-SDSIZE) /* Objects (8*bytes) */ +- #define EEPROMFLASH +- #define FLASHSIZE 32768 /* Bytes */ +- #define SYMBOLTABLESIZE 512 /* Bytes */ +- #define CODESIZE 128 /* Bytes */ +- #define STACKDIFF 840 +- #define CPU_ATSAMD21 +- +-#elif defined(ARDUINO_SAMD_ZERO) /* Put this last, otherwise overrides the Adafruit boards */ +- #define WORKSPACESIZE (2640-SDSIZE) /* Objects (8*bytes) */ +- #define EEPROMFLASH +- #define FLASHSIZE 32768 /* Bytes */ +- #define CODESIZE 128 /* Bytes */ +- #define SDCARD_SS_PIN 10 +- #define STACKDIFF 320 +- #define CPU_ATSAMD21 +- +-#elif defined(ARDUINO_BBC_MICROBIT) || defined(ARDUINO_SINOBIT) +- #define WORKSPACESIZE 1344 /* Objects (8*bytes) */ +- #define CODESIZE 64 /* Bytes */ +- #define STACKDIFF 320 +- #define CPU_NRF51822 +- +-#elif defined(ARDUINO_BBC_MICROBIT_V2) +- #define WORKSPACESIZE 12928 /* Objects (8*bytes) */ +- #define CODESIZE 128 /* Bytes */ +- #define STACKDIFF 320 +- #define CPU_NRF52833 +- +-#elif defined(ARDUINO_CALLIOPE_MINI) +- #define WORKSPACESIZE 3392 /* Objects (8*bytes) */ +- #define CODESIZE 64 /* Bytes */ +- #define STACKDIFF 320 +- #define CPU_NRF51822 +- +-#elif defined(ARDUINO_NRF52840_ITSYBITSY) || defined(ARDUINO_Seeed_XIAO_nRF52840) || defined(ARDUINO_Seeed_XIAO_nRF52840_Sense) || defined(ARDUINO_NRF52840_CIRCUITPLAY) +- #define WORKSPACESIZE (21120-SDSIZE) /* Objects (8*bytes) */ +- #define DATAFLASH +- #define FLASHSIZE 2048000 /* 2 MBytes */ +- #define CODESIZE 256 /* Bytes */ +- #define STACKDIFF 8 +- #define CPU_NRF52840 +- +-#elif defined(ARDUINO_NRF52840_CLUE) +- #define WORKSPACESIZE (21120-SDSIZE) /* Objects (8*bytes) */ +- #define DATAFLASH +- #define FLASHSIZE 2048000 /* 2 MBytes */ +- #define CODESIZE 256 /* Bytes */ +- #define STACKDIFF 8 +- #define CPU_NRF52840 +- #if defined(gfxsupport) +- const int COLOR_WHITE = 0xffff, COLOR_BLACK = 0; +- #include +- #include +- Adafruit_ST7789 tft = Adafruit_ST7789(&SPI1, PIN_TFT_CS, PIN_TFT_DC, PIN_TFT_RST); +- #endif +- +-#elif defined(MAX32620) +- #define WORKSPACESIZE (24704-SDSIZE) /* Objects (8*bytes) */ +- #define SYMBOLTABLESIZE 1024 /* Bytes */ +- #define CODESIZE 256 /* Bytes */ +- #define STACKDIFF 320 +- #define CPU_MAX32620 +- #define Wire1 Wire2 +- +-#elif defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY41) +- #define WORKSPACESIZE 60000 /* Objects (8*bytes) */ +- #define LITTLEFS (960 * 1024) +- #include +- LittleFS_Program LittleFS; +- #define CODESIZE 256 /* Bytes */ +- #define STACKDIFF 15000 +- #define CPU_iMXRT1062 +- #define SDCARD_SS_PIN BUILTIN_SDCARD +- #define BitOrder uint8_t +- #undef RAMFUNC +- #define RAMFUNC FASTRUN +- #undef MEMBANK +- #define MEMBANK DMAMEM +- +-#elif defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_QTPY_RP2040) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || defined(ARDUINO_SEEED_XIAO_RP2040) +- #define WORKSPACESIZE (22912-SDSIZE) /* Objects (8*bytes) */ +- #define LITTLEFS +- #include +- #define FILE_WRITE_BEGIN "w" +- #define FILE_READ "r" +- #define CODESIZE 256 /* Bytes */ +- #define STACKDIFF 320 +- #define CPU_RP2040 +- +-#elif defined(ARDUINO_RASPBERRY_PI_PICO_W) +- #define WORKSPACESIZE (15536-SDSIZE) /* Objects (8*bytes) */ +- #define LITTLEFS +- #include +- #include +- #define FILE_WRITE_BEGIN "w" +- #define FILE_READ "r" +- #define CODESIZE 256 /* Bytes */ +- #define STACKDIFF 320 +- #define CPU_RP2040 +- +-#else +-#error "Board not supported!" +-#endif +- +-// C Macros +- +-#define nil NULL +-#define car(x) (((object *) (x))->car) +-#define cdr(x) (((object *) (x))->cdr) +- +-#define first(x) (((object *) (x))->car) +-#define second(x) (car(cdr(x))) +-#define cddr(x) (cdr(cdr(x))) +-#define third(x) (car(cdr(cdr(x)))) +- +-#define push(x, y) ((y) = cons((x),(y))) +-#define pop(y) ((y) = cdr(y)) +- +-#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)) +-#define unmark(x) (car(x) = (object *)(((uintptr_t)(car(x))) & ~MARKBIT)) +-#define marked(x) ((((uintptr_t)(car(x))) & MARKBIT) != 0) +-#define MARKBIT 1 +- +-#define setflag(x) (Flags = Flags | 1<<(x)) +-#define clrflag(x) (Flags = Flags & ~(1<<(x))) +-#define tstflag(x) (Flags & 1<<(x)) +- +-#define issp(x) (x == ' ' || x == '\n' || x == '\r' || x == '\t') +-#define isbr(x) (x == ')' || x == '(' || x == '"' || x == '#') +-#define longsymbolp(x) (((x)->name & 0x03) == 0) +-#define twist(x) ((uint32_t)((x)<<2) | (((x) & 0xC0000000)>>30)) +-#define untwist(x) (((x)>>2 & 0x3FFFFFFF) | ((x) & 0x03)<<30) +-#define arraysize(x) (sizeof(x) / sizeof(x[0])) +-#define PACKEDS 0x43238000 +-#define BUILTINS 0xF4240000 +-#define ENDFUNCTIONS 1536 +- +-// Code marker stores start and end of code block +-#define startblock(x) ((x->integer) & 0xFFFF) +-#define endblock(x) ((x->integer) >> 16 & 0xFFFF) +- +-// Constants +- +-const int TRACEMAX = 3; // Number of traced functions +-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, WIFISTREAM, STRINGSTREAM, GFXSTREAM }; +-enum fntypes_t { OTHER_FORMS, TAIL_FORMS, FUNCTIONS, SPECIAL_FORMS }; +- +-// Stream names used by printobject +-const char serialstream[] PROGMEM = "serial"; +-const char i2cstream[] PROGMEM = "i2c"; +-const char spistream[] PROGMEM = "spi"; +-const char sdstream[] PROGMEM = "sd"; +-const char wifistream[] PROGMEM = "wifi"; +-const char stringstream[] PROGMEM = "string"; +-const char gfxstream[] PROGMEM = "gfx"; +-const char *const streamname[] PROGMEM = {serialstream, i2cstream, spistream, sdstream, wifistream, stringstream, gfxstream}; +- +-// Typedefs +- +-typedef uint32_t symbol_t; +- +-typedef struct sobject { +- union { +- struct { +- sobject *car; +- sobject *cdr; +- }; +- struct { +- unsigned int type; +- union { +- symbol_t name; +- int integer; +- int chars; // For strings +- float single_float; +- }; +- }; +- }; +-} object; +- +-typedef object *(*fn_ptr_type)(object *, object *); +-typedef void (*mapfun_t)(object *, object **); +-typedef int (*intfn_ptr_type)(int w, int x, int y, int z); +- +-typedef const struct { +- const char *string; +- fn_ptr_type fptr; +- uint8_t minmax; +- const char *doc; +-} tbl_entry_t; +- +-typedef int (*gfun_t)(); +-typedef void (*pfun_t)(char); +- +-typedef uint16_t builtin_t; +- +-enum builtins: builtin_t { NIL, TEE, NOTHING, OPTIONAL, INITIALELEMENT, ELEMENTTYPE, BIT, AMPREST, LAMBDA, LET, LETSTAR, +-CLOSURE, PSTAR, QUOTE, DEFUN, DEFVAR, DEFCODE, CAR, FIRST, CDR, REST, NTH, AREF, STRINGFN, PINMODE, +-DIGITALWRITE, ANALOGREAD, ANALOGREFERENCE, REGISTER, FORMAT, +- }; +- +-// Global variables +- +-object Workspace[WORKSPACESIZE] WORDALIGNED MEMBANK; +-#if defined(CODESIZE) +-RAMFUNC uint8_t MyCode[CODESIZE] WORDALIGNED; +-#endif +- +-jmp_buf toplevel_handler; +-jmp_buf *handler = &toplevel_handler; +-unsigned int Freespace = 0; +-object *Freelist; +-unsigned int I2Ccount; +-unsigned int TraceFn[TRACEMAX]; +-unsigned int TraceDepth[TRACEMAX]; +-builtin_t Context; +- +-object *GlobalEnv; +-object *GCStack = NULL; +-object *GlobalString; +-object *GlobalStringTail; +-int GlobalStringIndex = 0; +-uint8_t PrintCount = 0; +-uint8_t BreakLevel = 0; +-char LastChar = 0; +-char LastPrint = 0; +- +-// Flags +-enum flag { PRINTREADABLY, RETURNFLAG, ESCAPE, EXITEDITOR, LIBRARYLOADED, NOESC, NOECHO, MUFFLEERRORS }; +-volatile uint8_t Flags = 0b00001; // PRINTREADABLY set by default +- +-// Forward references +-object *tee; +-void pfstring (PGM_P s, pfun_t pfun); +- +-// Error handling +- +-/* +- errorsub - used by all the error routines. +- Prints: "Error: 'fname' string", where fname is the name of the Lisp function in which the error occurred. +-*/ +-void errorsub (symbol_t fname, PGM_P string) { +- pfl(pserial); pfstring(PSTR("Error: "), pserial); +- if (fname != sym(NIL)) { +- pserial('\''); +- psymbol(fname, pserial); +- pserial('\''); pserial(' '); +- } +- pfstring(string, pserial); +-} +- +-void errorend () { GCStack = NULL; longjmp(*handler, 1); } +- +-/* +- errorsym - prints an error message and reenters the REPL. +- Prints: "Error: 'fname' string: symbol", where fname is the name of the user Lisp function in which the error occurred, +- and symbol is the object generating the error. +-*/ +-void errorsym (symbol_t fname, PGM_P string, object *symbol) { +- if (!tstflag(MUFFLEERRORS)) { +- errorsub(fname, string); +- pserial(':'); pserial(' '); +- printobject(symbol, pserial); +- pln(pserial); +- } +- errorend(); +-} +- +-/* +- errorsym2 - prints an error message and reenters the REPL. +- Prints: "Error: 'fname' string", where fname is the name of the user Lisp function in which the error occurred. +-*/ +-void errorsym2 (symbol_t fname, PGM_P string) { +- if (!tstflag(MUFFLEERRORS)) { +- errorsub(fname, string); +- pln(pserial); +- } +- errorend(); +-} +- +-/* +- error - prints an error message and reenters the REPL. +- Prints: "Error: 'Context' string: symbol", where Context is the name of the built-in Lisp function in which the error occurred, +- and symbol is the object generating the error. +-*/ +-void error (PGM_P string, object *symbol) { +- errorsym(sym(Context), string, symbol); +-} +- +-/* +- error2 - prints an error message and reenters the REPL. +- Prints: "Error: 'Context' string", where Context is the name of the built-in Lisp function in which the error occurred. +-*/ +-void error2 (PGM_P string) { +- errorsym2(sym(Context), string); +-} +- +-/* +- formaterr - displays a format error with a ^ pointing to the error +-*/ +-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('^'); +- error2(string); +- pln(pserial); +- GCStack = NULL; +- longjmp(*handler, 1); +-} +- +-// Save space as these are used multiple times +-const char notanumber[] PROGMEM = "argument is not a number"; +-const char notaninteger[] PROGMEM = "argument is not an integer"; +-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 divisionbyzero[] PROGMEM = "division by zero"; +-const char indexnegative[] PROGMEM = "index can't be negative"; +-const char invalidarg[] PROGMEM = "invalid argument"; +-const char invalidkey[] PROGMEM = "invalid keyword"; +-const char illegalclause[] PROGMEM = "illegal clause"; +-const char invalidpin[] PROGMEM = "invalid pin"; +-const char oddargs[] PROGMEM = "odd number of arguments"; +-const char indexrange[] PROGMEM = "index out of range"; +-const char canttakecar[] PROGMEM = "can't take car"; +-const char canttakecdr[] PROGMEM = "can't take cdr"; +-const char unknownstreamtype[] PROGMEM = "unknown stream type"; +- +-// Set up workspace +- +-/* +- initworkspace - initialises the workspace into a linked list of free objects +-*/ +-void initworkspace () { +- Freelist = NULL; +- for (int i=WORKSPACESIZE-1; i>=0; i--) { +- object *obj = &Workspace[i]; +- car(obj) = NULL; +- cdr(obj) = Freelist; +- Freelist = obj; +- Freespace++; +- } +-} +- +-/* +- myalloc - returns the first object from the linked list of free objects +-*/ +-object *myalloc () { +- if (Freespace == 0) error2(PSTR("no room")); +- object *temp = Freelist; +- Freelist = cdr(Freelist); +- Freespace--; +- return temp; +-} +- +-/* +- myfree - adds obj to the linked list of free objects. +- inline makes gc significantly faster +-*/ +-inline void myfree (object *obj) { +- car(obj) = NULL; +- cdr(obj) = Freelist; +- Freelist = obj; +- Freespace++; +-} +- +-// Make each type of object +- +-/* +- number - make an integer object with value n and return it +-*/ +-object *number (int n) { +- object *ptr = myalloc(); +- ptr->type = NUMBER; +- ptr->integer = n; +- return ptr; +-} +- +-/* +- makefloat - make a floating point object with value f and return it +-*/ +-object *makefloat (float f) { +- object *ptr = myalloc(); +- ptr->type = FLOAT; +- ptr->single_float = f; +- return ptr; +-} +- +-/* +- character - make a character object with value c and return it +-*/ +-object *character (uint8_t c) { +- object *ptr = myalloc(); +- ptr->type = CHARACTER; +- ptr->chars = c; +- return ptr; +-} +- +-/* +- cons - make a cons with arg1 and arg2 return it +-*/ +-object *cons (object *arg1, object *arg2) { +- object *ptr = myalloc(); +- ptr->car = arg1; +- ptr->cdr = arg2; +- return ptr; +-} +- +-/* +- symbol - make a symbol object with value name and return it +-*/ +-object *symbol (symbol_t name) { +- object *ptr = myalloc(); +- ptr->type = SYMBOL; +- ptr->name = name; +- return ptr; +-} +- +-/* +- bsymbol - make a built-in symbol +-*/ +-inline object *bsymbol (builtin_t name) { +- return intern(twist(name+BUILTINS)); +-} +- +-/* +- codehead - make a code header object with value entry and return it +-*/ +-object *codehead (int entry) { +- object *ptr = myalloc(); +- ptr->type = CODE; +- ptr->integer = entry; +- return ptr; +-} +- +-/* +- intern - looks through the workspace for an existing occurrence of symbol name and returns it, +- otherwise calls symbol(name) to create a new symbol. +-*/ +-object *intern (symbol_t name) { +- for (int i=0; itype == SYMBOL && obj->name == name) return obj; +- } +- return symbol(name); +-} +- +-/* +- eqsymbols - compares the long string/symbol obj with the string in buffer. +-*/ +-bool eqsymbols (object *obj, char *buffer) { +- object *arg = cdr(obj); +- int i = 0; +- while (!(arg == NULL && buffer[i] == 0)) { +- if (arg == NULL || buffer[i] == 0) return false; +- int test = 0, shift = 24; +- for (int j=0; j<4; j++, i++) { +- if (buffer[i] == 0) break; +- test = test | buffer[i]<chars != test) return false; +- arg = car(arg); +- } +- return true; +-} +- +-/* +- internlong - looks through the workspace for an existing occurrence of the long symbol in buffer and returns it, +- otherwise calls lispstring(buffer) to create a new symbol. +-*/ +-object *internlong (char *buffer) { +- for (int i=0; itype == SYMBOL && longsymbolp(obj) && eqsymbols(obj, buffer)) return obj; +- } +- object *obj = lispstring(buffer); +- obj->type = SYMBOL; +- return obj; +-} +- +-/* +- stream - makes a stream object defined by streamtype and address, and returns it +-*/ +-object *stream (uint8_t streamtype, uint8_t address) { +- object *ptr = myalloc(); +- ptr->type = STREAM; +- ptr->integer = streamtype<<8 | address; +- return ptr; +-} +- +-/* +- newstring - makes an empty string object and returns it +-*/ +-object *newstring () { +- object *ptr = myalloc(); +- ptr->type = STRING; +- ptr->chars = 0; +- return ptr; +-} +- +-// Garbage collection +- +-/* +- markobject - recursively marks reachable objects, starting from obj +-*/ +-void markobject (object *obj) { +- MARK: +- if (obj == NULL) return; +- if (marked(obj)) return; +- +- object* arg = car(obj); +- unsigned int type = obj->type; +- mark(obj); +- +- if (type >= PAIR || type == ZZERO) { // cons +- markobject(arg); +- obj = cdr(obj); +- goto MARK; +- } +- +- if (type == ARRAY) { +- obj = cdr(obj); +- goto MARK; +- } +- +- if ((type == STRING) || (type == SYMBOL && longsymbolp(obj))) { +- obj = cdr(obj); +- while (obj != NULL) { +- arg = car(obj); +- mark(obj); +- obj = arg; +- } +- } +-} +- +-/* +- sweep - goes through the workspace freeing objects that have not been marked, +- and unmarks marked objects +-*/ +-void sweep () { +- Freelist = NULL; +- Freespace = 0; +- for (int i=WORKSPACESIZE-1; i>=0; i--) { +- object *obj = &Workspace[i]; +- if (!marked(obj)) myfree(obj); else unmark(obj); +- } +-} +- +-/* +- gc - performs garbage collection by calling markobject() on each of the pointers to objects in use, +- followed by sweep() to free unused objects. +-*/ +-void gc (object *form, object *env) { +- #if defined(printgcs) +- int start = Freespace; +- #endif +- markobject(tee); +- markobject(GlobalEnv); +- markobject(GCStack); +- markobject(form); +- markobject(env); +- sweep(); +- #if defined(printgcs) +- pfl(pserial); pserial('{'); pint(Freespace - start, pserial); pserial('}'); +- #endif +-} +- +-// Compact image +- +-/* +- movepointer - corrects pointers to an object that has moved from 'from' to 'to' +-*/ +-void movepointer (object *from, object *to) { +- for (int i=0; itype) & ~MARKBIT; +- if (marked(obj) && (type >= ARRAY || type==ZZERO || (type == SYMBOL && longsymbolp(obj)))) { +- if (car(obj) == (object *)((uintptr_t)from | MARKBIT)) +- car(obj) = (object *)((uintptr_t)to | MARKBIT); +- if (cdr(obj) == from) cdr(obj) = to; +- } +- } +- // Fix strings and long symbols +- for (int i=0; itype) & ~MARKBIT; +- if (type == STRING || (type == SYMBOL && longsymbolp(obj))) { +- obj = cdr(obj); +- while (obj != NULL) { +- if (cdr(obj) == to) cdr(obj) = from; +- obj = (object *)((uintptr_t)(car(obj)) & ~MARKBIT); +- } +- } +- } +- } +-} +- +-/* +- compactimage - compacts the image by moving objects to the lowest possible position in the workspace +-*/ +-uintptr_t compactimage (object **arg) { +- markobject(tee); +- markobject(GlobalEnv); +- markobject(GCStack); +- object *firstfree = Workspace; +- while (marked(firstfree)) firstfree++; +- object *obj = &Workspace[WORKSPACESIZE-1]; +- while (firstfree < obj) { +- if (marked(obj)) { +- car(firstfree) = car(obj); +- cdr(firstfree) = cdr(obj); +- unmark(obj); +- movepointer(obj, firstfree); +- if (GlobalEnv == obj) GlobalEnv = firstfree; +- if (GCStack == obj) GCStack = firstfree; +- if (*arg == obj) *arg = firstfree; +- while (marked(firstfree)) firstfree++; +- } +- obj--; +- } +- sweep(); +- return firstfree - Workspace; +-} +- +-// Make SD card filename +- +-char *MakeFilename (object *arg, char *buffer) { +- int max = BUFFERSIZE-1; +- buffer[0]='/'; +- int i = 1; +- do { +- char c = nthchar(arg, i-1); +- if (c == '\0') break; +- buffer[i++] = c; +- } while (i>8 & 0xFF); +- file.write(data>>16 & 0xFF); file.write(data>>24 & 0xFF); +-} +- +-int SDRead32 (File file) { +- uintptr_t b0 = file.read(); uintptr_t b1 = file.read(); +- uintptr_t b2 = file.read(); uintptr_t b3 = file.read(); +- return b0 | b1<<8 | b2<<16 | b3<<24; +-} +-#elif defined(LITTLEFS) +-void FSWrite32 (File file, uint32_t data) { +- union { uint32_t data2; uint8_t u8[4]; }; +- data2 = data; +- if (file.write(u8, 4) != 4) error2(PSTR("not enough room")); +-} +- +-uint32_t FSRead32 (File file) { +- union { uint32_t data; uint8_t u8[4]; }; +- file.read(u8, 4); +- return data; +-} +-#elif defined(DATAFLASH) +-// Winbond DataFlash support for Adafruit M4 Express boards +-#define PAGEPROG 0x02 +-#define READSTATUS 0x05 +-#define READDATA 0x03 +-#define WRITEENABLE 0x06 +-#define BLOCK64K 0xD8 +-#define READID 0x90 +- +-// Arduino pins used for dataflash +-#if defined(ARDUINO_ITSYBITSY_M0) || defined(ARDUINO_SAMD_FEATHER_M0_EXPRESS) +-const int sck = 38, ssel = 39, mosi = 37, miso = 36; +-#elif defined(EXTERNAL_FLASH_USE_QSPI) +-const int sck = PIN_QSPI_SCK, ssel = PIN_QSPI_CS, mosi = PIN_QSPI_IO0, miso = PIN_QSPI_IO1; +-#endif +- +-void FlashBusy () { +- digitalWrite(ssel, 0); +- FlashWrite(READSTATUS); +- while ((FlashReadByte() & 1) != 0); +- digitalWrite(ssel, 1); +-} +- +-inline void FlashWrite (uint8_t data) { +- shiftOut(mosi, sck, MSBFIRST, data); +-} +- +-inline uint8_t FlashReadByte () { +- return shiftIn(miso, sck, MSBFIRST); +-} +- +-void FlashWriteByte (uint32_t *addr, uint8_t data) { +- // New page +- if (((*addr) & 0xFF) == 0) { +- digitalWrite(ssel, 1); +- FlashBusy(); +- FlashWriteEnable(); +- digitalWrite(ssel, 0); +- FlashWrite(PAGEPROG); +- FlashWrite((*addr)>>16); +- FlashWrite((*addr)>>8); +- FlashWrite(0); +- } +- FlashWrite(data); +- (*addr)++; +-} +- +-void FlashWriteEnable () { +- digitalWrite(ssel, 0); +- FlashWrite(WRITEENABLE); +- digitalWrite(ssel, 1); +-} +- +-bool FlashCheck () { +- uint8_t devID; +- digitalWrite(ssel, HIGH); pinMode(ssel, OUTPUT); +- pinMode(sck, OUTPUT); +- pinMode(mosi, OUTPUT); +- pinMode(miso, INPUT); +- digitalWrite(sck, LOW); digitalWrite(mosi, HIGH); +- digitalWrite(ssel, LOW); +- FlashWrite(READID); +- for (uint8_t i=0; i<4; i++) FlashReadByte(); +- devID = FlashReadByte(); +- digitalWrite(ssel, HIGH); +- return (devID == 0x14 || devID == 0x15 || devID == 0x16); // true = found correct device +-} +- +-void FlashBeginWrite (uint32_t *addr, uint32_t bytes) { +- *addr = 0; +- uint8_t blocks = (bytes+65535)/65536; +- // Erase 64K +- for (uint8_t b=0; b>8 & 0xFF); +- FlashWriteByte(addr, data>>16 & 0xFF); FlashWriteByte(addr, data>>24 & 0xFF); +-} +- +-inline void FlashEndWrite (uint32_t *addr) { +- (void) addr; +- digitalWrite(ssel, 1); +- FlashBusy(); +-} +- +-void FlashBeginRead (uint32_t *addr) { +- *addr = 0; +- FlashBusy(); +- digitalWrite(ssel, 0); +- FlashWrite(READDATA); +- FlashWrite(0); FlashWrite(0); FlashWrite(0); +-} +- +-uint32_t FlashRead32 (uint32_t *addr) { +- (void) addr; +- uint8_t b0 = FlashReadByte(); uint8_t b1 = FlashReadByte(); +- uint8_t b2 = FlashReadByte(); uint8_t b3 = FlashReadByte(); +- return b0 | b1<<8 | b2<<16 | b3<<24; +-} +- +-inline void FlashEndRead(uint32_t *addr) { +- (void) addr; +- digitalWrite(ssel, 1); +-} +- +-#elif defined(EEPROMFLASH) +-// For ATSAMD21 +-__attribute__((__aligned__(256))) static const uint8_t flash_store[FLASHSIZE] = { }; +- +-void row_erase (const volatile void *addr) { +- NVMCTRL->ADDR.reg = ((uint32_t)addr) / 2; +- NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER; +- while (!NVMCTRL->INTFLAG.bit.READY); +-} +- +-void page_clear () { +- // Execute "PBC" Page Buffer Clear +- NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_PBC; +- while (NVMCTRL->INTFLAG.bit.READY == 0); +-} +- +-void page_write () { +- NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_WP; +- while (NVMCTRL->INTFLAG.bit.READY == 0); +-} +- +-bool FlashCheck() { +- return true; +-} +- +-void FlashBeginWrite(uint32_t *addr, uint32_t bytes) { +- (void) bytes; +- *addr = (uint32_t)flash_store; +- // Disable automatic page write +- NVMCTRL->CTRLB.bit.MANW = 1; +-} +- +-void FlashWrite32 (uint32_t *addr, uint32_t data) { +- if (((*addr) & 0xFF) == 0) row_erase((const volatile void *)(*addr)); +- if (((*addr) & 0x3F) == 0) page_clear(); +- *(volatile uint32_t *)(*addr) = data; +- (*addr) = (*addr) + 4; +- if (((*addr) & 0x3F) == 0) page_write(); +-} +- +-void FlashEndWrite (uint32_t *addr) { +- if (((*addr) & 0x3F) != 0) page_write(); +-} +- +-void FlashBeginRead(uint32_t *addr) { +- *addr = (uint32_t)flash_store; +-} +- +-uint32_t FlashRead32 (uint32_t *addr) { +- uint32_t data = *(volatile const uint32_t *)(*addr); +- (*addr) = (*addr) + 4; +- return data; +-} +- +-void FlashEndRead (uint32_t *addr) { +- (void) addr; +-} +-#endif +- +-int saveimage (object *arg) { +-#if defined(sdcardsupport) +- unsigned int imagesize = compactimage(&arg); +- SD.begin(SDCARD_SS_PIN); +- File file; +- if (stringp(arg)) { +- char buffer[BUFFERSIZE]; +- file = SD.open(MakeFilename(arg, buffer), O_RDWR | O_CREAT | O_TRUNC); +- if (!file) error2(PSTR("problem saving to SD card or invalid filename")); +- arg = NULL; +- } else if (arg == NULL || listp(arg)) { +- file = SD.open("/ULISP.IMG", O_RDWR | O_CREAT | O_TRUNC); +- if (!file) error2(PSTR("problem saving to SD card")); +- } else error(invalidarg, arg); +- SDWrite32(file, (uintptr_t)arg); +- SDWrite32(file, imagesize); +- SDWrite32(file, (uintptr_t)GlobalEnv); +- SDWrite32(file, (uintptr_t)GCStack); +- for (int i=0; i FLASHSIZE) error(PSTR("image too large"), number(imagesize)); +- uint32_t addr; +- FlashBeginWrite(&addr, bytesneeded); +- FlashWrite32(&addr, (uintptr_t)arg); +- FlashWrite32(&addr, imagesize); +- FlashWrite32(&addr, (uintptr_t)GlobalEnv); +- FlashWrite32(&addr, (uintptr_t)GCStack); +- for (int i=0; itype; +- return type >= PAIR || type == ZZERO; +-} +- +-/* +- atom - implements Lisp atom +-*/ +-#define atom(x) (!consp(x)) +- +-/* +- listp - implements Lisp listp +-*/ +-bool listp (object *x) { +- if (x == NULL) return true; +- unsigned int type = x->type; +- return type >= PAIR || type == ZZERO; +-} +- +-/* +- improperp - tests whether x is an improper list +-*/ +-#define improperp(x) (!listp(x)) +- +-object *quote (object *arg) { +- return cons(bsymbol(QUOTE), cons(arg,NULL)); +-} +- +-// Radix 40 encoding +- +-/* +- builtin - converts a symbol name to builtin +-*/ +-builtin_t builtin (symbol_t name) { +- return (builtin_t)(untwist(name) - BUILTINS); +-} +- +-/* +- sym - converts a builtin to a symbol name +-*/ +-symbol_t sym (builtin_t x) { +- return twist(x + BUILTINS); +-} +- +-/* +- toradix40 - returns a number from 0 to 39 if the character can be encoded, or -1 otherwise. +-*/ +-int8_t toradix40 (char ch) { +- if (ch == 0) return 0; +- if (ch >= '0' && ch <= '9') return ch-'0'+1; +- if (ch == '-') return 37; if (ch == '*') return 38; if (ch == '$') return 39; +- ch = ch | 0x20; +- if (ch >= 'a' && ch <= 'z') return ch-'a'+11; +- return -1; // Invalid +-} +- +-/* +- fromradix40 - returns the character encoded by the number n. +-*/ +-char fromradix40 (char n) { +- if (n >= 1 && n <= 10) return '0'+n-1; +- if (n >= 11 && n <= 36) return 'a'+n-11; +- if (n == 37) return '-'; if (n == 38) return '*'; if (n == 39) return '$'; +- return 0; +-} +- +-/* +- pack40 - packs six radix40-encoded characters from buffer into a 32-bit number and returns it. +-*/ +-uint32_t pack40 (char *buffer) { +- int x = 0, j = 0; +- for (int i=0; i<6; i++) { +- x = x * 40 + toradix40(buffer[j]); +- if (buffer[j] != 0) j++; +- } +- return x; +-} +- +-/* +- valid40 - returns true if the symbol in buffer can be encoded as six radix40-encoded characters. +-*/ +-bool valid40 (char *buffer) { +- int t = 11; +- for (int i=0; i<6; i++) { +- if (toradix40(buffer[i]) < t) return false; +- if (buffer[i] == 0) break; +- t = 0; +- } +- return true; +-} +- +-/* +- digitvalue - returns the numerical value of a hexadecimal digit, or 16 if invalid. +-*/ +-int8_t digitvalue (char d) { +- if (d>='0' && d<='9') return d-'0'; +- d = d | 0x20; +- if (d>='a' && d<='f') return d-'a'+10; +- return 16; +-} +- +-/* +- checkinteger - check that obj is an integer and return it +-*/ +-int checkinteger (object *obj) { +- if (!integerp(obj)) error(notaninteger, obj); +- return obj->integer; +-} +- +-/* +- checkbitvalue - check that obj is an integer equal to 0 or 1 and return it +-*/ +-int checkbitvalue (object *obj) { +- if (!integerp(obj)) error(notaninteger, obj); +- int n = obj->integer; +- if (n & ~1) error(PSTR("argument is not a bit value"), obj); +- return n; +-} +- +-/* +- checkintfloat - check that obj is an integer or floating-point number and return the number +-*/ +-float checkintfloat (object *obj) { +- if (integerp(obj)) return (float)obj->integer; +- if (!floatp(obj)) error(notanumber, obj); +- return obj->single_float; +-} +- +-/* +- checkchar - check that obj is a character and return the character +-*/ +-int checkchar (object *obj) { +- if (!characterp(obj)) error(PSTR("argument is not a character"), obj); +- return obj->chars; +-} +- +-/* +- checkstring - check that obj is a string +-*/ +-object *checkstring (object *obj) { +- if (!stringp(obj)) error(notastring, obj); +- return obj; +-} +- +-int isstream (object *obj){ +- if (!streamp(obj)) error(PSTR("not a stream"), obj); +- return obj->integer; +-} +- +-int isbuiltin (object *obj, builtin_t n) { +- return symbolp(obj) && obj->name == sym(n); +-} +- +-bool builtinp (symbol_t name) { +- return (untwist(name) >= BUILTINS); +-} +- +-int checkkeyword (object *obj) { +- if (!keywordp(obj)) error(PSTR("argument is not a keyword"), obj); +- builtin_t kname = builtin(obj->name); +- uint8_t context = getminmax(kname); +- if (context != 0 && context != Context) error(invalidkey, obj); +- return ((int)lookupfn(kname)); +-} +- +-/* +- checkargs - checks that the number of objects in the list args +- is within the range specified in the symbol lookup table +-*/ +-void checkargs (object *args) { +- int nargs = listlength(args); +- checkminmax(Context, nargs); +-} +- +-/* +- eq - implements Lisp eq +-*/ +-boolean eq (object *arg1, object *arg2) { +- if (arg1 == arg2) return true; // Same object +- if ((arg1 == nil) || (arg2 == nil)) return false; // Not both values +- if (arg1->cdr != arg2->cdr) return false; // Different values +- if (symbolp(arg1) && symbolp(arg2)) return true; // Same symbol +- if (integerp(arg1) && integerp(arg2)) return true; // Same integer +- if (floatp(arg1) && floatp(arg2)) return true; // Same float +- if (characterp(arg1) && characterp(arg2)) return true; // Same character +- return false; +-} +- +-/* +- equal - implements Lisp equal +-*/ +-boolean equal (object *arg1, object *arg2) { +- if (stringp(arg1) && stringp(arg2)) return stringcompare(cons(arg1, cons(arg2, nil)), false, false, true); +- if (consp(arg1) && consp(arg2)) return (equal(car(arg1), car(arg2)) && equal(cdr(arg1), cdr(arg2))); +- return eq(arg1, arg2); +-} +- +-/* +- listlength - returns the length of a list +-*/ +-int listlength (object *list) { +- int length = 0; +- while (list != NULL) { +- if (improperp(list)) error2(notproper); +- list = cdr(list); +- length++; +- } +- return length; +-} +- +-/* +- checkarguments - checks the arguments list in a special form such as with-xxx, +- dolist, or dotimes. +-*/ +-object *checkarguments (object *args, int min, int max) { +- if (args == NULL) error2(noargument); +- args = first(args); +- if (!listp(args)) error(notalist, args); +- int length = listlength(args); +- if (length < min) error(toofewargs, args); +- if (length > max) error(toomanyargs, args); +- return args; +-} +- +-// Mathematical helper functions +- +-/* +- add_floats - used by fn_add +- Converts the numbers in args to floats, adds them to fresult, and returns the sum as a Lisp float. +-*/ +-object *add_floats (object *args, float fresult) { +- while (args != NULL) { +- object *arg = car(args); +- fresult = fresult + checkintfloat(arg); +- args = cdr(args); +- } +- return makefloat(fresult); +-} +- +-/* +- subtract_floats - used by fn_subtract with more than one argument +- Converts the numbers in args to floats, subtracts them from fresult, and returns the result as a Lisp float. +-*/ +-object *subtract_floats (object *args, float fresult) { +- while (args != NULL) { +- object *arg = car(args); +- fresult = fresult - checkintfloat(arg); +- args = cdr(args); +- } +- return makefloat(fresult); +-} +- +-/* +- negate - used by fn_subtract with one argument +- If the result is an integer, and negating it doesn't overflow, keep the result as an integer. +- Otherwise convert the result to a float, negate it, and return the result as a Lisp float. +-*/ +-object *negate (object *arg) { +- if (integerp(arg)) { +- int result = arg->integer; +- if (result == INT_MIN) return makefloat(-result); +- else return number(-result); +- } else if (floatp(arg)) return makefloat(-(arg->single_float)); +- else error(notanumber, arg); +- return nil; +-} +- +-/* +- multiply_floats - used by fn_multiply +- Converts the numbers in args to floats, adds them to fresult, and returns the result as a Lisp float. +-*/ +-object *multiply_floats (object *args, float fresult) { +- while (args != NULL) { +- object *arg = car(args); +- fresult = fresult * checkintfloat(arg); +- args = cdr(args); +- } +- return makefloat(fresult); +-} +- +-/* +- divide_floats - used by fn_divide +- Converts the numbers in args to floats, divides fresult by them, and returns the result as a Lisp float. +-*/ +-object *divide_floats (object *args, float fresult) { +- while (args != NULL) { +- object *arg = car(args); +- float f = checkintfloat(arg); +- if (f == 0.0) error2(divisionbyzero); +- fresult = fresult / f; +- args = cdr(args); +- } +- return makefloat(fresult); +-} +- +-/* +- myround - rounds +- Returns t if the argument is a floating-point number. +-*/ +-int myround (float number) { +- return (number >= 0) ? (int)(number + 0.5) : (int)(number - 0.5); +-} +- +-/* +- compare - a generic compare function +- Used to implement the other comparison functions. +- If lt is true the result is true if each argument is less than the next argument. +- If gt is true the result is true if each argument is greater than the next argument. +- If eq is true the result is true if each argument is equal to the next argument. +-*/ +-object *compare (object *args, bool lt, bool gt, bool eq) { +- object *arg1 = first(args); +- args = cdr(args); +- while (args != NULL) { +- object *arg2 = first(args); +- if (integerp(arg1) && integerp(arg2)) { +- if (!lt && ((arg1->integer) < (arg2->integer))) return nil; +- if (!eq && ((arg1->integer) == (arg2->integer))) return nil; +- if (!gt && ((arg1->integer) > (arg2->integer))) return nil; +- } else { +- if (!lt && (checkintfloat(arg1) < checkintfloat(arg2))) return nil; +- if (!eq && (checkintfloat(arg1) == checkintfloat(arg2))) return nil; +- if (!gt && (checkintfloat(arg1) > checkintfloat(arg2))) return nil; +- } +- arg1 = arg2; +- args = cdr(args); +- } +- return tee; +-} +- +-/* +- intpower - calculates base to the power exp as an integer +-*/ +-int intpower (int base, int exp) { +- int result = 1; +- while (exp) { +- if (exp & 1) result = result * base; +- exp = exp / 2; +- base = base * base; +- } +- return result; +-} +- +-// Association lists +- +-/* +- assoc - looks for key in an association list and returns the matching pair, or nil if not found +-*/ +-object *assoc (object *key, object *list) { +- while (list != NULL) { +- if (improperp(list)) error(notproper, list); +- object *pair = first(list); +- if (!listp(pair)) error(PSTR("element is not a list"), pair); +- if (pair != NULL && eq(key,car(pair))) return pair; +- list = cdr(list); +- } +- return nil; +-} +- +-/* +- delassoc - deletes the pair matching key from an association list and returns the key, or nil if not found +-*/ +-object *delassoc (object *key, object **alist) { +- object *list = *alist; +- object *prev = NULL; +- while (list != NULL) { +- object *pair = first(list); +- if (eq(key,car(pair))) { +- if (prev == NULL) *alist = cdr(list); +- else cdr(prev) = cdr(list); +- return key; +- } +- prev = list; +- list = cdr(list); +- } +- return nil; +-} +- +-// Array utilities +- +-/* +- nextpower2 - returns the smallest power of 2 that is equal to or greater than n +-*/ +-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; +-} +- +-/* +- buildarray - builds an array with n elements using a tree of size s which must be a power of 2 +- The elements are initialised to the default def +-*/ +-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 (object *dims, object *def, bool bitp) { +- int size = 1; +- object *dimensions = dims; +- while (dims != NULL) { +- int d = car(dims)->integer; +- if (d < 0) error2(PSTR("dimension can't be negative")); +- size = size * d; +- dims = cdr(dims); +- } +- // Bit array identified by making first dimension negative +- if (bitp) { +- size = (size + sizeof(int)*8 - 1)/(sizeof(int)*8); +- car(dimensions) = number(-(car(dimensions)->integer)); +- } +- 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; +-} +- +-/* +- arrayref - returns a pointer to the element specified by index in the array of size s +-*/ +-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; +-} +- +-/* +- getarray - gets a pointer to an element in a multi-dimensional array, given a list of the subscripts subs +- If the first subscript is negative it's a bit array and bit is set to the bit number +-*/ +-object **getarray (object *array, object *subs, object *env, int *bit) { +- int index = 0, size = 1, s; +- *bit = -1; +- bool bitp = false; +- object *dims = cddr(array); +- while (dims != NULL && subs != NULL) { +- int d = car(dims)->integer; +- if (d < 0) { d = -d; bitp = true; } +- if (env) s = checkinteger(eval(car(subs), env)); else s = checkinteger(car(subs)); +- if (s < 0 || s >= d) error(PSTR("subscript out of range"), car(subs)); +- size = size * d; +- index = index * d + s; +- dims = cdr(dims); subs = cdr(subs); +- } +- if (dims != NULL) error2(PSTR("too few subscripts")); +- if (subs != NULL) error2(PSTR("too many subscripts")); +- if (bitp) { +- size = (size + sizeof(int)*8 - 1)/(sizeof(int)*8); +- *bit = index & (sizeof(int)==4 ? 0x1F : 0x0F); +- index = index>>(sizeof(int)==4 ? 5 : 4); +- } +- return arrayref(array, index, size); +-} +- +-/* +- rslice - reads a slice of an array recursively +-*/ +-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 (!consp(args)) error2(PSTR("initial contents don't match array type")); +- if (cdr(dims) == NULL) { +- object **p = arrayref(array, index, size); +- *p = car(args); +- } else rslice(array, size, index, cdr(dims), car(args)); +- args = cdr(args); +- } +-} +- +-/* +- readarray - reads a list structure from args and converts it to a d-dimensional array. +- Uses rslice for each of the slices of the array. +-*/ +-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++) { +- if (!listp(list)) error2(PSTR("initial contents don't match array type")); +- int l = listlength(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(head, NULL, false); +- rslice(array, size, 0, head, args); +- return array; +-} +- +-/* +- readbitarray - reads an item in the format #*1010101000110 by reading it and returning a list of integers, +- and then converting that to a bit array +-*/ +-object *readbitarray (gfun_t gfun) { +- char ch = gfun(); +- object *head = NULL; +- object *tail = NULL; +- while (!issp(ch) && !isbr(ch)) { +- if (ch != '0' && ch != '1') error2(PSTR("illegal character in bit array")); +- object *cell = cons(number(ch - '0'), NULL); +- if (head == NULL) head = cell; +- else tail->cdr = cell; +- tail = cell; +- ch = gfun(); +- } +- LastChar = ch; +- int size = listlength(head); +- object *array = makearray(cons(number(size), NULL), number(0), true); +- size = (size + sizeof(int)*8 - 1)/(sizeof(int)*8); +- int index = 0; +- while (head != NULL) { +- object **loc = arrayref(array, index>>(sizeof(int)==4 ? 5 : 4), size); +- int bit = index & (sizeof(int)==4 ? 0x1F : 0x0F); +- *loc = number((((*loc)->integer) & ~(1<integer)<integer; +- if (d < 0) d = -d; +- for (int i = 0; i < d; i++) { +- if (i && spaces) pfun(' '); +- int index = slice * d + i; +- if (cdr(dims) == NULL) { +- if (bitp) pint(((*arrayref(array, index>>(sizeof(int)==4 ? 5 : 4), size))->integer)>> +- (index & (sizeof(int)==4 ? 0x1F : 0x0F)) & 1, pfun); +- else printobject(*arrayref(array, index, size), pfun); +- } else { pfun('('); pslice(array, size, index, cdr(dims), pfun, bitp); pfun(')'); } +- } +-} +- +-/* +- printarray - prints an array in the appropriate Lisp format +-*/ +-void printarray (object *array, pfun_t pfun) { +- object *dimensions = cddr(array); +- object *dims = dimensions; +- bool bitp = false; +- int size = 1, n = 0; +- while (dims != NULL) { +- int d = car(dims)->integer; +- if (d < 0) { bitp = true; d = -d; } +- size = size * d; +- dims = cdr(dims); n++; +- } +- if (bitp) size = (size + sizeof(int)*8 - 1)/(sizeof(int)*8); +- pfun('#'); +- if (n == 1 && bitp) { pfun('*'); pslice(array, size, -1, dimensions, pfun, bitp); } +- else { +- if (n > 1) { pint(n, pfun); pfun('A'); } +- pfun('('); pslice(array, size, 0, dimensions, pfun, bitp); pfun(')'); +- } +-} +- +-// String utilities +- +-void indent (uint8_t spaces, char ch, pfun_t pfun) { +- for (uint8_t i=0; ichars & 0xFFFFFF) == 0) { +- (*tail)->chars = (*tail)->chars | ch<<16; return; +- } else if (((*tail)->chars & 0xFFFF) == 0) { +- (*tail)->chars = (*tail)->chars | ch<<8; return; +- } else if (((*tail)->chars & 0xFF) == 0) { +- (*tail)->chars = (*tail)->chars | ch; return; +- } else { +- cell = myalloc(); car(*tail) = cell; +- } +- car(cell) = NULL; cell->chars = ch<<24; *tail = cell; +-} +- +-/* +- copystring - returns a copy of a Lisp string +-*/ +-object *copystring (object *arg) { +- object *obj = newstring(); +- object *ptr = obj; +- arg = cdr(arg); +- while (arg != NULL) { +- object *cell = myalloc(); car(cell) = NULL; +- if (cdr(obj) == NULL) cdr(obj) = cell; else car(ptr) = cell; +- ptr = cell; +- ptr->chars = arg->chars; +- arg = car(arg); +- } +- return obj; +-} +- +-/* +- readstring - reads characters from an input stream up to delimiter delim +- and returns a Lisp string +-*/ +-object *readstring (uint8_t delim, gfun_t gfun) { +- object *obj = newstring(); +- object *tail = obj; +- int ch = gfun(); +- if (ch == -1) return nil; +- while ((ch != delim) && (ch != -1)) { +- if (ch == '\\') ch = gfun(); +- buildstring(ch, &tail); +- ch = gfun(); +- } +- return obj; +-} +- +-/* +- stringlength - returns the length of a Lisp string +- Handles Lisp strings packed two characters per 16-bit word, or four characters per 32-bit word +-*/ +-int stringlength (object *form) { +- int length = 0; +- form = cdr(form); +- while (form != NULL) { +- int chars = form->chars; +- for (int i=(sizeof(int)-1)*8; i>=0; i=i-8) { +- if (chars>>i & 0xFF) length++; +- } +- form = car(form); +- } +- return length; +-} +- +-/* +- nthchar - returns the nth character from a Lisp string +- Handles Lisp strings packed two characters per 16-bit word, or four characters per 32-bit word +-*/ +-uint8_t nthchar (object *string, int n) { +- object *arg = cdr(string); +- int top; +- if (sizeof(int) == 4) { top = n>>2; n = 3 - (n&3); } +- else { top = n>>1; n = 1 - (n&1); } +- for (int i=0; ichars)>>(n*8) & 0xFF; +-} +- +-/* +- gstr - reads a character from a string stream +-*/ +-int gstr () { +- if (LastChar) { +- char temp = LastChar; +- LastChar = 0; +- return temp; +- } +- char c = nthchar(GlobalString, GlobalStringIndex++); +- if (c != 0) return c; +- return '\n'; // -1? +-} +- +-/* +- pstr - prints a character to a string stream +-*/ +-void pstr (char c) { +- buildstring(c, &GlobalStringTail); +-} +- +-/* +- lispstring - converts a C string to a Lisp string +-*/ +-object *lispstring (char *s) { +- object *obj = newstring(); +- object *tail = obj; +- while(1) { +- char ch = *s++; +- if (ch == 0) break; +- if (ch == '\\') ch = *s++; +- buildstring(ch, &tail); +- } +- return obj; +-} +- +-/* +- stringcompare - a generic string compare function +- Used to implement the other string comparison functions. +- If lt is true the result is true if each argument is less than the next argument. +- If gt is true the result is true if each argument is greater than the next argument. +- If eq is true the result is true if each argument is equal to the next argument. +-*/ +-bool stringcompare (object *args, bool lt, bool gt, bool eq) { +- object *arg1 = checkstring(first(args)); +- object *arg2 = checkstring(second(args)); +- arg1 = cdr(arg1); +- arg2 = cdr(arg2); +- while ((arg1 != NULL) || (arg2 != NULL)) { +- if (arg1 == NULL) return lt; +- if (arg2 == NULL) return gt; +- if (arg1->chars < arg2->chars) return lt; +- if (arg1->chars > arg2->chars) return gt; +- arg1 = car(arg1); +- arg2 = car(arg2); +- } +- return eq; +-} +- +-/* +- documentation - returns the documentation string of a built-in or user-defined function. +-*/ +-object *documentation (object *arg, object *env) { +- if (!symbolp(arg)) error(notasymbol, arg); +- object *pair = findpair(arg, env); +- if (pair != NULL) { +- object *val = cdr(pair); +- if (listp(val) && first(val)->name == sym(LAMBDA) && cdr(val) != NULL && cddr(val) != NULL) { +- if (stringp(third(val))) return third(val); +- } +- } +- symbol_t docname = arg->name; +- if (!builtinp(docname)) return nil; +- char *docstring = lookupdoc(builtin(docname)); +- if (docstring == NULL) return nil; +- return lispstring(docstring); +-} +- +-/* +- apropos - finds the user-defined and built-in functions whose names contain the specified string or symbol, +- and prints them if print is true, or returns them in a list. +-*/ +-object *apropos (object *arg, bool print) { +- char buf[17], buf2[33]; +- char *part = cstring(princtostring(arg), buf, 17); +- object *result = cons(NULL, NULL); +- object *ptr = result; +- // User-defined? +- object *globals = GlobalEnv; +- while (globals != NULL) { +- object *pair = first(globals); +- object *var = car(pair); +- object *val = cdr(pair); +- char *full = cstring(princtostring(var), buf2, 33); +- if (strstr(full, part) != NULL) { +- if (print) { +- printsymbol(var, pserial); pserial(' '); pserial('('); +- if (consp(val) && symbolp(car(val)) && builtin(car(val)->name) == LAMBDA) pfstring(PSTR("user function"), pserial); +- else if (consp(val) && car(val)->type == CODE) pfstring(PSTR("code"), pserial); +- else pfstring(PSTR("user symbol"), pserial); +- pserial(')'); pln(pserial); +- } else { +- cdr(ptr) = cons(var, NULL); ptr = cdr(ptr); +- } +- } +- globals = cdr(globals); +- } +- // Built-in? +- int entries = tablesize(0) + tablesize(1); +- for (int i = 0; i < entries; i++) { +- if (findsubstring(part, (builtin_t)i)) { +- if (print) { +- uint8_t fntype = getminmax(i)>>6; +- pbuiltin((builtin_t)i, pserial); pserial(' '); pserial('('); +- if (fntype == FUNCTIONS) pfstring(PSTR("function"), pserial); +- else if (fntype == SPECIAL_FORMS) pfstring(PSTR("special form"), pserial); +- else pfstring(PSTR("symbol/keyword"), pserial); +- pserial(')'); pln(pserial); +- } else { +- cdr(ptr) = cons(bsymbol(i), NULL); ptr = cdr(ptr); +- } +- } +- } +- return cdr(result); +-} +- +-/* +- cstring - converts a Lisp string to a C string in buffer and returns buffer +- Handles Lisp strings packed two characters per 16-bit word, or four characters per 32-bit word +-*/ +-char *cstring (object *form, char *buffer, int buflen) { +- form = cdr(checkstring(form)); +- int index = 0; +- while (form != NULL) { +- int chars = form->integer; +- for (int i=(sizeof(int)-1)*8; i>=0; i=i-8) { +- char ch = chars>>i & 0xFF; +- if (ch) { +- if (index >= buflen-1) error2(PSTR("no room for string")); +- buffer[index++] = ch; +- } +- } +- form = car(form); +- } +- buffer[index] = '\0'; +- return buffer; +-} +- +-/* +- ipstring - parses an IP address from a Lisp string and returns it as an IPAddress type (uint32_t) +- Handles Lisp strings packed two characters per 16-bit word, or four characters per 32-bit word +-*/ +-uint32_t ipstring (object *form) { +- form = cdr(checkstring(form)); +- int p = 0; +- union { uint32_t ipaddress; uint8_t ipbytes[4]; } ; +- ipaddress = 0; +- while (form != NULL) { +- int chars = form->integer; +- for (int i=(sizeof(int)-1)*8; i>=0; i=i-8) { +- char ch = chars>>i & 0xFF; +- if (ch) { +- if (ch == '.') { p++; if (p > 3) error2(PSTR("illegal IP address")); } +- else ipbytes[p] = (ipbytes[p] * 10) + ch - '0'; +- } +- } +- form = car(form); +- } +- return ipaddress; +-} +- +-// Lookup variable in environment +- +-object *value (symbol_t n, object *env) { +- while (env != NULL) { +- object *pair = car(env); +- if (pair != NULL && car(pair)->name == n) return pair; +- env = cdr(env); +- } +- return nil; +-} +- +-/* +- findpair - returns the (var . value) pair bound to variable var in the local or global environment +-*/ +-object *findpair (object *var, object *env) { +- symbol_t name = var->name; +- object *pair = value(name, env); +- if (pair == NULL) pair = value(name, GlobalEnv); +- return pair; +-} +- +-/* +- boundp - tests whether var is bound to a value +-*/ +-bool boundp (object *var, object *env) { +- if (!symbolp(var)) error(notasymbol, var); +- return (findpair(var, env) != NULL); +-} +- +-/* +- findvalue - returns the value bound to variable var, or gives an error if unbound +-*/ +-object *findvalue (object *var, object *env) { +- object *pair = findpair(var, env); +- if (pair == NULL) error(PSTR("unknown variable"), var); +- return pair; +-} +- +-// Handling closures +- +-object *closure (int tc, symbol_t name, object *function, object *args, object **env) { +- object *state = car(function); +- function = cdr(function); +- int trace = 0; +- if (name) trace = tracing(name); +- if (trace) { +- indent(TraceDepth[trace-1]<<1, ' ', pserial); +- pint(TraceDepth[trace-1]++, pserial); +- pserial(':'); pserial(' '); pserial('('); printsymbol(symbol(name), pserial); +- } +- object *params = first(function); +- if (!listp(params)) errorsym(name, notalist, params); +- function = cdr(function); +- // Dropframe +- if (tc) { +- if (*env != NULL && car(*env) == NULL) { +- pop(*env); +- while (*env != NULL && car(*env) != NULL) pop(*env); +- } else push(nil, *env); +- } +- // Push state +- while (consp(state)) { +- object *pair = first(state); +- push(pair, *env); +- state = cdr(state); +- } +- // Add arguments to environment +- bool optional = false; +- while (params != NULL) { +- object *value; +- object *var = first(params); +- if (isbuiltin(var, OPTIONAL)) optional = true; +- else { +- if (consp(var)) { +- if (!optional) errorsym(name, PSTR("invalid default value"), var); +- if (args == NULL) value = eval(second(var), *env); +- else { value = first(args); args = cdr(args); } +- var = first(var); +- if (!symbolp(var)) errorsym(name, PSTR("illegal optional parameter"), var); +- } else if (!symbolp(var)) { +- errorsym(name, PSTR("illegal function parameter"), var); +- } else if (isbuiltin(var, AMPREST)) { +- params = cdr(params); +- var = first(params); +- value = args; +- args = NULL; +- } else { +- if (args == NULL) { +- if (optional) value = nil; +- else errorsym2(name, toofewargs); +- } else { value = first(args); args = cdr(args); } +- } +- push(cons(var,value), *env); +- if (trace) { pserial(' '); printobject(value, pserial); } +- } +- params = cdr(params); +- } +- if (args != NULL) errorsym2(name, toomanyargs); +- if (trace) { pserial(')'); pln(pserial); } +- // Do an implicit progn +- if (tc) push(nil, *env); +- return tf_progn(function, *env); +-} +- +-object *apply (object *function, object *args, object *env) { +- if (symbolp(function)) { +- builtin_t fname = builtin(function->name); +- if ((fname < ENDFUNCTIONS) && ((getminmax(fname)>>6) == FUNCTIONS)) { +- Context = fname; +- checkargs(args); +- return ((fn_ptr_type)lookupfn(fname))(args, env); +- } else function = eval(function, env); +- } +- if (consp(function) && isbuiltin(car(function), LAMBDA)) { +- object *result = closure(0, sym(NIL), function, args, &env); +- return eval(result, env); +- } +- if (consp(function) && isbuiltin(car(function), CLOSURE)) { +- function = cdr(function); +- object *result = closure(0, sym(NIL), function, args, &env); +- return eval(result, env); +- } +- error(PSTR("illegal function"), function); +- return NULL; +-} +- +-// In-place operations +- +-/* +- place - returns a pointer to an object referenced in the second argument of an +- in-place operation such as setf. bit is used to indicate the bit position in a bit array +-*/ +-object **place (object *args, object *env, int *bit) { +- *bit = -1; +- if (atom(args)) return &cdr(findvalue(args, env)); +- object* function = first(args); +- if (symbolp(function)) { +- symbol_t sname = function->name; +- if (sname == sym(CAR) || sname == sym(FIRST)) { +- object *value = eval(second(args), env); +- if (!listp(value)) error(canttakecar, value); +- return &car(value); +- } +- if (sname == sym(CDR) || sname == sym(REST)) { +- object *value = eval(second(args), env); +- if (!listp(value)) error(canttakecdr, value); +- return &cdr(value); +- } +- if (sname == sym(NTH)) { +- int index = checkinteger(eval(second(args), env)); +- object *list = eval(third(args), env); +- if (atom(list)) error(PSTR("second argument to nth is not a list"), list); +- while (index > 0) { +- list = cdr(list); +- if (list == NULL) error2(PSTR("index to nth is out of range")); +- index--; +- } +- return &car(list); +- } +- if (sname == sym(AREF)) { +- object *array = eval(second(args), env); +- if (!arrayp(array)) error(PSTR("first argument is not an array"), array); +- return getarray(array, cddr(args), env, bit); +- } +- } +- error2(PSTR("illegal place")); +- return nil; +-} +- +-// Checked car and cdr +- +-/* +- carx - car with error checking +-*/ +-object *carx (object *arg) { +- if (!listp(arg)) error(canttakecar, arg); +- if (arg == nil) return nil; +- return car(arg); +-} +- +-/* +- cdrx - cdr with error checking +-*/ +-object *cdrx (object *arg) { +- if (!listp(arg)) error(canttakecdr, arg); +- if (arg == nil) return nil; +- return cdr(arg); +-} +- +-/* +- cxxxr - implements a general cxxxr function, +- pattern is a sequence of bits 0b1xxx where x is 0 for a and 1 for d. +-*/ +-object *cxxxr (object *args, uint8_t pattern) { +- object *arg = first(args); +- while (pattern != 1) { +- if ((pattern & 1) == 0) arg = carx(arg); else arg = cdrx(arg); +- pattern = pattern>>1; +- } +- return arg; +-} +- +-// Mapping helper functions +- +-/* +- mapcarfun - function specifying how to combine the results in mapcar +-*/ +-void mapcarfun (object *result, object **tail) { +- object *obj = cons(result,NULL); +- cdr(*tail) = obj; *tail = obj; +-} +- +-/* +- mapcanfun - function specifying how to combine the results in mapcan +-*/ +-void mapcanfun (object *result, object **tail) { +- if (cdr(*tail) != NULL) error(notproper, *tail); +- while (consp(result)) { +- cdr(*tail) = result; *tail = result; +- result = cdr(result); +- } +-} +- +-/* +- mapcarcan - function used by marcar and mapcan +- It takes the arguments, the env, and a function specifying how the results are combined. +-*/ +-object *mapcarcan (object *args, object *env, mapfun_t fun) { +- object *function = first(args); +- args = cdr(args); +- object *params = cons(NULL, NULL); +- push(params,GCStack); +- object *head = cons(NULL, NULL); +- push(head,GCStack); +- object *tail = head; +- // Make parameters +- while (true) { +- object *tailp = params; +- object *lists = args; +- while (lists != NULL) { +- object *list = car(lists); +- if (list == NULL) { +- pop(GCStack); pop(GCStack); +- return cdr(head); +- } +- if (improperp(list)) error(notproper, list); +- object *obj = cons(first(list),NULL); +- car(lists) = cdr(list); +- cdr(tailp) = obj; tailp = obj; +- lists = cdr(lists); +- } +- object *result = apply(function, cdr(params), env); +- fun(result, &tail); +- } +-} +- +-// I2C interface for up to two ports, using Arduino Wire +- +-void I2Cinit (TwoWire *port, bool enablePullup) { +- (void) enablePullup; +- port->begin(); +-} +- +-int I2Cread (TwoWire *port) { +- return port->read(); +-} +- +-void I2Cwrite (TwoWire *port, uint8_t data) { +- port->write(data); +-} +- +-bool I2Cstart (TwoWire *port, uint8_t address, uint8_t read) { +- int ok = true; +- if (read == 0) { +- port->beginTransmission(address); +- ok = (port->endTransmission(true) == 0); +- port->beginTransmission(address); +- } +- else port->requestFrom(address, I2Ccount); +- return ok; +-} +- +-bool I2Crestart (TwoWire *port, uint8_t address, uint8_t read) { +- int error = (port->endTransmission(false) != 0); +- if (read == 0) port->beginTransmission(address); +- else port->requestFrom(address, I2Ccount); +- return error ? false : true; +-} +- +-void I2Cstop (TwoWire *port, uint8_t read) { +- if (read == 0) port->endTransmission(); // Check for error? +-} +- +-// Streams +- +-// Simplify board differences +-#if defined(ARDUINO_NRF52840_CLUE) || defined(ARDUINO_GRAND_CENTRAL_M4) || defined(ARDUINO_PYBADGE_M4) || defined(ARDUINO_PYGAMER_M4) || defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY41) || defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +-#define ULISP_SPI1 +-#endif +-#if defined(ARDUINO_WIO_TERMINAL) || defined(ARDUINO_BBC_MICROBIT_V2) || defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY41) || defined(MAX32620) || defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_RASPBERRY_PI_PICO_W) || defined(ARDUINO_ADAFRUIT_QTPY_RP2040) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) +-#define ULISP_I2C1 +-#endif +-#if defined(ARDUINO_SAM_DUE) || defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY41) +-#define ULISP_SERIAL3 +-#elif defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +-#define ULISP_SERIAL2 +-#elif !defined(CPU_NRF51822) && !defined(CPU_NRF52833) && !defined(ARDUINO_FEATHER_F405) +-#define ULISP_SERIAL1 +-#endif +-#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +-#define ULISP_WIFI +-#endif +- +-inline int spiread () { return SPI.transfer(0); } +-#if defined(ULISP_SPI1) +-inline int spi1read () { return SPI1.transfer(0); } +-#endif +-inline int i2cread () { return I2Cread(&Wire); } +-#if defined(ULISP_I2C1) +-inline int i2c1read () { return I2Cread(&Wire1); } +-#endif +-#if defined(ULISP_SERIAL3) +-inline int serial3read () { while (!Serial3.available()) testescape(); return Serial3.read(); } +-#endif +-#if defined(ULISP_SERIAL3) || defined(ULISP_SERIAL2) +-inline int serial2read () { while (!Serial2.available()) testescape(); return Serial2.read(); } +-#endif +-#if defined(ULISP_SERIAL3) || defined(ULISP_SERIAL2) || defined(ULISP_SERIAL1) +-inline int serial1read () { while (!Serial1.available()) testescape(); return Serial1.read(); } +-#endif +-#if defined(sdcardsupport) +-File SDpfile, SDgfile; +-inline int SDread () { +- if (LastChar) { +- char temp = LastChar; +- LastChar = 0; +- return temp; +- } +- return SDgfile.read(); +-} +-#endif +- +-#if defined(ULISP_WIFI) +-WiFiClient client; +-WiFiServer server(80); +- +-inline int WiFiread () { +- if (LastChar) { +- char temp = LastChar; +- LastChar = 0; +- return temp; +- } +- return client.read(); +-} +-#endif +- +-void serialbegin (int address, int baud) { +- #if defined(ULISP_SERIAL3) +- if (address == 1) Serial1.begin((long)baud*100); +- else if (address == 2) Serial2.begin((long)baud*100); +- else if (address == 3) Serial3.begin((long)baud*100); +- #elif defined(ULISP_SERIAL2) +- if (address == 1) Serial1.begin((long)baud*100); +- else if (address == 2) Serial2.begin((long)baud*100); +- #elif defined(ULISP_SERIAL1) +- if (address == 1) Serial1.begin((long)baud*100); +- #else +- (void) baud; +- if (false); +- #endif +- else error(PSTR("port not supported"), number(address)); +-} +- +-void serialend (int address) { +- #if defined(ULISP_SERIAL3) +- 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(ULISP_SERIAL2) +- if (address == 1) {Serial1.flush(); Serial1.end(); } +- else if (address == 2) {Serial2.flush(); Serial2.end(); } +- #elif defined(ULISP_SERIAL1) +- if (address == 1) {Serial1.flush(); Serial1.end(); } +- #else +- if (false); +- #endif +- else error(PSTR("port not supported"), number(address)); +-} +- +-gfun_t gstreamfun (object *args) { +- int streamtype = SERIALSTREAM; +- int address = 0; +- gfun_t gfun = gserial; +- if (args != NULL) { +- int stream = isstream(first(args)); +- streamtype = stream>>8; address = stream & 0xFF; +- } +- if (streamtype == I2CSTREAM) { +- if (address < 128) gfun = i2cread; +- #if defined(ULISP_I2C1) +- else gfun = i2c1read; +- #endif +- } else if (streamtype == SPISTREAM) { +- if (address < 128) gfun = spiread; +- #if defined(ULISP_SPI1) +- else gfun = spi1read; +- #endif +- } +- else if (streamtype == SERIALSTREAM) { +- if (address == 0) gfun = gserial; +- #if defined(ULISP_SERIAL3) +- else if (address == 1) gfun = serial1read; +- else if (address == 2) gfun = serial2read; +- else if (address == 3) gfun = serial3read; +- #elif defined(ULISP_SERIAL2) +- else if (address == 1) gfun = serial1read; +- else if (address == 2) gfun = serial2read; +- #elif defined(ULISP_SERIAL1) +- else if (address == 1) gfun = serial1read; +- #endif +- } +- #if defined(sdcardsupport) +- else if (streamtype == SDSTREAM) gfun = (gfun_t)SDread; +- #endif +- #if defined(ULISP_WIFI) +- else if (streamtype == WIFISTREAM) gfun = (gfun_t)WiFiread; +- #endif +- else error2(PSTR("unknown stream type")); +- return gfun; +-} +- +-inline void spiwrite (char c) { SPI.transfer(c); } +-#if defined(ULISP_SPI1) +-inline void spi1write (char c) { SPI1.transfer(c); } +-#endif +-inline void i2cwrite (char c) { I2Cwrite(&Wire, c); } +-#if defined(ULISP_I2C1) +-inline void i2c1write (char c) { I2Cwrite(&Wire1, c); } +-#endif +-#if defined(ULISP_SERIAL3) +-inline void serial1write (char c) { Serial1.write(c); } +-inline void serial2write (char c) { Serial2.write(c); } +-inline void serial3write (char c) { Serial3.write(c); } +-#elif defined(ULISP_SERIAL2) +-inline void serial2write (char c) { Serial2.write(c); } +-inline void serial1write (char c) { Serial1.write(c); } +-#elif defined(ULISP_SERIAL1) +-inline void serial1write (char c) { Serial1.write(c); } +-#endif +-#if defined(sdcardsupport) +-inline void SDwrite (char c) { SDpfile.write(c); } +-#endif +-#if defined(ULISP_WIFI) +-inline void WiFiwrite (char c) { client.write(c); } +-#endif +-#if defined(gfxsupport) +-inline void gfxwrite (char c) { tft.write(c); } +-#endif +- +-pfun_t pstreamfun (object *args) { +- int streamtype = SERIALSTREAM; +- int address = 0; +- pfun_t pfun = pserial; +- if (args != NULL && first(args) != NULL) { +- int stream = isstream(first(args)); +- streamtype = stream>>8; address = stream & 0xFF; +- } +- if (streamtype == I2CSTREAM) { +- if (address < 128) pfun = i2cwrite; +- #if defined(ULISP_I2C1) +- else pfun = i2c1write; +- #endif +- } else if (streamtype == SPISTREAM) { +- if (address < 128) pfun = spiwrite; +- #if defined(ULISP_SPI1) +- else pfun = spi1write; +- #endif +- } else if (streamtype == SERIALSTREAM) { +- if (address == 0) pfun = pserial; +- #if defined(ULISP_SERIAL3) +- else if (address == 1) pfun = serial1write; +- else if (address == 2) pfun = serial2write; +- else if (address == 3) pfun = serial3write; +- #elif defined(ULISP_SERIAL2) +- else if (address == 1) pfun = serial1write; +- else if (address == 2) pfun = serial2write; +- #elif defined(ULISP_SERIAL1) +- 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 +- #if defined(ULISP_WIFI) +- else if (streamtype == WIFISTREAM) pfun = (pfun_t)WiFiwrite; +- #endif +- else error2(PSTR("unknown stream type")); +- return pfun; +-} +- +-// Check pins - these are board-specific not processor-specific +- +-void checkanalogread (int pin) { +-#if defined(ARDUINO_SAM_DUE) +- if (!(pin>=54 && pin<=65)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_SAMD_ZERO) +- if (!(pin>=14 && pin<=19)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_SAMD_MKRZERO) +- if (!(pin>=15 && pin<=21)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_ITSYBITSY_M0) +- if (!(pin>=14 && pin<=25)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_NEOTRINKEY_M0) +- if (!(pin==1 || pin==2 || pin==6)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_GEMMA_M0) +- if (!(pin>=8 && pin<=10)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_QTPY_M0) +- if (!((pin>=0 && pin<=3) || (pin>=6 && pin<=10))) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_SEEED_XIAO_M0) +- if (!(pin>=0 && pin<=10)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_METRO_M4) +- if (!(pin>=14 && pin<=21)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_ITSYBITSY_M4) || defined(ARDUINO_FEATHER_M4) +- if (!(pin>=14 && pin<=20)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_PYBADGE_M4) +- if (!(pin>=14 && pin<=23)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_PYGAMER_M4) +- if (!(pin>=14 && pin<=25)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_WIO_TERMINAL) +- if (!((pin>=0 && pin<=8))) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_GRAND_CENTRAL_M4) +- if (!((pin>=67 && pin<=74) || (pin>=54 && pin<=61))) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_BBC_MICROBIT) || defined(ARDUINO_SINOBIT) +- if (!((pin>=0 && pin<=4) || pin==10)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_BBC_MICROBIT_V2) +- if (!((pin>=0 && pin<=4) || pin==10 || pin==29)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_CALLIOPE_MINI) +- if (!(pin==1 || pin==2 || (pin>=4 && pin<=6) || pin==21)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_NRF52840_ITSYBITSY) +- if (!(pin>=14 && pin<=20)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_Seeed_XIAO_nRF52840) || defined(ARDUINO_Seeed_XIAO_nRF52840_Sense) +- if (!(pin>=0 && pin<=5)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_NRF52840_CLUE) +- if (!((pin>=0 && pin<=4) || pin==10 || pin==12 || pin==16)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_NRF52840_CIRCUITPLAY) +- if (!(pin==0 || (pin>=2 && pin<=3) || pin==6 || (pin>=9 && pin<=10) || (pin>=22 && pin<=23))) error(invalidpin, number(pin)); +-#elif defined(MAX32620) +- if (!(pin>=49 && pin<=52)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_TEENSY40) +- if (!((pin>=14 && pin<=27))) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_TEENSY41) +- if (!((pin>=14 && pin<=27) || (pin>=38 && pin<=41))) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_RASPBERRY_PI_PICO_W) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || defined(ARDUINO_ADAFRUIT_QTPY_RP2040) || defined(ARDUINO_SEEED_XIAO_RP2040) +- if (!(pin>=26 && pin<=29)) error(invalidpin, number(pin)); +-#endif +-} +- +-void checkanalogwrite (int pin) { +-#if defined(ARDUINO_SAM_DUE) +- if (!((pin>=2 && pin<=13) || pin==66 || pin==67)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_SAMD_ZERO) +- if (!((pin>=3 && pin<=6) || (pin>=8 && pin<=13) || pin==14)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_SAMD_MKRZERO) +- if (!((pin>=0 && pin<=8) || pin==10 || pin==18 || pin==19)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_ITSYBITSY_M0) +- if (!((pin>=3 && pin<=6) || (pin>=8 && pin<=13) || (pin>=15 && pin<=16) || (pin>=22 && pin<=25))) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_NEOTRINKEY_M0) +- error2(PSTR("not supported")); +-#elif defined(ARDUINO_GEMMA_M0) +- if (!(pin==0 || pin==2 || pin==9 || pin==10)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_QTPY_M0) +- if (!(pin==0 || (pin>=2 && pin<=10))) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_SEEED_XIAO_M0) +- if (!(pin>=0 && pin<=10)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_METRO_M4) +- if (!(pin>=0 && pin<=15)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_ITSYBITSY_M4) +- if (!(pin==0 || pin==1 || pin==4 || pin==5 || pin==7 || (pin>=9 && pin<=15) || pin==21 || pin==22)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_FEATHER_M4) +- if (!(pin==0 || pin==1 || (pin>=4 && pin<=6) || (pin>=9 && pin<=13) || pin==14 || pin==15 || pin==17 || pin==21 || pin==22)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_PYBADGE_M4) +- if (!(pin==4 || pin==7 || pin==9 || (pin>=12 && pin<=13) || (pin>=24 && pin<=25) || (pin>=46 && pin<=47))) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_PYGAMER_M4) +- if (!(pin==4 || pin==7 || pin==9 || (pin>=12 && pin<=13) || (pin>=26 && pin<=27) || (pin>=46 && pin<=47))) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_WIO_TERMINAL) +- if (!((pin>=0 && pin<=2) || pin==6 || pin==8 || (pin>=12 && pin<=20) || pin==24)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_GRAND_CENTRAL_M4) +- if (!((pin>=2 && pin<=9) || pin==11 || (pin>=13 && pin<=45) || pin==48 || (pin>=50 && pin<=53) || pin==58 || pin==61 || pin==68 || pin==69)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_BBC_MICROBIT) || defined(ARDUINO_BBC_MICROBIT_V2) || defined(ARDUINO_SINOBIT) +- if (!(pin>=0 && pin<=32)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_CALLIOPE_MINI) +- if (!(pin>=0 && pin<=30)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_NRF52840_ITSYBITSY) +- if (!(pin>=0 && pin<=25)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_NRF52840_CLUE) +- if (!(pin>=0 && pin<=46)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_NRF52840_CIRCUITPLAY) +- if (!(pin>=0 && pin<=35)) error(invalidpin, number(pin)); +-#elif defined(MAX32620) +- if (!((pin>=20 && pin<=29) || pin==32 || (pin>=40 && pin<=48))) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_TEENSY40) +- if (!((pin>=0 && pin<=15) || (pin>=18 && pin<=19) || (pin>=22 && pin<=25) || (pin>=28 && pin<=29) || (pin>=33 && pin<=39))) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_TEENSY41) +- if (!((pin>=0 && pin<=15) || (pin>=18 && pin<=19) || (pin>=22 && pin<=25) || (pin>=28 && pin<=29) || pin==33 || (pin>=36 && pin<=37))) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || defined(ARDUINO_ADAFRUIT_QTPY_RP2040) || defined(ARDUINO_SEEED_XIAO_RP2040) +- if (!(pin>=0 && pin<=29)) error(invalidpin, number(pin)); +-#elif defined(ARDUINO_RASPBERRY_PI_PICO_W) +- if (!((pin>=0 && pin<=29) || pin == 32)) error(invalidpin, number(pin)); +-#endif +-} +- +-// Note +- +-const int scale[] PROGMEM = {4186,4435,4699,4978,5274,5588,5920,6272,6645,7040,7459,7902}; +- +-void playnote (int pin, int note, int octave) { +-#if defined(ARDUINO_NRF52840_CLUE) || defined(ARDUINO_NRF52840_CIRCUITPLAY) || defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_RASPBERRY_PI_PICO_W) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || defined(ARDUINO_ADAFRUIT_QTPY_RP2040) || defined(ARDUINO_WIO_TERMINAL) || defined(ARDUINO_SEEED_XIAO_RP2040) +- int prescaler = 8 - octave - note/12; +- if (prescaler<0 || prescaler>8) error(PSTR("octave out of range"), number(prescaler)); +- tone(pin, scale[note%12]>>prescaler); +-#else +- (void) pin, (void) note, (void) octave; +-#endif +-} +- +-void nonote (int pin) { +-#if defined(ARDUINO_NRF52840_CLUE) || defined(ARDUINO_NRF52840_CIRCUITPLAY) || defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_RASPBERRY_PI_PICO_W) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || defined(ARDUINO_ADAFRUIT_QTPY_RP2040) || defined(ARDUINO_WIO_TERMINAL) || defined(ARDUINO_SEEED_XIAO_RP2040) +- noTone(pin); +-#else +- (void) pin; +-#endif +-} +- +-// Sleep +- +-#if defined(CPU_ATSAMD21) +-void WDT_Handler(void) { +- // ISR for watchdog early warning +- WDT->CTRL.bit.ENABLE = 0; // Disable watchdog +- while(WDT->STATUS.bit.SYNCBUSY); // Sync CTRL write +- WDT->INTFLAG.bit.EW = 1; // Clear interrupt flag +-} +-#endif +- +-void initsleep () { +-#if defined(CPU_ATSAMD21) +- // One-time initialization of watchdog timer. +- +- // Generic clock generator 2, divisor = 32 (2^(DIV+1)) +- GCLK->GENDIV.reg = GCLK_GENDIV_ID(2) | GCLK_GENDIV_DIV(4); +- // Enable clock generator 2 using low-power 32KHz oscillator. +- // With /32 divisor above, this yields 1024Hz clock. +- GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(2) | +- GCLK_GENCTRL_GENEN | +- GCLK_GENCTRL_SRC_OSCULP32K | +- GCLK_GENCTRL_DIVSEL; +- while(GCLK->STATUS.bit.SYNCBUSY); +- // WDT clock = clock gen 2 +- GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID_WDT | +- GCLK_CLKCTRL_CLKEN | +- GCLK_CLKCTRL_GEN_GCLK2; +- +- // Enable WDT early-warning interrupt +- NVIC_DisableIRQ(WDT_IRQn); +- NVIC_ClearPendingIRQ(WDT_IRQn); +- NVIC_SetPriority(WDT_IRQn, 0); // Top priority +- NVIC_EnableIRQ(WDT_IRQn); +-#endif +-} +- +-void doze (int secs) { +-#if defined(CPU_ATSAMD21) +- WDT->CTRL.reg = 0; // Disable watchdog for config +- while(WDT->STATUS.bit.SYNCBUSY); +- WDT->INTENSET.bit.EW = 1; // Enable early warning interrupt +- WDT->CONFIG.bit.PER = 0xB; // Period = max +- WDT->CONFIG.bit.WINDOW = 0x7; // Set time of interrupt = 1024 cycles = 1 sec +- WDT->CTRL.bit.WEN = 1; // Enable window mode +- while(WDT->STATUS.bit.SYNCBUSY); // Sync CTRL write +- +- SysTick->CTRL = 0; // Stop SysTick interrupts +- +- while (secs > 0) { +- WDT->CLEAR.reg = WDT_CLEAR_CLEAR_KEY;// Clear watchdog interval +- while(WDT->STATUS.bit.SYNCBUSY); +- WDT->CTRL.bit.ENABLE = 1; // Start watchdog now! +- while(WDT->STATUS.bit.SYNCBUSY); +- SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; // Deepest sleep +- __DSB(); +- __WFI(); // Wait for interrupt +- secs--; +- } +- SysTick->CTRL = 7; // Restart SysTick interrupts +-#else +- delay(1000*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++; +-} +- +-/* +- atomwidth - calculates the character width of an atom +-*/ +-uint8_t atomwidth (object *obj) { +- PrintCount = 0; +- printobject(obj, pcount); +- return PrintCount; +-} +- +-uint8_t basewidth (object *obj, uint8_t base) { +- PrintCount = 0; +- pintbase(obj->integer, base, pcount); +- return PrintCount; +-} +- +-bool quoted (object *obj) { +- return (consp(obj) && car(obj) != NULL && car(obj)->name == sym(QUOTE) && consp(cdr(obj)) && cddr(obj) == NULL); +-} +- +-int subwidth (object *obj, int w) { +- if (atom(obj)) return w - atomwidth(obj); +- if (quoted(obj)) obj = car(cdr(obj)); +- 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; +-} +- +-/* +- superprint - the main pretty-print subroutine +-*/ +-void superprint (object *form, int lm, pfun_t pfun) { +- if (atom(form)) { +- if (symbolp(form) && form->name == sym(NOTHING)) printsymbol(form, 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); +-} +- +-/* +- supersub - subroutine used by pprint +-*/ +-void supersub (object *form, int lm, int super, pfun_t pfun) { +- int special = 0, separate = 1; +- object *arg = car(form); +- if (symbolp(arg) && builtinp(arg->name)) { +- uint8_t minmax = getminmax(builtin(arg->name)); +- if (minmax == 0327 || minmax == 0313) special = 2; // defun, setq, setf, defvar +- else if (minmax == 0317 || minmax == 0017 || minmax == 0117 || minmax == 0123) special = 1; +- } +- while (form != NULL) { +- if (atom(form)) { pfstring(PSTR(" . "), pfun); printobject(form, pfun); pfun(')'); return; } +- else if (separate) { pfun('('); separate = 0; } +- else if (special) { pfun(' '); special--; } +- else if (!super) pfun(' '); +- else { pln(pfun); indent(lm, ' ', pfun); } +- superprint(car(form), lm, pfun); +- form = cdr(form); +- } +- pfun(')'); return; +-} +- +-/* +- edit - the Lisp tree editor +- Steps through a function definition, editing it a bit at a time, using single-key editing commands. +-*/ +-object *edit (object *fun) { +- while (1) { +- if (tstflag(EXITEDITOR)) return fun; +- char c = gserial(); +- if (c == 'q') setflag(EXITEDITOR); +- else if (c == 'b') return fun; +- else if (c == 'r') fun = read(gserial); +- else if (c == '\n') { pfl(pserial); superprint(fun, 0, pserial); pln(pserial); } +- else if (c == 'c') fun = cons(read(gserial), fun); +- else if (atom(fun)) pserial('!'); +- else if (c == 'd') fun = cons(car(fun), edit(cdr(fun))); +- else if (c == 'a') fun = cons(edit(car(fun)), cdr(fun)); +- else if (c == 'x') fun = cdr(fun); +- else pserial('?'); +- } +-} +- +-// Assembler +- +-object *call (int entry, int nargs, object *args, object *env) { +-#if defined(CODESIZE) +- (void) env; +- int param[4]; +- 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); +-#else +- return nil; +-#endif +-} +- +-void putcode (object *arg, int origin, int pc) { +-#if defined(CODESIZE) +- int code = checkinteger(arg); +- MyCode[origin+pc] = code & 0xff; +- MyCode[origin+pc+1] = (code>>8) & 0xff; +- #if defined(assemblerlist) +- printhex4(pc, pserial); +- printhex4(code, pserial); +- #endif +-#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); +- indent(5, ' ', 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(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) { +- (void) env; +- checkargs(args); +- return first(args); +-} +- +-/* +- (or item*) +- Evaluates its arguments until one returns non-nil, and returns its value. +-*/ +-object *sp_or (object *args, object *env) { +- while (args != NULL) { +- object *val = eval(car(args), env); +- if (val != NULL) return val; +- args = cdr(args); +- } +- return nil; +-} +- +-/* +- (defun name (parameters) form*) +- Defines a function. +-*/ +-object *sp_defun (object *args, object *env) { +- (void) env; +- checkargs(args); +- object *var = first(args); +- if (!symbolp(var)) error(notasymbol, var); +- object *val = cons(bsymbol(LAMBDA), cdr(args)); +- object *pair = value(var->name, GlobalEnv); +- if (pair != NULL) cdr(pair) = val; +- else push(cons(var, val), GlobalEnv); +- return var; +-} +- +-/* +- (defvar variable form) +- Defines a global variable. +-*/ +-object *sp_defvar (object *args, object *env) { +- checkargs(args); +- object *var = first(args); +- if (!symbolp(var)) error(notasymbol, var); +- object *val = NULL; +- args = cdr(args); +- if (args != NULL) { setflag(NOESC); val = eval(first(args), env); clrflag(NOESC); } +- object *pair = value(var->name, GlobalEnv); +- if (pair != NULL) cdr(pair) = val; +- else push(cons(var, val), GlobalEnv); +- return var; +-} +- +-/* +- (setq symbol value [symbol value]*) +- For each pair of arguments assigns the value of the second argument +- to the variable specified in the first argument. +-*/ +-object *sp_setq (object *args, object *env) { +- object *arg = nil; +- while (args != NULL) { +- if (cdr(args) == NULL) error2(oddargs); +- object *pair = findvalue(first(args), env); +- arg = eval(second(args), env); +- cdr(pair) = arg; +- args = cddr(args); +- } +- return arg; +-} +- +-/* +- (loop forms*) +- Executes its arguments repeatedly until one of the arguments calls (return), +- which then causes an exit from the loop. +-*/ +-object *sp_loop (object *args, object *env) { +- object *start = args; +- for (;;) { +- args = start; +- while (args != NULL) { +- object *result = eval(car(args),env); +- if (tstflag(RETURNFLAG)) { +- clrflag(RETURNFLAG); +- return result; +- } +- args = cdr(args); +- } +- } +-} +- +-/* +- (return [value]) +- Exits from a (dotimes ...), (dolist ...), or (loop ...) loop construct and returns value. +-*/ +-object *sp_return (object *args, object *env) { +- object *result = eval(tf_progn(args,env), env); +- setflag(RETURNFLAG); +- return result; +-} +- +-/* +- (push item place) +- Modifies the value of place, which should be a list, to add item onto the front of the list, +- and returns the new list. +-*/ +-object *sp_push (object *args, object *env) { +- int bit; +- checkargs(args); +- object *item = eval(first(args), env); +- object **loc = place(second(args), env, &bit); +- push(item, *loc); +- return *loc; +-} +- +-/* +- (pop place) +- Modifies the value of place, which should be a list, to remove its first item, and returns that item. +-*/ +-object *sp_pop (object *args, object *env) { +- int bit; +- checkargs(args); +- object **loc = place(first(args), env, &bit); +- object *result = car(*loc); +- pop(*loc); +- return result; +-} +- +-// Accessors +- +-/* +- (incf place [number]) +- Increments a place, which should have an numeric value, and returns the result. +- The third argument is an optional increment which defaults to 1. +-*/ +-object *sp_incf (object *args, object *env) { +- int bit; +- checkargs(args); +- object **loc = place(first(args), env, &bit); +- args = cdr(args); +- +- object *x = *loc; +- object *inc = (args != NULL) ? eval(first(args), env) : NULL; +- +- if (bit != -1) { +- int increment; +- if (inc == NULL) increment = 1; else increment = checkbitvalue(inc); +- int newvalue = (((*loc)->integer)>>bit & 1) + increment; +- +- if (newvalue & ~1) error2(PSTR("result is not a bit value")); +- *loc = number((((*loc)->integer) & ~(1<integer; +- +- if (inc == NULL) increment = 1; else increment = inc->integer; +- +- if (increment < 1) { +- if (INT_MIN - increment > value) *loc = makefloat((float)value + (float)increment); +- else *loc = number(value + increment); +- } else { +- if (INT_MAX - increment < value) *loc = makefloat((float)value + (float)increment); +- else *loc = number(value + increment); +- } +- } else error2(notanumber); +- return *loc; +-} +- +-/* +- (decf place [number]) +- Decrements a place, which should have an numeric value, and returns the result. +- The third argument is an optional decrement which defaults to 1. +-*/ +-object *sp_decf (object *args, object *env) { +- int bit; +- checkargs(args); +- object **loc = place(first(args), env, &bit); +- args = cdr(args); +- +- object *x = *loc; +- object *dec = (args != NULL) ? eval(first(args), env) : NULL; +- +- if (bit != -1) { +- int decrement; +- if (dec == NULL) decrement = 1; else decrement = checkbitvalue(dec); +- int newvalue = (((*loc)->integer)>>bit & 1) - decrement; +- +- if (newvalue & ~1) error2(PSTR("result is not a bit value")); +- *loc = number((((*loc)->integer) & ~(1<integer; +- +- if (dec == NULL) decrement = 1; else decrement = dec->integer; +- +- if (decrement < 1) { +- if (INT_MAX + decrement < value) *loc = makefloat((float)value - (float)decrement); +- else *loc = number(value - decrement); +- } else { +- if (INT_MIN + decrement > value) *loc = makefloat((float)value - (float)decrement); +- else *loc = number(value - decrement); +- } +- } else error2(notanumber); +- return *loc; +-} +- +-/* +- (setf place value [place value]*) +- For each pair of arguments modifies a place to the result of evaluating value. +-*/ +-object *sp_setf (object *args, object *env) { +- int bit; +- object *arg = nil; +- while (args != NULL) { +- if (cdr(args) == NULL) error2(oddargs); +- object **loc = place(first(args), env, &bit); +- arg = eval(second(args), env); +- if (bit == -1) *loc = arg; +- else *loc = number((checkinteger(*loc) & ~(1<name); +- args = cdr(args); +- } +- int i = 0; +- while (i < TRACEMAX) { +- if (TraceFn[i] != 0) args = cons(symbol(TraceFn[i]), args); +- i++; +- } +- return args; +-} +- +-/* +- (untrace [function]*) +- Turns off tracing of up to TRACEMAX user-defined functions, and returns a list of the functions untraced. +- If no functions are specified it untraces all functions. +-*/ +-object *sp_untrace (object *args, object *env) { +- (void) env; +- if (args == NULL) { +- int i = 0; +- while (i < TRACEMAX) { +- if (TraceFn[i] != 0) args = cons(symbol(TraceFn[i]), args); +- TraceFn[i] = 0; +- i++; +- } +- } else { +- while (args != NULL) { +- object *var = first(args); +- if (!symbolp(var)) error(notasymbol, var); +- untrace(var->name); +- args = cdr(args); +- } +- } +- return args; +-} +- +-/* +- (for-millis ([number]) form*) +- Executes the forms and then waits until a total of number milliseconds have elapsed. +- Returns the total number of milliseconds taken. +-*/ +-object *sp_formillis (object *args, object *env) { +- object *param = checkarguments(args, 0, 1); +- unsigned long start = millis(); +- unsigned long now, total = 0; +- if (param != NULL) total = checkinteger(eval(first(param), env)); +- eval(tf_progn(cdr(args),env), env); +- do { +- now = millis() - start; +- testescape(); +- } while (now < total); +- if (now <= INT_MAX) return number(now); +- return nil; +-} +- +-/* +- (time form) +- Prints the value returned by the form, and the time taken to evaluate the form +- in milliseconds or seconds. +-*/ +-object *sp_time (object *args, object *env) { +- unsigned long start = millis(); +- object *result = eval(first(args), env); +- unsigned long elapsed = millis() - start; +- printobject(result, pserial); +- pfstring(PSTR("\nTime: "), pserial); +- if (elapsed < 1000) { +- pint(elapsed, pserial); +- pfstring(PSTR(" ms\n"), pserial); +- } else { +- elapsed = elapsed+50; +- pint(elapsed/1000, pserial); +- pserial('.'); pint((elapsed/100)%10, pserial); +- pfstring(PSTR(" s\n"), pserial); +- } +- return bsymbol(NOTHING); +-} +- +-/* +- (with-output-to-string (str) form*) +- Returns a string containing the output to the stream variable str. +-*/ +-object *sp_withoutputtostring (object *args, object *env) { +- object *params = checkarguments(args, 1, 1); +- object *var = first(params); +- object *pair = cons(var, stream(STRINGSTREAM, 0)); +- push(pair,env); +- object *string = startstring(); +- push(string, GCStack); +- object *forms = cdr(args); +- eval(tf_progn(forms,env), env); +- pop(GCStack); +- return string; +-} +- +-/* +- (with-serial (str port [baud]) form*) +- Evaluates the forms with str bound to a serial-stream using port. +- The optional baud gives the baud rate divided by 100, default 96. +-*/ +-object *sp_withserial (object *args, object *env) { +- object *params = checkarguments(args, 2, 3); +- object *var = first(params); +- int address = checkinteger(eval(second(params), env)); +- params = cddr(params); +- int baud = 96; +- if (params != NULL) baud = checkinteger(eval(first(params), env)); +- object *pair = cons(var, stream(SERIALSTREAM, address)); +- push(pair,env); +- serialbegin(address, baud); +- object *forms = cdr(args); +- object *result = eval(tf_progn(forms,env), env); +- serialend(address); +- return result; +-} +- +-/* +- (with-i2c (str [port] address [read-p]) form*) +- Evaluates the forms with str bound to an i2c-stream defined by address. +- If read-p is nil or omitted the stream is written to, otherwise it specifies the number of bytes +- to be read from the stream. If port is omitted it defaults to 0, otherwise it specifies the port, 0 or 1. +-*/ +-object *sp_withi2c (object *args, object *env) { +- object *params = checkarguments(args, 2, 4); +- object *var = first(params); +- int address = checkinteger(eval(second(params), env)); +- params = cddr(params); +- if ((address == 0 || address == 1) && params != NULL) { +- address = address * 128 + checkinteger(eval(first(params), env)); +- params = cdr(params); +- } +- int read = 0; // Write +- I2Ccount = 0; +- if (params != NULL) { +- object *rw = eval(first(params), env); +- if (integerp(rw)) I2Ccount = rw->integer; +- read = (rw != NULL); +- } +- // Top bit of address is I2C port +- TwoWire *port = &Wire; +- #if defined(ULISP_I2C1) +- if (address > 127) port = &Wire1; +- #endif +- I2Cinit(port, 1); // Pullups +- object *pair = cons(var, (I2Cstart(port, address & 0x7F, read)) ? stream(I2CSTREAM, address) : nil); +- push(pair,env); +- object *forms = cdr(args); +- object *result = eval(tf_progn(forms,env), env); +- I2Cstop(port, read); +- return result; +-} +- +-/* +- (with-spi (str pin [clock] [bitorder] [mode] [port]) form*) +- Evaluates the forms with str bound to an spi-stream. +- The parameters specify the enable pin, clock in kHz (default 4000), +- bitorder 0 for LSBFIRST and 1 for MSBFIRST (default 1), SPI mode (default 0), and port 0 or 1 (default 0). +-*/ +-object *sp_withspi (object *args, object *env) { +- object *params = checkarguments(args, 2, 6); +- object *var = first(params); +- params = cdr(params); +- if (params == NULL) error2(nostream); +- int pin = checkinteger(eval(car(params), env)); +- pinMode(pin, OUTPUT); +- digitalWrite(pin, HIGH); +- params = cdr(params); +- int clock = 4000, mode = SPI_MODE0, address = 0; // Defaults +- BitOrder bitorder = MSBFIRST; +- if (params != NULL) { +- clock = checkinteger(eval(car(params), env)); +- params = cdr(params); +- if (params != NULL) { +- bitorder = (checkinteger(eval(car(params), env)) == 0) ? LSBFIRST : MSBFIRST; +- params = cdr(params); +- if (params != NULL) { +- int modeval = checkinteger(eval(car(params), env)); +- mode = (modeval == 3) ? SPI_MODE3 : (modeval == 2) ? SPI_MODE2 : (modeval == 1) ? SPI_MODE1 : SPI_MODE0; +- params = cdr(params); +- if (params != NULL) { +- address = checkinteger(eval(car(params), 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) || defined(ARDUINO_PYBADGE_M4) || defined(ARDUINO_PYGAMER_M4) || defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY41) +- if (address == 1) spiClass = &SPI1; +- #endif +- spiClass->begin(); +- spiClass->beginTransaction(SPISettings(((unsigned long)clock * 1000), bitorder, mode)); +- digitalWrite(pin, LOW); +- object *forms = cdr(args); +- object *result = eval(tf_progn(forms,env), env); +- digitalWrite(pin, HIGH); +- spiClass->endTransaction(); +- return result; +-} +- +-/* +- (with-sd-card (str filename [mode]) form*) +- Evaluates the forms with str bound to an sd-stream reading from or writing to the file filename. +- If mode is omitted the file is read, otherwise 0 means read, 1 write-append, or 2 write-overwrite. +-*/ +-object *sp_withsdcard (object *args, object *env) { +- #if defined(sdcardsupport) +- object *params = checkarguments(args, 2, 3); +- object *var = first(params); +- params = cdr(params); +- if (params == NULL) error2(PSTR("no filename specified")); +- object *filename = eval(first(params), env); +- params = cdr(params); +- SD.begin(SDCARD_SS_PIN); +- int mode = 0; +- if (params != NULL && first(params) != NULL) mode = checkinteger(first(params)); +- int oflag = O_READ; +- if (mode == 1) oflag = O_RDWR | O_CREAT | O_APPEND; else if (mode == 2) oflag = O_RDWR | O_CREAT | O_TRUNC; +- if (mode >= 1) { +- char buffer[BUFFERSIZE]; +- SDpfile = SD.open(MakeFilename(filename, buffer), oflag); +- if (!SDpfile) error2(PSTR("problem writing to SD card or invalid filename")); +- } else { +- char buffer[BUFFERSIZE]; +- SDgfile = SD.open(MakeFilename(filename, buffer), oflag); +- if (!SDgfile) error2(PSTR("problem reading from SD card or invalid filename")); +- } +- object *pair = cons(var, stream(SDSTREAM, 1)); +- push(pair,env); +- object *forms = cdr(args); +- object *result = eval(tf_progn(forms,env), env); +- if (mode >= 1) SDpfile.close(); else SDgfile.close(); +- return result; +- #else +- (void) args, (void) env; +- error2(PSTR("not supported")); +- return nil; +- #endif +-} +- +-// Assembler +- +-/* +- (defcode name (parameters) form*) +- Creates a machine-code function called name from a series of 16-bit integers given in the body of the form. +- These are written into RAM, and can be executed by calling the function in the same way as a normal Lisp function. +-*/ +-object *sp_defcode (object *args, object *env) { +-#if defined(CODESIZE) +- setflag(NOESC); +- checkargs(args); +- object *var = first(args); +- object *params = second(args); +- if (!symbolp(var)) error(PSTR("not a symbol"), var); +- +- // Make parameters into synonyms for registers r0, r1, etc +- int regn = 0; +- while (params != NULL) { +- if (regn > 3) error(PSTR("more than 4 parameters"), var); +- object *regpair = cons(car(params), bsymbol((builtin_t)((toradix40('r')*40+toradix40('0')+regn)*2560000))); // Symbol for r0 etc +- push(regpair,env); +- regn++; +- params = cdr(params); +- } +- +- // Make *pc* a local variable for program counter +- object *pcpair = cons(bsymbol(PSTAR), number(0)); +- push(pcpair,env); +- +- args = cdr(args); +- +- // Make labels into local variables +- object *entries = cdr(args); +- while (entries != NULL) { +- object *arg = first(entries); +- if (symbolp(arg)) { +- object *pair = cons(arg,number(0)); +- push(pair,env); +- } +- entries = cdr(entries); +- } +- +- // First pass +- int origin = 0; +- int codesize = assemble(1, origin, cdr(args), env, pcpair); +- +- // See if it will fit +- object *globals = GlobalEnv; +- while (globals != NULL) { +- object *pair = car(globals); +- if (pair != NULL && car(pair) != var && consp(cdr(pair))) { // Exclude me if I already exist +- object *codeid = second(pair); +- if (codeid->type == CODE) { +- codesize = codesize + endblock(codeid) - startblock(codeid); +- } +- } +- globals = cdr(globals); +- } +- if (codesize > CODESIZE) error(PSTR("not enough room for code"), var); +- +- // Compact the code block, removing gaps +- origin = 0; +- object *block; +- int smallest; +- +- do { +- smallest = CODESIZE; +- globals = GlobalEnv; +- while (globals != NULL) { +- object *pair = car(globals); +- if (pair != NULL && car(pair) != var && consp(cdr(pair))) { // Exclude me if I already exist +- object *codeid = second(pair); +- if (codeid->type == CODE) { +- if (startblock(codeid) < smallest && startblock(codeid) >= origin) { +- smallest = startblock(codeid); +- block = codeid; +- } +- } +- } +- globals = cdr(globals); +- } +- +- // Compact fragmentation if necessary +- if (smallest == origin) origin = endblock(block); // No gap +- else if (smallest < CODESIZE) { // Slide block down +- int target = origin; +- for (int i=startblock(block); iinteger = target<<16 | origin; +- origin = target; +- } +- +- } while (smallest < CODESIZE); +- +- // Second pass - origin is first free location +- codesize = assemble(2, origin, cdr(args), env, pcpair); +- +- object *val = cons(codehead((origin+codesize)<<16 | origin), args); +- object *pair = value(var->name, GlobalEnv); +- if (pair != NULL) cdr(pair) = val; +- else push(cons(var, val), GlobalEnv); +- clrflag(NOESC); +- return var; +-#else +- error2(PSTR("not available")); +- return nil; +-#endif +-} +- +-// Tail-recursive forms +- +-/* +- (progn form*) +- Evaluates several forms grouped together into a block, and returns the result of evaluating the last form. +-*/ +-object *tf_progn (object *args, object *env) { +- if (args == NULL) return nil; +- object *more = cdr(args); +- while (more != NULL) { +- object *result = eval(car(args),env); +- if (tstflag(RETURNFLAG)) return result; +- args = more; +- more = cdr(args); +- } +- return car(args); +-} +- +-/* +- (if test then [else]) +- Evaluates test. If it's non-nil the form then is evaluated and returned; +- otherwise the form else is evaluated and returned. +-*/ +-object *tf_if (object *args, object *env) { +- if (args == NULL || cdr(args) == NULL) error2(toofewargs); +- if (eval(first(args), env) != nil) return second(args); +- args = cddr(args); +- return (args != NULL) ? first(args) : nil; +-} +- +-/* +- (cond ((test form*) (test form*) ... )) +- Each argument is a list consisting of a test optionally followed by one or more forms. +- If the test evaluates to non-nil the forms are evaluated, and the last value is returned as the result of the cond. +- If the test evaluates to nil, none of the forms are evaluated, and the next argument is processed in the same way. +-*/ +-object *tf_cond (object *args, object *env) { +- while (args != NULL) { +- object *clause = first(args); +- if (!consp(clause)) error(illegalclause, clause); +- object *test = eval(first(clause), env); +- object *forms = cdr(clause); +- if (test != nil) { +- if (forms == NULL) return quote(test); else return tf_progn(forms, env); +- } +- args = cdr(args); +- } +- return nil; +-} +- +-/* +- (when test form*) +- Evaluates the test. If it's non-nil the forms are evaluated and the last value is returned. +-*/ +-object *tf_when (object *args, object *env) { +- if (args == NULL) error2(noargument); +- if (eval(first(args), env) != nil) return tf_progn(cdr(args),env); +- else return nil; +-} +- +-/* +- (unless test form*) +- Evaluates the test. If it's nil the forms are evaluated and the last value is returned. +-*/ +-object *tf_unless (object *args, object *env) { +- if (args == NULL) error2(noargument); +- if (eval(first(args), env) != nil) return nil; +- else return tf_progn(cdr(args),env); +-} +- +-/* +- (case keyform ((key form*) (key form*) ... )) +- Evaluates a keyform to produce a test key, and then tests this against a series of arguments, +- each of which is a list containing a key optionally followed by one or more forms. +-*/ +-object *tf_case (object *args, object *env) { +- object *test = eval(first(args), env); +- args = cdr(args); +- while (args != NULL) { +- object *clause = first(args); +- if (!consp(clause)) error(illegalclause, clause); +- object *key = car(clause); +- object *forms = cdr(clause); +- if (consp(key)) { +- while (key != NULL) { +- if (eq(test,car(key))) return tf_progn(forms, env); +- key = cdr(key); +- } +- } else if (eq(test,key) || eq(key,tee)) return tf_progn(forms, env); +- args = cdr(args); +- } +- return nil; +-} +- +-/* +- (and item*) +- Evaluates its arguments until one returns nil, and returns the last value. +-*/ +-object *tf_and (object *args, object *env) { +- if (args == NULL) return tee; +- object *more = cdr(args); +- while (more != NULL) { +- if (eval(car(args), env) == NULL) return nil; +- args = more; +- more = cdr(args); +- } +- return car(args); +-} +- +-// Core functions +- +-/* +- (not item) +- Returns t if its argument is nil, or nil otherwise. Equivalent to null. +-*/ +-object *fn_not (object *args, object *env) { +- (void) env; +- return (first(args) == nil) ? tee : nil; +-} +- +-/* +- (cons item item) +- If the second argument is a list, cons returns a new list with item added to the front of the list. +- If the second argument isn't a list cons returns a dotted pair. +-*/ +-object *fn_cons (object *args, object *env) { +- (void) env; +- return cons(first(args), second(args)); +-} +- +-/* +- (atom item) +- Returns t if its argument is a single number, symbol, or nil. +-*/ +-object *fn_atom (object *args, object *env) { +- (void) env; +- return atom(first(args)) ? tee : nil; +-} +- +-/* +- (listp item) +- Returns t if its argument is a list. +-*/ +-object *fn_listp (object *args, object *env) { +- (void) env; +- return listp(first(args)) ? tee : nil; +-} +- +-/* +- (consp item) +- Returns t if its argument is a non-null list. +-*/ +-object *fn_consp (object *args, object *env) { +- (void) env; +- return consp(first(args)) ? tee : nil; +-} +- +-/* +- (symbolp item) +- Returns t if its argument is a symbol. +-*/ +-object *fn_symbolp (object *args, object *env) { +- (void) env; +- object *arg = first(args); +- return (arg == NULL || symbolp(arg)) ? tee : nil; +-} +- +-/* +- (arrayp item) +- Returns t if its argument is an array. +-*/ +-object *fn_arrayp (object *args, object *env) { +- (void) env; +- return arrayp(first(args)) ? tee : nil; +-} +- +-/* +- (boundp item) +- Returns t if its argument is a symbol with a value. +-*/ +-object *fn_boundp (object *args, object *env) { +- return boundp(first(args), env) ? tee : nil; +-} +- +-/* +- (keywordp item) +- Returns t if its argument is a keyword. +-*/ +-object *fn_keywordp (object *args, object *env) { +- (void) env; +- return keywordp(first(args)) ? tee : nil; +-} +- +-/* +- (set symbol value [symbol value]*) +- For each pair of arguments, assigns the value of the second argument to the value of the first argument. +-*/ +-object *fn_setfn (object *args, object *env) { +- object *arg = nil; +- while (args != NULL) { +- if (cdr(args) == NULL) error2(oddargs); +- object *pair = findvalue(first(args), env); +- arg = second(args); +- cdr(pair) = arg; +- args = cddr(args); +- } +- return arg; +-} +- +-/* +- (streamp item) +- Returns t if its argument is a stream. +-*/ +-object *fn_streamp (object *args, object *env) { +- (void) env; +- object *arg = first(args); +- return streamp(arg) ? tee : nil; +-} +- +-/* +- (eq item item) +- Tests whether the two arguments are the same symbol, same character, equal numbers, +- or point to the same cons, and returns t or nil as appropriate. +-*/ +-object *fn_eq (object *args, object *env) { +- (void) env; +- return eq(first(args), second(args)) ? tee : nil; +-} +- +-/* +- (equal item item) +- Tests whether the two arguments are the same symbol, same character, equal numbers, +- or point to the same cons, and returns t or nil as appropriate. +-*/ +-object *fn_equal (object *args, object *env) { +- (void) env; +- return equal(first(args), second(args)) ? tee : nil; +-} +- +-// List functions +- +-/* +- (car list) +- Returns the first item in a list. +-*/ +-object *fn_car (object *args, object *env) { +- (void) env; +- return carx(first(args)); +-} +- +-/* +- (cdr list) +- Returns a list with the first item removed. +-*/ +-object *fn_cdr (object *args, object *env) { +- (void) env; +- return cdrx(first(args)); +-} +- +-/* +- (caar list) +-*/ +-object *fn_caar (object *args, object *env) { +- (void) env; +- return cxxxr(args, 0b100); +-} +- +-/* +- (cadr list) +-*/ +-object *fn_cadr (object *args, object *env) { +- (void) env; +- return cxxxr(args, 0b101); +-} +- +-/* +- (cdar list) +- Equivalent to (cdr (car list)). +-*/ +-object *fn_cdar (object *args, object *env) { +- (void) env; +- return cxxxr(args, 0b110); +-} +- +-/* +- (cddr list) +- Equivalent to (cdr (cdr list)). +-*/ +-object *fn_cddr (object *args, object *env) { +- (void) env; +- return cxxxr(args, 0b111); +-} +- +-/* +- (caaar list) +- Equivalent to (car (car (car list))). +-*/ +-object *fn_caaar (object *args, object *env) { +- (void) env; +- return cxxxr(args, 0b1000); +-} +- +-/* +- (caadr list) +- Equivalent to (car (car (cdar list))). +-*/ +-object *fn_caadr (object *args, object *env) { +- (void) env; +- return cxxxr(args, 0b1001);; +-} +- +-/* +- (cadar list) +- Equivalent to (car (cdr (car list))). +-*/ +-object *fn_cadar (object *args, object *env) { +- (void) env; +- return cxxxr(args, 0b1010); +-} +- +-/* +- (caddr list) +- Equivalent to (car (cdr (cdr list))). +-*/ +-object *fn_caddr (object *args, object *env) { +- (void) env; +- return cxxxr(args, 0b1011); +-} +- +-/* +- (cdaar list) +- Equivalent to (cdar (car (car list))). +-*/ +-object *fn_cdaar (object *args, object *env) { +- (void) env; +- return cxxxr(args, 0b1100); +-} +- +-/* +- (cdadr list) +- Equivalent to (cdr (car (cdr list))). +-*/ +-object *fn_cdadr (object *args, object *env) { +- (void) env; +- return cxxxr(args, 0b1101); +-} +- +-/* +- (cddar list) +- Equivalent to (cdr (cdr (car list))). +-*/ +-object *fn_cddar (object *args, object *env) { +- (void) env; +- return cxxxr(args, 0b1110); +-} +- +-/* +- (cdddr list) +- Equivalent to (cdr (cdr (cdr list))). +-*/ +-object *fn_cdddr (object *args, object *env) { +- (void) env; +- return cxxxr(args, 0b1111); +-} +- +-/* +- (length item) +- Returns the number of items in a list, the length of a string, or the length of a one-dimensional array. +-*/ +-object *fn_length (object *args, object *env) { +- (void) env; +- object *arg = first(args); +- if (listp(arg)) return number(listlength(arg)); +- if (stringp(arg)) return number(stringlength(arg)); +- if (!(arrayp(arg) && cdr(cddr(arg)) == NULL)) error(PSTR("argument is not a list, 1d array, or string"), arg); +- return number(abs(first(cddr(arg))->integer)); +-} +- +-/* +- (array-dimensions item) +- Returns a list of the dimensions of an array. +-*/ +-object *fn_arraydimensions (object *args, object *env) { +- (void) env; +- object *array = first(args); +- if (!arrayp(array)) error(PSTR("argument is not an array"), array); +- object *dimensions = cddr(array); +- return (first(dimensions)->integer < 0) ? cons(number(-(first(dimensions)->integer)), cdr(dimensions)) : dimensions; +-} +- +-/* +- (list item*) +- Returns a list of the values of its arguments. +-*/ +-object *fn_list (object *args, object *env) { +- (void) env; +- return args; +-} +- +-/* +- (make-array size [:initial-element element] [:element-type 'bit]) +- If size is an integer it creates a one-dimensional array with elements from 0 to size-1. +- If size is a list of n integers it creates an n-dimensional array with those dimensions. +- If :element-type 'bit is specified the array is a bit array. +-*/ +-object *fn_makearray (object *args, object *env) { +- (void) env; +- object *def = nil; +- bool bitp = false; +- object *dims = first(args); +- if (dims == NULL) error2(PSTR("dimensions can't be nil")); +- else if (atom(dims)) dims = cons(dims, NULL); +- args = cdr(args); +- while (args != NULL && cdr(args) != NULL) { +- object *var = first(args); +- if (isbuiltin(first(args), INITIALELEMENT)) def = second(args); +- else if (isbuiltin(first(args), ELEMENTTYPE) && isbuiltin(second(args), BIT)) bitp = true; +- else error(PSTR("argument not recognised"), var); +- args = cddr(args); +- } +- if (bitp) { +- if (def == nil) def = number(0); +- else def = number(-checkbitvalue(def)); // 1 becomes all ones +- } +- return makearray(dims, def, bitp); +-} +- +-/* +- (reverse list) +- Returns a list with the elements of list in reverse order. +-*/ +-object *fn_reverse (object *args, object *env) { +- (void) env; +- object *list = first(args); +- object *result = NULL; +- while (list != NULL) { +- if (improperp(list)) error(notproper, list); +- push(first(list),result); +- list = cdr(list); +- } +- return result; +-} +- +-/* +- (nth number list) +- Returns the nth item in list, counting from zero. +-*/ +-object *fn_nth (object *args, object *env) { +- (void) env; +- int n = checkinteger(first(args)); +- if (n < 0) error(indexnegative, first(args)); +- object *list = second(args); +- while (list != NULL) { +- if (improperp(list)) error(notproper, list); +- if (n == 0) return car(list); +- list = cdr(list); +- n--; +- } +- return nil; +-} +- +-/* +- (aref array index [index*]) +- Returns an element from the specified array. +-*/ +-object *fn_aref (object *args, object *env) { +- (void) env; +- int bit; +- object *array = first(args); +- if (!arrayp(array)) error(PSTR("first argument is not an array"), array); +- object *loc = *getarray(array, cdr(args), 0, &bit); +- if (bit == -1) return loc; +- else return number((loc->integer)>>bit & 1); +-} +- +-/* +- (assoc key list) +- Looks up a key in an association list of (key . value) pairs, +- and returns the matching pair, or nil if no pair is found. +-*/ +-object *fn_assoc (object *args, object *env) { +- (void) env; +- object *key = first(args); +- object *list = second(args); +- return assoc(key,list); +-} +- +-/* +- (member item list) +- Searches for an item in a list, using eq, and returns the list starting from the first occurrence of the item, +- or nil if it is not found. +-*/ +-object *fn_member (object *args, object *env) { +- (void) env; +- object *item = first(args); +- object *list = second(args); +- while (list != NULL) { +- if (improperp(list)) error(notproper, list); +- if (eq(item,car(list))) return list; +- list = cdr(list); +- } +- return nil; +-} +- +-/* +- (apply function list) +- Returns the result of evaluating function, with the list of arguments specified by the second parameter. +-*/ +-object *fn_apply (object *args, object *env) { +- object *previous = NULL; +- object *last = args; +- while (cdr(last) != NULL) { +- previous = last; +- last = cdr(last); +- } +- object *arg = car(last); +- if (!listp(arg)) error(notalist, arg); +- cdr(previous) = arg; +- return apply(first(args), cdr(args), env); +-} +- +-/* +- (funcall function argument*) +- Evaluates function with the specified arguments. +-*/ +-object *fn_funcall (object *args, object *env) { +- return apply(first(args), cdr(args), env); +-} +- +-/* +- (append list*) +- Joins its arguments, which should be lists, into a single list. +-*/ +-object *fn_append (object *args, object *env) { +- (void) env; +- object *head = NULL; +- object *tail; +- while (args != NULL) { +- object *list = first(args); +- if (!listp(list)) error(notalist, list); +- while (consp(list)) { +- object *obj = cons(car(list), cdr(list)); +- if (head == NULL) head = obj; +- else cdr(tail) = obj; +- tail = obj; +- list = cdr(list); +- if (cdr(args) != NULL && improperp(list)) error(notproper, first(args)); +- } +- args = cdr(args); +- } +- return head; +-} +- +-/* +- (mapc function list1 [list]*) +- Applies the function to each element in one or more lists, ignoring the results. +- It returns the first list argument. +-*/ +-object *fn_mapc (object *args, object *env) { +- object *function = first(args); +- args = cdr(args); +- object *result = first(args); +- push(result,GCStack); +- object *params = cons(NULL, NULL); +- push(params,GCStack); +- // Make parameters +- while (true) { +- object *tailp = params; +- object *lists = args; +- while (lists != NULL) { +- object *list = car(lists); +- if (list == NULL) { +- pop(GCStack); pop(GCStack); +- return result; +- } +- if (improperp(list)) error(notproper, list); +- object *obj = cons(first(list),NULL); +- car(lists) = cdr(list); +- cdr(tailp) = obj; tailp = obj; +- lists = cdr(lists); +- } +- apply(function, cdr(params), env); +- } +-} +- +-/* +- (mapcar function list1 [list]*) +- Applies the function to each element in one or more lists, and returns the resulting list. +-*/ +-object *fn_mapcar (object *args, object *env) { +- return mapcarcan(args, env, mapcarfun); +-} +- +-/* +- (mapcan function list1 [list]*) +- Applies the function to each element in one or more lists. The results should be lists, +- and these are appended together to give the value returned. +-*/ +-object *fn_mapcan (object *args, object *env) { +- return mapcarcan(args, env, mapcanfun); +-} +- +-// Arithmetic functions +- +-/* +- (+ number*) +- Adds its arguments together. +- If each argument is an integer, and the running total doesn't overflow, the result is an integer, +- otherwise a floating-point number. +-*/ +-object *fn_add (object *args, object *env) { +- (void) env; +- int result = 0; +- while (args != NULL) { +- object *arg = car(args); +- if (floatp(arg)) return add_floats(args, (float)result); +- else if (integerp(arg)) { +- int val = arg->integer; +- if (val < 1) { if (INT_MIN - val > result) return add_floats(args, (float)result); } +- else { if (INT_MAX - val < result) return add_floats(args, (float)result); } +- result = result + val; +- } else error(notanumber, arg); +- args = cdr(args); +- } +- return number(result); +-} +- +-/* +- (- number*) +- If there is one argument, negates the argument. +- If there are two or more arguments, subtracts the second and subsequent arguments from the first argument. +- If each argument is an integer, and the running total doesn't overflow, returns the result as an integer, +- otherwise a floating-point number. +-*/ +-object *fn_subtract (object *args, object *env) { +- (void) env; +- object *arg = car(args); +- args = cdr(args); +- if (args == NULL) return negate(arg); +- else if (floatp(arg)) return subtract_floats(args, arg->single_float); +- else if (integerp(arg)) { +- int result = arg->integer; +- while (args != NULL) { +- arg = car(args); +- if (floatp(arg)) return subtract_floats(args, result); +- else if (integerp(arg)) { +- int val = (car(args))->integer; +- if (val < 1) { if (INT_MAX + val < result) return subtract_floats(args, result); } +- else { if (INT_MIN + val > result) return subtract_floats(args, result); } +- result = result - val; +- } else error(notanumber, arg); +- args = cdr(args); +- } +- return number(result); +- } else error(notanumber, arg); +- return nil; +-} +- +-/* +- (* number*) +- Multiplies its arguments together. +- If each argument is an integer, and the running total doesn't overflow, the result is an integer, +- otherwise it's a floating-point number. +-*/ +-object *fn_multiply (object *args, object *env) { +- (void) env; +- int result = 1; +- while (args != NULL){ +- object *arg = car(args); +- if (floatp(arg)) return multiply_floats(args, result); +- else if (integerp(arg)) { +- int64_t val = result * (int64_t)(arg->integer); +- if ((val > INT_MAX) || (val < INT_MIN)) return multiply_floats(args, result); +- result = val; +- } else error(notanumber, arg); +- args = cdr(args); +- } +- return number(result); +-} +- +-/* +- (/ number*) +- Divides the first argument by the second and subsequent arguments. +- If each argument is an integer, and each division produces an exact result, the result is an integer; +- otherwise it's a floating-point number. +-*/ +-object *fn_divide (object *args, object *env) { +- (void) env; +- object* arg = first(args); +- args = cdr(args); +- // One argument +- if (args == NULL) { +- if (floatp(arg)) { +- float f = arg->single_float; +- if (f == 0.0) error2(PSTR("division by zero")); +- return makefloat(1.0 / f); +- } else if (integerp(arg)) { +- int i = arg->integer; +- if (i == 0) error2(PSTR("division by zero")); +- else if (i == 1) return number(1); +- else return makefloat(1.0 / i); +- } else error(notanumber, arg); +- } +- // Multiple arguments +- if (floatp(arg)) return divide_floats(args, arg->single_float); +- else if (integerp(arg)) { +- int result = arg->integer; +- while (args != NULL) { +- arg = car(args); +- if (floatp(arg)) { +- return divide_floats(args, result); +- } else if (integerp(arg)) { +- int i = arg->integer; +- if (i == 0) error2(PSTR("division by zero")); +- if ((result % i) != 0) return divide_floats(args, result); +- if ((result == INT_MIN) && (i == -1)) return divide_floats(args, result); +- result = result / i; +- args = cdr(args); +- } else error(notanumber, arg); +- } +- return number(result); +- } else error(notanumber, arg); +- return nil; +-} +- +-/* +- (mod number number) +- Returns its first argument modulo the second argument. +- If both arguments are integers the result is an integer; otherwise it's a floating-point number. +-*/ +-object *fn_mod (object *args, object *env) { +- (void) env; +- object *arg1 = first(args); +- object *arg2 = second(args); +- if (integerp(arg1) && integerp(arg2)) { +- int divisor = arg2->integer; +- if (divisor == 0) error2(PSTR("division by zero")); +- int dividend = arg1->integer; +- int remainder = dividend % divisor; +- if ((dividend<0) != (divisor<0)) remainder = remainder + divisor; +- return number(remainder); +- } else { +- float fdivisor = checkintfloat(arg2); +- if (fdivisor == 0.0) error2(PSTR("division by zero")); +- float fdividend = checkintfloat(arg1); +- float fremainder = fmod(fdividend , fdivisor); +- if ((fdividend<0) != (fdivisor<0)) fremainder = fremainder + fdivisor; +- return makefloat(fremainder); +- } +-} +- +-/* +- (1+ number) +- Adds one to its argument and returns it. +- If the argument is an integer the result is an integer if possible; +- otherwise it's a floating-point number. +-*/ +-object *fn_oneplus (object *args, object *env) { +- (void) env; +- object* arg = first(args); +- if (floatp(arg)) return makefloat((arg->single_float) + 1.0); +- else if (integerp(arg)) { +- int result = arg->integer; +- if (result == INT_MAX) return makefloat((arg->integer) + 1.0); +- else return number(result + 1); +- } else error(notanumber, arg); +- return nil; +-} +- +-/* +- (1- number) +- Subtracts one from its argument and returns it. +- If the argument is an integer the result is an integer if possible; +- otherwise it's a floating-point number. +-*/ +-object *fn_oneminus (object *args, object *env) { +- (void) env; +- object* arg = first(args); +- if (floatp(arg)) return makefloat((arg->single_float) - 1.0); +- else if (integerp(arg)) { +- int result = arg->integer; +- if (result == INT_MIN) return makefloat((arg->integer) - 1.0); +- else return number(result - 1); +- } else error(notanumber, arg); +- return nil; +-} +- +-/* +- (abs number) +- Returns the absolute, positive value of its argument. +- If the argument is an integer the result will be returned as an integer if possible, +- otherwise a floating-point number. +-*/ +-object *fn_abs (object *args, object *env) { +- (void) env; +- object *arg = first(args); +- if (floatp(arg)) return makefloat(abs(arg->single_float)); +- else if (integerp(arg)) { +- int result = arg->integer; +- if (result == INT_MIN) return makefloat(abs((float)result)); +- else return number(abs(result)); +- } else error(notanumber, arg); +- return nil; +-} +- +-/* +- (random number) +- If number is an integer returns a random number between 0 and one less than its argument. +- Otherwise returns a floating-point number between zero and number. +-*/ +-object *fn_random (object *args, object *env) { +- (void) env; +- object *arg = first(args); +- if (integerp(arg)) return number(random(arg->integer)); +- else if (floatp(arg)) return makefloat((float)rand()/(float)(RAND_MAX/(arg->single_float))); +- else error(notanumber, arg); +- return nil; +-} +- +-/* +- (max number*) +- Returns the maximum of one or more arguments. +-*/ +-object *fn_maxfn (object *args, object *env) { +- (void) env; +- object* result = first(args); +- args = cdr(args); +- while (args != NULL) { +- object *arg = car(args); +- if (integerp(result) && integerp(arg)) { +- if ((arg->integer) > (result->integer)) result = arg; +- } else if ((checkintfloat(arg) > checkintfloat(result))) result = arg; +- args = cdr(args); +- } +- return result; +-} +- +-/* +- (min number*) +- Returns the minimum of one or more arguments. +-*/ +-object *fn_minfn (object *args, object *env) { +- (void) env; +- object* result = first(args); +- args = cdr(args); +- while (args != NULL) { +- object *arg = car(args); +- if (integerp(result) && integerp(arg)) { +- if ((arg->integer) < (result->integer)) result = arg; +- } else if ((checkintfloat(arg) < checkintfloat(result))) result = arg; +- args = cdr(args); +- } +- return result; +-} +- +-// Arithmetic comparisons +- +-/* +- (/= number*) +- Returns t if none of the arguments are equal, or nil if two or more arguments are equal. +-*/ +-object *fn_noteq (object *args, object *env) { +- (void) env; +- while (args != NULL) { +- object *nargs = args; +- object *arg1 = first(nargs); +- nargs = cdr(nargs); +- while (nargs != NULL) { +- object *arg2 = first(nargs); +- if (integerp(arg1) && integerp(arg2)) { +- if ((arg1->integer) == (arg2->integer)) return nil; +- } else if ((checkintfloat(arg1) == checkintfloat(arg2))) return nil; +- nargs = cdr(nargs); +- } +- args = cdr(args); +- } +- return tee; +-} +- +-/* +- (= number*) +- Returns t if all the arguments, which must be numbers, are numerically equal, and nil otherwise. +-*/ +-object *fn_numeq (object *args, object *env) { +- (void) env; +- return compare(args, false, false, true); +-} +- +-/* +- (< number*) +- Returns t if each argument is less than the next argument, and nil otherwise. +-*/ +-object *fn_less (object *args, object *env) { +- (void) env; +- return compare(args, true, false, false); +-} +- +-/* +- (<= number*) +- Returns t if each argument is less than or equal to the next argument, and nil otherwise. +-*/ +-object *fn_lesseq (object *args, object *env) { +- (void) env; +- return compare(args, true, false, true); +-} +- +-/* +- (> number*) +- Returns t if each argument is greater than the next argument, and nil otherwise. +-*/ +-object *fn_greater (object *args, object *env) { +- (void) env; +- return compare(args, false, true, false); +-} +- +-/* +- (>= number*) +- Returns t if each argument is greater than or equal to the next argument, and nil otherwise. +-*/ +-object *fn_greatereq (object *args, object *env) { +- (void) env; +- return compare(args, false, true, true); +-} +- +-/* +- (plusp number) +- Returns t if the argument is greater than zero, or nil otherwise. +-*/ +-object *fn_plusp (object *args, object *env) { +- (void) env; +- object *arg = first(args); +- if (floatp(arg)) return ((arg->single_float) > 0.0) ? tee : nil; +- else if (integerp(arg)) return ((arg->integer) > 0) ? tee : nil; +- else error(notanumber, arg); +- return nil; +-} +- +-/* +- (minusp number) +- Returns t if the argument is less than zero, or nil otherwise. +-*/ +-object *fn_minusp (object *args, object *env) { +- (void) env; +- object *arg = first(args); +- if (floatp(arg)) return ((arg->single_float) < 0.0) ? tee : nil; +- else if (integerp(arg)) return ((arg->integer) < 0) ? tee : nil; +- else error(notanumber, arg); +- return nil; +-} +- +-/* +- (zerop number) +- Returns t if the argument is zero. +-*/ +-object *fn_zerop (object *args, object *env) { +- (void) env; +- object *arg = first(args); +- if (floatp(arg)) return ((arg->single_float) == 0.0) ? tee : nil; +- else if (integerp(arg)) return ((arg->integer) == 0) ? tee : nil; +- else error(notanumber, arg); +- return nil; +-} +- +-/* +- (oddp number) +- Returns t if the integer argument is odd. +-*/ +-object *fn_oddp (object *args, object *env) { +- (void) env; +- int arg = checkinteger(first(args)); +- return ((arg & 1) == 1) ? tee : nil; +-} +- +-/* +- (evenp number) +- Returns t if the integer argument is even. +-*/ +-object *fn_evenp (object *args, object *env) { +- (void) env; +- int arg = checkinteger(first(args)); +- return ((arg & 1) == 0) ? tee : nil; +-} +- +-// Number functions +- +-/* +- (integerp number) +- Returns t if the argument is an integer. +-*/ +-object *fn_integerp (object *args, object *env) { +- (void) env; +- return integerp(first(args)) ? tee : nil; +-} +- +-/* +- (numberp number) +- Returns t if the argument is a number. +-*/ +-object *fn_numberp (object *args, object *env) { +- (void) env; +- object *arg = first(args); +- return (integerp(arg) || floatp(arg)) ? tee : nil; +-} +- +-// Floating-point functions +- +-/* +- (float number) +- Returns its argument converted to a floating-point number. +-*/ +-object *fn_floatfn (object *args, object *env) { +- (void) env; +- object *arg = first(args); +- return (floatp(arg)) ? arg : makefloat((float)(arg->integer)); +-} +- +-/* +- (floatp number) +- Returns t if the argument is a floating-point number. +-*/ +-object *fn_floatp (object *args, object *env) { +- (void) env; +- return floatp(first(args)) ? tee : nil; +-} +- +-/* +- (sin number) +- Returns sin(number). +-*/ +-object *fn_sin (object *args, object *env) { +- (void) env; +- return makefloat(sin(checkintfloat(first(args)))); +-} +- +-/* +- (cos number) +- Returns cos(number). +-*/ +-object *fn_cos (object *args, object *env) { +- (void) env; +- return makefloat(cos(checkintfloat(first(args)))); +-} +- +-/* +- (tan number) +- Returns tan(number). +-*/ +-object *fn_tan (object *args, object *env) { +- (void) env; +- return makefloat(tan(checkintfloat(first(args)))); +-} +- +-/* +- (asin number) +- Returns asin(number). +-*/ +-object *fn_asin (object *args, object *env) { +- (void) env; +- return makefloat(asin(checkintfloat(first(args)))); +-} +- +-/* +- (acos number) +- Returns acos(number). +-*/ +-object *fn_acos (object *args, object *env) { +- (void) env; +- return makefloat(acos(checkintfloat(first(args)))); +-} +- +-/* +- (atan number1 [number2]) +- Returns the arc tangent of number1/number2, in radians. If number2 is omitted it defaults to 1. +-*/ +-object *fn_atan (object *args, object *env) { +- (void) env; +- object *arg = first(args); +- float div = 1.0; +- args = cdr(args); +- if (args != NULL) div = checkintfloat(first(args)); +- return makefloat(atan2(checkintfloat(arg), div)); +-} +- +-/* +- (sinh number) +- Returns sinh(number). +-*/ +-object *fn_sinh (object *args, object *env) { +- (void) env; +- return makefloat(sinh(checkintfloat(first(args)))); +-} +- +-/* +- (cosh number) +- Returns cosh(number). +-*/ +-object *fn_cosh (object *args, object *env) { +- (void) env; +- return makefloat(cosh(checkintfloat(first(args)))); +-} +- +-/* +- (tanh number) +- Returns tanh(number). +-*/ +-object *fn_tanh (object *args, object *env) { +- (void) env; +- return makefloat(tanh(checkintfloat(first(args)))); +-} +- +-/* +- (exp number) +- Returns exp(number). +-*/ +-object *fn_exp (object *args, object *env) { +- (void) env; +- return makefloat(exp(checkintfloat(first(args)))); +-} +- +-/* +- (sqrt number) +- Returns sqrt(number). +-*/ +-object *fn_sqrt (object *args, object *env) { +- (void) env; +- return makefloat(sqrt(checkintfloat(first(args)))); +-} +- +-/* +- (log number [base]) +- Returns the logarithm of number to the specified base. If base is omitted it defaults to e. +-*/ +-object *fn_log (object *args, object *env) { +- (void) env; +- object *arg = first(args); +- float fresult = log(checkintfloat(arg)); +- args = cdr(args); +- if (args == NULL) return makefloat(fresult); +- else return makefloat(fresult / log(checkintfloat(first(args)))); +-} +- +-/* +- (expt number power) +- Returns number raised to the specified power. +- Returns the result as an integer if the arguments are integers and the result will be within range, +- otherwise a floating-point number. +-*/ +-object *fn_expt (object *args, object *env) { +- (void) env; +- object *arg1 = first(args); object *arg2 = second(args); +- float float1 = checkintfloat(arg1); +- float value = log(abs(float1)) * checkintfloat(arg2); +- if (integerp(arg1) && integerp(arg2) && ((arg2->integer) >= 0) && (abs(value) < 21.4875)) +- return number(intpower(arg1->integer, arg2->integer)); +- if (float1 < 0) { +- if (integerp(arg2)) return makefloat((arg2->integer & 1) ? -exp(value) : exp(value)); +- else error2(PSTR("invalid result")); +- } +- return makefloat(exp(value)); +-} +- +-/* +- (ceiling number [divisor]) +- Returns ceil(number/divisor). If omitted, divisor is 1. +-*/ +-object *fn_ceiling (object *args, object *env) { +- (void) env; +- object *arg = first(args); +- args = cdr(args); +- if (args != NULL) return number(ceil(checkintfloat(arg) / checkintfloat(first(args)))); +- else return number(ceil(checkintfloat(arg))); +-} +- +-/* +- (floor number [divisor]) +- Returns floor(number/divisor). If omitted, divisor is 1. +-*/ +-object *fn_floor (object *args, object *env) { +- (void) env; +- object *arg = first(args); +- args = cdr(args); +- if (args != NULL) return number(floor(checkintfloat(arg) / checkintfloat(first(args)))); +- else return number(floor(checkintfloat(arg))); +-} +- +-/* +- (truncate number [divisor]) +- Returns the integer part of number/divisor. If divisor is omitted it defaults to 1. +-*/ +-object *fn_truncate (object *args, object *env) { +- (void) env; +- object *arg = first(args); +- args = cdr(args); +- if (args != NULL) return number((int)(checkintfloat(arg) / checkintfloat(first(args)))); +- else return number((int)(checkintfloat(arg))); +-} +- +-/* +- (round number [divisor]) +- Returns the integer closest to number/divisor. If divisor is omitted it defaults to 1. +-*/ +-object *fn_round (object *args, object *env) { +- (void) env; +- object *arg = first(args); +- args = cdr(args); +- if (args != NULL) return number(myround(checkintfloat(arg) / checkintfloat(first(args)))); +- else return number(myround(checkintfloat(arg))); +-} +- +-// Characters +- +-/* +- (char string n) +- Returns the nth character in a string, counting from zero. +-*/ +-object *fn_char (object *args, object *env) { +- (void) env; +- object *arg = first(args); +- if (!stringp(arg)) error(notastring, arg); +- object *n = second(args); +- char c = nthchar(arg, checkinteger(n)); +- if (c == 0) error(indexrange, n); +- return character(c); +-} +- +-/* +- (char-code character) +- Returns the ASCII code for a character, as an integer. +-*/ +-object *fn_charcode (object *args, object *env) { +- (void) env; +- return number(checkchar(first(args))); +-} +- +-/* +- (code-char integer) +- Returns the character for the specified ASCII code. +-*/ +-object *fn_codechar (object *args, object *env) { +- (void) env; +- return character(checkinteger(first(args))); +-} +- +-/* +- (characterp item) +- Returns t if the argument is a character and nil otherwise. +-*/ +-object *fn_characterp (object *args, object *env) { +- (void) env; +- return characterp(first(args)) ? tee : nil; +-} +- +-// Strings +- +-/* +- (stringp item) +- Returns t if the argument is a string and nil otherwise. +-*/ +-object *fn_stringp (object *args, object *env) { +- (void) env; +- return stringp(first(args)) ? tee : nil; +-} +- +-/* +- (string= string string) +- Tests whether two strings are the same. +-*/ +-object *fn_stringeq (object *args, object *env) { +- (void) env; +- return stringcompare(args, false, false, true) ? tee : nil; +-} +- +-/* +- (string< string string) +- Returns t if the first string is alphabetically less than the second string, and nil otherwise. +-*/ +-object *fn_stringless (object *args, object *env) { +- (void) env; +- return stringcompare(args, true, false, false) ? tee : nil; +-} +- +-/* +- (string> string string) +- Returns t if the first string is alphabetically greater than the second string, and nil otherwise. +-*/ +-object *fn_stringgreater (object *args, object *env) { +- (void) env; +- return stringcompare(args, false, true, false) ? tee : nil; +-} +- +-/* +- (sort list test) +- Destructively sorts list according to the test function, using an insertion sort, and returns the sorted list. +-*/ +-object *fn_sort (object *args, object *env) { +- if (first(args) == NULL) return nil; +- object *list = cons(nil,first(args)); +- push(list,GCStack); +- object *predicate = second(args); +- object *compare = cons(NULL, cons(NULL, NULL)); +- push(compare,GCStack); +- object *ptr = cdr(list); +- while (cdr(ptr) != NULL) { +- object *go = list; +- while (go != ptr) { +- car(compare) = car(cdr(ptr)); +- car(cdr(compare)) = car(cdr(go)); +- if (apply(predicate, compare, env)) break; +- go = cdr(go); +- } +- if (go != ptr) { +- object *obj = cdr(ptr); +- cdr(ptr) = cdr(obj); +- cdr(obj) = cdr(go); +- cdr(go) = obj; +- } else ptr = cdr(ptr); +- } +- pop(GCStack); pop(GCStack); +- return cdr(list); +-} +- +-/* +- (string item) +- Converts its argument to a string. +-*/ +-object *fn_stringfn (object *args, object *env) { +- return fn_princtostring(args, env); +-} +- +-/* +- (concatenate 'string string*) +- Joins together the strings given in the second and subsequent arguments, and returns a single string. +-*/ +-object *fn_concatenate (object *args, object *env) { +- (void) env; +- object *arg = first(args); +- if (builtin(arg->name) != STRINGFN) error2(PSTR("only supports strings")); +- args = cdr(args); +- object *result = newstring(); +- object *tail = result; +- while (args != NULL) { +- object *obj = checkstring(first(args)); +- obj = cdr(obj); +- while (obj != NULL) { +- int quad = obj->chars; +- while (quad != 0) { +- char ch = quad>>((sizeof(int)-1)*8) & 0xFF; +- buildstring(ch, &tail); +- quad = quad<<8; +- } +- obj = car(obj); +- } +- args = cdr(args); +- } +- return result; +-} +- +-/* +- (subseq seq start [end]) +- Returns a subsequence of a list or string from item start to item end-1. +-*/ +-object *fn_subseq (object *args, object *env) { +- (void) env; +- object *arg = first(args); +- int start = checkinteger(second(args)), end; +- if (start < 0) error(indexnegative, second(args)); +- args = cddr(args); +- if (listp(arg)) { +- int length = listlength(arg); +- if (args != NULL) end = checkinteger(car(args)); else end = length; +- if (start > end || end > length) error2(indexrange); +- object *result = cons(NULL, NULL); +- object *ptr = result; +- for (int x = 0; x < end; x++) { +- if (x >= start) { cdr(ptr) = cons(car(arg), NULL); ptr = cdr(ptr); } +- arg = cdr(arg); +- } +- return cdr(result); +- } else if (stringp(arg)) { +- int length = stringlength(arg); +- if (args != NULL) end = checkinteger(car(args)); else end = length; +- if (start > end || end > length) error2(indexrange); +- object *result = newstring(); +- object *tail = result; +- for (int i=start; i= 0) return number(value << count); +- else return number(value >> abs(count)); +-} +- +-/* +- (logbitp bit value) +- Returns t if bit number bit in value is a '1', and nil if it is a '0'. +-*/ +-object *fn_logbitp (object *args, object *env) { +- (void) env; +- int index = checkinteger(first(args)); +- int value = checkinteger(second(args)); +- return (bitRead(value, index) == 1) ? tee : nil; +-} +- +-// System functions +- +-/* +- (eval form*) +- Evaluates its argument an extra time. +-*/ +-object *fn_eval (object *args, object *env) { +- return eval(first(args), env); +-} +- +-/* +- (globals) +- Returns a list of global variables. +-*/ +-object *fn_globals (object *args, object *env) { +- (void) args, (void) env; +- object *result = cons(NULL, NULL); +- object *ptr = result; +- object *arg = GlobalEnv; +- while (arg != NULL) { +- cdr(ptr) = cons(car(car(arg)), NULL); ptr = cdr(ptr); +- arg = cdr(arg); +- } +- return cdr(result); +-} +- +-/* +- (locals) +- Returns an association list of local variables and their values. +-*/ +-object *fn_locals (object *args, object *env) { +- (void) args; +- return env; +-} +- +-/* +- (makunbound symbol) +- Removes the value of the symbol from GlobalEnv and returns the symbol. +-*/ +-object *fn_makunbound (object *args, object *env) { +- (void) env; +- object *var = first(args); +- if (!symbolp(var)) error(notasymbol, var); +- delassoc(var, &GlobalEnv); +- return var; +-} +- +-/* +- (break) +- Inserts a breakpoint in the program. When evaluated prints Break! and reenters the REPL. +-*/ +-object *fn_break (object *args, object *env) { +- (void) args; +- pfstring(PSTR("\nBreak!\n"), pserial); +- BreakLevel++; +- repl(env); +- BreakLevel--; +- return nil; +-} +- +-/* +- (read [stream]) +- Reads an atom or list from the serial input and returns it. +- If stream is specified the item is read from the specified stream. +-*/ +-object *fn_read (object *args, object *env) { +- (void) env; +- gfun_t gfun = gstreamfun(args); +- return read(gfun); +-} +- +-/* +- (prin1 item [stream]) +- Prints its argument, and returns its value. +- Strings are printed with quotation marks and escape characters. +-*/ +-object *fn_prin1 (object *args, object *env) { +- (void) env; +- object *obj = first(args); +- pfun_t pfun = pstreamfun(cdr(args)); +- printobject(obj, pfun); +- return obj; +-} +- +-/* +- (print item [stream]) +- Prints its argument with quotation marks and escape characters, on a new line, and followed by a space. +- If stream is specified the argument is printed to the specified stream. +-*/ +-object *fn_print (object *args, object *env) { +- (void) env; +- object *obj = first(args); +- pfun_t pfun = pstreamfun(cdr(args)); +- pln(pfun); +- printobject(obj, pfun); +- pfun(' '); +- return obj; +-} +- +-/* +- (princ item [stream]) +- Prints its argument, and returns its value. +- Characters and strings are printed without quotation marks or escape characters. +-*/ +-object *fn_princ (object *args, object *env) { +- (void) env; +- object *obj = first(args); +- pfun_t pfun = pstreamfun(cdr(args)); +- prin1object(obj, pfun); +- return obj; +-} +- +-/* +- (terpri [stream]) +- Prints a new line, and returns nil. +- If stream is specified the new line is written to the specified stream. +-*/ +-object *fn_terpri (object *args, object *env) { +- (void) env; +- pfun_t pfun = pstreamfun(args); +- pln(pfun); +- return nil; +-} +- +-/* +- (read-byte stream) +- Reads a byte from a stream and returns it. +-*/ +-object *fn_readbyte (object *args, object *env) { +- (void) env; +- gfun_t gfun = gstreamfun(args); +- int c = gfun(); +- return (c == -1) ? nil : number(c); +-} +- +-/* +- (read-line [stream]) +- Reads characters from the serial input up to a newline character, and returns them as a string, excluding the newline. +- If stream is specified the line is read from the specified stream. +-*/ +-object *fn_readline (object *args, object *env) { +- (void) env; +- gfun_t gfun = gstreamfun(args); +- return readstring('\n', gfun); +-} +- +-/* +- (write-byte number [stream]) +- Writes a byte to a stream. +-*/ +-object *fn_writebyte (object *args, object *env) { +- (void) env; +- int value = checkinteger(first(args)); +- pfun_t pfun = pstreamfun(cdr(args)); +- (pfun)(value); +- return nil; +-} +- +-/* +- (write-string string [stream]) +- Writes a string. If stream is specified the string is written to the stream. +-*/ +-object *fn_writestring (object *args, object *env) { +- (void) env; +- object *obj = first(args); +- pfun_t pfun = pstreamfun(cdr(args)); +- char temp = Flags; +- clrflag(PRINTREADABLY); +- printstring(obj, pfun); +- Flags = temp; +- return nil; +-} +- +-/* +- (write-line string [stream]) +- Writes a string terminated by a newline character. If stream is specified the string is written to the stream. +-*/ +-object *fn_writeline (object *args, object *env) { +- (void) env; +- object *obj = first(args); +- pfun_t pfun = pstreamfun(cdr(args)); +- char temp = Flags; +- clrflag(PRINTREADABLY); +- printstring(obj, pfun); +- pln(pfun); +- Flags = temp; +- return nil; +-} +- +-/* +- (restart-i2c stream [read-p]) +- Restarts an i2c-stream. +- If read-p is nil or omitted the stream is written to. +- If read-p is an integer it specifies the number of bytes to be read from the stream. +-*/ +-object *fn_restarti2c (object *args, object *env) { +- (void) env; +- int stream = first(args)->integer; +- args = cdr(args); +- int read = 0; // Write +- I2Ccount = 0; +- if (args != NULL) { +- object *rw = first(args); +- if (integerp(rw)) I2Ccount = rw->integer; +- read = (rw != NULL); +- } +- int address = stream & 0xFF; +- if (stream>>8 != I2CSTREAM) error2(PSTR("not an i2c stream")); +- TwoWire *port; +- if (address < 128) port = &Wire; +- #if defined(ULISP_I2C1) +- else port = &Wire1; +- #endif +- return I2Crestart(port, address & 0x7F, read) ? tee : nil; +-} +- +-/* +- (gc) +- Forces a garbage collection and prints the number of objects collected, and the time taken. +-*/ +-object *fn_gc (object *obj, object *env) { +- int initial = Freespace; +- unsigned long start = micros(); +- gc(obj, env); +- unsigned long elapsed = micros() - start; +- pfstring(PSTR("Space: "), pserial); +- pint(Freespace - initial, pserial); +- pfstring(PSTR(" bytes, Time: "), pserial); +- pint(elapsed, pserial); +- pfstring(PSTR(" us\n"), pserial); +- return nil; +-} +- +-/* +- (room) +- Returns the number of free Lisp cells remaining. +-*/ +-object *fn_room (object *args, object *env) { +- (void) args, (void) env; +- return number(Freespace); +-} +- +-/* +- (save-image [symbol]) +- Saves the current uLisp image to non-volatile memory or SD card so it can be loaded using load-image. +-*/ +-object *fn_saveimage (object *args, object *env) { +- if (args != NULL) args = eval(first(args), env); +- return number(saveimage(args)); +-} +- +-/* +- (load-image [filename]) +- Loads a saved uLisp image from non-volatile memory or SD card. +-*/ +-object *fn_loadimage (object *args, object *env) { +- (void) env; +- if (args != NULL) args = first(args); +- return number(loadimage(args)); +-} +- +-/* +- (cls) +- Prints a clear-screen character. +-*/ +-object *fn_cls (object *args, object *env) { +- (void) args, (void) env; +- pserial(12); +- return nil; +-} +- +-// Arduino procedures +- +-/* +- (pinmode pin mode) +- Sets the input/output mode of an Arduino pin number, and returns nil. +- The mode parameter can be an integer, a keyword, or t or nil. +-*/ +-object *fn_pinmode (object *args, object *env) { +- (void) env; int pin; +- object *arg = first(args); +- if (keywordp(arg)) pin = checkkeyword(arg); +- else pin = checkinteger(first(args)); +- int pm = INPUT; +- arg = second(args); +- if (keywordp(arg)) pm = checkkeyword(arg); +- else if (integerp(arg)) { +- int mode = arg->integer; +- if (mode == 1) pm = OUTPUT; else if (mode == 2) pm = INPUT_PULLUP; +- #if defined(INPUT_PULLDOWN) +- else if (mode == 4) pm = INPUT_PULLDOWN; +- #endif +- } else if (arg != nil) pm = OUTPUT; +- pinMode(pin, pm); +- return nil; +-} +- +-/* +- (digitalread pin) +- Reads the state of the specified Arduino pin number and returns t (high) or nil (low). +-*/ +-object *fn_digitalread (object *args, object *env) { +- (void) env; +- int pin; +- object *arg = first(args); +- if (keywordp(arg)) pin = checkkeyword(arg); +- else pin = checkinteger(arg); +- if (digitalRead(pin) != 0) return tee; else return nil; +-} +- +-/* +- (digitalwrite pin state) +- Sets the state of the specified Arduino pin number. +-*/ +-object *fn_digitalwrite (object *args, object *env) { +- (void) env; +- int pin; +- object *arg = first(args); +- if (keywordp(arg)) pin = checkkeyword(arg); +- else pin = checkinteger(arg); +- arg = second(args); +- int mode; +- if (keywordp(arg)) mode = checkkeyword(arg); +- else if (integerp(arg)) mode = arg->integer ? HIGH : LOW; +- else mode = (arg != nil) ? HIGH : LOW; +- digitalWrite(pin, mode); +- return arg; +-} +- +-/* +- (analogread pin) +- Reads the specified Arduino analogue pin number and returns the value. +-*/ +-object *fn_analogread (object *args, object *env) { +- (void) env; +- int pin; +- object *arg = first(args); +- if (keywordp(arg)) pin = checkkeyword(arg); +- else { +- pin = checkinteger(arg); +- checkanalogread(pin); +- } +- return number(analogRead(pin)); +-} +- +-/* +- (analogreference keyword) +- Specifies a keyword to set the analogue reference voltage used for analogue input. +-*/ +-object *fn_analogreference (object *args, object *env) { +- (void) env; +- object *arg = first(args); +- #if defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY41) || defined(MAX32620) || defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_RASPBERRY_PI_PICO_W) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || defined(ARDUINO_ADAFRUIT_QTPY_RP2040) +- error2(PSTR("not supported")); +- #else +- analogReference((eAnalogReference)checkkeyword(arg)); +- #endif +- return arg; +-} +- +-/* +- (analogreadresolution bits) +- Specifies the resolution for the analogue inputs on platforms that support it. +- The default resolution on all platforms is 10 bits. +-*/ +-object *fn_analogreadresolution (object *args, object *env) { +- (void) env; +- object *arg = first(args); +- #if defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || defined(ARDUINO_ADAFRUIT_QTPY_RP2040) +- error2(PSTR("not supported")); +- #else +- analogReadResolution(checkinteger(arg)); +- #endif +- return arg; +-} +- +-/* +- (analogwrite pin value) +- Writes the value to the specified Arduino pin number. +-*/ +-object *fn_analogwrite (object *args, object *env) { +- (void) env; +- int pin; +- object *arg = first(args); +- if (keywordp(arg)) pin = checkkeyword(arg); +- else pin = checkinteger(arg); +- checkanalogwrite(pin); +- object *value = second(args); +- analogWrite(pin, checkinteger(value)); +- return value; +-} +- +-/* +- (analogwrite pin value) +- Sets the analogue write resolution. +-*/ +-object *fn_analogwriteresolution (object *args, object *env) { +- (void) env; +- object *arg = first(args); +- analogWriteResolution(checkinteger(arg)); +- return arg; +-} +- +-/* +- (delay number) +- Delays for a specified number of milliseconds. +-*/ +-object *fn_delay (object *args, object *env) { +- (void) env; +- object *arg1 = first(args); +- delay(checkinteger(arg1)); +- return arg1; +-} +- +-/* +- (millis) +- Returns the time in milliseconds that uLisp has been running. +-*/ +-object *fn_millis (object *args, object *env) { +- (void) args, (void) env; +- return number(millis()); +-} +- +-/* +- (sleep secs) +- Puts the processor into a low-power sleep mode for secs. +- Only supported on some platforms. On other platforms it does delay(1000*secs). +-*/ +-object *fn_sleep (object *args, object *env) { +- (void) env; +- object *arg1 = first(args); +- doze(checkinteger(arg1)); +- return arg1; +-} +- +-/* +- (note [pin] [note] [octave]) +- Generates a square wave on pin. +- The argument note represents the note in the well-tempered scale, from 0 to 11, +- where 0 represents C, 1 represents C#, and so on. +- The argument octave can be from 3 to 6. If omitted it defaults to 0. +-*/ +-object *fn_note (object *args, object *env) { +- (void) env; +- static int pin = 255; +- if (args != NULL) { +- pin = checkinteger(first(args)); +- int note = 0; +- if (cddr(args) != NULL) note = checkinteger(second(args)); +- int octave = 0; +- if (cddr(args) != NULL) octave = checkinteger(third(args)); +- playnote(pin, note, octave); +- } else nonote(pin); +- return nil; +-} +- +-/* +- (register address [value]) +- Reads or writes the value of a peripheral register. +- If value is not specified the function returns the value of the register at address. +- If value is specified the value is written to the register at address and the function returns value. +-*/ +-object *fn_register (object *args, object *env) { +- (void) env; +- object *arg = first(args); +- int addr; +- if (keywordp(arg)) addr = checkkeyword(arg); +- else addr = checkinteger(first(args)); +- if (cdr(args) == NULL) return number(*(uint32_t *)addr); +- (*(uint32_t *)addr) = checkinteger(second(args)); +- return second(args); +-} +- +-// Tree Editor +- +-/* +- (edit 'function) +- Calls the Lisp tree editor to allow you to edit a function definition. +-*/ +-object *fn_edit (object *args, object *env) { +- object *fun = first(args); +- object *pair = findvalue(fun, env); +- clrflag(EXITEDITOR); +- object *arg = edit(eval(fun, env)); +- cdr(pair) = arg; +- return arg; +-} +- +-// Pretty printer +- +-/* +- (pprint item [str]) +- Prints its argument, using the pretty printer, to display it formatted in a structured way. +- If str is specified it prints to the specified stream. It returns no value. +-*/ +-object *fn_pprint (object *args, object *env) { +- (void) env; +- object *obj = first(args); +- pfun_t pfun = pstreamfun(cdr(args)); +- #if defined(gfxsupport) +- if (pfun == gfxwrite) ppwidth = GFXPPWIDTH; +- #endif +- pln(pfun); +- superprint(obj, 0, pfun); +- ppwidth = PPWIDTH; +- return bsymbol(NOTHING); +-} +- +-/* +- (pprintall [str]) +- Pretty-prints the definition of every function and variable defined in the uLisp workspace. +- If str is specified it prints to the specified stream. It returns no value. +-*/ +-object *fn_pprintall (object *args, object *env) { +- (void) env; +- pfun_t pfun = pstreamfun(args); +- #if defined(gfxsupport) +- if (pfun == gfxwrite) ppwidth = GFXPPWIDTH; +- #endif +- object *globals = GlobalEnv; +- while (globals != NULL) { +- object *pair = first(globals); +- object *var = car(pair); +- object *val = cdr(pair); +- pln(pfun); +- if (consp(val) && symbolp(car(val)) && builtin(car(val)->name) == LAMBDA) { +- superprint(cons(bsymbol(DEFUN), cons(var, cdr(val))), 0, pfun); +- } else if (consp(val) && car(val)->type == CODE) { +- superprint(cons(bsymbol(DEFCODE), cons(var, cdr(val))), 0, pfun); +- } else { +- superprint(cons(bsymbol(DEFVAR), cons(var, cons(quote(val), NULL))), 0, pfun); +- } +- pln(pfun); +- testescape(); +- globals = cdr(globals); +- } +- ppwidth = PPWIDTH; +- return bsymbol(NOTHING); +-} +- +-// Format +- +-/* +- (format output controlstring [arguments]*) +- Outputs its arguments formatted according to the format directives in controlstring. +-*/ +-object *fn_format (object *args, object *env) { +- (void) env; +- pfun_t pfun = pserial; +- object *output = first(args); +- object *obj; +- if (output == nil) { obj = startstring(); pfun = pstr; } +- else if (output != tee) pfun = pstreamfun(args); +- object *formatstr = checkstring(second(args)); +- object *save = NULL; +- args = cddr(args); +- int len = stringlength(formatstr); +- uint8_t n = 0, width = 0, w, bra = 0; +- char pad = ' '; +- bool tilde = false, mute = false, comma = false, quote = false; +- while (n < len) { +- char ch = nthchar(formatstr, n); +- char ch2 = ch & ~0x20; // force to upper case +- if (tilde) { +- if (ch == '}') { +- if (save == NULL) formaterr(formatstr, PSTR("no matching ~{"), n); +- if (args == NULL) { args = cdr(save); save = NULL; } else n = bra; +- mute = false; tilde = false; +- } +- else if (!mute) { +- 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 && args == NULL) mute = true; +- 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; +- if (args == NULL) mute = true; +- } +- else if (ch2 == 'A' || ch2 == 'S' || ch2 == 'D' || ch2 == 'G' || ch2 == 'X' || ch2 == 'B') { +- 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' || ch2 == 'B') { +- if (integerp(arg)) { +- uint8_t base = (ch2 == 'B') ? 2 : 16; +- uint8_t hw = basewidth(arg, base); if (width < hw) w = 0; else w = width-hw; +- indent(w, pad, pfun); pintbase(arg->integer, base, pfun); +- } else { +- 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 if (!mute) pfun(ch); +- } +- n++; +- } +- if (output == nil) return obj; +- else return nil; +-} +- +-// LispLibrary +- +-/* +- (require 'symbol) +- Loads the definition of a function defined with defun, or a variable defined with defvar, from the Lisp Library. +- It returns t if it was loaded, or nil if the symbol is already defined or isn't defined in the Lisp Library. +-*/ +-object *fn_require (object *args, object *env) { +- object *arg = first(args); +- object *globals = GlobalEnv; +- if (!symbolp(arg)) error(notasymbol, arg); +- while (globals != NULL) { +- object *pair = first(globals); +- object *var = car(pair); +- if (symbolp(var) && var == arg) return nil; +- globals = cdr(globals); +- } +- GlobalStringIndex = 0; +- object *line = read(glibrary); +- while (line != NULL) { +- // Is this the definition we want +- symbol_t fname = first(line)->name; +- if ((fname == sym(DEFUN) || fname == sym(DEFVAR)) && symbolp(second(line)) && second(line)->name == arg->name) { +- eval(line, env); +- return tee; +- } +- line = read(glibrary); +- } +- return nil; +-} +- +-/* +- (list-library) +- Prints a list of the functions defined in the List Library. +-*/ +-object *fn_listlibrary (object *args, object *env) { +- (void) args, (void) env; +- GlobalStringIndex = 0; +- object *line = read(glibrary); +- while (line != NULL) { +- builtin_t bname = builtin(first(line)->name); +- if (bname == DEFUN || bname == DEFVAR) { +- printsymbol(second(line), pserial); pserial(' '); +- } +- line = read(glibrary); +- } +- return bsymbol(NOTHING); +-} +- +-// Documentation +- +-/* +- (? item) +- Prints the documentation string of a built-in or user-defined function. +-*/ +-object *sp_help (object *args, object *env) { +- if (args == NULL) error2(noargument); +- object *docstring = documentation(first(args), env); +- if (docstring) { +- char temp = Flags; +- clrflag(PRINTREADABLY); +- printstring(docstring, pserial); +- Flags = temp; +- } +- return bsymbol(NOTHING); +-} +- +-/* +- (documentation 'symbol [type]) +- Returns the documentation string of a built-in or user-defined function. The type argument is ignored. +-*/ +-object *fn_documentation (object *args, object *env) { +- return documentation(first(args), env); +-} +- +-/* +- (apropos item) +- Prints the user-defined and built-in functions whose names contain the specified string or symbol. +-*/ +-object *fn_apropos (object *args, object *env) { +- (void) env; +- apropos(first(args), true); +- return bsymbol(NOTHING); +-} +- +-/* +- (apropos-list item) +- Returns a list of user-defined and built-in functions whose names contain the specified string or symbol. +-*/ +-object *fn_aproposlist (object *args, object *env) { +- (void) env; +- return apropos(first(args), false); +-} +- +-// Error handling +- +-/* +- (unwind-protect form1 [forms]*) +- Evaluates form1 and forms in order and returns the value of form1, +- but guarantees to evaluate forms even if an error occurs in form1. +-*/ +-object *sp_unwindprotect (object *args, object *env) { +- if (args == NULL) error2(toofewargs); +- object *current_GCStack = GCStack; +- jmp_buf dynamic_handler; +- jmp_buf *previous_handler = handler; +- handler = &dynamic_handler; +- object *protected_form = first(args); +- object *result; +- +- bool signaled = false; +- if (!setjmp(dynamic_handler)) { +- result = eval(protected_form, env); +- } else { +- GCStack = current_GCStack; +- signaled = true; +- } +- handler = previous_handler; +- +- object *protective_forms = cdr(args); +- while (protective_forms != NULL) { +- eval(car(protective_forms), env); +- if (tstflag(RETURNFLAG)) break; +- protective_forms = cdr(protective_forms); +- } +- +- if (!signaled) return result; +- GCStack = NULL; +- longjmp(*handler, 1); +-} +- +-/* +- (ignore-errors [forms]*) +- Evaluates forms ignoring errors. +-*/ +-object *sp_ignoreerrors (object *args, object *env) { +- object *current_GCStack = GCStack; +- jmp_buf dynamic_handler; +- jmp_buf *previous_handler = handler; +- handler = &dynamic_handler; +- object *result = nil; +- +- bool muffled = tstflag(MUFFLEERRORS); +- setflag(MUFFLEERRORS); +- bool signaled = false; +- if (!setjmp(dynamic_handler)) { +- while (args != NULL) { +- result = eval(car(args), env); +- if (tstflag(RETURNFLAG)) break; +- args = cdr(args); +- } +- } else { +- GCStack = current_GCStack; +- signaled = true; +- } +- handler = previous_handler; +- if (!muffled) clrflag(MUFFLEERRORS); +- +- if (signaled) return bsymbol(NOTHING); +- else return result; +-} +- +-/* +- (error controlstring [arguments]*) +- Signals an error. The message is printed by format using the controlstring and arguments. +-*/ +-object *sp_error (object *args, object *env) { +- object *message = eval(cons(bsymbol(FORMAT), cons(nil, args)), env); +- if (!tstflag(MUFFLEERRORS)) { +- char temp = Flags; +- clrflag(PRINTREADABLY); +- pfstring(PSTR("Error: "), pserial); printstring(message, pserial); +- Flags = temp; +- pln(pserial); +- } +- GCStack = NULL; +- longjmp(*handler, 1); +-} +- +-// Wi-Fi +- +-/* +- (with-client (str [address port]) form*) +- Evaluates the forms with str bound to a wifi-stream. +-*/ +-object *sp_withclient (object *args, object *env) { +- #if defined(ULISP_WIFI) +- object *params = checkarguments(args, 1, 3); +- object *var = first(params); +- char buffer[BUFFERSIZE]; +- params = cdr(params); +- int n; +- if (params == NULL) { +- client = server.available(); +- if (!client) return nil; +- n = 2; +- } else { +- object *address = eval(first(params), env); +- object *port = eval(second(params), env); +- int success; +- if (stringp(address)) success = client.connect(cstring(address, buffer, BUFFERSIZE), checkinteger(port)); +- else if (integerp(address)) success = client.connect(address->integer, checkinteger(port)); +- else error2(PSTR("invalid address")); +- if (!success) return nil; +- n = 1; +- } +- object *pair = cons(var, stream(WIFISTREAM, n)); +- push(pair,env); +- object *forms = cdr(args); +- object *result = eval(tf_progn(forms,env), env); +- client.stop(); +- return result; +- #else +- (void) args, (void) env; +- error2(PSTR("not supported")); +- return nil; +- #endif +-} +- +-/* +- (available stream) +- Returns the number of bytes available for reading from the wifi-stream, or zero if no bytes are available. +-*/ +-object *fn_available (object *args, object *env) { +- #if defined (ULISP_WIFI) +- (void) env; +- if (isstream(first(args))>>8 != WIFISTREAM) error2(PSTR("invalid stream")); +- return number(client.available()); +- #else +- (void) args, (void) env; +- error2(PSTR("not supported")); +- return nil; +- #endif +-} +- +-/* +- (wifi-server) +- Starts a Wi-Fi server running. It returns nil. +-*/ +-object *fn_wifiserver (object *args, object *env) { +- #if defined (ULISP_WIFI) +- (void) args, (void) env; +- server.begin(); +- return nil; +- #else +- (void) args, (void) env; +- error2(PSTR("not supported")); +- return nil; +- #endif +-} +- +-/* +- (wifi-softap ssid [password channel hidden]) +- Set up a soft access point to establish a Wi-Fi network. +- Returns the IP address as a string or nil if unsuccessful. +-*/ +-object *fn_wifisoftap (object *args, object *env) { +- #if defined (ULISP_WIFI) +- (void) env; +- char ssid[33], pass[65]; +- object *first = first(args); args = cdr(args); +- if (args == NULL) WiFi.beginAP(cstring(first, ssid, 33)); +- else { +- object *second = first(args); +- args = cdr(args); +- int channel = 1; +- if (args != NULL) { +- channel = checkinteger(first(args)); +- args = cdr(args); +- } +- WiFi.beginAP(cstring(first, ssid, 33), cstring(second, pass, 65), channel); +- } +- return lispstring((char*)"192.168.4.1"); +- #else +- (void) args, (void) env; +- error2(PSTR("not supported")); +- return nil; +- #endif +-} +- +-/* +- (connected stream) +- Returns t or nil to indicate if the client on stream is connected. +-*/ +-object *fn_connected (object *args, object *env) { +- #if defined (ULISP_WIFI) +- (void) env; +- if (isstream(first(args))>>8 != WIFISTREAM) error2(PSTR("invalid stream")); +- return client.connected() ? tee : nil; +- #else +- (void) args, (void) env; +- error2(PSTR("not supported")); +- return nil; +- #endif +-} +- +-/* +- (wifi-localip) +- Returns the IP address of the local network as a string. +-*/ +-object *fn_wifilocalip (object *args, object *env) { +- #if defined (ULISP_WIFI) +- (void) args, (void) env; +- return lispstring((char*)WiFi.localIP().toString().c_str()); +- #else +- (void) args, (void) env; +- error2(PSTR("not supported")); +- return nil; +- #endif +-} +- +-/* +- (wifi-connect [ssid pass]) +- Connects to the Wi-Fi network ssid using password pass. It returns the IP address as a string. +-*/ +-object *fn_wificonnect (object *args, object *env) { +- #if defined (ULISP_WIFI) +- (void) env; +- char ssid[33], pass[65]; +- if (args == NULL) { WiFi.disconnect(); return nil; } +- if (cdr(args) == NULL) WiFi.begin(cstring(first(args), ssid, 33)); +- else { +- if (cddr(args) != NULL) WiFi.config(ipstring(third(args))); +- WiFi.begin(cstring(first(args), ssid, 33), cstring(second(args), pass, 65)); +- } +- int result = WiFi.waitForConnectResult(); +- if (result == WL_CONNECTED) return lispstring((char*)WiFi.localIP().toString().c_str()); +- else if (result == WL_NO_SSID_AVAIL) error2(PSTR("network not found")); +- else if (result == WL_CONNECT_FAILED) error2(PSTR("connection failed")); +- else error2(PSTR("unable to connect")); +- return nil; +- #else +- (void) args, (void) env; +- error2(PSTR("not supported")); +- return nil; +- #endif +-} +- +-// Graphics functions +- +-/* +- (with-gfx (str) form*) +- Evaluates the forms with str bound to an gfx-stream so you can print text +- to the graphics display using the standard uLisp print commands. +-*/ +-object *sp_withgfx (object *args, object *env) { +-#if defined(gfxsupport) +- object *params = checkarguments(args, 1, 1); +- 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(PSTR("not supported")); +- return nil; +-#endif +-} +- +-/* +- (draw-pixel x y [colour]) +- Draws a pixel at coordinates (x,y) in colour, or white if omitted. +-*/ +-object *fn_drawpixel (object *args, object *env) { +- (void) env; +- #if defined(gfxsupport) +- uint16_t colour = COLOR_WHITE; +- if (cddr(args) != NULL) colour = checkinteger(third(args)); +- tft.drawPixel(checkinteger(first(args)), checkinteger(second(args)), colour); +- #else +- (void) args; +- #endif +- return nil; +-} +- +-/* +- (draw-line x0 y0 x1 y1 [colour]) +- Draws a line from (x0,y0) to (x1,y1) in colour, or white if omitted. +-*/ +-object *fn_drawline (object *args, object *env) { +- (void) env; +- #if defined(gfxsupport) +- uint16_t params[4], colour = COLOR_WHITE; +- for (int i=0; i<4; i++) { params[i] = checkinteger(car(args)); args = cdr(args); } +- if (args != NULL) colour = checkinteger(car(args)); +- tft.drawLine(params[0], params[1], params[2], params[3], colour); +- #else +- (void) args; +- #endif +- return nil; +-} +- +-/* +- (draw-rect x y w h [colour]) +- Draws an outline rectangle with its top left corner at (x,y), with width w, +- and with height h. The outline is drawn in colour, or white if omitted. +-*/ +-object *fn_drawrect (object *args, object *env) { +- (void) env; +- #if defined(gfxsupport) +- uint16_t params[4], colour = COLOR_WHITE; +- for (int i=0; i<4; i++) { params[i] = checkinteger(car(args)); args = cdr(args); } +- if (args != NULL) colour = checkinteger(car(args)); +- tft.drawRect(params[0], params[1], params[2], params[3], colour); +- #else +- (void) args; +- #endif +- return nil; +-} +- +-/* +- (fill-rect x y w h [colour]) +- Draws a filled rectangle with its top left corner at (x,y), with width w, +- and with height h. The outline is drawn in colour, or white if omitted. +-*/ +-object *fn_fillrect (object *args, object *env) { +- (void) env; +- #if defined(gfxsupport) +- uint16_t params[4], colour = COLOR_WHITE; +- for (int i=0; i<4; i++) { params[i] = checkinteger(car(args)); args = cdr(args); } +- if (args != NULL) colour = checkinteger(car(args)); +- tft.fillRect(params[0], params[1], params[2], params[3], colour); +- #else +- (void) args; +- #endif +- return nil; +-} +- +-/* +- (draw-circle x y r [colour]) +- Draws an outline circle with its centre at (x, y) and with radius r. +- The circle is drawn in colour, or white if omitted. +-*/ +-object *fn_drawcircle (object *args, object *env) { +- (void) env; +- #if defined(gfxsupport) +- uint16_t params[3], colour = COLOR_WHITE; +- for (int i=0; i<3; i++) { params[i] = checkinteger(car(args)); args = cdr(args); } +- if (args != NULL) colour = checkinteger(car(args)); +- tft.drawCircle(params[0], params[1], params[2], colour); +- #else +- (void) args; +- #endif +- return nil; +-} +- +-/* +- (fill-circle x y r [colour]) +- Draws a filled circle with its centre at (x, y) and with radius r. +- The circle is drawn in colour, or white if omitted. +-*/ +-object *fn_fillcircle (object *args, object *env) { +- (void) env; +- #if defined(gfxsupport) +- uint16_t params[3], colour = COLOR_WHITE; +- for (int i=0; i<3; i++) { params[i] = checkinteger(car(args)); args = cdr(args); } +- if (args != NULL) colour = checkinteger(car(args)); +- tft.fillCircle(params[0], params[1], params[2], colour); +- #else +- (void) args; +- #endif +- return nil; +-} +- +-/* +- (draw-round-rect x y w h radius [colour]) +- Draws an outline rounded rectangle with its top left corner at (x,y), with width w, +- height h, and corner radius radius. The outline is drawn in colour, or white if omitted. +-*/ +-object *fn_drawroundrect (object *args, object *env) { +- (void) env; +- #if defined(gfxsupport) +- uint16_t params[5], colour = COLOR_WHITE; +- for (int i=0; i<5; i++) { params[i] = checkinteger(car(args)); args = cdr(args); } +- if (args != NULL) colour = checkinteger(car(args)); +- tft.drawRoundRect(params[0], params[1], params[2], params[3], params[4], colour); +- #else +- (void) args; +- #endif +- return nil; +-} +- +-/* +- (fill-round-rect x y w h radius [colour]) +- Draws a filled rounded rectangle with its top left corner at (x,y), with width w, +- height h, and corner radius radius. The outline is drawn in colour, or white if omitted. +-*/ +-object *fn_fillroundrect (object *args, object *env) { +- (void) env; +- #if defined(gfxsupport) +- uint16_t params[5], colour = COLOR_WHITE; +- for (int i=0; i<5; i++) { params[i] = checkinteger(car(args)); args = cdr(args); } +- if (args != NULL) colour = checkinteger(car(args)); +- tft.fillRoundRect(params[0], params[1], params[2], params[3], params[4], colour); +- #else +- (void) args; +- #endif +- return nil; +-} +- +-/* +- (draw-triangle x0 y0 x1 y1 x2 y2 [colour]) +- Draws an outline triangle between (x1,y1), (x2,y2), and (x3,y3). +- The outline is drawn in colour, or white if omitted. +-*/ +-object *fn_drawtriangle (object *args, object *env) { +- (void) env; +- #if defined(gfxsupport) +- uint16_t params[6], colour = COLOR_WHITE; +- for (int i=0; i<6; i++) { params[i] = checkinteger(car(args)); args = cdr(args); } +- if (args != NULL) colour = checkinteger(car(args)); +- tft.drawTriangle(params[0], params[1], params[2], params[3], params[4], params[5], colour); +- #else +- (void) args; +- #endif +- return nil; +-} +- +-/* +- (fill-triangle x0 y0 x1 y1 x2 y2 [colour]) +- Draws a filled triangle between (x1,y1), (x2,y2), and (x3,y3). +- The outline is drawn in colour, or white if omitted. +-*/ +-object *fn_filltriangle (object *args, object *env) { +- (void) env; +- #if defined(gfxsupport) +- uint16_t params[6], colour = COLOR_WHITE; +- for (int i=0; i<6; i++) { params[i] = checkinteger(car(args)); args = cdr(args); } +- if (args != NULL) colour = checkinteger(car(args)); +- tft.fillTriangle(params[0], params[1], params[2], params[3], params[4], params[5], colour); +- #else +- (void) args; +- #endif +- return nil; +-} +- +-/* +- (draw-char x y char [colour background size]) +- Draws the character char with its top left corner at (x,y). +- The character is drawn in a 5 x 7 pixel font in colour against background, +- which default to white and black respectively. +- The character can optionally be scaled by size. +-*/ +-object *fn_drawchar (object *args, object *env) { +- (void) env; +- #if defined(gfxsupport) +- uint16_t colour = COLOR_WHITE, bg = COLOR_BLACK, size = 1; +- object *more = cdr(cddr(args)); +- if (more != NULL) { +- colour = checkinteger(car(more)); +- more = cdr(more); +- if (more != NULL) { +- bg = checkinteger(car(more)); +- more = cdr(more); +- if (more != NULL) size = checkinteger(car(more)); +- } +- } +- tft.drawChar(checkinteger(first(args)), checkinteger(second(args)), checkchar(third(args)), +- colour, bg, size); +- #else +- (void) args; +- #endif +- return nil; +-} +- +-/* +- (set-cursor x y) +- Sets the start point for text plotting to (x, y). +-*/ +-object *fn_setcursor (object *args, object *env) { +- (void) env; +- #if defined(gfxsupport) +- tft.setCursor(checkinteger(first(args)), checkinteger(second(args))); +- #else +- (void) args; +- #endif +- return nil; +-} +- +-/* +- (set-text-color colour [background]) +- Sets the text colour for text plotted using (with-gfx ...). +-*/ +-object *fn_settextcolor (object *args, object *env) { +- (void) env; +- #if defined(gfxsupport) +- if (cdr(args) != NULL) tft.setTextColor(checkinteger(first(args)), checkinteger(second(args))); +- else tft.setTextColor(checkinteger(first(args))); +- #else +- (void) args; +- #endif +- return nil; +-} +- +-/* +- (set-text-size scale) +- Scales text by the specified size, default 1. +-*/ +-object *fn_settextsize (object *args, object *env) { +- (void) env; +- #if defined(gfxsupport) +- tft.setTextSize(checkinteger(first(args))); +- #else +- (void) args; +- #endif +- return nil; +-} +- +-/* +- (set-text-wrap boolean) +- Specified whether text wraps at the right-hand edge of the display; the default is t. +-*/ +-object *fn_settextwrap (object *args, object *env) { +- (void) env; +- #if defined(gfxsupport) +- tft.setTextWrap(first(args) != NULL); +- #else +- (void) args; +- #endif +- return nil; +-} +- +-/* +- (fill-screen [colour]) +- Fills or clears the screen with colour, default black. +-*/ +-object *fn_fillscreen (object *args, object *env) { +- (void) env; +- #if defined(gfxsupport) +- uint16_t colour = COLOR_BLACK; +- if (args != NULL) colour = checkinteger(first(args)); +- tft.fillScreen(colour); +- #else +- (void) args; +- #endif +- return nil; +-} +- +-/* +- (set-rotation option) +- Sets the display orientation for subsequent graphics commands; values are 0, 1, 2, or 3. +-*/ +-object *fn_setrotation (object *args, object *env) { +- (void) env; +- #if defined(gfxsupport) +- tft.setRotation(checkinteger(first(args))); +- #else +- (void) args; +- #endif +- return nil; +-} +- +-/* +- (invert-display boolean) +- Mirror-images the display. +-*/ +-object *fn_invertdisplay (object *args, object *env) { +- (void) env; +- #if defined(gfxsupport) +- tft.invertDisplay(first(args) != NULL); +- #else +- (void) args; +- #endif +- return nil; +-} +- +-// Built-in symbol names +-const char string0[] PROGMEM = "nil"; +-const char string1[] PROGMEM = "t"; +-const char string2[] PROGMEM = "nothing"; +-const char string3[] PROGMEM = "&optional"; +-const char string4[] PROGMEM = ":initial-element"; +-const char string5[] PROGMEM = ":element-type"; +-const char string6[] PROGMEM = "bit"; +-const char string7[] PROGMEM = "&rest"; +-const char string8[] PROGMEM = "lambda"; +-const char string9[] PROGMEM = "let"; +-const char string10[] PROGMEM = "let*"; +-const char string11[] PROGMEM = "closure"; +-const char string12[] PROGMEM = "*pc*"; +-const char string13[] PROGMEM = "quote"; +-const char string14[] PROGMEM = "defun"; +-const char string15[] PROGMEM = "defvar"; +-const char string16[] PROGMEM = "defcode"; +-const char string17[] PROGMEM = "car"; +-const char string18[] PROGMEM = "first"; +-const char string19[] PROGMEM = "cdr"; +-const char string20[] PROGMEM = "rest"; +-const char string21[] PROGMEM = "nth"; +-const char string22[] PROGMEM = "aref"; +-const char string23[] PROGMEM = "string"; +-const char string24[] PROGMEM = "pinmode"; +-const char string25[] PROGMEM = "digitalwrite"; +-const char string26[] PROGMEM = "analogread"; +-const char string27[] PROGMEM = "analogreference"; +-const char string28[] PROGMEM = "register"; +-const char string29[] PROGMEM = "format"; +-const char string30[] PROGMEM = "or"; +-const char string31[] PROGMEM = "setq"; +-const char string32[] PROGMEM = "loop"; +-const char string33[] PROGMEM = "return"; +-const char string34[] PROGMEM = "push"; +-const char string35[] PROGMEM = "pop"; +-const char string36[] PROGMEM = "incf"; +-const char string37[] PROGMEM = "decf"; +-const char string38[] PROGMEM = "setf"; +-const char string39[] PROGMEM = "dolist"; +-const char string40[] PROGMEM = "dotimes"; +-const char string41[] PROGMEM = "trace"; +-const char string42[] PROGMEM = "untrace"; +-const char string43[] PROGMEM = "for-millis"; +-const char string44[] PROGMEM = "time"; +-const char string45[] PROGMEM = "with-output-to-string"; +-const char string46[] PROGMEM = "with-serial"; +-const char string47[] PROGMEM = "with-i2c"; +-const char string48[] PROGMEM = "with-spi"; +-const char string49[] PROGMEM = "with-sd-card"; +-const char string50[] PROGMEM = "progn"; +-const char string51[] PROGMEM = "if"; +-const char string52[] PROGMEM = "cond"; +-const char string53[] PROGMEM = "when"; +-const char string54[] PROGMEM = "unless"; +-const char string55[] PROGMEM = "case"; +-const char string56[] PROGMEM = "and"; +-const char string57[] PROGMEM = "not"; +-const char string58[] PROGMEM = "null"; +-const char string59[] PROGMEM = "cons"; +-const char string60[] PROGMEM = "atom"; +-const char string61[] PROGMEM = "listp"; +-const char string62[] PROGMEM = "consp"; +-const char string63[] PROGMEM = "symbolp"; +-const char string64[] PROGMEM = "arrayp"; +-const char string65[] PROGMEM = "boundp"; +-const char string66[] PROGMEM = "keywordp"; +-const char string67[] PROGMEM = "set"; +-const char string68[] PROGMEM = "streamp"; +-const char string69[] PROGMEM = "eq"; +-const char string70[] PROGMEM = "equal"; +-const char string71[] PROGMEM = "caar"; +-const char string72[] PROGMEM = "cadr"; +-const char string73[] PROGMEM = "second"; +-const char string74[] PROGMEM = "cdar"; +-const char string75[] PROGMEM = "cddr"; +-const char string76[] PROGMEM = "caaar"; +-const char string77[] PROGMEM = "caadr"; +-const char string78[] PROGMEM = "cadar"; +-const char string79[] PROGMEM = "caddr"; +-const char string80[] PROGMEM = "third"; +-const char string81[] PROGMEM = "cdaar"; +-const char string82[] PROGMEM = "cdadr"; +-const char string83[] PROGMEM = "cddar"; +-const char string84[] PROGMEM = "cdddr"; +-const char string85[] PROGMEM = "length"; +-const char string86[] PROGMEM = "array-dimensions"; +-const char string87[] PROGMEM = "list"; +-const char string88[] PROGMEM = "make-array"; +-const char string89[] PROGMEM = "reverse"; +-const char string90[] PROGMEM = "assoc"; +-const char string91[] PROGMEM = "member"; +-const char string92[] PROGMEM = "apply"; +-const char string93[] PROGMEM = "funcall"; +-const char string94[] PROGMEM = "append"; +-const char string95[] PROGMEM = "mapc"; +-const char string96[] PROGMEM = "mapcar"; +-const char string97[] PROGMEM = "mapcan"; +-const char string98[] PROGMEM = "+"; +-const char string99[] PROGMEM = "-"; +-const char string100[] PROGMEM = "*"; +-const char string101[] PROGMEM = "/"; +-const char string102[] PROGMEM = "mod"; +-const char string103[] PROGMEM = "1+"; +-const char string104[] PROGMEM = "1-"; +-const char string105[] PROGMEM = "abs"; +-const char string106[] PROGMEM = "random"; +-const char string107[] PROGMEM = "max"; +-const char string108[] PROGMEM = "min"; +-const char string109[] PROGMEM = "/="; +-const char string110[] PROGMEM = "="; +-const char string111[] PROGMEM = "<"; +-const char string112[] PROGMEM = "<="; +-const char string113[] PROGMEM = ">"; +-const char string114[] PROGMEM = ">="; +-const char string115[] PROGMEM = "plusp"; +-const char string116[] PROGMEM = "minusp"; +-const char string117[] PROGMEM = "zerop"; +-const char string118[] PROGMEM = "oddp"; +-const char string119[] PROGMEM = "evenp"; +-const char string120[] PROGMEM = "integerp"; +-const char string121[] PROGMEM = "numberp"; +-const char string122[] PROGMEM = "float"; +-const char string123[] PROGMEM = "floatp"; +-const char string124[] PROGMEM = "sin"; +-const char string125[] PROGMEM = "cos"; +-const char string126[] PROGMEM = "tan"; +-const char string127[] PROGMEM = "asin"; +-const char string128[] PROGMEM = "acos"; +-const char string129[] PROGMEM = "atan"; +-const char string130[] PROGMEM = "sinh"; +-const char string131[] PROGMEM = "cosh"; +-const char string132[] PROGMEM = "tanh"; +-const char string133[] PROGMEM = "exp"; +-const char string134[] PROGMEM = "sqrt"; +-const char string135[] PROGMEM = "log"; +-const char string136[] PROGMEM = "expt"; +-const char string137[] PROGMEM = "ceiling"; +-const char string138[] PROGMEM = "floor"; +-const char string139[] PROGMEM = "truncate"; +-const char string140[] PROGMEM = "round"; +-const char string141[] PROGMEM = "char"; +-const char string142[] PROGMEM = "char-code"; +-const char string143[] PROGMEM = "code-char"; +-const char string144[] PROGMEM = "characterp"; +-const char string145[] PROGMEM = "stringp"; +-const char string146[] PROGMEM = "string="; +-const char string147[] PROGMEM = "string<"; +-const char string148[] PROGMEM = "string>"; +-const char string149[] PROGMEM = "sort"; +-const char string150[] PROGMEM = "concatenate"; +-const char string151[] PROGMEM = "subseq"; +-const char string152[] PROGMEM = "search"; +-const char string153[] PROGMEM = "read-from-string"; +-const char string154[] PROGMEM = "princ-to-string"; +-const char string155[] PROGMEM = "prin1-to-string"; +-const char string156[] PROGMEM = "logand"; +-const char string157[] PROGMEM = "logior"; +-const char string158[] PROGMEM = "logxor"; +-const char string159[] PROGMEM = "lognot"; +-const char string160[] PROGMEM = "ash"; +-const char string161[] PROGMEM = "logbitp"; +-const char string162[] PROGMEM = "eval"; +-const char string163[] PROGMEM = "globals"; +-const char string164[] PROGMEM = "locals"; +-const char string165[] PROGMEM = "makunbound"; +-const char string166[] PROGMEM = "break"; +-const char string167[] PROGMEM = "read"; +-const char string168[] PROGMEM = "prin1"; +-const char string169[] PROGMEM = "print"; +-const char string170[] PROGMEM = "princ"; +-const char string171[] PROGMEM = "terpri"; +-const char string172[] PROGMEM = "read-byte"; +-const char string173[] PROGMEM = "read-line"; +-const char string174[] PROGMEM = "write-byte"; +-const char string175[] PROGMEM = "write-string"; +-const char string176[] PROGMEM = "write-line"; +-const char string177[] PROGMEM = "restart-i2c"; +-const char string178[] PROGMEM = "gc"; +-const char string179[] PROGMEM = "room"; +-const char string180[] PROGMEM = "save-image"; +-const char string181[] PROGMEM = "load-image"; +-const char string182[] PROGMEM = "cls"; +-const char string183[] PROGMEM = "digitalread"; +-const char string184[] PROGMEM = "analogreadresolution"; +-const char string185[] PROGMEM = "analogwrite"; +-const char string186[] PROGMEM = "analogwriteresolution"; +-const char string187[] PROGMEM = "delay"; +-const char string188[] PROGMEM = "millis"; +-const char string189[] PROGMEM = "sleep"; +-const char string190[] PROGMEM = "note"; +-const char string191[] PROGMEM = "edit"; +-const char string192[] PROGMEM = "pprint"; +-const char string193[] PROGMEM = "pprintall"; +-const char string194[] PROGMEM = "require"; +-const char string195[] PROGMEM = "list-library"; +-const char string196[] PROGMEM = "?"; +-const char string197[] PROGMEM = "documentation"; +-const char string198[] PROGMEM = "apropos"; +-const char string199[] PROGMEM = "apropos-list"; +-const char string200[] PROGMEM = "unwind-protect"; +-const char string201[] PROGMEM = "ignore-errors"; +-const char string202[] PROGMEM = "error"; +-const char string203[] PROGMEM = "with-client"; +-const char string204[] PROGMEM = "available"; +-const char string205[] PROGMEM = "wifi-server"; +-const char string206[] PROGMEM = "wifi-softap"; +-const char string207[] PROGMEM = "connected"; +-const char string208[] PROGMEM = "wifi-localip"; +-const char string209[] PROGMEM = "wifi-connect"; +-const char string210[] PROGMEM = "with-gfx"; +-const char string211[] PROGMEM = "draw-pixel"; +-const char string212[] PROGMEM = "draw-line"; +-const char string213[] PROGMEM = "draw-rect"; +-const char string214[] PROGMEM = "fill-rect"; +-const char string215[] PROGMEM = "draw-circle"; +-const char string216[] PROGMEM = "fill-circle"; +-const char string217[] PROGMEM = "draw-round-rect"; +-const char string218[] PROGMEM = "fill-round-rect"; +-const char string219[] PROGMEM = "draw-triangle"; +-const char string220[] PROGMEM = "fill-triangle"; +-const char string221[] PROGMEM = "draw-char"; +-const char string222[] PROGMEM = "set-cursor"; +-const char string223[] PROGMEM = "set-text-color"; +-const char string224[] PROGMEM = "set-text-size"; +-const char string225[] PROGMEM = "set-text-wrap"; +-const char string226[] PROGMEM = "fill-screen"; +-const char string227[] PROGMEM = "set-rotation"; +-const char string228[] PROGMEM = "invert-display"; +-const char string229[] PROGMEM = ":led-builtin"; +-const char string230[] PROGMEM = ":high"; +-const char string231[] PROGMEM = ":low"; +-#if defined(CPU_ATSAMD21) +-const char string232[] PROGMEM = ":input"; +-const char string233[] PROGMEM = ":input-pullup"; +-const char string234[] PROGMEM = ":input-pulldown"; +-const char string235[] PROGMEM = ":output"; +-const char string236[] PROGMEM = ":ar-default"; +-const char string237[] PROGMEM = ":ar-internal1v0"; +-const char string238[] PROGMEM = ":ar-internal1v65"; +-const char string239[] PROGMEM = ":ar-internal2v23"; +-const char string240[] PROGMEM = ":ar-external"; +-const char string241[] PROGMEM = ":pa-dir"; +-const char string242[] PROGMEM = ":pa-dirclr"; +-const char string243[] PROGMEM = ":pa-dirset"; +-const char string244[] PROGMEM = ":pa-dirtgl"; +-const char string245[] PROGMEM = ":pa-out"; +-const char string246[] PROGMEM = ":pa-outclr"; +-const char string247[] PROGMEM = ":pa-outset"; +-const char string248[] PROGMEM = ":pa-outtgl"; +-const char string249[] PROGMEM = ":pa-in"; +-const char string250[] PROGMEM = ":pb-dir"; +-const char string251[] PROGMEM = ":pb-dirclr"; +-const char string252[] PROGMEM = ":pb-dirset"; +-const char string253[] PROGMEM = ":pb-dirtgl"; +-const char string254[] PROGMEM = ":pb-out"; +-const char string255[] PROGMEM = ":pb-outclr"; +-const char string256[] PROGMEM = ":pb-outset"; +-const char string257[] PROGMEM = ":pb-outtgl"; +-const char string258[] PROGMEM = ":pb-in"; +-#elif defined(CPU_ATSAMD51) +-const char string232[] PROGMEM = ":input"; +-const char string233[] PROGMEM = ":input-pullup"; +-const char string234[] PROGMEM = ":input-pulldown"; +-const char string235[] PROGMEM = ":output"; +-const char string236[] PROGMEM = ":ar-default"; +-const char string237[] PROGMEM = ":ar-internal1v0"; +-const char string238[] PROGMEM = ":ar-internal1v1"; +-const char string239[] PROGMEM = ":ar-internal1v2"; +-const char string240[] PROGMEM = ":ar-internal1v25"; +-const char string241[] PROGMEM = ":ar-internal1v65"; +-const char string242[] PROGMEM = ":ar-internal2v0"; +-const char string243[] PROGMEM = ":ar-internal2v2"; +-const char string244[] PROGMEM = ":ar-internal2v23"; +-const char string245[] PROGMEM = ":ar-internal2v4"; +-const char string246[] PROGMEM = ":ar-internal2v5"; +-const char string247[] PROGMEM = ":ar-external"; +-const char string248[] PROGMEM = ":pa-dir"; +-const char string249[] PROGMEM = ":pa-dirclr"; +-const char string250[] PROGMEM = ":pa-dirset"; +-const char string251[] PROGMEM = ":pa-dirtgl"; +-const char string252[] PROGMEM = ":pa-out"; +-const char string253[] PROGMEM = ":pa-outclr"; +-const char string254[] PROGMEM = ":pa-outset"; +-const char string255[] PROGMEM = ":pa-outtgl"; +-const char string256[] PROGMEM = ":pa-in"; +-const char string257[] PROGMEM = ":pb-dir"; +-const char string258[] PROGMEM = ":pb-dirclr"; +-const char string259[] PROGMEM = ":pb-dirset"; +-const char string260[] PROGMEM = ":pb-dirtgl"; +-const char string261[] PROGMEM = ":pb-out"; +-const char string262[] PROGMEM = ":pb-outclr"; +-const char string263[] PROGMEM = ":pb-outset"; +-const char string264[] PROGMEM = ":pb-outtgl"; +-const char string265[] PROGMEM = ":pb-in"; +-#elif defined(CPU_NRF51822) +-const char string232[] PROGMEM = ":input"; +-const char string233[] PROGMEM = ":input-pullup"; +-const char string234[] PROGMEM = ":input-pulldown"; +-const char string235[] PROGMEM = ":output"; +-const char string236[] PROGMEM = ":ar-default"; +-const char string237[] PROGMEM = ":ar-vbg"; +-const char string238[] PROGMEM = ":ar-supply-one-half"; +-const char string239[] PROGMEM = ":ar-supply-one-third"; +-const char string240[] PROGMEM = ":ar-ext0"; +-const char string241[] PROGMEM = ":ar-ext1"; +-const char string242[] PROGMEM = ":p0-out"; +-const char string243[] PROGMEM = ":p0-outset"; +-const char string244[] PROGMEM = ":p0-outclr"; +-const char string245[] PROGMEM = ":p0-in"; +-const char string246[] PROGMEM = ":p0-dir"; +-const char string247[] PROGMEM = ":p0-dirset"; +-const char string248[] PROGMEM = ":p0-dirclr"; +-#elif defined(CPU_NRF52840) +-const char string232[] PROGMEM = ":input"; +-const char string233[] PROGMEM = ":input-pullup"; +-const char string234[] PROGMEM = ":input-pulldown"; +-const char string235[] PROGMEM = ":output"; +-const char string236[] PROGMEM = ":ar-default"; +-const char string237[] PROGMEM = ":ar-internal"; +-const char string238[] PROGMEM = ":ar-internal-3-0"; +-const char string239[] PROGMEM = ":ar-internal-2-4"; +-const char string240[] PROGMEM = ":ar-internal-1-8"; +-const char string241[] PROGMEM = ":ar-internal-1-2"; +-const char string242[] PROGMEM = ":ar-vdd4"; +-const char string243[] PROGMEM = ":p0-out"; +-const char string244[] PROGMEM = ":p0-outset"; +-const char string245[] PROGMEM = ":p0-outclr"; +-const char string246[] PROGMEM = ":p0-in"; +-const char string247[] PROGMEM = ":p0-dir"; +-const char string248[] PROGMEM = ":p0-dirset"; +-const char string249[] PROGMEM = ":p0-dirclr"; +-const char string250[] PROGMEM = ":p1-out"; +-const char string251[] PROGMEM = ":p1-outset"; +-const char string252[] PROGMEM = ":p1-outclr"; +-const char string253[] PROGMEM = ":p1-in"; +-const char string254[] PROGMEM = ":p1-dir"; +-const char string255[] PROGMEM = ":p1-dirset"; +-const char string256[] PROGMEM = ":p1-dirclr"; +-#elif defined(CPU_NRF52833) +-const char string232[] PROGMEM = ":input"; +-const char string233[] PROGMEM = ":input-pullup"; +-const char string234[] PROGMEM = ":input-pulldown"; +-const char string235[] PROGMEM = ":output"; +-const char string236[] PROGMEM = ":ar-default"; +-const char string237[] PROGMEM = ":ar-internal"; +-const char string238[] PROGMEM = ":ar-vdd4"; +-const char string239[] PROGMEM = ":p0-out"; +-const char string240[] PROGMEM = ":p0-outset"; +-const char string241[] PROGMEM = ":p0-outclr"; +-const char string242[] PROGMEM = ":p0-in"; +-const char string243[] PROGMEM = ":p0-dir"; +-const char string244[] PROGMEM = ":p0-dirset"; +-const char string245[] PROGMEM = ":p0-dirclr"; +-const char string246[] PROGMEM = ":p1-out"; +-const char string247[] PROGMEM = ":p1-outset"; +-const char string248[] PROGMEM = ":p1-outclr"; +-const char string249[] PROGMEM = ":p1-in"; +-const char string250[] PROGMEM = ":p1-dir"; +-const char string251[] PROGMEM = ":p1-dirset"; +-const char string252[] PROGMEM = ":p1-dirclr"; +-#elif defined(CPU_iMXRT1062) +-const char string232[] PROGMEM = ":input"; +-const char string233[] PROGMEM = ":input-pullup"; +-const char string234[] PROGMEM = ":input-pulldown"; +-const char string235[] PROGMEM = ":output"; +-const char string236[] PROGMEM = ":output-opendrain"; +-#elif defined(CPU_MAX32620) +-const char string232[] PROGMEM = ":input"; +-const char string233[] PROGMEM = ":input-pullup"; +-const char string234[] PROGMEM = ":output"; +-const char string235[] PROGMEM = ":default"; +-const char string236[] PROGMEM = ":external"; +-#elif defined(CPU_RP2040) +-const char string232[] PROGMEM = ":input"; +-const char string233[] PROGMEM = ":input-pullup"; +-const char string234[] PROGMEM = ":input-pulldown"; +-const char string235[] PROGMEM = ":output"; +-const char string236[] PROGMEM = ":gpio-in"; +-const char string237[] PROGMEM = ":gpio-out"; +-const char string238[] PROGMEM = ":gpio-out-set"; +-const char string239[] PROGMEM = ":gpio-out-clr"; +-const char string240[] PROGMEM = ":gpio-out-xor"; +-const char string241[] PROGMEM = ":gpio-oe"; +-const char string242[] PROGMEM = ":gpio-oe-set"; +-const char string243[] PROGMEM = ":gpio-oe-clr"; +-const char string244[] PROGMEM = ":gpio-oe-xor"; +-#endif +- +-// Documentation strings +-const char doc0[] PROGMEM = "nil\n" +-"A symbol equivalent to the empty list (). Also represents false."; +-const char doc1[] PROGMEM = "t\n" +-"A symbol representing true."; +-const char doc2[] PROGMEM = "nothing\n" +-"A symbol with no value.\n" +-"It is useful if you want to suppress printing the result of evaluating a function."; +-const char doc3[] PROGMEM = "&optional\n" +-"Can be followed by one or more optional parameters in a lambda or defun parameter list."; +-const char doc7[] PROGMEM = "&rest\n" +-"Can be followed by a parameter in a lambda or defun parameter list,\n" +-"and is assigned a list of the corresponding arguments."; +-const char doc8[] PROGMEM = "(lambda (parameter*) form*)\n" +-"Creates an unnamed function with parameters. The body is evaluated with the parameters as local variables\n" +-"whose initial values are defined by the values of the forms after the lambda form."; +-const char doc9[] PROGMEM = "(let ((var value) ... ) forms*)\n" +-"Declares local variables with values, and evaluates the forms with those local variables."; +-const char doc10[] PROGMEM = "(let* ((var value) ... ) forms*)\n" +-"Declares local variables with values, and evaluates the forms with those local variables.\n" +-"Each declaration can refer to local variables that have been defined earlier in the let*."; +-const char doc14[] PROGMEM = "(defun name (parameters) form*)\n" +-"Defines a function."; +-const char doc15[] PROGMEM = "(defvar variable form)\n" +-"Defines a global variable."; +-const char doc16[] PROGMEM = "(defcode name (parameters) form*)\n" +-"Creates a machine-code function called name from a series of 16-bit integers given in the body of the form.\n" +-"These are written into RAM, and can be executed by calling the function in the same way as a normal Lisp function."; +-const char doc17[] PROGMEM = "(car list)\n" +-"Returns the first item in a list."; +-const char doc19[] PROGMEM = "(cdr list)\n" +-"Returns a list with the first item removed."; +-const char doc21[] PROGMEM = "(nth number list)\n" +-"Returns the nth item in list, counting from zero."; +-const char doc22[] PROGMEM = "(aref array index [index*])\n" +-"Returns an element from the specified array."; +-const char doc23[] PROGMEM = "(string item)\n" +-"Converts its argument to a string."; +-const char doc24[] PROGMEM = "(pinmode pin mode)\n" +-"Sets the input/output mode of an Arduino pin number, and returns nil.\n" +-"The mode parameter can be an integer, a keyword, or t or nil."; +-const char doc25[] PROGMEM = "(digitalwrite pin state)\n" +-"Sets the state of the specified Arduino pin number."; +-const char doc26[] PROGMEM = "(analogread pin)\n" +-"Reads the specified Arduino analogue pin number and returns the value."; +-const char doc27[] PROGMEM = "(analogreference keyword)\n" +-"Specifies a keyword to set the analogue reference voltage used for analogue input."; +-const char doc28[] PROGMEM = "(register address [value])\n" +-"Reads or writes the value of a peripheral register.\n" +-"If value is not specified the function returns the value of the register at address.\n" +-"If value is specified the value is written to the register at address and the function returns value."; +-const char doc29[] PROGMEM = "(format output controlstring [arguments]*)\n" +-"Outputs its arguments formatted according to the format directives in controlstring."; +-const char doc30[] PROGMEM = "(or item*)\n" +-"Evaluates its arguments until one returns non-nil, and returns its value."; +-const char doc31[] PROGMEM = "(setq symbol value [symbol value]*)\n" +-"For each pair of arguments assigns the value of the second argument\n" +-"to the variable specified in the first argument."; +-const char doc32[] PROGMEM = "(loop forms*)\n" +-"Executes its arguments repeatedly until one of the arguments calls (return),\n" +-"which then causes an exit from the loop."; +-const char doc33[] PROGMEM = "(return [value])\n" +-"Exits from a (dotimes ...), (dolist ...), or (loop ...) loop construct and returns value."; +-const char doc34[] PROGMEM = "(push item place)\n" +-"Modifies the value of place, which should be a list, to add item onto the front of the list,\n" +-"and returns the new list."; +-const char doc35[] PROGMEM = "(pop place)\n" +-"Modifies the value of place, which should be a list, to remove its first item, and returns that item."; +-const char doc36[] PROGMEM = "(incf place [number])\n" +-"Increments a place, which should have an numeric value, and returns the result.\n" +-"The third argument is an optional increment which defaults to 1."; +-const char doc37[] PROGMEM = "(decf place [number])\n" +-"Decrements a place, which should have an numeric value, and returns the result.\n" +-"The third argument is an optional decrement which defaults to 1."; +-const char doc38[] PROGMEM = "(setf place value [place value]*)\n" +-"For each pair of arguments modifies a place to the result of evaluating value."; +-const char doc39[] PROGMEM = "(dolist (var list [result]) form*)\n" +-"Sets the local variable var to each element of list in turn, and executes the forms.\n" +-"It then returns result, or nil if result is omitted."; +-const char doc40[] PROGMEM = "(dotimes (var number [result]) form*)\n" +-"Executes the forms number times, with the local variable var set to each integer from 0 to number-1 in turn.\n" +-"It then returns result, or nil if result is omitted."; +-const char doc41[] PROGMEM = "(trace [function]*)\n" +-"Turns on tracing of up to TRACEMAX user-defined functions,\n" +-"and returns a list of the functions currently being traced."; +-const char doc42[] PROGMEM = "(untrace [function]*)\n" +-"Turns off tracing of up to TRACEMAX user-defined functions, and returns a list of the functions untraced.\n" +-"If no functions are specified it untraces all functions."; +-const char doc43[] PROGMEM = "(for-millis ([number]) form*)\n" +-"Executes the forms and then waits until a total of number milliseconds have elapsed.\n" +-"Returns the total number of milliseconds taken."; +-const char doc44[] PROGMEM = "(time form)\n" +-"Prints the value returned by the form, and the time taken to evaluate the form\n" +-"in milliseconds or seconds."; +-const char doc45[] PROGMEM = "(with-output-to-string (str) form*)\n" +-"Returns a string containing the output to the stream variable str."; +-const char doc46[] PROGMEM = "(with-serial (str port [baud]) form*)\n" +-"Evaluates the forms with str bound to a serial-stream using port.\n" +-"The optional baud gives the baud rate divided by 100, default 96."; +-const char doc47[] PROGMEM = "(with-i2c (str [port] address [read-p]) form*)\n" +-"Evaluates the forms with str bound to an i2c-stream defined by address.\n" +-"If read-p is nil or omitted the stream is written to, otherwise it specifies the number of bytes\n" +-"to be read from the stream. If port is omitted it defaults to 0, otherwise it specifies the port, 0 or 1."; +-const char doc48[] PROGMEM = "(with-spi (str pin [clock] [bitorder] [mode] [port]) form*)\n" +-"Evaluates the forms with str bound to an spi-stream.\n" +-"The parameters specify the enable pin, clock in kHz (default 4000),\n" +-"bitorder 0 for LSBFIRST and 1 for MSBFIRST (default 1), SPI mode (default 0), and port 0 or 1 (default 0)."; +-const char doc49[] PROGMEM = "(with-sd-card (str filename [mode]) form*)\n" +-"Evaluates the forms with str bound to an sd-stream reading from or writing to the file filename.\n" +-"If mode is omitted the file is read, otherwise 0 means read, 1 write-append, or 2 write-overwrite."; +-const char doc50[] PROGMEM = "(progn form*)\n" +-"Evaluates several forms grouped together into a block, and returns the result of evaluating the last form."; +-const char doc51[] PROGMEM = "(if test then [else])\n" +-"Evaluates test. If it's non-nil the form then is evaluated and returned;\n" +-"otherwise the form else is evaluated and returned."; +-const char doc52[] PROGMEM = "(cond ((test form*) (test form*) ... ))\n" +-"Each argument is a list consisting of a test optionally followed by one or more forms.\n" +-"If the test evaluates to non-nil the forms are evaluated, and the last value is returned as the result of the cond.\n" +-"If the test evaluates to nil, none of the forms are evaluated, and the next argument is processed in the same way."; +-const char doc53[] PROGMEM = "(when test form*)\n" +-"Evaluates the test. If it's non-nil the forms are evaluated and the last value is returned."; +-const char doc54[] PROGMEM = "(unless test form*)\n" +-"Evaluates the test. If it's nil the forms are evaluated and the last value is returned."; +-const char doc55[] PROGMEM = "(case keyform ((key form*) (key form*) ... ))\n" +-"Evaluates a keyform to produce a test key, and then tests this against a series of arguments,\n" +-"each of which is a list containing a key optionally followed by one or more forms."; +-const char doc56[] PROGMEM = "(and item*)\n" +-"Evaluates its arguments until one returns nil, and returns the last value."; +-const char doc57[] PROGMEM = "(not item)\n" +-"Returns t if its argument is nil, or nil otherwise. Equivalent to null."; +-const char doc59[] PROGMEM = "(cons item item)\n" +-"If the second argument is a list, cons returns a new list with item added to the front of the list.\n" +-"If the second argument isn't a list cons returns a dotted pair."; +-const char doc60[] PROGMEM = "(atom item)\n" +-"Returns t if its argument is a single number, symbol, or nil."; +-const char doc61[] PROGMEM = "(listp item)\n" +-"Returns t if its argument is a list."; +-const char doc62[] PROGMEM = "(consp item)\n" +-"Returns t if its argument is a non-null list."; +-const char doc63[] PROGMEM = "(symbolp item)\n" +-"Returns t if its argument is a symbol."; +-const char doc64[] PROGMEM = "(arrayp item)\n" +-"Returns t if its argument is an array."; +-const char doc65[] PROGMEM = "(boundp item)\n" +-"Returns t if its argument is a symbol with a value."; +-const char doc66[] PROGMEM = "(keywordp item)\n" +-"Returns t if its argument is a keyword."; +-const char doc67[] PROGMEM = "(set symbol value [symbol value]*)\n" +-"For each pair of arguments, assigns the value of the second argument to the value of the first argument."; +-const char doc68[] PROGMEM = "(streamp item)\n" +-"Returns t if its argument is a stream."; +-const char doc69[] PROGMEM = "(eq item item)\n" +-"Tests whether the two arguments are the same symbol, same character, equal numbers,\n" +-"or point to the same cons, and returns t or nil as appropriate."; +-const char doc70[] PROGMEM = "(equal item item)\n" +-"Tests whether the two arguments are the same symbol, same character, equal numbers,\n" +-"or point to the same cons, and returns t or nil as appropriate."; +-const char doc71[] PROGMEM = "(caar list)"; +-const char doc72[] PROGMEM = "(cadr list)"; +-const char doc74[] PROGMEM = "(cdar list)\n" +-"Equivalent to (cdr (car list))."; +-const char doc75[] PROGMEM = "(cddr list)\n" +-"Equivalent to (cdr (cdr list))."; +-const char doc76[] PROGMEM = "(caaar list)\n" +-"Equivalent to (car (car (car list)))."; +-const char doc77[] PROGMEM = "(caadr list)\n" +-"Equivalent to (car (car (cdar list)))."; +-const char doc78[] PROGMEM = "(cadar list)\n" +-"Equivalent to (car (cdr (car list)))."; +-const char doc79[] PROGMEM = "(caddr list)\n" +-"Equivalent to (car (cdr (cdr list)))."; +-const char doc81[] PROGMEM = "(cdaar list)\n" +-"Equivalent to (cdar (car (car list)))."; +-const char doc82[] PROGMEM = "(cdadr list)\n" +-"Equivalent to (cdr (car (cdr list)))."; +-const char doc83[] PROGMEM = "(cddar list)\n" +-"Equivalent to (cdr (cdr (car list)))."; +-const char doc84[] PROGMEM = "(cdddr list)\n" +-"Equivalent to (cdr (cdr (cdr list)))."; +-const char doc85[] PROGMEM = "(length item)\n" +-"Returns the number of items in a list, the length of a string, or the length of a one-dimensional array."; +-const char doc86[] PROGMEM = "(array-dimensions item)\n" +-"Returns a list of the dimensions of an array."; +-const char doc87[] PROGMEM = "(list item*)\n" +-"Returns a list of the values of its arguments."; +-const char doc88[] PROGMEM = "(make-array size [:initial-element element] [:element-type 'bit])\n" +-"If size is an integer it creates a one-dimensional array with elements from 0 to size-1.\n" +-"If size is a list of n integers it creates an n-dimensional array with those dimensions.\n" +-"If :element-type 'bit is specified the array is a bit array."; +-const char doc89[] PROGMEM = "(reverse list)\n" +-"Returns a list with the elements of list in reverse order."; +-const char doc90[] PROGMEM = "(assoc key list)\n" +-"Looks up a key in an association list of (key . value) pairs,\n" +-"and returns the matching pair, or nil if no pair is found."; +-const char doc91[] PROGMEM = "(member item list)\n" +-"Searches for an item in a list, using eq, and returns the list starting from the first occurrence of the item,\n" +-"or nil if it is not found."; +-const char doc92[] PROGMEM = "(apply function list)\n" +-"Returns the result of evaluating function, with the list of arguments specified by the second parameter."; +-const char doc93[] PROGMEM = "(funcall function argument*)\n" +-"Evaluates function with the specified arguments."; +-const char doc94[] PROGMEM = "(append list*)\n" +-"Joins its arguments, which should be lists, into a single list."; +-const char doc95[] PROGMEM = "(mapc function list1 [list]*)\n" +-"Applies the function to each element in one or more lists, ignoring the results.\n" +-"It returns the first list argument."; +-const char doc96[] PROGMEM = "(mapcar function list1 [list]*)\n" +-"Applies the function to each element in one or more lists, and returns the resulting list."; +-const char doc97[] PROGMEM = "(mapcan function list1 [list]*)\n" +-"Applies the function to each element in one or more lists. The results should be lists,\n" +-"and these are appended together to give the value returned."; +-const char doc98[] PROGMEM = "(+ number*)\n" +-"Adds its arguments together.\n" +-"If each argument is an integer, and the running total doesn't overflow, the result is an integer,\n" +-"otherwise a floating-point number."; +-const char doc99[] PROGMEM = "(- number*)\n" +-"If there is one argument, negates the argument.\n" +-"If there are two or more arguments, subtracts the second and subsequent arguments from the first argument.\n" +-"If each argument is an integer, and the running total doesn't overflow, returns the result as an integer,\n" +-"otherwise a floating-point number."; +-const char doc100[] PROGMEM = "(* number*)\n" +-"Multiplies its arguments together.\n" +-"If each argument is an integer, and the running total doesn't overflow, the result is an integer,\n" +-"otherwise it's a floating-point number."; +-const char doc101[] PROGMEM = "(/ number*)\n" +-"Divides the first argument by the second and subsequent arguments.\n" +-"If each argument is an integer, and each division produces an exact result, the result is an integer;\n" +-"otherwise it's a floating-point number."; +-const char doc102[] PROGMEM = "(mod number number)\n" +-"Returns its first argument modulo the second argument.\n" +-"If both arguments are integers the result is an integer; otherwise it's a floating-point number."; +-const char doc103[] PROGMEM = "(1+ number)\n" +-"Adds one to its argument and returns it.\n" +-"If the argument is an integer the result is an integer if possible;\n" +-"otherwise it's a floating-point number."; +-const char doc104[] PROGMEM = "(1- number)\n" +-"Subtracts one from its argument and returns it.\n" +-"If the argument is an integer the result is an integer if possible;\n" +-"otherwise it's a floating-point number."; +-const char doc105[] PROGMEM = "(abs number)\n" +-"Returns the absolute, positive value of its argument.\n" +-"If the argument is an integer the result will be returned as an integer if possible,\n" +-"otherwise a floating-point number."; +-const char doc106[] PROGMEM = "(random number)\n" +-"If number is an integer returns a random number between 0 and one less than its argument.\n" +-"Otherwise returns a floating-point number between zero and number."; +-const char doc107[] PROGMEM = "(max number*)\n" +-"Returns the maximum of one or more arguments."; +-const char doc108[] PROGMEM = "(min number*)\n" +-"Returns the minimum of one or more arguments."; +-const char doc109[] PROGMEM = "(/= number*)\n" +-"Returns t if none of the arguments are equal, or nil if two or more arguments are equal."; +-const char doc110[] PROGMEM = "(= number*)\n" +-"Returns t if all the arguments, which must be numbers, are numerically equal, and nil otherwise."; +-const char doc111[] PROGMEM = "(< number*)\n" +-"Returns t if each argument is less than the next argument, and nil otherwise."; +-const char doc112[] PROGMEM = "(<= number*)\n" +-"Returns t if each argument is less than or equal to the next argument, and nil otherwise."; +-const char doc113[] PROGMEM = "(> number*)\n" +-"Returns t if each argument is greater than the next argument, and nil otherwise."; +-const char doc114[] PROGMEM = "(>= number*)\n" +-"Returns t if each argument is greater than or equal to the next argument, and nil otherwise."; +-const char doc115[] PROGMEM = "(plusp number)\n" +-"Returns t if the argument is greater than zero, or nil otherwise."; +-const char doc116[] PROGMEM = "(minusp number)\n" +-"Returns t if the argument is less than zero, or nil otherwise."; +-const char doc117[] PROGMEM = "(zerop number)\n" +-"Returns t if the argument is zero."; +-const char doc118[] PROGMEM = "(oddp number)\n" +-"Returns t if the integer argument is odd."; +-const char doc119[] PROGMEM = "(evenp number)\n" +-"Returns t if the integer argument is even."; +-const char doc120[] PROGMEM = "(integerp number)\n" +-"Returns t if the argument is an integer."; +-const char doc121[] PROGMEM = "(numberp number)\n" +-"Returns t if the argument is a number."; +-const char doc122[] PROGMEM = "(float number)\n" +-"Returns its argument converted to a floating-point number."; +-const char doc123[] PROGMEM = "(floatp number)\n" +-"Returns t if the argument is a floating-point number."; +-const char doc124[] PROGMEM = "(sin number)\n" +-"Returns sin(number)."; +-const char doc125[] PROGMEM = "(cos number)\n" +-"Returns cos(number)."; +-const char doc126[] PROGMEM = "(tan number)\n" +-"Returns tan(number)."; +-const char doc127[] PROGMEM = "(asin number)\n" +-"Returns asin(number)."; +-const char doc128[] PROGMEM = "(acos number)\n" +-"Returns acos(number)."; +-const char doc129[] PROGMEM = "(atan number1 [number2])\n" +-"Returns the arc tangent of number1/number2, in radians. If number2 is omitted it defaults to 1."; +-const char doc130[] PROGMEM = "(sinh number)\n" +-"Returns sinh(number)."; +-const char doc131[] PROGMEM = "(cosh number)\n" +-"Returns cosh(number)."; +-const char doc132[] PROGMEM = "(tanh number)\n" +-"Returns tanh(number)."; +-const char doc133[] PROGMEM = "(exp number)\n" +-"Returns exp(number)."; +-const char doc134[] PROGMEM = "(sqrt number)\n" +-"Returns sqrt(number)."; +-const char doc135[] PROGMEM = "(log number [base])\n" +-"Returns the logarithm of number to the specified base. If base is omitted it defaults to e."; +-const char doc136[] PROGMEM = "(expt number power)\n" +-"Returns number raised to the specified power.\n" +-"Returns the result as an integer if the arguments are integers and the result will be within range,\n" +-"otherwise a floating-point number."; +-const char doc137[] PROGMEM = "(ceiling number [divisor])\n" +-"Returns ceil(number/divisor). If omitted, divisor is 1."; +-const char doc138[] PROGMEM = "(floor number [divisor])\n" +-"Returns floor(number/divisor). If omitted, divisor is 1."; +-const char doc139[] PROGMEM = "(truncate number [divisor])\n" +-"Returns the integer part of number/divisor. If divisor is omitted it defaults to 1."; +-const char doc140[] PROGMEM = "(round number [divisor])\n" +-"Returns the integer closest to number/divisor. If divisor is omitted it defaults to 1."; +-const char doc141[] PROGMEM = "(char string n)\n" +-"Returns the nth character in a string, counting from zero."; +-const char doc142[] PROGMEM = "(char-code character)\n" +-"Returns the ASCII code for a character, as an integer."; +-const char doc143[] PROGMEM = "(code-char integer)\n" +-"Returns the character for the specified ASCII code."; +-const char doc144[] PROGMEM = "(characterp item)\n" +-"Returns t if the argument is a character and nil otherwise."; +-const char doc145[] PROGMEM = "(stringp item)\n" +-"Returns t if the argument is a string and nil otherwise."; +-const char doc146[] PROGMEM = "(string= string string)\n" +-"Tests whether two strings are the same."; +-const char doc147[] PROGMEM = "(string< string string)\n" +-"Returns t if the first string is alphabetically less than the second string, and nil otherwise."; +-const char doc148[] PROGMEM = "(string> string string)\n" +-"Returns t if the first string is alphabetically greater than the second string, and nil otherwise."; +-const char doc149[] PROGMEM = "(sort list test)\n" +-"Destructively sorts list according to the test function, using an insertion sort, and returns the sorted list."; +-const char doc150[] PROGMEM = "(concatenate 'string string*)\n" +-"Joins together the strings given in the second and subsequent arguments, and returns a single string."; +-const char doc151[] PROGMEM = "(subseq seq start [end])\n" +-"Returns a subsequence of a list or string from item start to item end-1."; +-const char doc152[] PROGMEM = "(search pattern target)\n" +-"Returns the index of the first occurrence of pattern in target,\n" +-"which can be lists or strings, or nil if it's not found."; +-const char doc153[] PROGMEM = "(read-from-string string)\n" +-"Reads an atom or list from the specified string and returns it."; +-const char doc154[] PROGMEM = "(princ-to-string item)\n" +-"Prints its argument to a string, and returns the string.\n" +-"Characters and strings are printed without quotation marks or escape characters."; +-const char doc155[] PROGMEM = "(prin1-to-string item [stream])\n" +-"Prints its argument to a string, and returns the string.\n" +-"Characters and strings are printed with quotation marks and escape characters,\n" +-"in a format that will be suitable for read-from-string."; +-const char doc156[] PROGMEM = "(logand [value*])\n" +-"Returns the bitwise & of the values."; +-const char doc157[] PROGMEM = "(logior [value*])\n" +-"Returns the bitwise | of the values."; +-const char doc158[] PROGMEM = "(logxor [value*])\n" +-"Returns the bitwise ^ of the values."; +-const char doc159[] PROGMEM = "(lognot value)\n" +-"Returns the bitwise logical NOT of the value."; +-const char doc160[] PROGMEM = "(ash value shift)\n" +-"Returns the result of bitwise shifting value by shift bits. If shift is positive, value is shifted to the left."; +-const char doc161[] PROGMEM = "(logbitp bit value)\n" +-"Returns t if bit number bit in value is a '1', and nil if it is a '0'."; +-const char doc162[] PROGMEM = "(eval form*)\n" +-"Evaluates its argument an extra time."; +-const char doc163[] PROGMEM = "(globals)\n" +-"Returns a list of global variables."; +-const char doc164[] PROGMEM = "(locals)\n" +-"Returns an association list of local variables and their values."; +-const char doc165[] PROGMEM = "(makunbound symbol)\n" +-"Removes the value of the symbol from GlobalEnv and returns the symbol."; +-const char doc166[] PROGMEM = "(break)\n" +-"Inserts a breakpoint in the program. When evaluated prints Break! and reenters the REPL."; +-const char doc167[] PROGMEM = "(read [stream])\n" +-"Reads an atom or list from the serial input and returns it.\n" +-"If stream is specified the item is read from the specified stream."; +-const char doc168[] PROGMEM = "(prin1 item [stream])\n" +-"Prints its argument, and returns its value.\n" +-"Strings are printed with quotation marks and escape characters."; +-const char doc169[] PROGMEM = "(print item [stream])\n" +-"Prints its argument with quotation marks and escape characters, on a new line, and followed by a space.\n" +-"If stream is specified the argument is printed to the specified stream."; +-const char doc170[] PROGMEM = "(princ item [stream])\n" +-"Prints its argument, and returns its value.\n" +-"Characters and strings are printed without quotation marks or escape characters."; +-const char doc171[] PROGMEM = "(terpri [stream])\n" +-"Prints a new line, and returns nil.\n" +-"If stream is specified the new line is written to the specified stream."; +-const char doc172[] PROGMEM = "(read-byte stream)\n" +-"Reads a byte from a stream and returns it."; +-const char doc173[] PROGMEM = "(read-line [stream])\n" +-"Reads characters from the serial input up to a newline character, and returns them as a string, excluding the newline.\n" +-"If stream is specified the line is read from the specified stream."; +-const char doc174[] PROGMEM = "(write-byte number [stream])\n" +-"Writes a byte to a stream."; +-const char doc175[] PROGMEM = "(write-string string [stream])\n" +-"Writes a string. If stream is specified the string is written to the stream."; +-const char doc176[] PROGMEM = "(write-line string [stream])\n" +-"Writes a string terminated by a newline character. If stream is specified the string is written to the stream."; +-const char doc177[] PROGMEM = "(restart-i2c stream [read-p])\n" +-"Restarts an i2c-stream.\n" +-"If read-p is nil or omitted the stream is written to.\n" +-"If read-p is an integer it specifies the number of bytes to be read from the stream."; +-const char doc178[] PROGMEM = "(gc)\n" +-"Forces a garbage collection and prints the number of objects collected, and the time taken."; +-const char doc179[] PROGMEM = "(room)\n" +-"Returns the number of free Lisp cells remaining."; +-const char doc180[] PROGMEM = "(save-image [symbol])\n" +-"Saves the current uLisp image to non-volatile memory or SD card so it can be loaded using load-image."; +-const char doc181[] PROGMEM = "(load-image [filename])\n" +-"Loads a saved uLisp image from non-volatile memory or SD card."; +-const char doc182[] PROGMEM = "(cls)\n" +-"Prints a clear-screen character."; +-const char doc183[] PROGMEM = "(digitalread pin)\n" +-"Reads the state of the specified Arduino pin number and returns t (high) or nil (low)."; +-const char doc184[] PROGMEM = "(analogreadresolution bits)\n" +-"Specifies the resolution for the analogue inputs on platforms that support it.\n" +-"The default resolution on all platforms is 10 bits."; +-const char doc185[] PROGMEM = "(analogwrite pin value)\n" +-"Writes the value to the specified Arduino pin number."; +-const char doc186[] PROGMEM = "(analogwrite pin value)\n" +-"Sets the analogue write resolution."; +-const char doc187[] PROGMEM = "(delay number)\n" +-"Delays for a specified number of milliseconds."; +-const char doc188[] PROGMEM = "(millis)\n" +-"Returns the time in milliseconds that uLisp has been running."; +-const char doc189[] PROGMEM = "(sleep secs)\n" +-"Puts the processor into a low-power sleep mode for secs.\n" +-"Only supported on some platforms. On other platforms it does delay(1000*secs)."; +-const char doc190[] PROGMEM = "(note [pin] [note] [octave])\n" +-"Generates a square wave on pin.\n" +-"The argument note represents the note in the well-tempered scale, from 0 to 11,\n" +-"where 0 represents C, 1 represents C#, and so on.\n" +-"The argument octave can be from 3 to 6. If omitted it defaults to 0."; +-const char doc191[] PROGMEM = "(edit 'function)\n" +-"Calls the Lisp tree editor to allow you to edit a function definition."; +-const char doc192[] PROGMEM = "(pprint item [str])\n" +-"Prints its argument, using the pretty printer, to display it formatted in a structured way.\n" +-"If str is specified it prints to the specified stream. It returns no value."; +-const char doc193[] PROGMEM = "(pprintall [str])\n" +-"Pretty-prints the definition of every function and variable defined in the uLisp workspace.\n" +-"If str is specified it prints to the specified stream. It returns no value."; +-const char doc194[] PROGMEM = "(require 'symbol)\n" +-"Loads the definition of a function defined with defun, or a variable defined with defvar, from the Lisp Library.\n" +-"It returns t if it was loaded, or nil if the symbol is already defined or isn't defined in the Lisp Library."; +-const char doc195[] PROGMEM = "(list-library)\n" +-"Prints a list of the functions defined in the List Library."; +-const char doc196[] PROGMEM = "(? item)\n" +-"Prints the documentation string of a built-in or user-defined function."; +-const char doc197[] PROGMEM = "(documentation 'symbol [type])\n" +-"Returns the documentation string of a built-in or user-defined function. The type argument is ignored."; +-const char doc198[] PROGMEM = "(apropos item)\n" +-"Prints the user-defined and built-in functions whose names contain the specified string or symbol."; +-const char doc199[] PROGMEM = "(apropos-list item)\n" +-"Returns a list of user-defined and built-in functions whose names contain the specified string or symbol."; +-const char doc200[] PROGMEM = "(unwind-protect form1 [forms]*)\n" +-"Evaluates form1 and forms in order and returns the value of form1,\n" +-"but guarantees to evaluate forms even if an error occurs in form1."; +-const char doc201[] PROGMEM = "(ignore-errors [forms]*)\n" +-"Evaluates forms ignoring errors."; +-const char doc202[] PROGMEM = "(error controlstring [arguments]*)\n" +-"Signals an error. The message is printed by format using the controlstring and arguments."; +-const char doc203[] PROGMEM = "(with-client (str [address port]) form*)\n" +-"Evaluates the forms with str bound to a wifi-stream."; +-const char doc204[] PROGMEM = "(available stream)\n" +-"Returns the number of bytes available for reading from the wifi-stream, or zero if no bytes are available."; +-const char doc205[] PROGMEM = "(wifi-server)\n" +-"Starts a Wi-Fi server running. It returns nil."; +-const char doc206[] PROGMEM = "(wifi-softap ssid [password channel hidden])\n" +-"Set up a soft access point to establish a Wi-Fi network.\n" +-"Returns the IP address as a string or nil if unsuccessful."; +-const char doc207[] PROGMEM = "(connected stream)\n" +-"Returns t or nil to indicate if the client on stream is connected."; +-const char doc208[] PROGMEM = "(wifi-localip)\n" +-"Returns the IP address of the local network as a string."; +-const char doc209[] PROGMEM = "(wifi-connect [ssid pass])\n" +-"Connects to the Wi-Fi network ssid using password pass. It returns the IP address as a string."; +-const char doc210[] PROGMEM = "(with-gfx (str) form*)\n" +-"Evaluates the forms with str bound to an gfx-stream so you can print text\n" +-"to the graphics display using the standard uLisp print commands."; +-const char doc211[] PROGMEM = "(draw-pixel x y [colour])\n" +-"Draws a pixel at coordinates (x,y) in colour, or white if omitted."; +-const char doc212[] PROGMEM = "(draw-line x0 y0 x1 y1 [colour])\n" +-"Draws a line from (x0,y0) to (x1,y1) in colour, or white if omitted."; +-const char doc213[] PROGMEM = "(draw-rect x y w h [colour])\n" +-"Draws an outline rectangle with its top left corner at (x,y), with width w,\n" +-"and with height h. The outline is drawn in colour, or white if omitted."; +-const char doc214[] PROGMEM = "(fill-rect x y w h [colour])\n" +-"Draws a filled rectangle with its top left corner at (x,y), with width w,\n" +-"and with height h. The outline is drawn in colour, or white if omitted."; +-const char doc215[] PROGMEM = "(draw-circle x y r [colour])\n" +-"Draws an outline circle with its centre at (x, y) and with radius r.\n" +-"The circle is drawn in colour, or white if omitted."; +-const char doc216[] PROGMEM = "(fill-circle x y r [colour])\n" +-"Draws a filled circle with its centre at (x, y) and with radius r.\n" +-"The circle is drawn in colour, or white if omitted."; +-const char doc217[] PROGMEM = "(draw-round-rect x y w h radius [colour])\n" +-"Draws an outline rounded rectangle with its top left corner at (x,y), with width w,\n" +-"height h, and corner radius radius. The outline is drawn in colour, or white if omitted."; +-const char doc218[] PROGMEM = "(fill-round-rect x y w h radius [colour])\n" +-"Draws a filled rounded rectangle with its top left corner at (x,y), with width w,\n" +-"height h, and corner radius radius. The outline is drawn in colour, or white if omitted."; +-const char doc219[] PROGMEM = "(draw-triangle x0 y0 x1 y1 x2 y2 [colour])\n" +-"Draws an outline triangle between (x1,y1), (x2,y2), and (x3,y3).\n" +-"The outline is drawn in colour, or white if omitted."; +-const char doc220[] PROGMEM = "(fill-triangle x0 y0 x1 y1 x2 y2 [colour])\n" +-"Draws a filled triangle between (x1,y1), (x2,y2), and (x3,y3).\n" +-"The outline is drawn in colour, or white if omitted."; +-const char doc221[] PROGMEM = "(draw-char x y char [colour background size])\n" +-"Draws the character char with its top left corner at (x,y).\n" +-"The character is drawn in a 5 x 7 pixel font in colour against background,\n" +-"which default to white and black respectively.\n" +-"The character can optionally be scaled by size."; +-const char doc222[] PROGMEM = "(set-cursor x y)\n" +-"Sets the start point for text plotting to (x, y)."; +-const char doc223[] PROGMEM = "(set-text-color colour [background])\n" +-"Sets the text colour for text plotted using (with-gfx ...)."; +-const char doc224[] PROGMEM = "(set-text-size scale)\n" +-"Scales text by the specified size, default 1."; +-const char doc225[] PROGMEM = "(set-text-wrap boolean)\n" +-"Specified whether text wraps at the right-hand edge of the display; the default is t."; +-const char doc226[] PROGMEM = "(fill-screen [colour])\n" +-"Fills or clears the screen with colour, default black."; +-const char doc227[] PROGMEM = "(set-rotation option)\n" +-"Sets the display orientation for subsequent graphics commands; values are 0, 1, 2, or 3."; +-const char doc228[] PROGMEM = "(invert-display boolean)\n" +-"Mirror-images the display."; +- +-// Built-in symbol lookup table +-const tbl_entry_t lookup_table[] PROGMEM = { +- { string0, NULL, 0000, doc0 }, +- { string1, NULL, 0000, doc1 }, +- { string2, NULL, 0000, doc2 }, +- { string3, NULL, 0000, doc3 }, +- { string4, NULL, 0000, NULL }, +- { string5, NULL, 0000, NULL }, +- { string6, NULL, 0000, NULL }, +- { string7, NULL, 0000, doc7 }, +- { string8, NULL, 0017, doc8 }, +- { string9, NULL, 0017, doc9 }, +- { string10, NULL, 0017, doc10 }, +- { string11, NULL, 0017, NULL }, +- { string12, NULL, 0007, NULL }, +- { string13, sp_quote, 0311, NULL }, +- { string14, sp_defun, 0327, doc14 }, +- { string15, sp_defvar, 0313, doc15 }, +- { string16, sp_defcode, 0307, doc16 }, +- { string17, fn_car, 0211, doc17 }, +- { string18, fn_car, 0211, NULL }, +- { string19, fn_cdr, 0211, doc19 }, +- { string20, fn_cdr, 0211, NULL }, +- { string21, fn_nth, 0222, doc21 }, +- { string22, fn_aref, 0227, doc22 }, +- { string23, fn_stringfn, 0211, doc23 }, +- { string24, fn_pinmode, 0222, doc24 }, +- { string25, fn_digitalwrite, 0222, doc25 }, +- { string26, fn_analogread, 0211, doc26 }, +- { string27, fn_analogreference, 0211, doc27 }, +- { string28, fn_register, 0212, doc28 }, +- { string29, fn_format, 0227, doc29 }, +- { string30, sp_or, 0307, doc30 }, +- { string31, sp_setq, 0327, doc31 }, +- { string32, sp_loop, 0307, doc32 }, +- { string33, sp_return, 0307, doc33 }, +- { string34, sp_push, 0322, doc34 }, +- { string35, sp_pop, 0311, doc35 }, +- { string36, sp_incf, 0312, doc36 }, +- { string37, sp_decf, 0312, doc37 }, +- { string38, sp_setf, 0327, doc38 }, +- { string39, sp_dolist, 0317, doc39 }, +- { string40, sp_dotimes, 0317, doc40 }, +- { string41, sp_trace, 0301, doc41 }, +- { string42, sp_untrace, 0301, doc42 }, +- { string43, sp_formillis, 0317, doc43 }, +- { string44, sp_time, 0311, doc44 }, +- { string45, sp_withoutputtostring, 0317, doc45 }, +- { string46, sp_withserial, 0317, doc46 }, +- { string47, sp_withi2c, 0317, doc47 }, +- { string48, sp_withspi, 0317, doc48 }, +- { string49, sp_withsdcard, 0327, doc49 }, +- { string50, tf_progn, 0107, doc50 }, +- { string51, tf_if, 0123, doc51 }, +- { string52, tf_cond, 0107, doc52 }, +- { string53, tf_when, 0117, doc53 }, +- { string54, tf_unless, 0117, doc54 }, +- { string55, tf_case, 0117, doc55 }, +- { string56, tf_and, 0107, doc56 }, +- { string57, fn_not, 0211, doc57 }, +- { string58, fn_not, 0211, NULL }, +- { string59, fn_cons, 0222, doc59 }, +- { string60, fn_atom, 0211, doc60 }, +- { string61, fn_listp, 0211, doc61 }, +- { string62, fn_consp, 0211, doc62 }, +- { string63, fn_symbolp, 0211, doc63 }, +- { string64, fn_arrayp, 0211, doc64 }, +- { string65, fn_boundp, 0211, doc65 }, +- { string66, fn_keywordp, 0211, doc66 }, +- { string67, fn_setfn, 0227, doc67 }, +- { string68, fn_streamp, 0211, doc68 }, +- { string69, fn_eq, 0222, doc69 }, +- { string70, fn_equal, 0222, doc70 }, +- { string71, fn_caar, 0211, doc71 }, +- { string72, fn_cadr, 0211, doc72 }, +- { string73, fn_cadr, 0211, NULL }, +- { string74, fn_cdar, 0211, doc74 }, +- { string75, fn_cddr, 0211, doc75 }, +- { string76, fn_caaar, 0211, doc76 }, +- { string77, fn_caadr, 0211, doc77 }, +- { string78, fn_cadar, 0211, doc78 }, +- { string79, fn_caddr, 0211, doc79 }, +- { string80, fn_caddr, 0211, NULL }, +- { string81, fn_cdaar, 0211, doc81 }, +- { string82, fn_cdadr, 0211, doc82 }, +- { string83, fn_cddar, 0211, doc83 }, +- { string84, fn_cdddr, 0211, doc84 }, +- { string85, fn_length, 0211, doc85 }, +- { string86, fn_arraydimensions, 0211, doc86 }, +- { string87, fn_list, 0207, doc87 }, +- { string88, fn_makearray, 0215, doc88 }, +- { string89, fn_reverse, 0211, doc89 }, +- { string90, fn_assoc, 0222, doc90 }, +- { string91, fn_member, 0222, doc91 }, +- { string92, fn_apply, 0227, doc92 }, +- { string93, fn_funcall, 0217, doc93 }, +- { string94, fn_append, 0207, doc94 }, +- { string95, fn_mapc, 0227, doc95 }, +- { string96, fn_mapcar, 0227, doc96 }, +- { string97, fn_mapcan, 0227, doc97 }, +- { string98, fn_add, 0207, doc98 }, +- { string99, fn_subtract, 0217, doc99 }, +- { string100, fn_multiply, 0207, doc100 }, +- { string101, fn_divide, 0217, doc101 }, +- { string102, fn_mod, 0222, doc102 }, +- { string103, fn_oneplus, 0211, doc103 }, +- { string104, fn_oneminus, 0211, doc104 }, +- { string105, fn_abs, 0211, doc105 }, +- { string106, fn_random, 0211, doc106 }, +- { string107, fn_maxfn, 0217, doc107 }, +- { string108, fn_minfn, 0217, doc108 }, +- { string109, fn_noteq, 0217, doc109 }, +- { string110, fn_numeq, 0217, doc110 }, +- { string111, fn_less, 0217, doc111 }, +- { string112, fn_lesseq, 0217, doc112 }, +- { string113, fn_greater, 0217, doc113 }, +- { string114, fn_greatereq, 0217, doc114 }, +- { string115, fn_plusp, 0211, doc115 }, +- { string116, fn_minusp, 0211, doc116 }, +- { string117, fn_zerop, 0211, doc117 }, +- { string118, fn_oddp, 0211, doc118 }, +- { string119, fn_evenp, 0211, doc119 }, +- { string120, fn_integerp, 0211, doc120 }, +- { string121, fn_numberp, 0211, doc121 }, +- { string122, fn_floatfn, 0211, doc122 }, +- { string123, fn_floatp, 0211, doc123 }, +- { string124, fn_sin, 0211, doc124 }, +- { string125, fn_cos, 0211, doc125 }, +- { string126, fn_tan, 0211, doc126 }, +- { string127, fn_asin, 0211, doc127 }, +- { string128, fn_acos, 0211, doc128 }, +- { string129, fn_atan, 0212, doc129 }, +- { string130, fn_sinh, 0211, doc130 }, +- { string131, fn_cosh, 0211, doc131 }, +- { string132, fn_tanh, 0211, doc132 }, +- { string133, fn_exp, 0211, doc133 }, +- { string134, fn_sqrt, 0211, doc134 }, +- { string135, fn_log, 0212, doc135 }, +- { string136, fn_expt, 0222, doc136 }, +- { string137, fn_ceiling, 0212, doc137 }, +- { string138, fn_floor, 0212, doc138 }, +- { string139, fn_truncate, 0212, doc139 }, +- { string140, fn_round, 0212, doc140 }, +- { string141, fn_char, 0222, doc141 }, +- { string142, fn_charcode, 0211, doc142 }, +- { string143, fn_codechar, 0211, doc143 }, +- { string144, fn_characterp, 0211, doc144 }, +- { string145, fn_stringp, 0211, doc145 }, +- { string146, fn_stringeq, 0222, doc146 }, +- { string147, fn_stringless, 0222, doc147 }, +- { string148, fn_stringgreater, 0222, doc148 }, +- { string149, fn_sort, 0222, doc149 }, +- { string150, fn_concatenate, 0217, doc150 }, +- { string151, fn_subseq, 0223, doc151 }, +- { string152, fn_search, 0222, doc152 }, +- { string153, fn_readfromstring, 0211, doc153 }, +- { string154, fn_princtostring, 0211, doc154 }, +- { string155, fn_prin1tostring, 0211, doc155 }, +- { string156, fn_logand, 0207, doc156 }, +- { string157, fn_logior, 0207, doc157 }, +- { string158, fn_logxor, 0207, doc158 }, +- { string159, fn_lognot, 0211, doc159 }, +- { string160, fn_ash, 0222, doc160 }, +- { string161, fn_logbitp, 0222, doc161 }, +- { string162, fn_eval, 0211, doc162 }, +- { string163, fn_globals, 0200, doc163 }, +- { string164, fn_locals, 0200, doc164 }, +- { string165, fn_makunbound, 0211, doc165 }, +- { string166, fn_break, 0200, doc166 }, +- { string167, fn_read, 0201, doc167 }, +- { string168, fn_prin1, 0212, doc168 }, +- { string169, fn_print, 0212, doc169 }, +- { string170, fn_princ, 0212, doc170 }, +- { string171, fn_terpri, 0201, doc171 }, +- { string172, fn_readbyte, 0202, doc172 }, +- { string173, fn_readline, 0201, doc173 }, +- { string174, fn_writebyte, 0212, doc174 }, +- { string175, fn_writestring, 0212, doc175 }, +- { string176, fn_writeline, 0212, doc176 }, +- { string177, fn_restarti2c, 0212, doc177 }, +- { string178, fn_gc, 0200, doc178 }, +- { string179, fn_room, 0200, doc179 }, +- { string180, fn_saveimage, 0201, doc180 }, +- { string181, fn_loadimage, 0201, doc181 }, +- { string182, fn_cls, 0200, doc182 }, +- { string183, fn_digitalread, 0211, doc183 }, +- { string184, fn_analogreadresolution, 0211, doc184 }, +- { string185, fn_analogwrite, 0222, doc185 }, +- { string186, fn_analogwriteresolution, 0211, doc186 }, +- { string187, fn_delay, 0211, doc187 }, +- { string188, fn_millis, 0200, doc188 }, +- { string189, fn_sleep, 0201, doc189 }, +- { string190, fn_note, 0203, doc190 }, +- { string191, fn_edit, 0211, doc191 }, +- { string192, fn_pprint, 0212, doc192 }, +- { string193, fn_pprintall, 0201, doc193 }, +- { string194, fn_require, 0211, doc194 }, +- { string195, fn_listlibrary, 0200, doc195 }, +- { string196, sp_help, 0311, doc196 }, +- { string197, fn_documentation, 0212, doc197 }, +- { string198, fn_apropos, 0211, doc198 }, +- { string199, fn_aproposlist, 0211, doc199 }, +- { string200, sp_unwindprotect, 0307, doc200 }, +- { string201, sp_ignoreerrors, 0307, doc201 }, +- { string202, sp_error, 0317, doc202 }, +- { string203, sp_withclient, 0312, doc203 }, +- { string204, fn_available, 0211, doc204 }, +- { string205, fn_wifiserver, 0200, doc205 }, +- { string206, fn_wifisoftap, 0204, doc206 }, +- { string207, fn_connected, 0211, doc207 }, +- { string208, fn_wifilocalip, 0200, doc208 }, +- { string209, fn_wificonnect, 0203, doc209 }, +- { string210, sp_withgfx, 0317, doc210 }, +- { string211, fn_drawpixel, 0223, doc211 }, +- { string212, fn_drawline, 0245, doc212 }, +- { string213, fn_drawrect, 0245, doc213 }, +- { string214, fn_fillrect, 0245, doc214 }, +- { string215, fn_drawcircle, 0234, doc215 }, +- { string216, fn_fillcircle, 0234, doc216 }, +- { string217, fn_drawroundrect, 0256, doc217 }, +- { string218, fn_fillroundrect, 0256, doc218 }, +- { string219, fn_drawtriangle, 0267, doc219 }, +- { string220, fn_filltriangle, 0267, doc220 }, +- { string221, fn_drawchar, 0236, doc221 }, +- { string222, fn_setcursor, 0222, doc222 }, +- { string223, fn_settextcolor, 0212, doc223 }, +- { string224, fn_settextsize, 0211, doc224 }, +- { string225, fn_settextwrap, 0211, doc225 }, +- { string226, fn_fillscreen, 0201, doc226 }, +- { string227, fn_setrotation, 0211, doc227 }, +- { string228, fn_invertdisplay, 0211, doc228 }, +- { string229, (fn_ptr_type)LED_BUILTIN, 0, NULL }, +- { string230, (fn_ptr_type)HIGH, DIGITALWRITE, NULL }, +- { string231, (fn_ptr_type)LOW, DIGITALWRITE, NULL }, +-#if defined(CPU_ATSAMD21) +- { string232, (fn_ptr_type)INPUT, PINMODE, NULL }, +- { string233, (fn_ptr_type)INPUT_PULLUP, PINMODE, NULL }, +- { string234, (fn_ptr_type)INPUT_PULLDOWN, PINMODE, NULL }, +- { string235, (fn_ptr_type)OUTPUT, PINMODE, NULL }, +- { string236, (fn_ptr_type)AR_DEFAULT, ANALOGREFERENCE, NULL }, +- { string237, (fn_ptr_type)AR_INTERNAL1V0, ANALOGREFERENCE, NULL }, +- { string238, (fn_ptr_type)AR_INTERNAL1V65, ANALOGREFERENCE, NULL }, +- { string239, (fn_ptr_type)AR_INTERNAL2V23, ANALOGREFERENCE, NULL }, +- { string240, (fn_ptr_type)AR_EXTERNAL, ANALOGREFERENCE, NULL }, +- { string241, (fn_ptr_type)&PORT->Group[0].DIR.reg, REGISTER, NULL }, +- { string242, (fn_ptr_type)&PORT->Group[0].DIRCLR.reg, REGISTER, NULL }, +- { string243, (fn_ptr_type)&PORT->Group[0].DIRSET.reg, REGISTER, NULL }, +- { string244, (fn_ptr_type)&PORT->Group[0].DIRTGL.reg, REGISTER, NULL }, +- { string245, (fn_ptr_type)&PORT->Group[0].OUT.reg, REGISTER, NULL }, +- { string246, (fn_ptr_type)&PORT->Group[0].OUTCLR.reg, REGISTER, NULL }, +- { string247, (fn_ptr_type)&PORT->Group[0].OUTSET.reg, REGISTER, NULL }, +- { string248, (fn_ptr_type)&PORT->Group[0].OUTTGL.reg, REGISTER, NULL }, +- { string249, (fn_ptr_type)&PORT->Group[0].IN.reg, REGISTER, NULL }, +- { string250, (fn_ptr_type)&PORT->Group[1].DIR.reg, REGISTER, NULL }, +- { string251, (fn_ptr_type)&PORT->Group[1].DIRCLR.reg, REGISTER, NULL }, +- { string252, (fn_ptr_type)&PORT->Group[1].DIRSET.reg, REGISTER, NULL }, +- { string253, (fn_ptr_type)&PORT->Group[1].DIRTGL.reg, REGISTER, NULL }, +- { string254, (fn_ptr_type)&PORT->Group[1].OUT.reg, REGISTER, NULL }, +- { string255, (fn_ptr_type)&PORT->Group[1].OUTCLR.reg, REGISTER, NULL }, +- { string256, (fn_ptr_type)&PORT->Group[1].OUTSET.reg, REGISTER, NULL }, +- { string257, (fn_ptr_type)&PORT->Group[1].OUTTGL.reg, REGISTER, NULL }, +- { string258, (fn_ptr_type)&PORT->Group[1].IN.reg, REGISTER, NULL }, +-#elif defined(CPU_ATSAMD51) +- { string232, (fn_ptr_type)INPUT, PINMODE, NULL }, +- { string233, (fn_ptr_type)INPUT_PULLUP, PINMODE, NULL }, +- { string234, (fn_ptr_type)INPUT_PULLDOWN, PINMODE, NULL }, +- { string235, (fn_ptr_type)OUTPUT, PINMODE, NULL }, +- { string236, (fn_ptr_type)AR_DEFAULT, ANALOGREFERENCE, NULL }, +- { string237, (fn_ptr_type)AR_INTERNAL1V0, ANALOGREFERENCE, NULL }, +- { string238, (fn_ptr_type)AR_INTERNAL1V1, ANALOGREFERENCE, NULL }, +- { string239, (fn_ptr_type)AR_INTERNAL1V2, ANALOGREFERENCE, NULL }, +- { string240, (fn_ptr_type)AR_INTERNAL1V25, ANALOGREFERENCE, NULL }, +- { string241, (fn_ptr_type)AR_INTERNAL1V65, ANALOGREFERENCE, NULL }, +- { string242, (fn_ptr_type)AR_INTERNAL2V0, ANALOGREFERENCE, NULL }, +- { string243, (fn_ptr_type)AR_INTERNAL2V2, ANALOGREFERENCE, NULL }, +- { string244, (fn_ptr_type)AR_INTERNAL2V23, ANALOGREFERENCE, NULL }, +- { string245, (fn_ptr_type)AR_INTERNAL2V4, ANALOGREFERENCE, NULL }, +- { string246, (fn_ptr_type)AR_INTERNAL2V5, ANALOGREFERENCE, NULL }, +- { string247, (fn_ptr_type)AR_EXTERNAL, ANALOGREFERENCE, NULL }, +- { string248, (fn_ptr_type)&PORT->Group[0].DIR.reg, REGISTER, NULL }, +- { string249, (fn_ptr_type)&PORT->Group[0].DIRCLR.reg, REGISTER, NULL }, +- { string250, (fn_ptr_type)&PORT->Group[0].DIRSET.reg, REGISTER, NULL }, +- { string251, (fn_ptr_type)&PORT->Group[0].DIRTGL.reg, REGISTER, NULL }, +- { string252, (fn_ptr_type)&PORT->Group[0].OUT.reg, REGISTER, NULL }, +- { string253, (fn_ptr_type)&PORT->Group[0].OUTCLR.reg, REGISTER, NULL }, +- { string254, (fn_ptr_type)&PORT->Group[0].OUTSET.reg, REGISTER, NULL }, +- { string255, (fn_ptr_type)&PORT->Group[0].OUTTGL.reg, REGISTER, NULL }, +- { string256, (fn_ptr_type)&PORT->Group[0].IN.reg, REGISTER, NULL }, +- { string257, (fn_ptr_type)&PORT->Group[1].DIR.reg, REGISTER, NULL }, +- { string258, (fn_ptr_type)&PORT->Group[1].DIRCLR.reg, REGISTER, NULL }, +- { string259, (fn_ptr_type)&PORT->Group[1].DIRSET.reg, REGISTER, NULL }, +- { string260, (fn_ptr_type)&PORT->Group[1].DIRTGL.reg, REGISTER, NULL }, +- { string261, (fn_ptr_type)&PORT->Group[1].OUT.reg, REGISTER, NULL }, +- { string262, (fn_ptr_type)&PORT->Group[1].OUTCLR.reg, REGISTER, NULL }, +- { string263, (fn_ptr_type)&PORT->Group[1].OUTSET.reg, REGISTER, NULL }, +- { string264, (fn_ptr_type)&PORT->Group[1].OUTTGL.reg, REGISTER, NULL }, +- { string265, (fn_ptr_type)&PORT->Group[1].IN.reg, REGISTER, NULL }, +-#elif defined(CPU_NRF51822) +- { string232, (fn_ptr_type)INPUT, PINMODE, NULL }, +- { string233, (fn_ptr_type)INPUT_PULLUP, PINMODE, NULL }, +- { string234, (fn_ptr_type)INPUT_PULLDOWN, PINMODE, NULL }, +- { string235, (fn_ptr_type)OUTPUT, PINMODE, NULL }, +- { string236, (fn_ptr_type)AR_DEFAULT, ANALOGREFERENCE, NULL }, +- { string237, (fn_ptr_type)AR_VBG, ANALOGREFERENCE, NULL }, +- { string238, (fn_ptr_type)AR_SUPPLY_ONE_HALF, ANALOGREFERENCE, NULL }, +- { string239, (fn_ptr_type)AR_SUPPLY_ONE_THIRD, ANALOGREFERENCE, NULL }, +- { string240, (fn_ptr_type)AR_EXT0, ANALOGREFERENCE, NULL }, +- { string241, (fn_ptr_type)AR_EXT1, ANALOGREFERENCE, NULL }, +- { string242, (fn_ptr_type)&NRF_GPIO->OUT, REGISTER, NULL }, +- { string243, (fn_ptr_type)&NRF_GPIO->OUTSET, REGISTER, NULL }, +- { string244, (fn_ptr_type)&NRF_GPIO->OUTCLR, REGISTER, NULL }, +- { string245, (fn_ptr_type)&NRF_GPIO->IN, REGISTER, NULL }, +- { string246, (fn_ptr_type)&NRF_GPIO->DIR, REGISTER, NULL }, +- { string247, (fn_ptr_type)&NRF_GPIO->DIRSET, REGISTER, NULL }, +- { string248, (fn_ptr_type)&NRF_GPIO->DIRCLR, REGISTER, NULL }, +-#elif defined(CPU_NRF52840) +- { string232, (fn_ptr_type)INPUT, PINMODE, NULL }, +- { string233, (fn_ptr_type)INPUT_PULLUP, PINMODE, NULL }, +- { string234, (fn_ptr_type)INPUT_PULLDOWN, PINMODE, NULL }, +- { string235, (fn_ptr_type)OUTPUT, PINMODE, NULL }, +- { string236, (fn_ptr_type)AR_DEFAULT, ANALOGREFERENCE, NULL }, +- { string237, (fn_ptr_type)AR_INTERNAL, ANALOGREFERENCE, NULL }, +- { string238, (fn_ptr_type)AR_INTERNAL_3_0, ANALOGREFERENCE, NULL }, +- { string239, (fn_ptr_type)AR_INTERNAL_2_4, ANALOGREFERENCE, NULL }, +- { string240, (fn_ptr_type)AR_INTERNAL_1_8, ANALOGREFERENCE, NULL }, +- { string241, (fn_ptr_type)AR_INTERNAL_1_2, ANALOGREFERENCE, NULL }, +- { string242, (fn_ptr_type)AR_VDD4, ANALOGREFERENCE, NULL }, +- { string243, (fn_ptr_type)&NRF_P0->OUT, REGISTER, NULL }, +- { string244, (fn_ptr_type)&NRF_P0->OUTSET, REGISTER, NULL }, +- { string245, (fn_ptr_type)&NRF_P0->OUTCLR, REGISTER, NULL }, +- { string246, (fn_ptr_type)&NRF_P0->IN, REGISTER, NULL }, +- { string247, (fn_ptr_type)&NRF_P0->DIR, REGISTER, NULL }, +- { string248, (fn_ptr_type)&NRF_P0->DIRSET, REGISTER, NULL }, +- { string249, (fn_ptr_type)&NRF_P0->DIRCLR, REGISTER, NULL }, +- { string250, (fn_ptr_type)&NRF_P1->OUT, REGISTER, NULL }, +- { string251, (fn_ptr_type)&NRF_P1->OUTSET, REGISTER, NULL }, +- { string252, (fn_ptr_type)&NRF_P1->OUTCLR, REGISTER, NULL }, +- { string253, (fn_ptr_type)&NRF_P1->IN, REGISTER, NULL }, +- { string254, (fn_ptr_type)&NRF_P1->DIR, REGISTER, NULL }, +- { string255, (fn_ptr_type)&NRF_P1->DIRSET, REGISTER, NULL }, +- { string256, (fn_ptr_type)&NRF_P1->DIRCLR, REGISTER, NULL }, +-#elif defined(CPU_NRF52833) +- { string232, (fn_ptr_type)INPUT, PINMODE, NULL }, +- { string233, (fn_ptr_type)INPUT_PULLUP, PINMODE, NULL }, +- { string234, (fn_ptr_type)INPUT_PULLDOWN, PINMODE, NULL }, +- { string235, (fn_ptr_type)OUTPUT, PINMODE, NULL }, +- { string236, (fn_ptr_type)AR_DEFAULT, ANALOGREFERENCE, NULL }, +- { string237, (fn_ptr_type)AR_INTERNAL, ANALOGREFERENCE, NULL }, +- { string238, (fn_ptr_type)AR_VDD4, ANALOGREFERENCE, NULL }, +- { string239, (fn_ptr_type)&NRF_P0->OUT, REGISTER, NULL }, +- { string240, (fn_ptr_type)&NRF_P0->OUTSET, REGISTER, NULL }, +- { string241, (fn_ptr_type)&NRF_P0->OUTCLR, REGISTER, NULL }, +- { string242, (fn_ptr_type)&NRF_P0->IN, REGISTER, NULL }, +- { string243, (fn_ptr_type)&NRF_P0->DIR, REGISTER, NULL }, +- { string244, (fn_ptr_type)&NRF_P0->DIRSET, REGISTER, NULL }, +- { string245, (fn_ptr_type)&NRF_P0->DIRCLR, REGISTER, NULL }, +- { string246, (fn_ptr_type)&NRF_P1->OUT, REGISTER, NULL }, +- { string247, (fn_ptr_type)&NRF_P1->OUTSET, REGISTER, NULL }, +- { string248, (fn_ptr_type)&NRF_P1->OUTCLR, REGISTER, NULL }, +- { string249, (fn_ptr_type)&NRF_P1->IN, REGISTER, NULL }, +- { string250, (fn_ptr_type)&NRF_P1->DIR, REGISTER, NULL }, +- { string251, (fn_ptr_type)&NRF_P1->DIRSET, REGISTER, NULL }, +- { string252, (fn_ptr_type)&NRF_P1->DIRCLR, REGISTER, NULL }, +-#elif defined(CPU_iMXRT1062) +- { string232, (fn_ptr_type)INPUT, PINMODE, NULL }, +- { string233, (fn_ptr_type)INPUT_PULLUP, PINMODE, NULL }, +- { string234, (fn_ptr_type)INPUT_PULLDOWN, PINMODE, NULL }, +- { string235, (fn_ptr_type)OUTPUT, PINMODE, NULL }, +- { string236, (fn_ptr_type)OUTPUT_OPENDRAIN, PINMODE, NULL }, +-#elif defined(CPU_MAX32620) +- { string232, (fn_ptr_type)INPUT, PINMODE, NULL }, +- { string233, (fn_ptr_type)INPUT_PULLUP, PINMODE, NULL }, +- { string234, (fn_ptr_type)OUTPUT, PINMODE, NULL }, +- { string235, (fn_ptr_type)DEFAULT, ANALOGREFERENCE, NULL }, +- { string236, (fn_ptr_type)EXTERNAL, ANALOGREFERENCE, NULL }, +-#elif defined(CPU_RP2040) +- { string232, (fn_ptr_type)INPUT, PINMODE, NULL }, +- { string233, (fn_ptr_type)INPUT_PULLUP, PINMODE, NULL }, +- { string234, (fn_ptr_type)INPUT_PULLDOWN, PINMODE, NULL }, +- { string235, (fn_ptr_type)OUTPUT, PINMODE, NULL }, +- { string236, (fn_ptr_type)(SIO_BASE+SIO_GPIO_IN_OFFSET), REGISTER, NULL }, +- { string237, (fn_ptr_type)(SIO_BASE+SIO_GPIO_OUT_OFFSET), REGISTER, NULL }, +- { string238, (fn_ptr_type)(SIO_BASE+SIO_GPIO_OUT_SET_OFFSET), REGISTER, NULL }, +- { string239, (fn_ptr_type)(SIO_BASE+SIO_GPIO_OUT_CLR_OFFSET), REGISTER, NULL }, +- { string240, (fn_ptr_type)(SIO_BASE+SIO_GPIO_OUT_XOR_OFFSET), REGISTER, NULL }, +- { string241, (fn_ptr_type)(SIO_BASE+SIO_GPIO_OE_OFFSET), REGISTER, NULL }, +- { string242, (fn_ptr_type)(SIO_BASE+SIO_GPIO_OE_SET_OFFSET), REGISTER, NULL }, +- { string243, (fn_ptr_type)(SIO_BASE+SIO_GPIO_OE_CLR_OFFSET), REGISTER, NULL }, +- { string244, (fn_ptr_type)(SIO_BASE+SIO_GPIO_OE_XOR_OFFSET), REGISTER, NULL }, +-#endif +-}; +- +-#if !defined(extensions) +-// Table cross-reference functions +- +-tbl_entry_t *tables[] = {lookup_table, NULL}; +-const unsigned int tablesizes[] = { arraysize(lookup_table), 0 }; +- +-const tbl_entry_t *table (int n) { +- return tables[n]; +-} +- +-unsigned int tablesize (int n) { +- return tablesizes[n]; +-} +-#endif +- +-// Table lookup functions +- +-/* +- lookupbuiltin - looks up a string in lookup_table[], and returns the index of its entry, +- or ENDFUNCTIONS if no match is found +-*/ +-builtin_t lookupbuiltin (char* c) { +- unsigned int end = 0, start; +- for (int n=0; n<2; n++) { +- start = end; +- int entries = tablesize(n); +- end = end + entries; +- for (int i=0; i> 3) & 0x07)) error2(toofewargs); +- if ((minmax & 0x07) != 0x07 && nargs>(minmax & 0x07)) error2(toomanyargs); +-} +- +-/* +- lookupdoc - looks up the documentation string for the built-in function name +-*/ +-char *lookupdoc (builtin_t name) { +- int n = namename))) return false; +- builtin_t name = builtin(obj->name); +- int n = name>4) gc(form, env); // GC when 1/16 of workspace left +- // Escape +- if (tstflag(ESCAPE)) { clrflag(ESCAPE); error2(PSTR("escape!"));} +- if (!tstflag(NOESC)) testescape(); +- +- if (form == NULL) return nil; +- +- if (form->type >= NUMBER && form->type <= STRING) return form; +- +- if (symbolp(form)) { +- symbol_t name = form->name; +- object *pair = value(name, env); +- if (pair != NULL) return cdr(pair); +- pair = value(name, GlobalEnv); +- if (pair != NULL) return cdr(pair); +- else if (builtinp(name)) return form; +- Context = NIL; +- error(PSTR("undefined"), form); +- } +- +- #if defined(CODESIZE) +- if (form->type == CODE) error2(PSTR("can't evaluate CODE header")); +- #endif +- +- // It's a list +- object *function = car(form); +- object *args = cdr(form); +- +- if (function == NULL) error(PSTR("illegal function"), nil); +- if (!listp(args)) error(PSTR("can't evaluate a dotted pair"), args); +- +- // List starts with a builtin symbol? +- if (symbolp(function) && builtinp(function->name)) { +- builtin_t name = builtin(function->name); +- +- if ((name == LET) || (name == LETSTAR)) { +- int TCstart = TC; +- if (args == NULL) error2(noargument); +- object *assigns = first(args); +- if (!listp(assigns)) error(notalist, assigns); +- object *forms = cdr(args); +- object *newenv = env; +- push(newenv, GCStack); +- while (assigns != NULL) { +- object *assign = car(assigns); +- if (!consp(assign)) push(cons(assign,nil), newenv); +- else if (cdr(assign) == NULL) push(cons(first(assign),nil), newenv); +- else push(cons(first(assign),eval(second(assign),env)), newenv); +- car(GCStack) = newenv; +- if (name == LETSTAR) env = newenv; +- assigns = cdr(assigns); +- } +- env = newenv; +- pop(GCStack); +- form = tf_progn(forms,env); +- TC = TCstart; +- goto EVAL; +- } +- +- if (name == LAMBDA) { +- if (env == NULL) return form; +- object *envcopy = NULL; +- while (env != NULL) { +- object *pair = first(env); +- if (pair != NULL) push(pair, envcopy); +- env = cdr(env); +- } +- return cons(bsymbol(CLOSURE), cons(envcopy,args)); +- } +- uint8_t fntype = getminmax(name)>>6; +- +- if (fntype == SPECIAL_FORMS) { +- Context = name; +- return ((fn_ptr_type)lookupfn(name))(args, env); +- } +- +- if (fntype == TAIL_FORMS) { +- Context = name; +- form = ((fn_ptr_type)lookupfn(name))(args, env); +- TC = 1; +- goto EVAL; +- } +- if (fntype == OTHER_FORMS) error(PSTR("can't be used as a function"), function); +- } +- +- // Evaluate the parameters - result in head +- object *fname = car(form); +- int TCstart = TC; +- object *head = cons(eval(fname, env), NULL); +- push(head, GCStack); // Don't GC the result list +- object *tail = head; +- form = cdr(form); +- int nargs = 0; +- +- while (form != NULL){ +- object *obj = cons(eval(car(form),env),NULL); +- cdr(tail) = obj; +- tail = obj; +- form = cdr(form); +- nargs++; +- } +- +- function = car(head); +- args = cdr(head); +- +- if (symbolp(function)) { +- builtin_t bname = builtin(function->name); +- if (!builtinp(function->name)) error(PSTR("not valid here"), fname); +- Context = bname; +- checkminmax(bname, nargs); +- object *result = ((fn_ptr_type)lookupfn(bname))(args, env); +- pop(GCStack); +- return result; +- } +- +- if (consp(function)) { +- symbol_t name = sym(NIL); +- if (!listp(fname)) name = fname->name; +- +- if (isbuiltin(car(function), LAMBDA)) { +- form = closure(TCstart, name, function, args, &env); +- pop(GCStack); +- int trace = tracing(fname->name); +- if (trace) { +- object *result = eval(form, env); +- indent((--(TraceDepth[trace-1]))<<1, ' ', pserial); +- pint(TraceDepth[trace-1], pserial); +- pserial(':'); pserial(' '); +- printobject(fname, pserial); pfstring(PSTR(" returned "), pserial); +- printobject(result, pserial); pln(pserial); +- return result; +- } else { +- TC = 1; +- goto EVAL; +- } +- } +- +- if (isbuiltin(car(function), CLOSURE)) { +- function = cdr(function); +- form = closure(TCstart, name, function, args, &env); +- pop(GCStack); +- TC = 1; +- goto EVAL; +- } +- +- if (car(function)->type == CODE) { +- int n = listlength(second(function)); +- if (nargsname, toofewargs); +- if (nargs>n) errorsym2(fname->name, toomanyargs); +- uint32_t entry = startblock(car(function)) + 1; +- pop(GCStack); +- return call(entry, n, args, env); +- } +- +- } +- error(PSTR("illegal function"), fname); return nil; +-} +- +-// Print functions +- +-/* +- pserial - prints a character to the serial port +-*/ +-void pserial (char c) { +- LastPrint = c; +- if (c == '\n') Serial.write('\r'); +- Serial.write(c); +-} +- +-const char ControlCodes[] PROGMEM = "Null\0SOH\0STX\0ETX\0EOT\0ENQ\0ACK\0Bell\0Backspace\0Tab\0Newline\0VT\0" +-"Page\0Return\0SO\0SI\0DLE\0DC1\0DC2\0DC3\0DC4\0NAK\0SYN\0ETB\0CAN\0EM\0SUB\0Escape\0FS\0GS\0RS\0US\0Space\0"; +- +-/* +- pcharacter - prints a character to a stream, escaping special characters if PRINTREADABLY is false +- If <= 32 prints character name; eg #\Space +- If < 127 prints ASCII; eg #\A +- Otherwise prints decimal; eg #\234 +-*/ +-void pcharacter (uint8_t c, pfun_t pfun) { +- if (!tstflag(PRINTREADABLY)) pfun(c); +- else { +- pfun('#'); pfun('\\'); +- if (c <= 32) { +- const char *p = ControlCodes; +- while (c > 0) {p = p + strlen(p) + 1; c--; } +- pfstring(p, pfun); +- } else if (c < 127) pfun(c); +- else pint(c, pfun); +- } +-} +- +-/* +- pstring - prints a C string to the specified stream +-*/ +-void pstring (char *s, pfun_t pfun) { +- while (*s) pfun(*s++); +-} +- +-/* +- plispstring - prints a Lisp string object to the specified stream +-*/ +-void plispstring (object *form, pfun_t pfun) { +- plispstr(form->name, pfun); +-} +- +-/* +- plispstr - prints a Lisp string name to the specified stream +-*/ +-void plispstr (symbol_t name, pfun_t pfun) { +- object *form = (object *)name; +- while (form != NULL) { +- 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('\\'); +- if (ch) pfun(ch); +- } +- form = car(form); +- } +-} +- +-/* +- printstring - prints a Lisp string object to the specified stream +- taking account of the PRINTREADABLY flag +-*/ +-void printstring (object *form, pfun_t pfun) { +- if (tstflag(PRINTREADABLY)) pfun('"'); +- plispstr(form->name, pfun); +- if (tstflag(PRINTREADABLY)) pfun('"'); +-} +- +-/* +- pbuiltin - prints a built-in symbol to the specified stream +-*/ +-void pbuiltin (builtin_t name, pfun_t pfun) { +- int p = 0; +- int n = name0; d = d/40) { +- uint32_t j = x/d; +- char c = fromradix40(j); +- if (c == 0) return; +- pfun(c); x = x - j*d; +- } +-} +- +-/* +- printsymbol - prints any symbol from a symbol object to the specified stream +-*/ +-void printsymbol (object *form, pfun_t pfun) { +- psymbol(form->name, pfun); +-} +- +-/* +- psymbol - prints any symbol from a symbol name to the specified stream +-*/ +-void psymbol (symbol_t name, pfun_t pfun) { +- if ((name & 0x03) == 0) plispstr(name, pfun); +- else { +- uint32_t value = untwist(name); +- if (value < PACKEDS) error2(PSTR("invalid symbol")); +- else if (value >= BUILTINS) pbuiltin((builtin_t)(value-BUILTINS), pfun); +- else pradix40(name, pfun); +- } +-} +- +-/* +- pfstring - prints a string from flash memory to the specified stream +-*/ +-void pfstring (const char *s, pfun_t pfun) { +- int p = 0; +- while (1) { +- char c = s[p++]; +- if (c == 0) return; +- pfun(c); +- } +-} +- +-/* +- pint - prints an integer in decimal to the specified stream +-*/ +-void pint (int i, pfun_t pfun) { +- uint32_t j = i; +- if (i<0) { pfun('-'); j=-i; } +- pintbase(j, 10, pfun); +-} +- +-/* +- pintbase - prints an integer in base 'base' to the specified stream +-*/ +-void pintbase (uint32_t i, uint8_t base, pfun_t pfun) { +- int lead = 0; uint32_t p = 1000000000; +- if (base == 2) p = 0x80000000; else if (base == 16) p = 0x10000000; +- for (uint32_t d=p; d>0; d=d/base) { +- uint32_t j = i/d; +- if (j!=0 || lead || d==1) { pfun((j<10) ? j+'0' : j+'W'); lead=1;} +- i = i - j*d; +- } +-} +- +-/* +- pinthex4 - prints a four-digit hexadecimal number with leading zeros to the specified stream +-*/ +-void printhex4 (int i, pfun_t pfun) { +- int p = 0x1000; +- for (int d=p; d>0; d=d/16) { +- int j = i/d; +- pfun((j<10) ? j+'0' : j + 'W'); +- i = i - j*d; +- } +- pfun(' '); +-} +- +-/* +- pmantissa - prints the mantissa of a floating-point number to the specified stream +-*/ +-void pmantissa (float f, pfun_t pfun) { +- int sig = floor(log10(f)); +- int mul = pow(10, 5 - sig); +- int i = round(f * mul); +- bool point = false; +- if (i == 1000000) { i = 100000; sig++; } +- if (sig < 0) { +- pfun('0'); pfun('.'); point = true; +- for (int j=0; j < - sig - 1; j++) pfun('0'); +- } +- mul = 100000; +- for (int j=0; j<7; j++) { +- int d = (int)(i / mul); +- pfun(d + '0'); +- i = i - d * mul; +- if (i == 0) { +- if (!point) { +- for (int k=j; k= 0) { pfun('.'); point = true; } +- mul = mul / 10; +- } +-} +- +-/* +- pfloat - prints a floating-point number to the specified stream +-*/ +-void pfloat (float f, pfun_t pfun) { +- if (isnan(f)) { pfstring(PSTR("NaN"), pfun); return; } +- if (f == 0.0) { pfun('0'); return; } +- if (isinf(f)) { pfstring(PSTR("Inf"), pfun); return; } +- if (f < 0) { pfun('-'); f = -f; } +- // Calculate exponent +- int e = 0; +- if (f < 1e-3 || f >= 1e5) { +- e = floor(log(f) / 2.302585); // log10 gives wrong result +- f = f / pow(10, e); +- } +- +- pmantissa (f, pfun); +- +- // Exponent +- if (e != 0) { +- pfun('e'); +- pint(e, pfun); +- } +-} +- +-/* +- pln - prints a newline to the specified stream +-*/ +-inline void pln (pfun_t pfun) { +- pfun('\n'); +-} +- +-/* +- pfl - prints a newline to the specified stream if a newline has not just been printed +-*/ +-void pfl (pfun_t pfun) { +- if (LastPrint != '\n') pfun('\n'); +-} +- +-/* +- plist - prints a list to the specified stream +-*/ +-void plist (object *form, pfun_t pfun) { +- pfun('('); +- printobject(car(form), pfun); +- form = cdr(form); +- while (form != NULL && listp(form)) { +- pfun(' '); +- printobject(car(form), pfun); +- form = cdr(form); +- } +- if (form != NULL) { +- pfstring(PSTR(" . "), pfun); +- printobject(form, pfun); +- } +- pfun(')'); +-} +- +-/* +- pstream - prints a stream name to the specified stream +-*/ +-void pstream (object *form, pfun_t pfun) { +- pfun('<'); +- pfstring(streamname[(form->integer)>>8], pfun); +- pfstring(PSTR("-stream "), pfun); +- pint(form->integer & 0xFF, pfun); +- pfun('>'); +-} +- +-/* +- printobject - prints any Lisp object to the specified stream +-*/ +-void printobject (object *form, pfun_t pfun) { +- if (form == NULL) pfstring(PSTR("nil"), pfun); +- else if (listp(form) && isbuiltin(car(form), CLOSURE)) pfstring(PSTR(""), pfun); +- else if (listp(form)) plist(form, 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 != sym(NOTHING)) printsymbol(form, 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)) pstream(form, pfun); +- else error2(PSTR("error in print")); +-} +- +-/* +- prin1object - prints any Lisp object to the specified stream escaping special characters +-*/ +-void prin1object (object *form, pfun_t pfun) { +- char temp = Flags; +- clrflag(PRINTREADABLY); +- printobject(form, pfun); +- Flags = temp; +-} +- +-// Read functions +- +-/* +- glibrary - reads a character from the Lisp Library +-*/ +-int glibrary () { +- if (LastChar) { +- char temp = LastChar; +- LastChar = 0; +- return temp; +- } +- char c = LispLibrary[GlobalStringIndex++]; +- return (c != 0) ? c : -1; // -1? +-} +- +-/* +- loadfromlibrary - reads and evaluates a form from the Lisp Library +-*/ +-void loadfromlibrary (object *env) { +- GlobalStringIndex = 0; +- object *line = read(glibrary); +- while (line != NULL) { +- push(line, GCStack); +- eval(line, env); +- pop(GCStack); +- line = read(glibrary); +- } +-} +- +-// 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'); +-} +- +-/* +- Highlight - handles parenthesis highlighting with the line editor +-*/ +-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'); +- } +-} +- +-/* +- processkey - handles keys in the line editor +-*/ +-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; +-} +- +-/* +- gserial - gets a character from the serial port +-*/ +-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 +- unsigned long start = millis(); +- while (!Serial.available()) if (millis() - start > 1000) clrflag(NOECHO); +- char temp = Serial.read(); +- if (temp != '\n' && !tstflag(NOECHO)) pserial(temp); +- return temp; +-#endif +-} +- +-/* +- nextitem - reads the next token from the specified stream +-*/ +-object *nextitem (gfun_t gfun) { +- int ch = gfun(); +- while(issp(ch)) ch = gfun(); +- +- if (ch == ';') { +- do { ch = gfun(); if (ch == ';' || ch == '(') setflag(NOECHO); } +- while(ch != '('); +- } +- if (ch == '\n') ch = gfun(); +- if (ch == -1) return nil; +- if (ch == ')') return (object *)KET; +- if (ch == '(') return (object *)BRA; +- if (ch == '\'') return (object *)QUO; +- +- // Parse string +- if (ch == '"') return readstring('"', gfun); +- +- // Parse symbol, character, or number +- int index = 0, base = 10, sign = 1; +- char buffer[BUFFERSIZE]; +- int bufmax = BUFFERSIZE-3; // Max index +- unsigned int result = 0; +- bool isfloat = false; +- float fresult = 0.0; +- +- if (ch == '+') { +- buffer[index++] = ch; +- ch = gfun(); +- } else if (ch == '-') { +- sign = -1; +- buffer[index++] = ch; +- ch = gfun(); +- } else if (ch == '.') { +- buffer[index++] = ch; +- ch = gfun(); +- if (ch == ' ') return (object *)DOT; +- isfloat = true; +- } +- +- // Parse reader macros +- else if (ch == '#') { +- ch = gfun(); +- char ch2 = ch & ~0x20; // force to upper case +- if (ch == '\\') { // Character +- base = 0; ch = gfun(); +- if (issp(ch) || isbr(ch)) return character(ch); +- else LastChar = ch; +- } else if (ch == '|') { +- do { while (gfun() != '|'); } +- while (gfun() != '#'); +- return nextitem(gfun); +- } else if (ch2 == 'B') base = 2; +- else if (ch2 == 'O') base = 8; +- else if (ch2 == 'X') base = 16; +- else if (ch == '\'') return nextitem(gfun); +- else if (ch == '.') { +- setflag(NOESC); +- object *result = eval(read(gfun), NULL); +- clrflag(NOESC); +- return result; +- } +- else if (ch == '(') { LastChar = ch; return readarray(1, read(gfun)); } +- else if (ch == '*') return readbitarray(gfun); +- else if (ch >= '1' && ch <= '9' && (gfun() & ~0x20) == 'A') return readarray(ch - '0', read(gfun)); +- else error2(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); +- return number(result*sign); +- } else if (base == 0) { +- if (index == 1) return character(buffer[0]); +- const char* p = ControlCodes; char c = 0; +- while (c < 33) { +- if (strcasecmp(buffer, p) == 0) return character(c); +- p = p + strlen(p) + 1; c++; +- } +- if (index == 3) return character((buffer[0]*10+buffer[1])*10+buffer[2]-5328); +- error2(PSTR("unknown character")); +- } +- +- builtin_t x = lookupbuiltin(buffer); +- if (x == NIL) return nil; +- if (x != ENDFUNCTIONS) return bsymbol(x); +- if (index <= 6 && valid40(buffer)) return intern(twist(pack40(buffer))); +- return internlong(buffer); +-} +- +-/* +- readrest - reads the remaining tokens from the specified stream +-*/ +-object *readrest (gfun_t gfun) { +- object *item = nextitem(gfun); +- object *head = NULL; +- object *tail = NULL; +- +- while (item != (object *)KET) { +- if (item == (object *)BRA) { +- item = readrest(gfun); +- } else if (item == (object *)QUO) { +- item = cons(bsymbol(QUOTE), cons(read(gfun), NULL)); +- } else if (item == (object *)DOT) { +- tail->cdr = read(gfun); +- if (readrest(gfun) != NULL) error2(PSTR("malformed list")); +- return head; +- } else { +- object *cell = cons(item, NULL); +- if (head == NULL) head = cell; +- else tail->cdr = cell; +- tail = cell; +- item = nextitem(gfun); +- } +- } +- return head; +-} +- +-/* +- read - recursively reads a Lisp object from the stream gfun and returns it +-*/ +-object *read (gfun_t gfun) { +- object *item = nextitem(gfun); +- if (item == (object *)KET) error2(PSTR("incomplete list")); +- if (item == (object *)BRA) return readrest(gfun); +- if (item == (object *)DOT) return read(gfun); +- if (item == (object *)QUO) return cons(bsymbol(QUOTE), cons(read(gfun), NULL)); +- return item; +-} +- +-// Setup +- +-/* +- initenv - initialises the uLisp environment +-*/ +-void initenv () { +- GlobalEnv = NULL; +- tee = bsymbol(TEE); +-} +- +-/* +- initgfx - initialises the graphics +-*/ +-void initgfx () { +- #if defined(gfxsupport) +- #if defined(ARDUINO_PYBADGE_M4) || defined(ARDUINO_PYGAMER_M4) +- tft.initR(INITR_BLACKTAB); +- tft.setRotation(1); +- pinMode(TFT_BACKLIGHT, OUTPUT); +- digitalWrite(TFT_BACKLIGHT, HIGH); +- tft.fillScreen(0); +- #elif defined(ARDUINO_WIO_TERMINAL) +- tft.init(); +- tft.setRotation(3); +- tft.fillScreen(TFT_BLACK); +- #elif defined(ARDUINO_NRF52840_CLUE) +- tft.init(240, 240); +- tft.setRotation(1); +- tft.fillScreen(0); +- pinMode(34, OUTPUT); // Backlight +- digitalWrite(34, HIGH); +- #endif +- #endif +-} +- +-// Entry point from the Arduino IDE +-void setup () { +- Serial.begin(9600); +- int start = millis(); +- while ((millis() - start) < 5000) { if (Serial) break; } +- initworkspace(); +- initenv(); +- initsleep(); +- initgfx(); +- pfstring(PSTR("uLisp 4.4b "), pserial); pln(pserial); +-} +- +-// Read/Evaluate/Print loop +- +-/* +- repl - the Lisp Read/Evaluate/Print loop +-*/ +-void repl (object *env) { +- for (;;) { +- randomSeed(micros()); +- gc(NULL, env); +- #if defined(printfreespace) +- pint(Freespace, pserial); +- #endif +- if (BreakLevel) { +- pfstring(PSTR(" : "), pserial); +- pint(BreakLevel, pserial); +- } +- pserial('>'); pserial(' '); +- Context = NIL; +- object *line = read(gserial); +- #if defined(CPU_NRF52840) +- Serial.flush(); +- #endif +- if (BreakLevel && line == nil) { pln(pserial); return; } +- if (line == (object *)KET) error2(PSTR("unmatched right bracket")); +- push(line, GCStack); +- pfl(pserial); +- line = eval(line, env); +- pfl(pserial); +- printobject(line, pserial); +- pop(GCStack); +- pfl(pserial); +- pln(pserial); +- } +-} +- +-/* +- loop - the Arduino IDE main execution loop +-*/ +-void loop () { +- if (!setjmp(toplevel_handler)) { +- #if defined(resetautorun) +- volatile int autorun = 12; // Fudge to keep code size the same +- #else +- volatile int autorun = 13; +- #endif +- if (autorun == 12) autorunimage(); +- } +- ulispreset(); +- repl(NULL); +-} +- +-void ulispreset () { +- // Come here after error +- delay(100); while (Serial.available()) Serial.read(); +- clrflag(NOESC); BreakLevel = 0; +- for (int i=0; i + + #if defined(sdcardsupport) ++#if defined(ARDUINO_RASPBERRY_PI_PICO) ++ #include ++#endif + #include + #define SDSIZE 91 + #else +@@ -197,20 +208,38 @@ const char LispLibrary[] PROGMEM = ""; + + #elif defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_QTPY_RP2040) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || defined(ARDUINO_SEEED_XIAO_RP2040) + #define WORKSPACESIZE (22912-SDSIZE) /* Objects (8*bytes) */ +- #define LITTLEFS +- #include +- #define FILE_WRITE_BEGIN "w" +- #define FILE_READ "r" ++ ++ #if defined(sdcardsupport) ++ #define SDCARD_SS_PIN 17 ++ #else ++ #define LITTLEFS ++ #include ++ #define FILE_WRITE_BEGIN "w" ++ #define FILE_READ "r" ++ #endif ++ + #define CODESIZE 256 /* Bytes */ + #define STACKDIFF 320 + #define CPU_RP2040 + #if defined(gfxsupport) + const int COLOR_WHITE = 0xffff, COLOR_BLACK = 0; ++ /* + #include // Core graphics library + #include // Hardware-specific library for ST7789 + Adafruit_ST7789 tft = Adafruit_ST7789(5, 1, 3, 2, 0); // TTGO RP2040 TFT + #define TFT_BACKLIGHT 4 + #define TFT_I2C_POWER 22 ++ */ ++ ++ #include // Hardware-specific library ++ #if defined(CPI_PICOCALC) ++ #include ++ PCKeyboard pc_kbd; ++ TFT_eSPI tft = TFT_eSPI(320,320); ++ #else ++ TFT_eSPI tft = TFT_eSPI(); ++ #endif ++ + #endif + + #elif defined(ARDUINO_RASPBERRY_PI_PICO_W) +@@ -358,7 +387,7 @@ DIGITALWRITE, ANALOGREAD, ANALOGREFERENCE, REGISTER, FORMAT, + }; + + // Global variables +- ++HardwareSerial *chuankou;//pointer to which serial to use according the real board type + object Workspace[WORKSPACESIZE] WORDALIGNED MEMBANK; + #if defined(CODESIZE) + RAMFUNC uint8_t MyCode[CODESIZE] WORDALIGNED; +@@ -946,7 +975,18 @@ void FlashEndRead (uint32_t *addr) { + int saveimage (object *arg) { + #if defined(sdcardsupport) + unsigned int imagesize = compactimage(&arg); ++ #if defined(ARDUINO_RASPBERRY_PI_PICO) ++ #if defined(CPI_PICOCALC) ++ if(!SD.begin(SDCARD_SS_PIN, (uint32_t) SPI_HALF_SPEED, SPI)){ ++ error2(PSTR("problem init SD card")); ++ return 0; ++ } ++ #else ++ SD.begin(SDCARD_SS_PIN,(uint32_t) SPI_HALF_SPEED, SPI1); ++ #endif ++ #else + SD.begin(SDCARD_SS_PIN); ++ #endif + File file; + if (stringp(arg)) { + char buffer[BUFFERSIZE]; +@@ -969,7 +1009,7 @@ int saveimage (object *arg) { + } + file.close(); + return imagesize; +-#elif defined(LITTLEFS) ++#elif defined(LITTLEFS) && !defined(sdcardsupport) + unsigned int imagesize = compactimage(&arg); + LittleFS.begin(LITTLEFS); + File file; +@@ -1028,7 +1068,18 @@ int saveimage (object *arg) { + + int loadimage (object *arg) { + #if defined(sdcardsupport) ++ #if defined(ARDUINO_RASPBERRY_PI_PICO) ++ #if defined(CPI_PICOCALC) ++ if(!SD.begin(SDCARD_SS_PIN,(uint32_t) SPI_HALF_SPEED, SPI)){ ++ error2(PSTR("problem init SD card")); ++ return 0; ++ } ++ #else ++ SD.begin(SDCARD_SS_PIN,(uint32_t) SPI_HALF_SPEED, SPI1); ++ #endif ++ #else + SD.begin(SDCARD_SS_PIN); ++ #endif + File file; + if (stringp(arg)) { + char buffer[BUFFERSIZE]; +@@ -1109,7 +1160,18 @@ int loadimage (object *arg) { + + void autorunimage () { + #if defined(sdcardsupport) ++ #if defined(ARDUINO_RASPBERRY_PI_PICO) ++ #if defined(CPI_PICOCALC) ++ if(!SD.begin(SDCARD_SS_PIN, (uint32_t) SPI_HALF_SPEED, SPI)){ ++ error2(PSTR("problem init SD card")); ++ return; ++ } ++ #else ++ SD.begin(SDCARD_SS_PIN,(uint32_t) SPI_HALF_SPEED, SPI1); ++ #endif ++ #else + SD.begin(SDCARD_SS_PIN); ++ #endif + File file = SD.open("/ULISP.IMG"); + if (!file) error2(PSTR("problem autorunning from SD card")); + object *autorun = (object *)SDRead32(file); +@@ -2079,22 +2141,30 @@ object *mapcarcan (object *args, object *env, mapfun_t fun) { + } + } + +-// I2C interface for up to two ports, using Arduino Wire +- ++// I2C interface for up to two ports, using Arduino Wire,in picocalc,i2c0 is for keyboard + void I2Cinit (TwoWire *port, bool enablePullup) { + (void) enablePullup; ++ #if defined(ULISP_I2C1) + port->begin(); ++ #endif + } + + int I2Cread (TwoWire *port) { ++ #if defined(ULISP_I2C1) + return port->read(); ++ #else ++ return 0; ++ #endif + } + + void I2Cwrite (TwoWire *port, uint8_t data) { ++ #if defined(ULISP_I2C1) + port->write(data); ++ #endif + } + + bool I2Cstart (TwoWire *port, uint8_t address, uint8_t read) { ++#if defined(ULISP_I2C1) + int ok = true; + if (read == 0) { + port->beginTransmission(address); +@@ -2103,17 +2173,26 @@ bool I2Cstart (TwoWire *port, uint8_t address, uint8_t read) { + } + else port->requestFrom(address, I2Ccount); + return ok; ++#else ++ return false; ++#endif + } + + bool I2Crestart (TwoWire *port, uint8_t address, uint8_t read) { ++#if defined(ULISP_I2C1) + int error = (port->endTransmission(false) != 0); + if (read == 0) port->beginTransmission(address); + else port->requestFrom(address, I2Ccount); + return error ? false : true; ++#else ++ return false; ++#endif + } + + void I2Cstop (TwoWire *port, uint8_t read) { +- if (read == 0) port->endTransmission(); // Check for error? ++ #if defined(ULISP_I2C1) ++ if (read == 0) port->endTransmission(); // Check for error? ++ #endif + } + + // Streams +@@ -2128,7 +2207,8 @@ void I2Cstop (TwoWire *port, uint8_t read) { + #if defined(ARDUINO_SAM_DUE) || defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY41) || defined(ARDUINO_GRAND_CENTRAL_M4) + #define ULISP_SERIAL3 + #elif defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +-#define ULISP_SERIAL2 ++#define ULISP_SPI1 ++#define ULISP_SERIAL1 + #elif !defined(CPU_NRF51822) && !defined(CPU_NRF52833) && !defined(ARDUINO_FEATHER_F405) + #define ULISP_SERIAL1 + #endif +@@ -2189,7 +2269,14 @@ void serialbegin (int address, int baud) { + if (address == 1) Serial1.begin((long)baud*100); + else if (address == 2) Serial2.begin((long)baud*100); + #elif defined(ULISP_SERIAL1) +- if (address == 1) Serial1.begin((long)baud*100); ++ ++ #if defined(CPI_PICOCALC) ++ //waveshare use Serial1 for default ++ if (address == 1) {} ++ #else ++ if (address == 1) Serial1.begin((long)baud*100); ++ #endif ++ + #else + (void) baud; + if (false); +@@ -2206,7 +2293,11 @@ void serialend (int address) { + if (address == 1) {Serial1.flush(); Serial1.end(); } + else if (address == 2) {Serial2.flush(); Serial2.end(); } + #elif defined(ULISP_SERIAL1) +- if (address == 1) {Serial1.flush(); Serial1.end(); } ++ #if defined(CPI_PICOCALC) ++ if (address == 1) {Serial1.flush();} ++ #else ++ if (address == 1) {Serial1.flush(); Serial1.end(); } ++ #endif + #else + if (false); + #endif +@@ -2274,7 +2365,7 @@ inline void serial1write (char c) { Serial1.write(c); } + inline void serial1write (char c) { Serial1.write(c); } + #endif + #if defined(sdcardsupport) +-inline void SDwrite (char c) { SDpfile.write(c); } ++inline void SDwrite (char c) { SDpfile.write(uint8_t(c)); } + #endif + #if defined(ULISP_WIFI) + inline void WiFiwrite (char c) { client.write(c); } +@@ -3041,7 +3132,7 @@ object *sp_withserial (object *args, object *env) { + object *var = first(params); + int address = checkinteger(eval(second(params), env)); + params = cddr(params); +- int baud = 96; ++ int baud = BAUDRATE; + if (params != NULL) baud = checkinteger(eval(first(params), env)); + object *pair = cons(var, stream(SERIALSTREAM, address)); + push(pair,env); +@@ -3136,7 +3227,18 @@ object *sp_withsdcard (object *args, object *env) { + Context = temp; + if (!stringp(filename)) error(PSTR("filename is not a string"), filename); + params = cdr(params); ++ #if defined(ARDUINO_RASPBERRY_PI_PICO) ++ #if defined(CPI_PICOCALC) ++ if(!SD.begin(SDCARD_SS_PIN,(uint32_t) SPI_HALF_SPEED, SPI )){ ++ error2(PSTR("problem init SD card")); ++ return nil; ++ } ++ #else ++ SD.begin(SDCARD_SS_PIN,(uint32_t) SPI_HALF_SPEED, SPI1); ++ #endif ++ #else + SD.begin(SDCARD_SS_PIN); ++ #endif + int mode = 0; + if (params != NULL && first(params) != NULL) mode = checkinteger(first(params)); + int oflag = O_READ; +@@ -6673,7 +6775,7 @@ boolean findsubstring (char *part, builtin_t name) { + } + + void testescape () { +- if (Serial.available() && Serial.read() == '~') { error2(PSTR("escape!")); } // Context = NIL; ++ if (chuankou->available() && chuankou->read() == '~') { error2(PSTR("escape!")); } // Context = NIL; + } + + bool keywordp (object *obj) { +@@ -6700,7 +6802,7 @@ object *eval (object *form, object *env) { + int TC=0; + EVAL: + // Enough space? +- // Serial.println((uint32_t)sp - (uint32_t)&ENDSTACK); // Find best STACKDIFF value ++ // chuankou->println((uint32_t)sp - (uint32_t)&ENDSTACK); // Find best STACKDIFF value + if (((uint32_t)sp - (uint32_t)&ENDSTACK) < STACKDIFF) { Context = NIL; error2(PSTR("stack overflow")); } + if (Freespace <= WORKSPACESIZE>>4) gc(form, env); // GC when 1/16 of workspace left + // Escape +@@ -6864,8 +6966,10 @@ object *eval (object *form, object *env) { + + void pserial (char c) { + LastPrint = c; +- if (c == '\n') Serial.write('\r'); +- Serial.write(c); ++ if (!tstflag(NOECHO)) Display(c); // Don't display on T-Deck when paste in listing ++ if (c == '\n') chuankou->write('\r'); ++ chuankou->write(c); ++ + } + + const char ControlCodes[] PROGMEM = "Null\0SOH\0STX\0ETX\0EOT\0ENQ\0ACK\0Bell\0Backspace\0Tab\0Newline\0VT\0" +@@ -7106,24 +7210,34 @@ void loadfromlibrary (object *env) { + } + } + ++// PicoCalc terminal and keyboard support ++const int Columns = 53; ++const int Leading = 10; // Between 8 and 10 ++const int Lines = 320/Leading; ++const int LastColumn = Columns-1; ++const int LastLine = Lines-1; ++const char Cursor = 0x5f; ++ ++uint8_t Scroll = 0; ++ + // For line editor + const int TerminalWidth = 80; + volatile int WritePtr = 0, ReadPtr = 0, LastWritePtr = 0; +-const int KybdBufSize = 333; // 42*8 - 3 +-char KybdBuf[KybdBufSize]; ++const int KybdBufSize = Columns*Lines; ++char KybdBuf[KybdBufSize], ScrollBuf[Columns][Lines]; + 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); ++ chuankou->write('\e'); chuankou->write('['); ++ chuankou->write((char)('0'+ p/100)); ++ chuankou->write((char)('0'+ (p/10) % 10)); ++ chuankou->write((char)('0'+ p % 10)); ++ chuankou->write(c); + } + + void hilight (char c) { +- Serial.write('\e'); Serial.write('['); Serial.write(c); Serial.write('m'); ++ chuankou->write('\e'); chuankou->write('['); chuankou->write(c); chuankou->write('m'); + } + + void Highlight (int p, int wp, uint8_t invert) { +@@ -7141,11 +7255,11 @@ void Highlight (int p, int wp, uint8_t invert) { + if (up) esc(up, 'A'); + if (col > targetcol) esc(left, 'D'); else esc(-left, 'C'); + if (invert) hilight('7'); +- Serial.write('('); Serial.write('\b'); ++ chuankou->write('('); chuankou->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(')'); ++ chuankou->write('\b'); chuankou->write(')'); + if (invert) hilight('0'); + } + } +@@ -7168,7 +7282,7 @@ void processkey (char c) { + if (c == 8 || c == 0x7f) { // Backspace key + if (WritePtr > 0) { + WritePtr--; +- Serial.write(8); Serial.write(' '); Serial.write(8); ++ chuankou->write(8); chuankou->write(' '); chuankou->write(8); + if (WritePtr) c = KybdBuf[WritePtr-1]; + } + } else if (c == 9) { // tab or ctrl-I +@@ -7176,7 +7290,7 @@ void processkey (char c) { + WritePtr = LastWritePtr; + } else if (WritePtr < KybdBufSize) { + KybdBuf[WritePtr++] = c; +- Serial.write(c); ++ chuankou->write(c); + } + #if defined(vt100) + // Do new parenthesis highlight +@@ -7204,9 +7318,21 @@ int gserial () { + } + #if defined(lineeditor) + while (!KybdAvailable) { +- while (!Serial.available()); +- char temp = Serial.read(); +- processkey(temp); ++ if(chuankou->available()){ ++ char temp = chuankou->read(); ++ processkey(temp); ++ } ++ #if defined(i2ckbd) ++ if(pc_kbd.keyCount() > 0){ ++ const PCKeyboard::KeyEvent key = pc_kbd.keyEvent(); ++ if (key.state == PCKeyboard::StatePress) { ++ char temp = key.key; ++ if ((temp != 0) && (temp !=255) && (temp != 0xA1) && (temp != 0xA2) && (temp != 0xA3) && (temp != 0xA4) && (temp != 0xA5)) { ++ ProcessKey(temp); ++ } ++ } ++ } ++ #endif + } + if (ReadPtr != WritePtr) return KybdBuf[ReadPtr++]; + KybdAvailable = 0; +@@ -7214,8 +7340,8 @@ int gserial () { + return '\n'; + #else + unsigned long start = millis(); +- while (!Serial.available()) if (millis() - start > 1000) clrflag(NOECHO); +- char temp = Serial.read(); ++ while (!chuankou->available()) if (millis() - start > 1000) clrflag(NOECHO); ++ char temp = chuankou->read(); + if (temp != '\n' && !tstflag(NOECHO)) pserial(temp); + return temp; + #endif +@@ -7380,6 +7506,181 @@ object *read (gfun_t gfun) { + return item; + } + ++// Terminal ********************************************************************************** ++ ++// Plot character at absolute character cell position ++void PlotChar (uint8_t ch, uint8_t line, uint8_t column) { ++ #if defined(gfxsupport) ++ uint16_t y = line*Leading; ++ uint16_t x = column*6; ++ ScrollBuf[column][(line+Scroll) % Lines] = ch; ++ if (ch & 0x80) { ++ tft.drawChar(x, y, ch & 0x7f, TFT_BLACK, TFT_GREEN, 1); ++ } else { ++ tft.drawChar(x, y, ch & 0x7f, TFT_WHITE, TFT_BLACK, 1); ++ } ++#endif ++} ++ ++// Clears the bottom line and then scrolls the display up by one line ++void ScrollDisplay () { ++ #if defined(gfxsupport) ++ tft.fillRect(0, 320-Leading, 320, 10, TFT_BLACK); ++ for (uint8_t x = 0; x < Columns; x++) { ++ char c = ScrollBuf[x][Scroll]; ++ for (uint8_t y = 0; y < Lines-1; y++) { ++ char c2 = ScrollBuf[x][(y+Scroll+1) % Lines]; ++ if (c != c2) { ++ if (c2 & 0x80) { ++ tft.drawChar(x*6, y*Leading, c2 & 0x7f, TFT_BLACK, TFT_GREEN, 1); ++ } else { ++ tft.drawChar(x*6, y*Leading, c2 & 0x7f, TFT_WHITE, TFT_BLACK, 1); ++ } ++ c = c2; ++ } ++ } ++ } ++ // Tidy up graphics ++ for (uint8_t y = 0; y < Lines-1; y++) tft.fillRect(0, y*Leading+8, 320, 2, TFT_BLACK); ++ tft.fillRect(318, 0, 3, 320, TFT_BLACK); ++ for (int x=0; x= 17) && (c <= 20)) { // Parentheses ++ if (c == 17) PlotChar('(', line, column); ++ else if (c == 18) PlotChar('(' | 0x80, line, column); ++ else if (c == 19) PlotChar(')', line, column); ++ else PlotChar(')' | 0x80, line, column); ++ return; ++ } ++ if (c == STX) { invert = true; return; } ++ if (c == ETX) { invert = false; return; } ++ // Hide cursor ++ PlotChar(' ', line, column); ++ if (c == 0x7F) { // DEL ++ if (column == 0) { ++ line--; column = LastColumn; ++ } else column--; ++ } else if ((c & 0x7f) >= 32) { // Normal character ++ if (invert) PlotChar(c | 0x80, line, column++); else PlotChar(c, line, column++); ++ if (column > LastColumn) { ++ column = 0; ++ if (line == LastLine) ScrollDisplay(); else line++; ++ } ++ // Control characters ++ } else if (c == 12) { // Clear display ++ tft.fillScreen(COLOR_BLACK); line = 0; column = 0; Scroll = 0; ++ for (int col = 0; col < Columns; col++) { ++ for (int row = 0; row < Lines; row++) { ++ ScrollBuf[col][row] = 0; ++ } ++ } ++ } else if (c == '\n') { // Newline ++ column = 0; ++ if (line == LastLine) ScrollDisplay(); else line++; ++ } else if (c == VT) { ++ column = 0; Scroll = 0; line = LastLine - 2; ++ } else if (c == BEEP) tone(0, 440, 125); // Beep ++ // Show cursor ++ PlotChar(Cursor, line, column); ++ #endif ++} ++ ++// Keyboard ********************************************************************************** ++ ++void initkybd () { ++#ifdef ULISP_I2C1 ++ Wire1.setSDA(6); ++ Wire1.setSCL(7); ++ Wire1.begin(); ++ Wire1.setClock(10000); ++ pc_kbd.begin(0x1f,&Wire1); ++ #else ++ Wire.setSDA(4); ++ Wire.setSCL(5); ++ Wire.begin(); ++ Wire.setClock(10000); ++ pc_kbd.begin(); ++ #endif ++} ++ ++ ++// Parenthesis highlighting ++void HighLight(int p, uint8_t invert) { ++ if (p) { ++ for (int n=0; n < p; n++) Display(8); ++ Display(17 + invert); ++ for (int n=1; n < p; n++) Display(9); ++ Display(19 + invert); ++ Display(9); ++ } ++} ++void ProcessKey (char c) { ++ static int parenthesis = 0; ++ if (c == 27) { setflag(ESCAPE); return; } // Escape key ++ // Undo previous parenthesis highlight ++ HighLight(parenthesis, 0); ++ parenthesis = 0; ++ // 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--; ++ Display(0x7F); ++ if (WritePtr) c = KybdBuf[WritePtr-1]; ++ } ++ } else if (WritePtr < KybdBufSize) { ++ KybdBuf[WritePtr++] = c; ++ Display(c); ++ } ++ // 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; ++ } ++ } ++ HighLight(parenthesis, 1); ++ } ++ return; ++} ++ + // Setup + + void initenv () { +@@ -7406,13 +7707,12 @@ void initgfx () { + pinMode(34, OUTPUT); // Backlight + digitalWrite(34, HIGH); + #elif defined(ARDUINO_RASPBERRY_PI_PICO) +- tft.init(135, 240); +- pinMode(TFT_I2C_POWER, OUTPUT); +- digitalWrite(TFT_I2C_POWER, HIGH); +- tft.setRotation(1); +- tft.fillScreen(ST77XX_BLACK); +- pinMode(TFT_BACKLIGHT, OUTPUT); +- digitalWrite(TFT_BACKLIGHT, HIGH); ++ tft.init(); ++ #if defined(CPI_PICOCALC) ++ tft.setRotation(0); ++ tft.invertDisplay(1); ++ #endif ++ tft.fillScreen(TFT_BLACK); + #endif + #endif + } +@@ -7421,13 +7721,41 @@ void initgfx () { + void setup () { + Serial.begin(9600); + delay(2000); ++ #ifdef ULISP_SERIAL1 ++ chuankou = &Serial1; ++ #else ++ chuankou = &Serial; ++ #endif ++ ++ ++ chuankou->begin(BAUDRATE*100); ++ + int start = millis(); +- while ((millis() - start) < 5000) { if (Serial) break; } ++ while ((millis() - start) < 5000) { ++ #ifdef ULISP_SERIAL1 ++ if (Serial1) break; ++ #else ++ if (Serial) break; ++ #endif ++ } ++ ++#if defined(sdcardsupport) && defined(ARDUINO_RASPBERRY_PI_PICO) && defined(CPI_PICOCALC) ++ //picocalc no touch screen ++ pinMode(SDCARD_SS_PIN,OUTPUT); ++ digitalWrite(SDCARD_SS_PIN,1); ++ ++#endif ++ + initworkspace(); + initenv(); + initsleep(); + initgfx(); ++#if defined(i2ckbd) ++ initkybd(); ++#endif ++ + pfstring(PSTR("uLisp 4.5a "), pserial); pln(pserial); ++ + } + + // Read/Evaluate/Print loop +@@ -7447,7 +7775,7 @@ void repl (object *env) { + Context = NIL; + object *line = read(gserial); + #if defined(CPU_NRF52840) +- Serial.flush(); ++ chuankou->flush(); + #endif + if (BreakLevel && line == nil) { pln(pserial); return; } + if (line == (object *)KET) error2(PSTR("unmatched right bracket")); +@@ -7477,7 +7805,7 @@ void loop () { + + void ulispreset () { + // Come here after error +- delay(100); while (Serial.available()) Serial.read(); ++ delay(100); while (chuankou->available()) chuankou->read(); + clrflag(NOESC); BreakLevel = 0; + for (int i=0; i 0) error2(PSTR("wrong number of arguments")); +- +- // Return time +- unsigned long secs = Offset + now; +- object *seconds = number(secs%60); +- object *minutes = number((secs/60)%60); +- object *hours = number((secs/3600)%24); +- return cons(hours, cons(minutes, cons(seconds, NULL))); +-} +- +-// Symbol names +-const char stringnow[] PROGMEM = "now"; +- +-// Documentation strings +-const char docnow[] PROGMEM = "(now [hh mm ss])\n" +-"Sets the current time, or with no arguments returns the current time\n" +-"as a list of three integers (hh mm ss)."; +- +-// Symbol lookup table +-const tbl_entry_t lookup_table2[] PROGMEM = { +- { stringnow, fn_now, 0203, docnow }, +-}; +- +-// Table cross-reference functions +- +-tbl_entry_t *tables[] = {lookup_table, lookup_table2}; +-const unsigned int tablesizes[] = { arraysize(lookup_table), arraysize(lookup_table2) }; +- +-const tbl_entry_t *table (int n) { +- return tables[n]; +-} +- +-unsigned int tablesize (int n) { +- return tablesizes[n]; +-} diff --git a/wiki/arduino_uLisp_compile.png b/wiki/arduino_uLisp_compile.png new file mode 100644 index 0000000000000000000000000000000000000000..dfeaa51246d13d37306bd3fde8900888622db33a GIT binary patch literal 201195 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͛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