table of contents
| () | () | 
lisp(3gv) lisp(3gv)
NAME
  
   geomview lisp interpreter
NOTE
  
   This document describes the geomview 1.3 lisp interpreter.
  
   This version is incompatible with previous versions in
  
   several ways. Since the previous one was used mostly just
  
   by Geometry Center staff, I am not going to write a docu-
  
   ment detailing the changes. The geomview lisp interpreter
  
   is not very well documented in general because I am
  
   strongly	 considering phasing it out and replacing it with
  
   a real lisp interpreter in a future version of	geomview.
  
   If you have any questions about the current version or how
  
   to convert programs from an older version please contact
  
   me directly [ mbp@geomtech.com ].
SYNOPSIS
  
   #include "lisp.h"
  
   void	 LInit();
  
   Lake *	 LakeDefine(FILE *streamin, FILE *streamout, void *river);
  
   void	 LakeFree(Lake *lake);
  
   LObject * LNew(LType *type, LCell *cell);
  
   LObject * LRefIncr(LObject *obj);
  
   void	 LRefDecr(LObject *obj);
  
   void	 LWrite(FILE *fp, LObject *obj);
  
   void	 LFree(LObject *obj);
  
   LObject	 * LCopy(LObject *obj);
  
   LObject * LSexpr(Lake *lake);
  
   LObject * LEval(LObject *obj);
  
   LObject * LEvalSexpr(Lake *lake);
  
   LList	 * LListNew();
  
   LList	 * LListAppend(LList *list, LObject *obj);
  
   void	 LListFree(LList *list);
  
   LList *	 LListCopy(LList *list);
  
   LObject * LListEntry(LList *list, int n);
  
   int	 LListLength(LList *list);
  
   int	 LParseArgs(char *name, Lake *lake, LList *args, ...);
  
   int	 LDefun(char *name, LObjectFunc func, char *help);
  
   void	 LListWrite(FILE *fp, LList *list);
  
   LInterest * LInterestList(char *funcname);
  
   LObject * LEvalFunc(char *name, ...);
  
   int	 LArgClassValid(LType *type);
  
   void	 LHelpDef(char *key, char *message);
  
   LDEFINE(name, ltype, doc)
  
   LDECLARE((name,	LBEGIN, 	 ..., 	 LEND));
Geometry Center Oct 22 1992 1
DESCRIPTION
  
   Geomview	 contains a minimal lisp interpreter for parsing
  
   and evaluating commands.	 This lisp interpreter is part of
  
   the "-loogutil"	 library and thus any program which links
  
   with this library may use the interpreter. This	 provides
  
   a simple but powerful way to build up a command language.
  
   This manual page assumes that you are familiar	with the
  
   syntax of lisp. The first part describes the basics of
  
   using the interpreter. Some gory details that don't con-
  
   cern most users then follow.
  
   The main steps in using the lisp interpreter are
1. call Linit() to initialize the interpreter 2. make calls to LDefun(), one for each lisp function you want the interpreter to know about 3. define the "i/o lake" 4. parse input with calls to LSexpr() and evaluate the resulting lisp objects with LEval() (or use LEvalSexpr() to combine both steps).
  
   For example the following code defines a single function
  
   "f" and executes commands from standard input:
#include "lisp.h" Lake *lake; LObject *obj, *val;
LInit(); LDefun("f", f, NULL); lake = LakeDefine(stdin, stdout, NULL); while (!feof(stdin)) { obj = LSexpr(lake); val = LEval(obj); LFree(obj); LFree(val); }
  
   The second argument to LDefun()	is a function	 pointer;
  
   LDefun()	 sets up a correspondence between the string "f"
  
   and the function f, which is assumed to have been previ-
  
   ously declared.	 The section FUNCTION DEFINITIONS below
  
   gives the expected call syntax and behavior of such func-
  
   tions.	(The third argument to LDefun() is a pointer to a
  
   string which documents the function and may be NULL if you
  
   don't care about documentation.) LakeDefine() defines an
  
   i/o lake; this is a generalization of the notion of an i/o
  
   stream.	 Most programs don't need to use the generaliza-
  
   tion, though, and can simply pass FILE pointers as LakeDe-
  
   fine()'s	 first	two arguments and NULL as the third one.
  
   The section LAKES below gives the details for those who
  
   are interested.	 LSexpr() [which stands for Lisp Symbolic
  
   EXPRession] parses a single lisp expression from the lake,
  
   returning a lisp object which represents that expression.
Geometry Center Oct 22 1992 2
  
   The lisp object is returned as an LObject pointer, which
  
   points to an opaque structure containing a representation
  
   of the expression. LEval() then evaluates the object; it
  
   is during the	call to LEval() that the action of the
  
   expression takes place.	Note that the last two	lines of
  
   code in this example could have been replaced by the sin-
  
   gle line LEval(LSexpr(lake)) or, more efficiently, by LEv-
  
   alSexpr(lake).
FUNCTION DEFINITIONS
  
   The functions defined by calls to LDefun() are expected to
  
   have a certain call syntax; LEval() calls them	 when it
  
   encounters a call to the lisp function named with the cor-
  
   responding string. The	macro LDEFINE	is provided for
  
   declaring them.	For example:
LDEFINE(f, LSTRING, "(f a b) returns a string representing the0um of the integer a with the floating point number b.") { int a; float b; char buf[20], *s;
LDECLARE(("f", LBEGIN, LINT, &a, LFLOAT, &b, LEND)); sprintf(buf,"%f",a+b); s = strdup(buf); return LNew(LSTRING, &s); }
  
   The important things about this function are:
1. It is declared with the LDEFINE macro, the general syntax of which is LDEFINE(name, type, helpstr). name should be a valid C identifer and will be used to construct the actual name of the C function by prepending an 'L' and the name of the help string by prepending an 'H'. type should be a lisp object type identifier (see below) and determines the type of object that the function returns. helpstr is a documentation string.
2. The use of the LDECLARE macro. More about this below.
3. It returns an LObject *. All lisp functions must actually return a value. If you don't care what value they return you can return one of the pre-defined values Lnil or Lt (and specify LVOID as the type in the LDEFINE header).
  
   This particular	 example is a	 function which takes two
  
   arguments, an int and a float, and returns a string object
  
   representing their sum. A lisp call to this function
  
   might look like "(f 1 3.4)".
Geometry Center Oct 22 1992 3
  
   The LDECLARE macro, defined in lisp.h, sets up the corre-
  
   spondence between variables in the C code and arguments in
  
   the lisp call to the function. Note that the arguments to
  
   LDECLARE are delimited by *two* pairs of parentheses (this
  
   is because C does not allow macros with a variable number
  
   of arguments; LDECLARE	 thus actually takes one argument
  
   which is a parenthesized list of an arbitrary number of
  
   items).	The general usage of LDECLARE is
LDECLARE(( name, LBEGIN, <argspec>, ..., LEND ));
  
   where name is	the name of the function (as specified to
  
   LDefun()). <argspec> is an argument specification, which
  
   in general consists of a lisp type identifier followed by
  
   an address. The identifier indicates the data type of the
  
   argument. The	builtin	 type identifiers are LINT (inte-
  
   ger), LFLOAT (float), LSTRING (string), LLOBJECT (lisp
  
   object),	 and LLIST (lisp list). Applications may define
  
   additional types whose identifiers may also be used here;
  
   see the	 section CUSTOM LISP	TYPES below for details.
  
   There may be any number of <argspec>'s; the last	 must be
  
   followed by the special keyword LEND.
STOP HERE
  
   Most users of the lisp interpreter can stop reading this
  
   man page here. What follows is only used in advanced sit-
  
   uations.
EVALUATION OF FUNCTION ARGUMENTS
  
   Normally the lisp interpreter evaluates function arguments
  
   before passing them to the function; to prevent this eval-
  
   uation from happening	you can insert the special token
  
   LHOLD in an LDECLARE argument specification before the
  
   type keyword. For example
LHOLD, LLIST, &list,
  
   specifies an unevalutated list argument. This feature is
  
   really useful only for LLIST, LLOBJECT,	and array types
  
   (see below) since the other types evalutate to themselves.
ARRAYS
  
   In general an <argspec> in the LDECLARE call consists of a
  
   keyword	followed by the address of a scalar data type.
  
   Since it is relatively common to use a lisp list to repre-
  
   sent an	 array	of values, however, the special <argspec>
  
   keyword LARRAY is provided for dealing with them. It has
  
   a different syntax: it should be followed by a lisp type
Geometry Center Oct 22 1992 4
  
   identifier which specifies the type of the elements of the
  
   array and then	 by two addresses --- the address of an
  
   array and the address of an integer count. Upon entry to
  
   LDECLARE	 the count specifies	how many elements may be
  
   written into the array.	LDECLARE then modifies this num-
  
   ber to	indicate the number of entries actually parsed.
  
   For example:
LDEFINE(myfunc, ...) { float f[2]; int fn = 2; LDECLARE(("myfunc", LEBGIN LHOLD, LARRAY, f, &fn, LEND)); /* at this point the value of fn has been modified to be the number of entries actually appearing in the list argument; and this number of values have been written into the array f. */ ... }
  
   defines a function "myfunc" which takes a list of up to	2
  
   floats as its	only argument.	 Valid calls to "myfunc"
  
   would be "(myfunc ())", "(myfunc (7))",	and "(myfunc
    (7
  
   8))".
  
   Note the use of LHOLD; this is necessary because otherwise
  
   the lisp system would attempt to evaluate the list as	a
  
   function call before passing it off to myfunc.
OPTIONAL ARGUMENTS
  
   Normally	 the lisp interpreter will generate (to stderr) a
  
   reasonable error message if a function	 is called with
  
   fewer arguments	 than were specified in LDECLARE. Some
  
   functions, however, may	 have some arguments	that are
  
   optional. You can define a function which takes optional
  
   arguments by putting the keyword LOPTIONAL after the last
  
   required	 argument in the LDECLARE call. Any arguments
  
   specified in the list after that are considered	optional;
  
   the interpreter doesn't complain if they are not supplied.
  
   Note that all optional	arguments must	 come after all
  
   required arguments.
  
   Normally	 excess	 arguments also elicit an error message.
  
   The LREST keyword allows control over this situation. If
  
   LREST is followed by	a pointer to an LList * variable,
  
   then trailing arguments	 are parsed, evaluated (unless
  
   LHOLD was used), and	the list of them is stored in the
  
   given variable.	(Note that the value is an LList, not an
  
   LObject of type LLIST -- if there are no excess arguments,
  
   the value is NULL, not an empty LLIST.)	If LREST is fol-
  
   lowed by a NULL pointer, excess arguments are silently
Geometry Center Oct 22 1992 5
  
   ignored.	 LREST might be useful when a function's argument
  
   types are not known. It's not necessary to specify LEND
  
   after LREST.
LISP OBJECTS
  
   The basic data type of the lisp interpreter is	the lisp
  
   object;	it is	represented by an LObject pointer, which
  
   points to an opaque data	 structure. The functions for
  
   manipulating lisp objects (i.e. the object's methods) are:
LNew(): creates a new lisp object of the given type with the given value. The "type" argument is one of the values LSTRING or LLIST, or a type pointer defining a custom object type (see CUSTOM OBJECT TYPES below). LRefIncr(): increments the reference count of a lisp object. The lisp interpreter uses the convention that when a procedure returns a lisp object, the caller owns the object and thus has responsibility for freeing it. LRefIncr() can be used to increment the reference count of an existing object about to be returned. New objects created by LNew() have their reference count initialized to 1 and hence do not need to be LRefIncr()'ed. LRefDecr(): decrements the reference count of a lisp object. This should probably not be called by application programs; it is used internally. LWrite(): writes a formatted string representation of a lisp object to a stream. LFree(): free the space assoicated with a lisp object LCopy(): construct a copy of a lisp object
CUSTOM OBJECT TYPES
  
   In addition to the predefined lisp object types	 you may
  
   define your own custom types. This is done by construct-
  
   ing a structure containing various function pointers for
  
   manipulating objects of your	new type. The address of
  
   this structure is then the type identifier for this type
  
   and may	 be used in LDECLARE <argspec>'s and in LNew()
  
   calls. (The type names LINT,	 LSTRING and the other
  
   builtin	types are actually pointers to predefined struc-
  
   tures.)	The structure is of type LType as defined in
  
   lisp.h:
  
   struct LType {
/* name of type */ char *name;
/* size of corresponding C type */ int size;
Geometry Center Oct 22 1992 6
/* extract cell value from obj */ int (*fromobj)(/* LObject *obj, void *x */);
/* create a new LObject of this type */ LObject *(*toobj)(/* void *x */);
/* free a cell of this type */ void (*free)(/* void *x */);
/* write a cell value to a stream */ void (*write)(/* FILE *fp, void *x */);
/* test equality of two cells of this type */ int (*match)(/* void *a, void *b */);
/* pull a cell value from a va_list */ void (*pull)(/* va_list *a_list, void *x */);
/* parse an object of this type */ LObject *(*parse)(/* Lake *lake */);
/* magic number; always set to LTypeMagic */ int magic;
  
   };
  
   The void * pointers in the above point to objects of the
  
   type you are defining. For examples of how to define new
  
   types see the code in lisp.c that defines the string and
  
   list types. See also the file	 TYPES.DOC in	the lisp
  
   source code directory for further details.
LISTS
  
   The LList pointer is	used to refer to objects of type
  
   LLIST, which implement a linked list. The operations on
  
   these objects are LListNew(), LListLength(), LListEntry(),
  
   LListAppend(), LListCopy(), and	LListFree(). These are
  
   mostly used internally by the lisp system but are avail-
  
   able for outside use. Maybe I'll write more documentation
  
   for them later if it seems necessary.
LAKES The Lake structure is a generalization of an input stream.
  
   It contains three members: an input FILE	 pointer
  
   ("streamin"), an output FILE pointer ("streamout"), and
    an
  
   arbitrary pointer ("river"). The input	FILE pointer is
  
   required; the lisp interpreter assumes that every lake has
  
   a valid input file pointer. The output	FILE pointer is
  
   required	 if you do any operations that result in the
  
   intepreter producing any output.	 The third pointer may
  
   point to whatever you want. The lisp interpreter itself
  
   does not directly refer to this pointer.	 It may	 be used
  
   by the	parser	that you supply when defining a new lisp
Geometry Center Oct 22 1992 7
  
   object type.
  
   The term "Lake" is supposed to connote something more gen-
  
   eral than a stream; it also seemed particularly appropri-
  
   ate since this interpreter was written	in the	 City of
  
   Lakes.
HIDDEN LAKE ARGUMENTS AND OTHER WET THINGS
  
   This section is X rated. Don't read it unless you are
  
   really serious.
  
   The lisp interpreter works by first parsing (LSexpr()) an
  
   expression then	 evaluating it	 (LEval()). The LDECLARE
  
   macro is a mechanism which allows both	the syntax (for
  
   parsing)	 and the semantics (for evaluation) of an expres-
  
   sion to be specified in the same convenient place --- at
  
   the top	 of the C function which implements the function.
  
   The call syntax of all such C functions is
LObject *func(Lake *lake, LList *args)
  
   When parsing a call to the corresponding lisp	function,
  
   LSexpr()	 calls func with that lake pointer, and with args
  
   pointing to the head of the list in the parse tree corre-
  
   sponding to this function call.	LDECLARE parses the argu-
  
   ments in the call (by reading them from the lake) and
  
   appends	them to this list. (Note: the head of this list
  
   is the function itself,	so the	 first	argument becomes
  
   entry #2 in the list.)
  
   When evaluating the function call, LEval() calls func with
  
   lake=NULL and with args pointing to the	 call's	 argument
  
   list. (In this case the first entry of the list is the
  
   first argument.)	 LDECLARE then converts the arguments in
  
   the list into the appropriate C data types, writing their
  
   values into the addresses in the <argspec>s.
  
   One side-effect of using lake=NULL as the signal to evalu-
  
   ate rather than to parse is that the value of the lake
  
   pointer is not available at evaluation time. Some func-
  
   tions, however,	 may want to do something with the lake
  
   they were parsed from. For example, the	"write"	 function
  
   in geomview writes data to the output stream associated
  
   with its input stream. (In geomview these streams are all
  
   stored in a general "Pool" structure which is retained as
  
   the "river" member of the lake.)	 The special token LLAKE
  
   may be	used to cause the lake pointer to be saved in the
  
   args list at parse time and written into a variable at
  
   evaluation time. It is used	 exactly like	the other
Geometry Center Oct 22 1992 8
  
   (scalar) argument keywords:
LObject *func(Lake *lake, LList *args) Lake *mylake; LDECLARE(("myfunc", LBEGIN LARG_LAKE, &mylake, ... LARG_END));
  
   At evaluation time LDECLARE will set mylake to	have the
  
   value that lake had at parse time. This looks just like a
  
   specification for an argument to the lisp function but it
  
   is not	--- it is just a way to tell LDECLARE to remember
  
   the lake pointer between parse- and evaluation-time.
BUGS
  
   The documentation is incomplete.
AUTHOR
  
   The lisp interpreter was written mostly by Mark	 Phillips
  
   with lots of input and moral support from Stuart Levy and
  
   Tamara Munzner.
Geometry Center Oct 22 1992 9