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