VSLisp Programmers Guide: Core Library

Next Previous Contents

## 4. Core Library

Core VSLisp library is what you can use by function calls from your own program, or to write new VSLisp module. It also contains default Lisp system functions implementation (all that CARs, CDRs and other DEFUNs). To use it you'll need to know essential data structures (internals of Lists and Atoms), and a few simple core functions.

## 4.1 Data structures

The main data structure of VSLisp core library is LIST. It is defined in file `l_defs.h`.

> `

>     typedef struct {
>             unsigned char      f;
>             unsigned short int g;
>             void               * head;
>             void               * tail;
>             } _List;

> `

`f` is a type code. First bit of `f` is: 0 - ATOM, 1 - LIST. For ATOM there are following structure:

> `

>     typedef struct {
>             unsigned char      f;
>             unsigned short int g;
>             char               * a;
>             char               * b;
>             } * ATOM;

> `

For LIST:

> `

>     typedef struct _list {
>             unsigned char      f;
>             unsigned short int g;
>             union _l1          * h;
>             union _l1          * t;
>             } * LIST;

> `

Where `union _l1` is union of atom and list structures.

E.g. to access character value of ATOM head of LIST l, type `l->h.a->a`. To get `(cdr (cdr l))` use `l->t.l->t.l`.

`g` stands for Garbage Collector - it's just a number of links to this node. Try not to corrupt this field, and use it correctly.

`head`, `tail` are pointers to head and tail, or, for ATOM, pointer to ATOM value and, maybe, some extra information (destructor function for MISC Atom, or array size for ARRAY Atom).

## 4.2 Interface functions

`ilisp_init(int n)`

> VSLisp core library must be initialized by `lisp_init` call. `n` is a maximum number of symbols in global symbol table. If `LP_MALLOC` was not defined, ilisp_init() will create lists pool, which can be pretty large. If you don't like it, and there is no need in extreme evaluation speed, uncomment that macro definition in `l_defs.h`, and rebuild the library.

`LIST leval(LIST l,symtab *tab)`

> Evaluate list `l`, in symbol context `tab`. For default (global) context, use call `ReturnGlobal()` to get a pointer. There was a strange troubles with direct usage of global variable.

`LIST onesymeval(LIST l,symtab *tab)`

> Evaluate head of `l` if it is a list, or return value of symbol, which name is a head of `l`. Symbol name searched in symbol table `tab`, then in global table of current context. (for more information of contexts see `symtab` structure definition in `l_defs.h`.

`aatl1(LIST l)`

> Garbage Collector function. Call it every time before releasing pointer to LIST or ATOM structure, especially for returned by leval() and onesymeval(). Ignoration of `aatl1` call is a best way to huge memory leaks. Again, set `g` field correctly (to 0 when unlinked list or atom created), if you want `aatl1` understand it right.

`LIST mklist(LIST a,LIST b)`

> Create a new list with head `a` and tail `b`. If it is not linked to other list, `g` field must be zeroed. `mklist` can be used to create ATOM with value `a` and `b=NIL` or something you need in special ATOM. `f` field must be set to ATOM type in this case.

`deffun(symtab *tab,char *n,LIST (*f)(symtab *tab,LIST l))`

> Define hook `f` for a new system function named `n`. See example below. `tab` is needed to get current context, just use `ReturnGlobal()` here.

## 4.3 Core Lisp functions

There are only ONE function defined internally in `leval()` function body.

`x1 <-- (quote x1)` - return x1 without evaluation.

## 4.4 Function definition example

> `

>     LIST my_cool_function(symtab *tab,LIST l)
>     {
>       LIST t1,t2,ret;
>       char *s;
>       int l1,l2;
>       t2=l->t.l;                      /* Get first parameter. It is 'quoted' */
>       t1=onesymeval(l->t.l->t.l,tab); /* Evaluate second parameter */
>       /* We hope, t2 is ATOM. Any type checks are too expensive, let's believe
>          in programmer's accuracy */
>       l1=(int)GetDouble((ATOM)t1);
>       s=(char *)malloc(l1+1); /* t1 is a 'double' atom, which is
>                                a length of a new string */
>       l2=strlen(((ATOM)t2)->a);             /* ((ATOM)t2)->a is a char * value of
>                                                atom t2 */
>       if(l2<l1) strcpy(((ATOM)t2)->a,s);
>         else
>        strncpy(((ATOM)t2),s,l1);
>       ret=mklist((LIST)s,NIL);
>       ret->f=0;               /* ret is ATOM now */
>       ret->g=0;               /* NEVER forget this! */
>       aatl1(t1);              /* tell GC about t1, we don't need it any more */
>       return ret;
>     }

>      ....

>     deffun(ReturnGlobal(),"my-cool-function",&my_cool_function);

>      ....

> `

It was a pretty unusable function, which resizes string. But it illustrates all tricks you need to write a usable one.

Next Previous Contents