Here’s a draft article aimed at anyone who wants to extend uLisp, summarising how to convert between C variables of different types and the corresponding uLisp objects.
I’d welcome suggestions for improving it, or requests for other information it would be useful to add.
Integers
C to uLisp
The built-in function number() takes an int argument and returns a uLisp integer object.
For example, here’s the definition of the uLisp function (millis) which returns the value of the Arduino function millis() :
object *fn_millis (object *args, object *env) {
(void) args, (void) env;
return number(millis());
}
uLisp to C
The built-in function integer() takes a uLisp object and returns a C int . It causes an error if the parameter isn’t a uLisp integer.
For example, here’s the definition of the uLisp function (delay n) which takes one integer parameter and calls the Arduino function delay(n) . It returns n:
object *fn_delay (object *args, object *env) {
(void) env;
object *arg1 = first(args);
delay(integer(arg1));
return arg1;
}
Floats
C to uLisp
On 32-bit platforms the built-in function makefloat() takes a float argument and returns a uLisp floating-point object.
uLisp to C
On 32-bit platforms the built-in function fromfloat() takes a uLisp object and returns a C float . It causes an error if the parameter isn’t a uLisp floating-point number.
For example, you could define a uLisp function radians that converted a floating-point object from degrees to radians as follows:
object *fn_radians (object *args, object *env) {
(void) env;
object* arg = first(args);
return makefloat(fromfloat(arg) * 3.14159 / 180.0);
}
Characters
C to uLisp
The built-in function character() takes a char argument and returns a uLisp character object.
For example, here’s the definition of the Lisp function code-char which takes a uLisp integer object and converts it to a uLisp character object:
object *fn_codechar (object *args, object *env) {
(void) env;
return character(integer(first(args)));
}
uLisp to C
The built-in function fromchar() takes a uLisp object and returns a C integer. It causes an error if the parameter isn’t a uLisp character object.
For example, here’s the definition of the Lisp function char-code which takes a uLisp character object and converts it to a uLisp integer object:
object *fn_charcode (object *args, object *env) {
(void) env;
return number(fromchar(first(args)));
}
Strings
C to uLisp
The function lispstring() will take a C char* string and return a uLisp string object. This function is currently only provided in the ESP version of uLisp, as it is needed for the Wi-Fi extensions, but you can add it from the following definition:
object *lispstring (char *s) {
object *obj = myalloc();
obj->type = STRING;
char ch = *s++;
object *head = NULL;
int chars = 0;
while (ch) {
if (ch == '\\') ch = *s++;
buildstring(ch, &chars, &head);
ch = *s++;
}
obj->cdr = head;
return obj;
}
For example, here’s the definition of the uLisp Wi-Fi extension function (wifi-localip) which returns the local ip address as a uLisp string:
object *fn_wifilocalip (object *args, object *env) {
(void) args, (void) env;
return lispstring((char*)WiFi.localIP().toString().c_str());
}
uLisp to C
The function cstring() takes a uLisp string, a buffer, and the buffer length, and returns the buffer containing the uLisp string converted to a C string. This function is already provided in the ESP version of uLisp:
char *cstring (object *form, char *buffer, int buflen) {
int index = 0;
form = cdr(form);
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) error(PSTR("no room for string"));
buffer[index++] = ch;
}
}
form = car(form);
}
buffer[index] = '\0';
return buffer;
}
This function assumes that you’ve already checked that the uLisp object is a string. If necessary do this first using the stringp() macro.
A second function cstringbuf() is provided in the ESP version of uLisp. It’s simpler to use when you only need to buffer one string at a time because it uses uLisp’s built-in buffer for the string:
char *cstringbuf (object *arg) {
cstring(arg, SymbolTop, SYMBOLTABLESIZE-(SymbolTop-SymbolTable));
return SymbolTop;
}
The built-in buffer lives at the top of the symbol table and is guaranteed to have a minimum size of BUFFERSIZE , by default 34 characters.