<!doctype linuxdoc system>
<!-- WARNING: DOCUMENTATION IS INCOMPLETE! IF YOU REALLY NEED SOME -->
<!-- EXPLANATION, CONTACT THE AUTHOR [vsl@ontil.ihep.su]           -->
<!-- $Id: lisp.sgml,v 1.1.1.1 2000/05/07 20:26:26 mauhuur Exp $ -->
<!-- 

$Log: lisp.sgml,v $
Revision 1.1.1.1  2000/05/07 20:26:26  mauhuur
Initial import


  -->
<!-- -->


<article>

<!-- Title Information -->

<title>VSLisp Programmers Guide

<author>V.S.Lugovsky <htmlurl url="mailto:vsl@ontil.ihep.su"
                              name="[vsl@ontil.ihep.su]">,
<date> May 2000

<abstract>
 This is a somewhat complete guide to VSLisp4 interpreter and function 
libraries. 

 This work is supported in part by the Russian Foundation for Basic
Research under contract <tt>RFBR-1999-07-90-356</tt>.

</abstract>

<!-- Table of contents -->

<toc>

<sect> Introduction
<p>

 VSLisp is an embedded Lisp library and standalone interpreter. It's
very small, and runs on many platforms. It was developed as a graphics
scripting language for VMS, but now its development goes under Unix, 
and old Graph library is not supported now.
The last version with VMS support was <tt>2.5</tt>.

<sect1> Disclaimer
<p>

 VSLisp is not a Scheme or Common Lisp compatible. Surely, you can customize
it to look like one of them, but by default VSLisp is a yet another Lisp
dialect, and to work with it you'll need to understand the difference.

 VSLisp is a former "VSLisp". Again, IT IS NOT emacs ilisp, 
which is a gateway for CLisp and others.
<tt>i</tt> in the word VSLisp stands for "Interface", or "Interactive". 
Please forgive me, I haven't heard about other "ilisp" when
I started. Now it's too late to change this name.

 Supported platforms are only i386-linux and alpha-dec-osf. 
All others was not tested, but may be will work fine.

<sect1> Lisp language
<p>

 LisP language [List Processing language] is based on a LIST data structure.
List is a something like binary tree with ATOMS in it's terminal nodes.
Every list node have HEAD and TAIL (left and right tree links). 
In text representation it is "(HEAD TAIL)", where
paranthes (yes, this is why word 'Lisp' can be pronounced as "Lot of Idiotic
Senseless Paranthes") specifies LIST. By convention, if List's HEAD is a LIST
(another tree node), it must be in paranthes. Otherwise it is ATOM (terminal
node). Tail is always LIST, without paranthes. E.g., HEAD of list <tt>(A B
C)</tt> is atom <tt>A</tt>, and TAIL of this list is a list <tt>(B C)</tt>.
Another example: for list <tt>((A B) (C D))</tt> head is a list <tt>(A
B)</tt>, and tail is a list <tt>((C D))</tt>, with head <tt>(C D)</tt> and
tail <tt>NIL</tt>. (NIL is a NULL ATOM).

 Lisp language operates only with Symbols, Lists and Atoms. 
Every List can be evaluated - there are no 
principal difference between data and program code in
Lisp. Evaluation rules are very simple:
<itemize>
<item> If list's head is ATOM "a", function named "a" will be evaluated,
and list's tail will be a parameter's list.
<item> If list's head is LIST, Lambda-form will be evaluated. Lambda form is:
<quote>
  <tt>((lambda (formal-parameters) lists) real-parameters)</tt> - it's just a
function definition in the same place where this function is used. E.g:
<tt>((lambda (x y) (+ 1 (* x y))) 1 2)</tt>
</quote>
<item> Named function can be defined in interpreter internally (as <tt>+</tt>
and <tt>*</tt> function in previous example), and in SYMBOL TABLE, which can
be accessed by special system functions. Symbols is just like variables.
Function or lambda-form parameters treated as local for this function symbols.
<item> If the parameter name in lambda form prefixed by &amp symbol,
parameter value is <tt>quoted</tt>. It will not be evaluated.
<item> By default, complete parameters values list in lambda form defined in
symbol <tt>ParList</tt>.
</itemize>

 Surprise! It was a COMPLETE lisp language description. All you need now to
start programming in Lisp, is a set of system functions. It's differs in Lisp
dialects, and here I'll describe only internal VSLisp function set.

<sect1> VSLisp specific features
<p>

 VSLisp implements <tt>symtabs</tt>, which is not presented in other Lisp
dialects. That is a "local" symbol tables, stored in other symbols.
They are usable for property-lists and others, when fast name access is needed.

Traditional property-lists and others special lists are not implemented in
VSLisp core - just in <tt>colors</tt> library. Note, that <tt>symtabs</tt> is
just a simple hashtables.

<sect> Building
<p>

 To build VSLisp, just uncompress it's distribution archive, and then
do <tt>./configure</tt> in that directory. 
Maybe, you'll need some options - try
<tt>./configure --help</tt>.

 Now you can do <tt>make; make install</tt>.

 There are some <tt>define</tt>s in <tt>l_defs.h</tt>, and, maybe, you'll
want to change them before building. Please, read that file.
One thing I'll mention here: definition of <tt>LP_MALLOC</tt>. If you'll
define it, old <tt>malloc</tt> method will be used to allocate list's 
skeletons. It's somewhat slower, but it saves memory for small programs.

<sect> Invocation
<p>

  To run default standalone interpreter, just type '<tt>VSLisp</tt>':
<tscreen><verb>
$ VSLisp
VSLisp, V4.0 (c) by VSL, 1994-2000
Lisp>>
</verb></tscreen>

 Use command line parameter '<tt>-i filename</tt>' to specify script name.

<sect1> VSLisp scripts
<p>

 VSLisp executable script may look like this one:
<tscreen><verb>
#!/usr/bin/VSLisp -i
(print '"Hello World")
(exit)
</verb></tscreen>

 You must insert '<tt>(exit)</tt>' at the end of any script for 
compatibility - VSLisp may start interactive interpreter after loading script.

 Command line parameters list is defined in a Lisp symbol <tt>*pars*</tt>.

<sect1> Interaction
<p>

 In interactive mode VSLisp standalone interpreter waits for lists to
evaluate. Interactive session may look like:

<tscreen><verb>
[vsl@ontil vsl]$ VSLisp
VSLisp, V4.0 (c) by VSL, 1994-2000
Lisp>> (defun Fak (x) (if (= x 0) 1 (* x (Fak (- x 1)))))
 << ( lambda ( x) ( if ( = x 0) 1 ( * x ( Fak ( - x 1)))))
Lisp>> (Fak 10)
 << 3.6288e+06
Lisp>> (Fak 5)
 << 120
Lisp>>
</verb></tscreen>

 <tt>NOTE:</tt> Only lists will be evaluated, atoms just ignored.
e.g., you cannot do something like this:
<tscreen><verb>
Lisp>> (setq a 100)
 << 100
Lisp>> a
</verb></tscreen>

<sect> Core Library
<p>

 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. 

<sect1> Data structures
<p>

 The main data structure of VSLisp core library is LIST. 
It is defined in file <tt>l_defs.h</tt>.

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

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

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

 For LIST:

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

 Where <tt>union _l1</tt> is union of atom and list structures.

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

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

 <tt>head</tt>, <tt>tail</tt> 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).

<sect1> Interface functions
<p>

<tt>ilisp_init(int n)</tt>
<quote>
 VSLisp core library must be initialized by <tt>lisp_init</tt> call.
<tt>n</tt> is a maximum number of symbols in global symbol table.
If <tt>LP_MALLOC</tt> 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 <tt>l_defs.h</tt>,
and rebuild the library.
</quote>

<tt>LIST leval(LIST l,symtab *tab)</tt>
<quote>
 Evaluate list <tt>l</tt>, in symbol context <tt>tab</tt>.
For default (global) context, use call <tt>ReturnGlobal()</tt> to get a 
pointer. There was a strange troubles with direct usage of global variable.
</quote>

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

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

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

<tt>deffun(symtab *tab,char *n,LIST (*f)(symtab *tab,LIST l))</tt>
<quote>
 Define hook <tt>f</tt> for a new system function named <tt>n</tt>.
See example below. <tt>tab</tt> is needed to get current context,
just use <tt>ReturnGlobal()</tt> here.
</quote>

<sect1> Core Lisp functions
<p>

 There are only ONE function defined internally 
in <tt>leval()</tt> function body.

<tt>x1 <-- (quote x1)</tt> - return x1 without evaluation.

<sect1> Function definition example 
<p>

<tscreen><verb>
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",&amp;my_cool_function);

 ....

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

<sect> VSLisp functions
<p>

 VSLisp core library contains it's own Lisp dialect. All it's functions will
be explained in this chapter.

<sect1> Essential Lisp functions
<p>

<tt>l <-- (list x1 [x2 [x3 ...]])</tt> - Create a new list from elements x1,
x2, x3.

<tt>x <-- (car l)</tt> -  Get list's head or NIL. 

<tt>x <-- (cdr l)</tt> - Get list's tail or NIL. 

<tt>x <-- (nth n l)</tt> - Get numbered list element. First element is 0.

<tt>l <-- (cons l1 l2)</tt> - Create a list with head l1 and tail l2.

<tt>l <-- (append l x)</tt> - Append x to l's last tail's head.
<quote>
 Example:
<tscreen><verb>
Lisp>> (append '(a b c) '(d e f))
 << ( a b c ( d e f))
</verb></tscreen>
</quote>

<tt>l <-- (append1 l x)</tt> - Connect x to l's last tail.
<quote>
 Example:
<tscreen><verb>
Lisp>> (append1 '(a b c) '(d e f))
 << ( a b c d e f)
</verb></tscreen>
</quote>

<tt>x1 <-- (setq qa x1)</tt> - Define symbol <tt>a</tt> in global table, and
set it's value to <tt>x1</tt>. Symbol name is quoted.

<tt>x1 <-- (set x x1)</tt> - The same as <tt>setq</tt>, but symbol name
evaluated.

<tt>x1 <-- (setql qa x1 [t])</tt> - Define symbol in local table, or in
specified table.

<tt>x1 <-- (setl x x1 [t])</tt> - The same as <tt>setql</tt>, but symbol
name evaluated.

<tt>t <-- (stab n)</tt> - Create symbol table with maximum size <tt>n</tt>.

<tt>(atab y)</tt> - Append symbol table to local table.
<quote>
 Example:
<tscreen><verb>
(defun f (x)
  (atab (stab 3))
  (setql t (+ x 2))
  (/ x t)
)
</verb></tscreen>
 Here <tt>(atab (stab ...))</tt> construction is a something like local
variables definition in C function.
</quote>

<tt>x <-- (eval l)</tt> - Evaluate list <tt>l</tt>. Note - eval works in
current context, not like eval in Common Lisp.

<tt>c <-- (symbolp a)</tt> - Check is <tt>a</tt> a symbol name (global
symbol table)

<sect1> Text functions 
<p>

<sect1> File functions
<p>

<sect1> All others
<p>

<sect1> COLORS library
<p>

 <tt>colors</tt> library is defined internally in vslisp4 library, 
in <tt>LC1</tt> format. Colors named after famous "flavours". It is a 
something like OOP implementation for VSLisp, and some common functions
like <tt>defun</tt>.

</article>





