[net.sources] XLISP, part 2 of 4

jcw@cvl.UUCP (07/20/84)

This portion contains the first third of the C source for David
Betz' XLISP interpreter.

Tear at the dotted line, run sh(1) over it.

Jay Weber
---------------------------------------------------------------
: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
/bin/echo 'Extracting xlbind.c'
sed 's/^X//' <<'//go.sysin dd *' >xlbind.c
X		  /* xlbind - xlisp symbol binding routines */
X
X#ifdef CI_86
X#include "a:stdio.h"
X#include "xlisp.h"
X#endif
X
X#ifdef AZTEC
X#include "a:stdio.h"
X#include "xlisp.h"
X#endif
X
X#ifdef unix
X#include <stdio.h>
X#include <xlisp.h>
X#endif
X
X
X			     /* global variables */
X
Xstruct node *xlenv;
X
X
X	    /********************************************************
X	    *  xlunbind - unbind symbols bound in this environment  *
X	    ********************************************************/
X
Xxlunbind(env)
X  struct node *env;
X{
X    struct node *bnd;
X
X    for (; xlenv != env; xlenv = xlenv->n_listnext)
X    {
X	bnd = xlenv->n_listvalue;
X	bnd->n_bndsym->n_symvalue = bnd->n_bndvalue;
X    }
X}
X
X
X		     /**************************************
X		     *  xlbind - bind a symbol to a value  *
X		     **************************************/
X
Xxlbind(sym,val)
X  struct node *sym,*val;
X{
X    struct node *lptr,*bptr;
X
X    lptr = newnode(LIST);              /* Create new environment list entry */
X    lptr->n_listnext = xlenv;
X    xlenv = lptr;
X
X    lptr->n_listvalue = bptr = newnode(LIST);    /* New variable binding */
X    bptr->n_bndsym = sym;
X    bptr->n_bndvalue = val;
X}
X
X
X	    /*******************************************************
X	    *  xlfixbindings - make a new set of bindings visible  *
X	    *******************************************************/
X
Xxlfixbindings(env)
X  struct node *env;
X{
X    struct node *eptr,*bnd,*sym,*oldvalue;
X
X    for (eptr = xlenv; eptr != env; eptr = eptr->n_listnext) {
X	bnd = eptr->n_listvalue;
X	sym = bnd->n_bndsym;
X	oldvalue = sym->n_symvalue;
X	sym->n_symvalue = bnd->n_bndvalue;
X	bnd->n_bndvalue = oldvalue;
X    }
X}
//go.sysin dd *
/bin/chmod 664 xlbind.c
/bin/echo -n '	'; /bin/ls -ld xlbind.c
/bin/echo 'Extracting xldebug.c'
sed 's/^X//' <<'//go.sysin dd *' >xldebug.c
X		       /* xldebug - some debug routines */
X
X#ifdef CI_86
X#include "a:stdio.h"
X#include "xlisp.h"
X#endif
X
X#ifdef AZTEC
X#include "a:stdio.h"
X#include "xlisp.h"
X#endif
X
X#ifdef unix
X#include <stdio.h>
X#include <xlisp.h>
X#endif
X
X
X
Xint debug_level = 0;
XFILE *debug_fp = NULL;
X
X
X
X	      /***************************************************
X	      *  xldbgmsg : Display a message in the debug file  *
X	      ***************************************************/
X
Xxldbgmsg(s)
X    char *s;
X{
X    if (debug_fp)
X	 fprintf(debug_fp, "\n%s", s);
X}
X
X
X		  /*******************************************
X		  *  xldump : dump a node to the debug file  *
X		  *******************************************/
X
Xxldump(nptr)
X    struct node *nptr;
X{
X
X    if (debug_fp == NULL)              /* Debug file open ? */
X	 return;
X
X    fprintf(debug_fp, "\n@%4x : %2x   ", nptr, nptr->n_flags);
X
X    switch(nptr->n_type)
X    {
X    case FREE:
X	 fprintf(debug_fp, "FREE node");
X	 return;
X
X    case SYM:
X	 fprintf(debug_fp, "SYM %s = @%4x", nptr->n_symname, nptr->n_symvalue);
X	 return;
X
X    case LIST:
X	 fprintf(debug_fp, "LIST @%4x , @%4x", nptr->n_listvalue,
X		 nptr->n_listnext);
X	 return;
X
X    case SUBR:
X	 fprintf(debug_fp, "SUBR %4x", nptr->n_subr);
X	 return;
X
X    case INT:
X	 fprintf(debug_fp, "INT = %d", nptr->n_int);
X	 return;
X
X    case STR:
X	 fprintf(debug_fp, "STRING = %s", nptr->n_str);
X	 return;
X
X    case OBJ:
X	 fprintf(debug_fp, "OBJ @%4x , @%4x", nptr->n_obclass,
X		 nptr->n_obdata);
X	 return;
X
X    case FPTR:
X	 fprintf(debug_fp, "FILE  %4x", nptr->n_fp);
X	 return;
X
X    case KMAP:
X	 fprintf(debug_fp, "KMAP");
X	 return;
X
X#ifdef REALS
X    case REAL:
X	 fprintf(debug_fp, "REAL = %g", nptr->n_real);
X	 return;
X#endif
X
X    default:
X	 fprintf(debug_fp, "Type %d ?????????", nptr->n_type);
X	 return;
X    }
X}
X
X
X		/************************************************
X		*  debug : xlisp function to set debug options  *
X		************************************************/
X
Xstatic struct node *debug(args)
X    struct node *args;
X{
X    debug_level = xlevmatch(INT, &args)->n_int;
X
X    if (args != NULL)
X    {
X	 if (debug_fp)
X	      fclose(debug_fp);
X	 if ((debug_fp = fopen(xlevmatch(STR, &args)->n_str, "w")) == NULL)
X	      xlfail("Cannot open debug file");
X	 xllastarg(args);
X    }
X
X    return (NULL);
X}
X
X
X		  /*******************************************
X		  *  xldebuginit : initialize debug package  *
X		  *******************************************/
X
Xxldebuginit()
X{
X    debug_level = 0;
X    debug_fp = NULL;
X
X    xlsubr("debug", debug);
X}
//go.sysin dd *
/bin/chmod 664 xldebug.c
/bin/echo -n '	'; /bin/ls -ld xldebug.c
/bin/echo 'Extracting xldmem.c'
sed 's/^X//' <<'//go.sysin dd *' >xldmem.c
X	     /* xldmem - xlisp dynamic memory management routines */
X
X#ifdef CI_86
X#include "a:stdio.h"
X#include "xlisp.h"
X#endif
X
X#ifdef AZTEC
X#include "a:stdio.h"
X#include "xlisp.h"
X#endif
X
X#ifdef unix
X#include <stdio.h>
X#include <xlisp.h>
X#endif
X
X
X
X			    /* useful definitions */
X
X#define ALLOCSIZE (sizeof(struct segment) + anodes * sizeof(struct node))
X
X
X		    /* memory segment structure definition */
X
Xstruct segment {
X    int sg_size;
X    struct segment *sg_next;
X    struct node sg_nodes[];
X};
X
X			    /* external variables */
X
Xextern struct node *oblist;
Xextern struct node *xlstack;
Xextern struct node *xlenv;
X
X
X			    /* external procedures */
X
Xextern char *malloc();
Xextern char *calloc();
X
X
X			      /* local variables */
X
Xint anodes,nnodes,nsegs,nfree,gccalls;
Xstatic struct segment *segs;
Xstatic struct node *fnodes;
X
X
X		       /**********************************
X		       *  newnode - allocate a new node  *
X		       **********************************/
X
Xstruct node *newnode(type)
X  int type;
X{
X    struct node *nnode;
X
X    /* get a free node */
X    if ((nnode = fnodes) == NULL) {
X	gc();
X	if ((nnode = fnodes) == NULL)
X	    xlfail("insufficient node space");
X    }
X
X    /* unlink the node from the free list */
X    fnodes = nnode->n_right;
X    nfree -= 1;
X
X    /* initialize the new node */
X    nnode->n_type = type;
X    nnode->n_left = NULL;
X    nnode->n_right = NULL;
X
X    /* return the new node */
X    return (nnode);
X}
X
X
X /*****************************************************************************
X *  stralloc - allocate memory for a string adding a byte for the terminator  *
X *****************************************************************************/
X
Xchar *stralloc(size)
X  int size;
X{
X    char *sptr;
X
X    /* allocate memory for the string copy */
X    if ((sptr = malloc(size+1)) == NULL) {
X	gc();
X	if ((sptr = malloc(size+1)) == NULL)
X	    xlfail("insufficient string space");
X    }
X
X    /* return the new string memory */
X    return (sptr);
X}
X
X
X	       /**************************************************
X	       *  strsave - generate a dynamic copy of a string  *
X	       **************************************************/
X
Xchar *strsave(str)
X  char *str;
X{
X    char *sptr;
X
X    /*     */
X    sptr = stralloc(strlen(str));
X    strcpy(sptr,str);
X
X    /* return the new string */
X    return (sptr);
X}
X
X
X		       /*********************************
X		       *  strfree - free string memory  *
X		       *********************************/
X
Xstrfree(str)
X  char *str;
X{
X    free(str);
X}
X
X
X			   /*************************
X			   *  gc - garbage collect  *
X			   *************************/
X
Xstatic gc()
X{
X    unmark();                          /* Unmark all nodes */
X
X#ifdef DEBUG
X    xldbgmsg("\n\tOBLIST mark");
X    mark(oblist);
X    xldbgmsg("\n\tSTACK mark");
X    mark(xlstack);
X    xldbgmsg("\n\tENVIRONMENT");
X    mark(xlenv);
X#else
X    mark(oblist);                      /* Mark all accessible nodes */
X    mark(xlstack);
X    mark(xlenv);
X#endif
X
X    sweep();                           /* Sweep up the grabage */
X
X    if (fnodes == NULL)                /* Allocate more if necessary */
X	addseg();
X
X    gccalls += 1;
X}
X
X
X			 /******************************
X			 *  unmark - unmark each node  *
X			 ******************************/
X
Xstatic unmark()
X{
X    struct node *n = xlstack;
X
X    while (n != NULL)                       /* Unmark the stack */
X    {
X	n->n_flags &= ~(MARK | LEFT);
X	n = n->n_listnext;
X    }
X}
X
X		     /*************************************
X		     *  mark - mark all accessible nodes  *
X		     *************************************/
X
Xstatic mark(ptr)
X  struct node *ptr;
X{
X    struct node *this,*prev,*tmp;
X
X    if (ptr == NULL)                   /* Return on null */
X	return;
X
X    prev = NULL;                       /* Initialize */
X    this = ptr;
X
X    while (TRUE)                       /* Mark this list */
X    {
X	while (TRUE)                   /* Descend as far as we can */
X	{
X	    if (this->n_flags & MARK)  /* Node already marked ? */
X		break;
X	    else                       /* NO : mark it and its descendents */
X	    {
X
X#ifdef DEBUG
X		xldump(this);
X#endif
X		this->n_flags |= MARK; /* This node ...*/
X
X		if (left(this))        /* .. the left sublist */
X		{
X		    this->n_flags |= LEFT;
X		    tmp = prev;
X		    prev = this;
X		    this = prev->n_left;
X		    prev->n_left = tmp;
X		}
X		else
X		if (right(this))       /* .. the right sublist */
X		{
X		    this->n_flags &= ~LEFT;
X		    tmp = prev;
X		    prev = this;
X		    this = prev->n_right;
X		    prev->n_right = tmp;
X		}
X		else
X		    break;
X	    }
X	}
X
X	while (TRUE)                   /* Backup to last restart point */
X	{
X	    if (prev == NULL)          /* Finished yet ? */
X		return;
X
X	    if (prev->n_flags & LEFT)  /* Coming from left side ? */
X	    {
X		if (right(prev))
X		{
X		    prev->n_flags &= ~LEFT;
X		    tmp = prev->n_left;
X		    prev->n_left = this;
X		    this = prev->n_right;
X		    prev->n_right = tmp;
X		    break;
X		}
X		else
X		{
X		    tmp = prev;
X		    prev = tmp->n_left;
X		    tmp->n_left = this;
X		    this = tmp;
X		}
X	    }
X	    else                       /* came from the right side */
X	    {
X		tmp = prev;
X		prev = tmp->n_right;
X		tmp->n_right = this;
X		this = tmp;
X	    }
X	}
X    }
X}
X
X
X      /*******************************************************************
X      *  sweep - sweep all unmarked nodes and add them to the free list  *
X      *******************************************************************/
X
Xstatic sweep()
X{
X    struct segment *seg;
X    struct node *n;
X    int i;
X
X    fnodes = NULL;                               /* Empty the free list */
X    nfree = 0;
X
X    /* add all unmarked nodes */
X    for (seg = segs; seg != NULL; seg = seg->sg_next)
X	for (i = 0; i < seg->sg_size; i++)
X	    if (!((n = &seg->sg_nodes[i])->n_flags & MARK))
X	    {
X		switch (n->n_type)
X		{
X		case STR:
X			if (n->n_strtype == DYNAMIC && n->n_str != NULL)
X			    strfree(n->n_str);
X			break;
X
X		case SYM:
X			if (n->n_symname != NULL)
X			    strfree(n->n_symname);
X			break;
X
X#ifdef KEYMAPCLASS
X		case KMAP:
X			xlkmfree(n);
X			break;
X#endif
X		}
X
X		n->n_type = FREE;
X		n->n_left = NULL;
X		n->n_right = fnodes;
X		fnodes = n;
X		nfree += 1;
X	    }
X	    else
X		n->n_flags &= ~MARK;
X}
X
X
X	      /***************************************************
X	      *  addseg - add a segment to the available memory  *
X	      ***************************************************/
X
Xstatic int addseg()
X{
X    struct segment *newseg;
X    int i;
X
X				       /* allocate a new segment */
X    if ((newseg = (struct segment *) calloc(1,ALLOCSIZE)) != NULL)
X    {
X	newseg->sg_size = anodes;      /* Initialize the new segment */
X	newseg->sg_next = segs;
X	segs = newseg;
X				       /* add each new node to the free list */
X	for (i = 0; i < newseg->sg_size; i++)
X	{
X	    newseg->sg_nodes[i].n_right = fnodes;
X	    fnodes = &newseg->sg_nodes[i];
X	}
X
X	nnodes += anodes;              /* Update the statistics */
X	nfree += anodes;
X	nsegs += 1;
X
X	return (TRUE);                 /* return success */
X    }
X    else
X	return (FALSE);
X}
X
X
X		      /************************************
X		      *  left - check for a left sublist  *
X		      ************************************/
X
Xstatic int left(n)
X  struct node *n;
X{
X    switch (n->n_type)
X    {
X    case SYM:
X    case SUBR:
X    case INT:
X    case STR:
X    case FPTR:
X    case REAL:
X	    return (FALSE);
X
X#ifdef KEYMAPCLASS
X    case KMAP:
X	    xlkmmark(n);
X	    return (FALSE);
X#endif
X
X    case LIST:
X    case OBJ:
X	    return (n->n_left != NULL);
X
X    default:
X	    printf("bad node type (%d) found during left scan\n",n->n_type);
X	    exit();
X    }
X}
X
X
X		     /**************************************
X		     *  right - check for a right sublist  *
X		     **************************************/
X
Xstatic int right(n)
X  struct node *n;
X{
X    switch (n->n_type)
X    {
X    case SUBR:
X    case INT:
X    case REAL:
X    case STR:
X    case FPTR:
X    case KMAP:
X	    return (FALSE);
X
X    case SYM:
X    case LIST:
X    case OBJ:
X	    return (n->n_right != NULL);
X
X    default:
X	    printf("bad node type (%d) found during right scan\n",n->n_type);
X	    exit();
X    }
X}
X
X
X		      /************************************
X		      *  stats - print memory statistics  *
X		      ************************************/
X
Xstatic stats()
X{
X    printf("\nNodes:       %d\n",nnodes);
X    printf("Free nodes:  %d\n",nfree);
X    printf("Segments:    %d\n",nsegs);
X    printf("Allocate:    %d\n",anodes);
X    printf("Collections: %d\n\n",gccalls);
X}
X
X
X	     /*****************************************************
X	     *  fgc - xlisp function to force garbage collection  *
X	     *****************************************************/
X
Xstatic struct node *fgc(args)
X  struct node *args;
X{
X    xllastarg(args);                   /* No arguments */
X    gc();                              /* Collect that garbage */
X    return (NULL);
X}
X
X
X	    /*******************************************************
X	    *  fexpand - xlisp function to force memory expansion  *
X	    *******************************************************/
X
Xstatic struct node *fexpand(args)
X  struct node *args;
X{
X    struct node *val;
X    int n,i;
X
X				       /* get new number to allocate */
X    n = (args == NULL) ? 1 : xlevmatch(INT, &args)->n_int;
X    xllastarg(args);                   /* No more arguments */
X
X    for (i = 0; i < n; i++)            /* Allocate more segments */
X	if (!addseg())
X	    break;
X
X    val = newnode(INT);                /* Return number of segments added */
X    val->n_int = i;
X    return (val);
X}
X
X      /*******************************************************************
X      *  falloc - xlisp function to set the number of nodes to allocate  *
X      *******************************************************************/
X
Xstatic struct node *falloc(args)
X  struct node *args;
X{
X    struct node *val;
X    int n,oldn;
X
X    n = xlevmatch(INT,&args)->n_int;   /* new number to allocate */
X    xllastarg(args);                   /* No more arguments */
X
X    oldn = anodes;                     /* Set new number */
X    anodes = n;
X
X    val = newnode(INT);                /* Return old value */
X    val->n_int = oldn;
X    return (val);
X}
X
X
X	     /*****************************************************
X	     *  fmem - xlisp function to print memory statistics  *
X	     *****************************************************/
X
Xstatic struct node *fmem(args)
X  struct node *args;
X{
X    xllastarg(args);                   /* No arguments */
X    stats();                           /* Print statistics */
X    return (NULL);
X}
X
X
X	     /******************************************************
X	     *  xldmeminit - initialize the dynamic memory module  *
X	     ******************************************************/
X
Xxldmeminit()
X{
X    anodes = NNODES;                   /* Default number of nodes */
X    nnodes = nsegs = nfree = gccalls = 0;
X
X    xlsubr("gc",fgc);                  /* Define some xlisp functions */
X    xlsubr("expand",fexpand);
X    xlsubr("alloc",falloc);
X    xlsubr("mem",fmem);
X}
//go.sysin dd *
/bin/chmod 664 xldmem.c
/bin/echo -n '	'; /bin/ls -ld xldmem.c
/bin/echo 'Extracting xleval.c'
sed 's/^X//' <<'//go.sysin dd *' >xleval.c
X			  /* XLISP evaluation module */
X
X#ifdef CI_86
X#include "a:stdio.h"
X#include "xlisp.h"
X#endif
X
X
X#ifdef AZTEC
X#include "a:stdio.h"
X#include "a:setjmp.h"
X#include "xlisp.h"
X#endif
X
X#ifdef unix
X#include <stdio.h>
X#include <setjmp.h>
X#include <xlisp.h>
X#endif
X
X
X			     /* global variables */
X    struct node *xlstack;
X
X				/* trace stack */
X    static struct node *trace_stack[TDEPTH];
X    static int trace_pointer;
X
X			    /* external variables */
X    extern struct node *xlenv;
X
X			      /* local variables */
X    static struct node *slash;
X
X	   /* forward declarations (the extern hack is for decusc) */
X    extern struct node *evlist();
X    extern struct node *evsym();
X    extern struct node *evfun();
X
X
X		    /***************************************
X		    *  eval - the builtin function 'eval'  *
X		    ***************************************/
X
Xstatic struct node *eval(args)
X    struct node *args;
X{
X    struct node *oldstk,expr,*val;
X
X    oldstk = xlsave(&expr,NULL);                 /* Create new stack frame */
X
X    expr.n_ptr = xlevarg(&args);                 /* Expression to evaluate */
X    xllastarg(args);                             /* No more args ! */
X
X    val = xleval(expr.n_ptr);                    /* Do evaluation */
X
X    xlstack = oldstk;                            /* Restore old stack frame */
X    return (val);
X}
X
X		   /******************************************
X		   *  xleval - evaluate an xlisp expression  *
X		   ******************************************/
X
X
Xstruct node *xleval(expr)
X    struct node *expr;
X{
X    if (expr == NULL)                            /* Null evaluates to null */
X	return (NULL);
X
X    switch (expr->n_type)                        /* Value type */
X    {
X    case LIST:
X	    return (evlist(expr));
X
X    case SYM:
X	    return (evsym(expr));
X
X    case INT:
X    case STR:
X    case SUBR:
X    case REAL:
X	    return (expr);
X
X    default:
X	    xlfail("can't evaluate expression");
X    }
X}
X
X
X
X		     /*************************************
X		     *  xlsave - save nodes on the stack  *
X		     *************************************/
X
Xstruct node *xlsave(n)
X    struct node *n;
X{
X    struct node **nptr,*oldstk;
X
X    oldstk = xlstack;                            /* Save old stack pointer */
X
X    for (nptr = &n; *nptr != NULL; nptr++)       /* Save for each node */
X    {
X	(*nptr)->n_type = LIST;
X	(*nptr)->n_listvalue = NULL;
X	(*nptr)->n_listnext = xlstack;
X	xlstack = *nptr;
X    }
X
X    return (oldstk);                             /* Return old stack pointer */
X}
X
X
X
X			 /*****************************
X			 *  evlist - evaluate a list  *
X			 *****************************/
X
Xstatic struct node *evlist(nptr)
X    struct node *nptr;
X{
X    struct node *oldstk,fun,args,*val;
X
X    oldstk = xlsave(&fun,&args,NULL);            /* Creat a stack frame */
X
X    fun.n_ptr = nptr->n_listvalue;               /* Get function and arg list */
X    args.n_ptr = nptr->n_listnext;
X
X    tpush(nptr);                                 /* Add trace entry */
X
X    if ((fun.n_ptr = xleval(fun.n_ptr)) == NULL) /* Evaluate first expression */
X	xlfail("null function");
X
X    switch (fun.n_ptr->n_type)                   /* Evaluate function */
X    {
X    case SUBR:
X	    val = (*fun.n_ptr->n_subr)(args.n_ptr);
X	    break;
X
X    case LIST:
X	    val = evfun(fun.n_ptr,args.n_ptr);
X	    break;
X
X    case OBJ:
X	    val = xlsend(fun.n_ptr,args.n_ptr);
X	    break;
X
X    default:
X	    xlfail("bad function");
X    }
X
X    xlstack = oldstk;                            /* Restore old stack frame */
X    tpop();                                      /* Remove trace entry */
X    return (val);                                /* and return result value */
X}
X
X
X
X			 /******************************
X			 *  evsym - evaluate a symbol  *
X			 ******************************/
X
Xstatic struct node *evsym(sym)
X    struct node *sym;
X{
X    struct node *lptr;
X
X    if ((lptr = xlobsym(sym)) != NULL)           /* Check for current object */
X	return (lptr->n_listvalue);
X    else
X	return (sym->n_symvalue);
X}
X
X
X			/********************************
X			*  evfun - evaluate a function  *
X			********************************/
X
Xstatic struct node *evfun(fun,args)
X    struct node *fun,*args;
X{
X    struct node *oldenv,*oldstk,cptr,*fargs,*val;
X
X    oldstk = xlsave(&cptr,NULL);                 /* Creat a new stack frame */
X
X					    /* get the formal argument list */
X    if ((fargs = fun->n_listvalue) != NULL && fargs->n_type != LIST)
X	xlfail("bad formal argument list");
X
X    oldenv = xlenv;                              /* Bind the formal parameters*/
X    xlabind(fargs,args);
X    xlfixbindings(oldenv);
X
X    for (cptr.n_ptr = fun->n_listnext; cptr.n_ptr != NULL; )    /* execute */
X	val = xlevarg(&cptr.n_ptr);
X
X    xlunbind(oldenv);                            /* Restore environment */
X    xlstack = oldstk;                            /* ..then the stack frame */
X    return (val);                                /* ...and return result */
X}
X
X
X
X		/************************************************
X		*  xlabind - bind the arguments for a function  *
X		************************************************/
X
Xxlabind(fargs,aargs)
X    struct node *fargs,*aargs;
X{
X    struct node *oldstk,farg,aarg,val;
X
X    oldstk = xlsave(&farg,&aarg,&val,NULL);      /* Create a stack frame */
X
X    farg.n_ptr = fargs;                          /* Initialze the pointers */
X    aarg.n_ptr = aargs;
X
X    while (farg.n_ptr != NULL && aarg.n_ptr != NULL)  /* evaluate and bind */
X    {
X	if (farg.n_ptr->n_listvalue == slash)    /* Check for local separator*/
X	    break;
X
X	val.n_ptr = xlevarg(&aarg.n_ptr);        /* Evaluate the arg */
X	xlbind(farg.n_ptr->n_listvalue,val.n_ptr);    /* ..and bind to formal */
X
X	farg.n_ptr = farg.n_ptr->n_listnext;     /* Move pointer ahead */
X    }
X
X						 /* check for local variables */
X    if (farg.n_ptr != NULL && farg.n_ptr->n_listvalue == slash)
X	while ((farg.n_ptr = farg.n_ptr->n_listnext) != NULL)
X	    xlbind(farg.n_ptr->n_listvalue,NULL);
X
X    xlstack = oldstk;                            /* Restore old stack frame */
X
X    if (farg.n_ptr != aarg.n_ptr)                /* Check for correct # */
X	xlfail("incorrect number of arguments to a function");
X}
X
X
X
X		      /************************************
X		      *  xlfail - error handling routine  *
X		      ************************************/
X
Xxlfail(err)
X    char *err;
X{
X    printf("error: %s\n",err);         /* Print the error message */
X    xlunbind(NULL);                    /* Unbind any bound symbols */
X    xltin(TRUE);                       /* Restore input to terminal */
X    trace();                           /* Do the back trace */
X    trace_pointer = -1;
X    xlabort();                         /* Restart */
X}
X
X
X		  /********************************************
X		  *  tpush - add an entry to the trace stack  *
X		  ********************************************/
X
Xstatic tpush(nptr)
X    struct node *nptr;
X{
X    if (++trace_pointer < TDEPTH)
X	trace_stack[trace_pointer] = nptr;
X}
X
X
X
X		 /*********************************************
X		 *  tpop - pop an entry from the trace stack  *
X		 *********************************************/
X
Xstatic tpop()
X{
X    trace_pointer--;
X}
X
X
X
X			  /****************************
X			  *  trace - do a back trace  *
X			  ****************************/
X
Xstatic trace()
X{
X    for (; trace_pointer >= 0; trace_pointer--)
X	if (trace_pointer < TDEPTH)
X	 {
X	    xlprint(trace_stack[trace_pointer],TRUE);
X	    putchar('\n');
X	}
X}
X
X
X
X		    /***************************************
X		    *  xleinit - initialize the evaluator  *
X		    ***************************************/
X
Xxleinit()
X{
X    slash = xlenter("/");              /* the local variable separator */
X
X    trace_pointer = -1;                /* Initialize debugging */
X
X    xlsubr("eval",eval);               /* Built in functions from this module */
X}
//go.sysin dd *
/bin/chmod 664 xleval.c
/bin/echo -n '	'; /bin/ls -ld xleval.c
/bin/echo 'Extracting xlfio.c'
sed 's/^X//' <<'//go.sysin dd *' >xlfio.c
X			  /* xlfio - xlisp file i/o */
X
X#ifdef CI_86
X#include "a:stdio.h"
X#include "xlisp.h"
X#endif
X
X#ifdef AZTEC
X#include "a:stdio.h"
X#include "xlisp.h"
X#endif
X
X#ifdef unix
X#include <stdio.h>
X#include <xlisp.h>
X#endif
X
X
X			    /* external variables */
X
Xextern struct node *xlstack;
X
X
X			      /* local variables */
X
Xstatic char buf[STRMAX+1];
X
X
X			   /**************************
X			   *  xlfopen - open a file  *
X			   **************************/
X
Xstatic struct node *xlfopen(args)
X  struct node *args;
X{
X    struct node *oldstk,arg,fname,mode,*val;
X    FILE *fp;
X
X    oldstk = xlsave(&arg,&fname,&mode,NULL);
X    arg.n_ptr = args;
X
X    fname.n_ptr = xlevmatch(STR,&arg.n_ptr);
X    mode.n_ptr = xlevmatch(STR,&arg.n_ptr);
X
X    xllastarg(arg.n_ptr);
X
X    if ((fp = fopen(fname.n_ptr->n_str,
X			mode.n_ptr->n_str)) != NULL)
X    {
X	val = newnode(FPTR);
X	val->n_fp = fp;
X    }
X    else
X	val = NULL;
X
X    xlstack = oldstk;
X    return (val);
X}
X
X
X			  /****************************
X			  *  xlfclose - close a file  *
X			  ****************************/
X
Xstatic struct node *xlfclose(args)
X  struct node *args;
X{
X    struct node *fptr;
X
X    fptr = xlevmatch(FPTR,&args);
X
X    xllastarg(args);
X
X    if (fptr->n_fp == NULL)
X	xlfail("file not open");
X
X    fclose(fptr->n_fp);
X    fptr->n_fp = NULL;
X
X    return (NULL);
X}
X
X
X		   /*****************************************
X		   *  xlgetc - get a character from a file  *
X		   *****************************************/
X
Xstatic struct node *xlgetc(args)
X  struct node *args;
X{
X    struct node *val;
X    FILE *fp;
X    int ch;
X
X    if (args != NULL)
X	fp = xlevmatch(FPTR,&args)->n_fp;
X    else
X	fp = stdin;
X
X    xllastarg(args);
X
X    if (fp == NULL)
X	xlfail("file not open");
X
X    if ((ch = getc(fp)) != EOF)
X    {
X	val = newnode(INT);
X	val->n_int = ch;
X    }
X    else
X	val = NULL;
X
X    return (val);
X}
X
X
X		    /***************************************
X		    *  xlputc - put a character to a file  *
X		    ***************************************/
X
Xstatic struct node *xlputc(args)
X  struct node *args;
X{
X    struct node *oldstk,arg,chr;
X    FILE *fp;
X
X    oldstk = xlsave(&arg,&chr,NULL);
X    arg.n_ptr = args;
X
X    chr.n_ptr = xlevmatch(INT,&arg.n_ptr);
X
X    if (arg.n_ptr != NULL)
X	fp = xlevmatch(FPTR,&arg.n_ptr)->n_fp;
X    else
X	fp = stdout;
X
X    xllastarg(arg.n_ptr);
X
X    if (fp == NULL)
X	xlfail("file not open");
X
X    putc(chr.n_ptr->n_int,fp);
X
X    xlstack = oldstk;
X    return (chr.n_ptr);
X}
X
X
X		    /***************************************
X		    *  xlfgets - get a string from a file  *
X		    ***************************************/
X
Xstatic struct node *xlfgets(args)
X  struct node *args;
X{
X    struct node *str;
X    char *sptr;
X    FILE *fp;
X
X    if (args != NULL)
X	fp = xlevmatch(FPTR,&args)->n_fp;
X    else
X	fp = stdin;
X
X    xllastarg(args);
X
X    if (fp == NULL)
X	xlfail("file not open");
X
X    if (fgets(buf,STRMAX,fp) != NULL)
X    {
X	str = newnode(STR);
X	str->n_str = strsave(buf);
X
X	while (buf[strlen(buf)-1] != '\n')
X	{
X	    if (fgets(buf,STRMAX,fp) == NULL)
X		break;
X	    sptr = str->n_str;
X	    str->n_str = stralloc(strlen(sptr) + strlen(buf));
X	    strcpy(str->n_str,sptr);
X	    strcat(buf);
X	    strfree(sptr);
X	}
X    }
X    else
X	str = NULL;
X
X    return (str);
X}
X
X
X		     /*************************************
X		     *  xlfputs - put a string to a file  *
X		     *************************************/
X
Xstatic struct node *xlfputs(args)
X  struct node *args;
X{
X    struct node *oldstk,arg,str;
X    FILE *fp;
X
X    oldstk = xlsave(&arg,&str,NULL);
X    arg.n_ptr = args;
X
X    str.n_ptr = xlevmatch(STR,&arg.n_ptr);
X
X    if (arg.n_ptr != NULL)
X	fp = xlevmatch(FPTR,&arg.n_ptr)->n_fp;
X    else
X	fp = stdout;
X
X    xllastarg(arg.n_ptr);
X
X    if (fp == NULL)
X	xlfail("file not open");
X
X    fputs(str.n_ptr->n_str,fp);
X
X    xlstack = oldstk;
X    return (str.n_ptr);
X}
X
X
X		      /************************************
X		      *  xlfinit - initialize file stuff  *
X		      ************************************/
X
Xxlfinit()
X{
X    xlsubr("fopen",xlfopen);
X    xlsubr("fclose",xlfclose);
X    xlsubr("getc",xlgetc);
X    xlsubr("putc",xlputc);
X    xlsubr("fgets",xlfgets);
X    xlsubr("fputs",xlfputs);
X}
//go.sysin dd *
/bin/chmod 664 xlfio.c
/bin/echo -n '	'; /bin/ls -ld xlfio.c
/bin/echo 'Extracting xlsubr.c'
sed 's/^X//' <<'//go.sysin dd *' >xlsubr.c
X		     /* xlsubr - xlisp builtin functions */
X#ifdef CI_86
X#include "a:stdio.h"
X#include "xlisp.h"
X#endif
X
X#ifdef AZTEC
X#include "a:stdio.h"
X#include "xlisp.h"
X#endif
X
X#ifdef unix
X#include <stdio.h>
X#include <xlisp.h>
X#endif
X
X
X			    /* external variables */
X
Xextern int (*xlgetc)();
Xextern struct node *xlstack;
X
X
X			      /* local variables */
X
Xstatic char *sgetptr;
X
X
X		    /***************************************
X		    *  xlsubr - define a builtin function  *
X		    ***************************************/
X
Xxlsubr(sname,subr)
X  char *sname; struct node *(*subr)();
X{
X    struct node *sym;
X
X    sym = xlenter(sname);              /* Enter the symbol */
X
X    sym->n_symvalue = newnode(SUBR);   /* Initialize the value */
X    sym->n_symvalue->n_subr = subr;
X}
X
X
X		 /**********************************************
X		 *  xlsvar - define a builtin string variable  *
X		 **********************************************/
X
Xxlsvar(sname,str)
X  char *sname,*str;
X{
X    struct node *sym;
X
X    sym = xlenter(sname);              /* Enter the symbol */
X
X    sym->n_symvalue = newnode(STR);    /* Initialize the value */
X    sym->n_symvalue->n_str = strsave(str);
X}
X
X
X		       /**********************************
X		       *  xlarg - get the next argument  *
X		       **********************************/
X
Xstruct node *xlarg(pargs)
X  struct node **pargs;
X{
X    struct node *arg;
X
X    if (*pargs == NULL)                /* Does argument exist ? */
X	xlfail("too few arguments");
X
X    arg = (*pargs)->n_listvalue;       /* If so get its value */
X    *pargs = (*pargs)->n_listnext;     /* and mov arg pointer ahead */
X
X    return (arg);
X}
X
X
X	       /*************************************************
X	       *  xlmatch - get an argument and match its type  *
X	       *************************************************/
X
Xstruct node *xlmatch(type,pargs)
X  int type; struct node **pargs;
X{
X    struct node *arg;
X
X    arg = xlarg(pargs);                /* Get the argument */
X    if (type == LIST)                  /* Check its type */
X    {
X	if (arg != NULL && arg->n_type != LIST)
X	    xlfail("bad argument type");
X    }
X    else
X    {
X	if (arg == NULL || arg->n_type != type)
X	    xlfail("bad argument type");
X    }
X
X    return (arg);
X}
X
X
X	      /****************************************************
X	      *  xlevarg - get the next argument and evaluate it  *
X	      ****************************************************/
X
Xstruct node *xlevarg(pargs)
X  struct node **pargs;
X{
X    struct node *oldstk,val;
X
X    oldstk = xlsave(&val,NULL);        /* Creat new stack frame */
X
X    val.n_ptr = xlarg(pargs);          /* Get and evaluate the argument */
X    val.n_ptr = xleval(val.n_ptr);
X
X    xlstack = oldstk;                  /* Restore old stack frame */
X    return (val.n_ptr);
X}
X
X
X	 /*************************************************************
X	 *  xlevmatch - get an evaluated argument and match its type  *
X	 *************************************************************/
X
Xstruct node *xlevmatch(type,pargs)
X  int type; struct node **pargs;
X{
X    struct node *arg;
X
X    arg = xlevarg(pargs);              /* Get argument and check type */
X    if (type == LIST)
X    {
X	if (arg != NULL && arg->n_type != LIST)
X	    xlfail("bad argument type");
X    }
X    else
X    {
X	if (arg == NULL || arg->n_type != type)
X	    xlfail("bad argument type");
X    }
X
X    return (arg);
X}
X
X
X     /**********************************************************************
X     *  xllastarg - make sure the remainder of the argument list is empty  *
X     **********************************************************************/
X
Xxllastarg(args)
X  struct node *args;
X{
X    if (args != NULL)
X	xlfail("too many arguments");
X}
X
X
X		    /****************************************
X		    *  assign - assign a value to a symbol  *
X		    ****************************************/
X
Xstatic assign(sym,val)
X  struct node *sym,*val;
X{
X    struct node *lptr;
X
X    if ((lptr = xlobsym(sym)) != NULL)      /* Check for a current object */
X	lptr->n_listvalue = val;
X    else
X	sym->n_symvalue = val;
X}
X
X
X			/*******************************
X			*  set - builtin function set  *
X			*******************************/
X
Xstatic struct node *set(args)
X  struct node *args;
X{
X    struct node *oldstk,arg,sym,val;
X
X    oldstk = xlsave(&arg,&sym,&val,NULL);   /* Create new stack frame */
X    arg.n_ptr = args;
X
X    sym.n_ptr = xlevmatch(SYM,&arg.n_ptr);  /* Get symbol */
X    val.n_ptr = xlevarg(&arg.n_ptr);
X    xllastarg(arg.n_ptr);
X    assign(sym.n_ptr,val.n_ptr);
X
X    xlstack = oldstk;                       /* Restore old stack frame */
X    return (val.n_ptr);
X}
X
X
X		       /*********************************
X		       *  setq - builtin function setq  *
X		       *********************************/
X
Xstatic struct node *setq(args)
X  struct node *args;
X{
X    struct node *oldstk,arg,sym,val;
X
X    oldstk = xlsave(&arg,&sym,&val,NULL);   /* Create new stack frame */
X    arg.n_ptr = args;
X
X    sym.n_ptr = xlmatch(SYM,&arg.n_ptr);     /* get symbol */
X    val.n_ptr = xlevarg(&arg.n_ptr);
X    xllastarg(arg.n_ptr);
X    assign(sym.n_ptr,val.n_ptr);
X
X    xlstack = oldstk;                       /* Restore old stack frame */
X    return (val.n_ptr);
X}
X
X
X		      /************************************
X		      *  load - direct input from a file  *
X		      ************************************/
X
Xstatic struct node *load(args)
X  struct node *args;
X{
X    struct node *fname;
X
X    fname = xlevmatch(STR,&args);           /* Get file name */
X    xllastarg(args);
X
X    xlfin(fname->n_str);
X
X    return (fname);
X}
X
X
X		      /***********************************
X		      *  defun - builtin function defun  *
X		      ***********************************/
X
Xstatic struct node *defun(args)
X  struct node *args;
X{
X    struct node *oldstk,arg,sym,fargs,fun;
X
X    /* create a new stack frame */
X    oldstk = xlsave(&arg,&sym,&fargs,&fun,NULL);
X
X    /* initialize */
X    arg.n_ptr = args;
X
X    /* get the function symbol */
X    sym.n_ptr = xlmatch(SYM,&arg.n_ptr);
X
X    /* get the formal argument list */
X    fargs.n_ptr = xlmatch(LIST,&arg.n_ptr);
X
X    /* create a new function definition */
X    fun.n_ptr = newnode(LIST);
X    fun.n_ptr->n_listvalue = fargs.n_ptr;
X    fun.n_ptr->n_listnext = arg.n_ptr;
X
X    /* make the symbol point to a new function definition */
X    assign(sym.n_ptr,fun.n_ptr);
X
X    /* restore the previous stack frame */
X    xlstack = oldstk;
X
X    /* return the function symbol */
X    return (sym.n_ptr);
X}
X
X
X		   /******************************************
X		   *  sgetc - get a character from a string  *
X		   ******************************************/
X
Xstatic int sgetc()
X{
X    if (*sgetptr == 0)
X	return (-1);
X    else
X	return (*sgetptr++);
X}
X
X
X			 /******************************
X			 *  read - read an expression  *
X			 ******************************/
X
Xstatic struct node *read(args)
X  struct node *args;
X{
X    struct node *val;
X    int (*oldgetc)();
X
X    /* save the old input stream */
X    oldgetc = xlgetc;
X
X    /* get the string or file pointer */
X    if (args != NULL) {
X	sgetptr = xlevmatch(STR,&args)->n_str;
X	xlgetc = sgetc;
X    }
X
X    /* make sure there aren't any more arguments */
X    xllastarg(args);
X
X    val = xlread();
X    xlgetc = oldgetc;
X
X    return (val);
X}
X
X
X		      /************************************
X		      *  fwhile - builtin function while  *
X		      ************************************/
X
Xstatic struct node *fwhile(args)
X  struct node *args;
X{
X    struct node *oldstk,farg,arg,*val;
X
X    /* create a new stack frame */
X    oldstk = xlsave(&farg,&arg,NULL);
X
X    /* initialize */
X    farg.n_ptr = arg.n_ptr = args;
X
X    /* loop until test fails */
X    val = NULL;
X    for (; TRUE; arg.n_ptr = farg.n_ptr) {
X
X	/* evaluate the test expression */
X	if (!testvalue(xlevarg(&arg.n_ptr)))
X	    break;
X
X	/* evaluate each remaining argument */
X	while (arg.n_ptr != NULL)
X	    val = xlevarg(&arg.n_ptr);
X    }
X
X    /* restore the previous stack frame */
X    xlstack = oldstk;
X
X    /* return the last test expression value */
X    return (val);
X}
X
X
X		     /**************************************
X		     **************************************/
X
Xstatic struct node *frepeat(args)
X  struct node *args;
X{
X    struct node *oldstk,farg,arg,*val;
X    int cnt;
X
X    /* create a new stack frame */
X    oldstk = xlsave(&farg,&arg,NULL);
X
X    /* initialize */
X    arg.n_ptr = args;
X
X    cnt = xlevmatch(INT,&arg.n_ptr)->n_int;
X
X    /* save the first expression to repeat */
X    farg.n_ptr = arg.n_ptr;
X
X    /* loop until test fails */
X    val = NULL;
X    for (; cnt > 0; cnt--) {
X
X	/* evaluate each remaining argument */
X	while (arg.n_ptr != NULL)
X	    val = xlevarg(&arg.n_ptr);
X
X	/* restore pointer to first expression */
X    }
X
X    /* restore the previous stack frame */
X    xlstack = oldstk;
X
X    /* return the last test expression value */
X    return (val);
X}
X
X
X		    /***************************************
X		    *  foreach - builtin function foreach  *
X		    ***************************************/
X
Xstatic struct node *foreach(args)
X  struct node *args;
X{
X    struct node *oldstk,arg,sym,list,code,oldbnd,*val;
X
X    /* create a new stack frame */
X    oldstk = xlsave(&arg,&sym,&list,&code,&oldbnd,NULL);
X
X    /* initialize */
X    arg.n_ptr = args;
X
X    /* get the symbol to bind to each list element */
X    sym.n_ptr = xlmatch(SYM,&arg.n_ptr);
X    /* save the old binding of the symbol */
X    oldbnd.n_ptr = sym.n_ptr->n_symvalue;
X
X    /* get the list to iterate over */
X    list.n_ptr = xlevmatch(LIST,&arg.n_ptr);
X
X    /* save the pointer to the code */
X    code.n_ptr = arg.n_ptr;
X
X    /* loop until test fails */
X    val = NULL;
X    while (list.n_ptr != NULL) {
X
X	/* check the node type */
X	if (list.n_ptr->n_type != LIST)
X	    xlfail("bad node type in list");
X
X	/* bind the symbol to the list element */
X	sym.n_ptr->n_symvalue = list.n_ptr->n_listvalue;
X
X	/* evaluate each remaining argument */
X	while (arg.n_ptr != NULL)
X	    val = xlevarg(&arg.n_ptr);
X
X	/* point to the next list element */
X	list.n_ptr = list.n_ptr->n_listnext;
X
X	/* restore the pointer to the code */
X	arg.n_ptr = code.n_ptr;
X    }
X
X    /* restore the previous stack frame */
X    xlstack = oldstk;
X
X    /* restore the old binding of the symbol */
X    sym.n_ptr->n_symvalue = oldbnd.n_ptr;
X
X    /* return the last test expression value */
X    return (val);
X}
X
X
X			 /******************************
X			 *  fif - builtin function if  *
X			 ******************************/
X
Xstatic struct node *fif(args)
X  struct node *args;
X{
X    struct node *oldstk,arg,testexpr,thenexpr,elseexpr,*val;
X    int dothen;
X
X    /* create a new stack frame */
X    oldstk = xlsave(&arg,&testexpr,&thenexpr,&elseexpr,NULL);
X
X    /* initialize */
X    arg.n_ptr = args;
X
X    /* evaluate the test expression */
X    testexpr.n_ptr = xlevarg(&arg.n_ptr);
X
X    /* get the then clause */
X    thenexpr.n_ptr = xlmatch(LIST,&arg.n_ptr);
X
X    /* get the else clause */
X    if (arg.n_ptr != NULL)
X	elseexpr.n_ptr = xlmatch(LIST,&arg.n_ptr);
X    else
X	elseexpr.n_ptr = NULL;
X
X    /* make sure there aren't any more arguments */
X    xllastarg(arg.n_ptr);
X
X    /* figure out which expression to evaluate */
X    dothen = testvalue(testexpr.n_ptr);
X
X    /* default the result value to the value of the test expression */
X    val = testexpr.n_ptr;
X
X    /* evaluate the appropriate clause */
X    if (dothen)
X	while (thenexpr.n_ptr != NULL)
X	    val = xlevarg(&thenexpr.n_ptr);
X    else
X	while (elseexpr.n_ptr != NULL)
X	    val = xlevarg(&elseexpr.n_ptr);
X
X    /* restore the previous stack frame */
X    xlstack = oldstk;
X
X    /* return the last value */
X    return (val);
X}
X
X
X	      /****************************************************
X	      *  quote - builtin function to quote an expression  *
X	      ****************************************************/
X
Xstatic struct node *quote(args)
X  struct node *args;
X{
X    /* make sure there is exactly one argument */
X    if (args == NULL || args->n_listnext != NULL)
X	xlfail("incorrect number of arguments");
X
X    /* return the quoted expression */
X    return (args->n_listvalue);
X}
X
X
X			 /*****************************
X			 *  fexit - get out of xlisp  *
X			 *****************************/
X
Xfexit()
X{
X    exit();
X}
X
X
X		/***********************************************
X		*  testvalue - test a value for true or false  *
X		***********************************************/
X
Xstatic int testvalue(val)
X  struct node *val;
X{
X    /* check for a nil value */
X    if (val == NULL)
X	return (FALSE);
X
X    /* check the value type */
X    switch (val->n_type) {
X    case INT:
X	    return (val->n_int != 0);
X
X    case STR:
X	    return (strlen(val->n_str) != 0);
X
X    default:
X	    return (TRUE);
X    }
X}
X
X
X		   /******************************************
X		   *  xlinit - xlisp initialization routine  *
X		   ******************************************/
X
Xxlinit()
X{
X    /* enter a copyright notice into the oblist */
X    xlenter("Copyright-1983-by-David-Betz");
X
X    /* enter the builtin functions */
X    xlsubr("set",set);
X    xlsubr("setq",setq);
X    xlsubr("load",load);
X    xlsubr("read",read);
X    xlsubr("quote",quote);
X    xlsubr("while",fwhile);
X    xlsubr("repeat",frepeat);
X    xlsubr("foreach",foreach);
X    xlsubr("defun",defun);
X    xlsubr("if",fif);
X    xlsubr("exit",fexit);
X}
//go.sysin dd *
/bin/chmod 664 xlsubr.c
/bin/echo -n '	'; /bin/ls -ld xlsubr.c