[net.lang.lisp] problems with xlisp

toby@gargoyle.UChicago.UUCP (Toby Harness) (08/02/84)

> From: ksbc@hirst1.UUCP

> When I try to build xlisp, both under unix III and 4.1 I get an error msg
> from xldmem.c 
> line 31: illegal zero sized structure : sgnodes
> this is part od the definition of struct segment which reads:-
> struct node sg_nodes[];

> Anybody got any advice how to get round this:- 4.1 lets me get away with a
> warning, and xlisp seems to work:- however III wants it to be fatal.

I am posting this reply because I think it may be useful to other readers,
and because I wish to offer some other comments about xlisp.  Note also
that I will not use many "diffs", as I have changed around a fair bit
of code.  I will assume that everyone has read and installed the bug fixes
already posted.

To address the question above first:  The portable C complier, and hence 
most compliers derived from it (and evidently the sys iii complier), won`t
swallow such things as "struct node sg_nodes[]" -- they don`t make syntactic
(or is that lexical?  whatever) sense.  There was some discussion of this
in net.lang.c not that long ago, under the label "open-ended structures".

In any case, the thing you SHOULD do is change this empty structure to a
pointer to a structure, i.e. "struct node sg_nodes[]" to 
"struct node *sg_nodes".  I say "should" because this is the most portable 
way; you might be able to get away with "struct node sg_nodes[1]".  If you do
it the portable way, you will then have change how memory is allocated for 
this structure (that is, struct segment).  Fortunately this is done in only
one place, in addseg, also in xldmem.c (around line 324).  Change

if ((newseg = (struct segment *) calloc(1,ALLOCSIZE)) != NULL) {

to

if((newseg = (struct segment *) calloc(1, sizeof(struct segment))) != NULL &&
   (newseg->sg_nodes = (struct node *) calloc(anodes, sizeof(struct node)))
   != NULL) {

Another portable problem will be with xlsave in xleval.c  Xlsave is passed
a variable number of arguments throughout the xlisp code, but it makes (ok then,
the programmer made) some simple assumptions on how it would recieve those
arguments.  The following fix will only be useful to you if you are fortunate
enough to have <varargs.h>.  First, include a "#define VARARGS" under the
"#ifdef unix" in xlisp.h (I am assuming that varargs is only available to
unix sites), then, of course, you will have to put "#include <varargs.h>" under
the "#ifdef unix" at the top of xleval.c.  Finally, change xlsave to read:

#ifdef VARARGS
struct node *xlsave(va_alist)
	va_dcl
{
	va_list argptr;
	struct node *n, *oldstk;

	oldstk = xlstack;		/* Save old stack pointer */

	va_start(argptr)
	for(n = va_arg(argptr, struct node *); n != NULL;
	    n = va_arg(argptr, struct node *))
	{
		n->n_type = LIST;
		n->n_listvalue = NULL;
		n->n_listnext = xlstack;
		xlstack = n;
	}
	va_end(argptr);
	return(oldstk);			/* Return old stack pointer */
}
#else
struct node *xlsave(n)
...
#endif

(NOTE: the style above is that of the original source, not mine)

A word about reals:  I would think most people would want them, and I see
no reason why they are defined only for the CI-86 compiler when certainly
(for example) every unix C compiler I have seen supports floats.  If you do
"#define REALS" in xlisp.h, you will have to make the following changes
in xllist.c to get the subr "type" to handle them properly.  

Add

#ifdef REALS
static struct node *a_real;
#endif

to the "local variables" section near the top of the file.  Then add

#ifdef REALS
	case REAL: return (a_real);
#endif

to the switch in "type" (around line 140).  And finally put

#ifdef REALS
	a_real = xlenter("REAL");
#endif

along with the other "xlenter"`s in "xllinit" at the end of the file.


With all of that, xlisp seems to work.  There are some problems with
argument binding that I know of, specificly where the expers created
with defun seem to act like fexpers.  Some expers that bomb out leave
values bound to their arguments as well.  I would be interrested in
seeing true fexpers, and for that matter, macros and lexpers, if anyone
is up to it.  I DO realize that xlisp was never intended to be a full
implementation of lisp, but as it is the only lisp running on this
machine .... 

Included below is "xlunix.c", which is a group of utilities designed to
make xlisp more interactive with unix, and the documentation page (to
be tacked on to xlisp.doc) describing them.  They were written by me,
and are in the public domain.  If you wish to use these functions,
you will need to install the following (edited) diffs in xlisp.c:

2d1
< 
25a25
> #include <signal.h> 	/* TH*/
35a36,38
> #ifdef unix		/* TH*/
> static jmp_buf ljmp;
> #else
36a40
> #endif
69a78,82
> #ifdef unix			/* this has to occur after 'xltin' if 
> 				 * reading of '.xlisprc is to work  TH*/
>     xluninit();
> #endif
> 
74a88,93
> #ifdef unix			  /* TH*/
>     signal(SIGCLD, SIG_IGN);	  /* don`t worry when children die */
> 				  /* as created from "system" and "shell" */
> #endif
> 
76a96,98
> #ifdef unix
>     signal(SIGINT, xlintr);	  /* trap interrupts  TH*/
> #endif
100c122,130
<     longjmp(ljmp);
---
>     /*longjmp(ljmp); TH*/
>     longjmp(ljmp, 1);
> }
> 
> 
> xlintr() /* TH*/
> {
>     puts("\nintr");
>     xlabort();

Note that the signal catching, while not necessary, provides for resonable
interrupt servicing.


xlunix.c follows------------------------------------------------
			 /* xlunix - xlisp unix support routines */

			 /* note that it is assumed through-out this file
			  * that "unix" is defined.  This file was written
			  * by Toby Harness (changes in other files marked
			  * by 'TH')
			  */

#include <stdio.h>
#include <xlisp.h>

			/* external functions */
extern char *getenv();
extern char *strchr();
extern int xlfin();

			/* global vars */
extern char **environ;

			/* local vars */
static struct node *true;

		      /************************************
		      *  sys - execute "system" command   *
		      ************************************/

static struct node *sys(args)
  struct node *args;
{
    struct node *cmd;

    cmd = xlevmatch(STR,&args);
    xllastarg(args);

    return( (system(cmd->n_str) == 0) ? true : NULL);
}


		      /************************************
		      *  shell - escape to lower shell    *
		      ************************************/
		      /* this really should pick SHELL from the 
		       * bound vars (see bind_env)
		       */

static struct node *shell(args)
struct node *args;
{
    static char *shnam = NULL;
    int fstatus;

    xllastarg(args);

    if(shnam == NULL && (shnam = getenv("SHELL")) == NULL)
	shnam = "/bin/sh";

    if(fork() == 0) {
	execl(shnam, shnam, 0);
	puts("cannot exec shell");
    } else
    	wait(&fstatus);

    return( (fstatus == 0) ? true : NULL);
}



		   /****************************************
		   * bind_env - bind enviornment to atoms  *
		   ****************************************/

static bind_env()
{
	int i;
	char *cp;

	for(i = 0; environ[i] != NULL; i++) {
		cp = strchr(environ[i], '=');
		*cp = '\0';
		xlsvar(environ[i], cp+1);
		*cp = '=';
	}
}

		   /********************************
		   * cd - change working directory *
		   ********************************/

static struct node *cd(args)
struct node *args;
{
    struct node *cdir, *val;

    cdir = xlevmatch(STR, &args);
    xllastarg(args);

    return( (chdir(cdir->n_str) == 0) ? true : NULL);
}


		/******************************************
		* readrc - read in ".xlisprc" in HOME dir *
		******************************************/

static int readrc()
{
	char rcnam[128];

	strcpy(rcnam, getenv("HOME"));
	strcat(rcnam, "/.xlisprc");

	if(access(rcnam, 04) == 0)
		xlfin(rcnam);
}


		   /******************************************
		   * xluninit - unix initialization routine  *
		   *******************************************/

xluninit()
{
    bind_env();
    true = xlenter("t");
    xlsubr("system", sys);
    xlsubr("sh", shell);
    xlsubr("cd", cd);
    readrc();
}

xlisp.doc.a follows--------------------------------------------

	XLISP: An Experimental Object Oriented Language      Page 20
	FUNCTIONS


	Unix utility functions (local additions):


	(cd <expr>)	CHANGE DIRECTORY
	    <expr>	string expression
	    returns	t if successful, else nil
		
	(sh)		ESCAPE TO SHELL
	    returns	t if exit status is 0, else nil

	(system <expr>)	EXECUTE COMMAND IN A UNIX SHELL
	    <expr>	string expression to be executed
	    returns	t if exit status is 0, else nil


	In addition to these functions, all the environmental variables
	have been defined and bound to a string representation of their
	contents, e.g. if TERM=hp then `(print TERM)' would print "hp".

	The file ".xlisprc" in the user`s home directory, if it exists,
	is read-in on start up if no arguments are given.  If an argument
	is given, it is assumed to be a filename and is read-in in place
	of any ".xlisprc" file.


Sorry for the length of this.  I hope it has been of some help.

Toby Harness		Ogburn/Stouffer Center, University of Chicago
			...ihnp4!gargoyle!toby

ksbc@hirst1.UUCP (08/08/84)

When I try to build xlisp, both under unix III and 4.1 I get an error msg
from xldmem.c 
line 31: illegal zero sized structure : sgnodes
this is part od the deffinition of struct segment which reads:-
struct node sg_nodes[];

Anybody got any advice how to get round this:- 4.1 lets me get away with a
warning, and xlisp seems to work:- however III wants it to be fatal.

jfw@mit-eddie.UUCP (John Woods) (08/11/84)

You mentioned wondering about fexprs and lexprs in XLISP.  I have modified
(heavily) XLISP to have SUBRs and FSUBRs as well as EXPRs and FEXPRs.  In fact,
Creeping featurism has been rampant on my terminal.  MACROs are scheduled next,
now that I have property lists going.  When I think I have something reasonable,
I will post a note about the results -- people who are really interested can
send me mail at decvax!frog!john, genrad!mit-eddie!jfw, or JFW@MIT-XX (for ARPA
types).  Fun Fun Fun!!
		John Woods,  Charles River Data Systems, Framingham MA
		decvax!frog!john, genrad!mit-eddie!jfw, JFW@MIT-XX