Reputation: 1
I am writing a Lisp interpreter and I've decided to store the environment's symbols (true, false, cons, car, cdr, variables etc.) in a linked list, with each "entry" using the same structure used to store lisp atoms (in my code called a "cell").
The following structs and enums are defined:
typedef enum {STRING, FLOAT, SYMBOL, LIST} ctype;
typedef struct { void* data; ctype type; void* next; } cell;
I used a void*
with data
to point to the atom (or a symbol) so that I didn't have to fiddle with unions. next
points to the next cell. Since s-expressions can be nested, data
can also point to a cell, meaning that this implementation could have nested lists.
The following fundamental Lisp functions are defined as such:
cell* cons(cell* car, cell* cdr) { car->next = cdr; return car; }
cell* car(cell* head) { return head; }
cell* cdr(cell* head) { return head->next; }
and a function stnode()
is defined so that the manual memory allocation can be taken care of and cells can quickly be created:
cell* stnode(void* data, ctype type) {
cell* tmp = malloc(sizeof(cell));
tmp->data = malloc(sizeof(data));
tmp->type = type;
memcpy(tmp->data, data, sizeof(data));
return tmp;
}
Finally, I have the function stdenv, which returns a Linked List of cells containing pointers to functions that I would like to use in my lisp. These are cons(), car() and cdr().
cell* stdenv() {
return cons(stnode(&cons, SYMBOL), cons(stnode(&car, SYMBOL), stnode(&cdr, SYMBOL))); }
There are better recursive ways to achieve the above code, but I'll cross that bridge when I get to it. At this point with so little code it isn't worth adding complexity before I can guarantee the code actually works.
I've tested stnode()
with strings, booleans, integers and pointers to other structs, which all work fine (with proper void pointer dereferencing in place, of course) but I can't get function pointers to work. The problematic code is stdenv()
, here's the code I tried to use to test it:
cell* symbols = stdenv();
cell* cd = *(*symbols->data)(symbols);
printf("%p\n", cd->data);
...the assumption being that if everything was working as I expected, I should be presented with the memory address in the function (because of how I wrote stdenv
in this case it should be cons()).
Compiling with GCC on Ubuntu got me the following warnings and errors:
lisp.c: In function ‘main’:
lisp.c:26:15: warning: dereferencing ‘void *’ pointer
26 | cell* cd = *(*symbols->data)(symbols);
| ^~~~~~~~~~~~~~
lisp.c:26:15: error: called object is not a function or function pointer
26 | cell* cd = *(*symbols->data)(symbols);
| ~^~~~~~~~~~~~~~~
I can't figure out what's wrong with the code for stdenv, since I've passed the memory address of each function to cons()
.
Upvotes: 0
Views: 516