[comp.lang.lisp.x] Caling XLISP frling XLISP from C - help requested

colers@prlhp1.prl.philips.co.uk (Richard Cole) (01/22/91)

Hi Folks,
   we are trying to make a version of XLISP that can be called
from a C program as a function call (to a modified eval loop that only
evals once and then returns so we need to pass it something to
evaluate).  As far as we can see there are two avenues we could persue;
if someone can provide a definition of exactly what goes in an LVAL
structure we could modify xeval.  Alternatively we could modify the file
reading function instead.

Has anyone already done this ? (hope hope :-) ) or can anyone shed any
light as to what goes into LVAL ?

Any info greatly appreciated.

Richard Cole  <colers@prl.philips.co.uk>

AI Group
Philips Research Laboratories
Cross Oak Lane
Redhill
Surrey
RH1 5HA
UK

mayer@hplabsz.HP.COM (Niels Mayer) (01/24/91)

In article <1218@prlhp1.prl.philips.co.uk> colers@prl.philips.co.uk writes:
>Hi Folks,
>   we are trying to make a version of XLISP that can be called
>from a C program as a function call (to a modified eval loop that only
>evals once and then returns so we need to pass it something to
>evaluate).  As far as we can see there are two avenues we could persue;
>if someone can provide a definition of exactly what goes in an LVAL
>structure we could modify xeval.  Alternatively we could modify the file
>reading function instead.
>
>Has anyone already done this ? (hope hope :-) ) or can anyone shed any
>light as to what goes into LVAL ?

I've done this in WINTERP Motif Widget INTERPreter (anon ftp from host
expo.lcs.mit.edu directory contrib/winterp file winterp-1.01.tar.Z).

The following code fragment reads a lisp s-expression from a socket, turns
it into an XLISP unnamed stream. xlread() then reads from that stream as if
it were reading input from a FILE*, and xleval() evaluates the read
s-expression.

Although transforming character strings into an unnamed stream is somewhat
inefficient, it allows you to interface with xlisp's reader with a minimum
of changes to XLISP itself. I wanted to avoid modifications to xleval() and
xlread() because the changes required would be extensive, and because I
didn't want to support a version of XLISP that diverges from the
"standard".

  .
  .
  .
  int rdsock;
  static char rdbuf[BUFSIZ];
  .
  .
  .
  {
    /*
     * Read the sexpression from the socket -- note assumption that entire
     * sexpression is sent in one "packet" and then the socket is closed.
     */
    int len, i;
    LVAL sexp_stream, new_elt, last_elt = NIL;
    xlsave1(sexp_stream);	/* protect from gc */
    sexp_stream = newustream();	/* note - stream obj has ptrs for head and tail*/

    while (len = recv(rdsock, rdbuf, BUFSIZ, 0)) { /* read len characters into rdbuf */
      if (len < 0) {
	perror(app_name);
	sprintf(temptext, "%s: unable to recv\n", app_name);
	xlfatal(temptext);	/* CLEANUP & EXIT */
      }

      /* foreach character received, stuff it into an xlisp unnamed stream */
      for (i = 0; i < len; i++) {
	new_elt = cons(cvchar(rdbuf[i]), NIL);
	if (last_elt) {		/* if we've already created the head of the stream */
	  rplacd(last_elt, new_elt); /* add new_elt to the tail of the list */
	  last_elt = new_elt;	/* increment last_elt pointer */
	}
	else {			/* else create the head of the stream */
	  sethead(sexp_stream, new_elt);
	  last_elt = new_elt;
	}
      }
    }
    close(rdsock);		/* we've finished reading from the socket */
    
    if (last_elt)
      settail(sexp_stream, last_elt); /* streams are cdr-coded -- give ptr to tail */
    else			
      sexp_stream = NIL;	/* loop never executed, no characters read. */
    lisp_reader_hit_eof = !(Read_From_Stream_Eval_And_Print(sexp_stream));
    xlpop();			/*sexp_stream*/
  }


/*******************************************************************************
 * This fn reads from its input, which is assumed to be a xlisp stream.
 * returns false if EOF hit during read.
 ******************************************************************************/
int Read_From_Stream_Eval_And_Print(sexp_stream)
     LVAL sexp_stream;		/* make sure this is a stream, and not other LVAL */
{
  extern int xldebug;
  extern LVAL s_1plus,s_2plus,s_3plus,s_1star,s_2star,s_3star,s_minus;
  LVAL rep_expr;
  int read_result;

  xlprot1(sexp_stream);		/* protect against GC */
    
  /* Read Evaluate and Print the expression in sexp_stream */
  if ((read_result = xlread(sexp_stream, &rep_expr, FALSE))) {

    /* save the last expression returned by the reader */
    setvalue(s_3plus, getvalue(s_2plus));
    setvalue(s_2plus, getvalue(s_1plus));
    setvalue(s_1plus, getvalue(s_minus));
    setvalue(s_minus, rep_expr);

    /* evaluate the expression returned by the reader */
    rep_expr = xleval(rep_expr);

    /* save the last expression returned by the evaluator */
    setvalue(s_3star,getvalue(s_2star));
    setvalue(s_2star,getvalue(s_1star));
    setvalue(s_1star,rep_expr);

    if (xldebug)		/* print eval results */
      dbgprint(rep_expr);
    else
      stdprint(rep_expr);
  }

  else {			/* if reader hit EOF, just print a new line */
    if (xldebug)
      dbgputstr("\n");   
    else
      stdputstr("\n");
  }
  xlpop(/*sexp_stream*/);
  return (read_result);		/* return FALSE if hit EOF */
}


				--------------------

Homework for the reader:

	(1) it should be trivial to modify the code above to 
	read from a C character array, instead of a socket.

	(2) you need to consider where to set up Xlisp's error
	return longjmp() target (see xlisp.c and xldbug.c for examples).
	If the C call to the Xlisp evaluator causes an error, you should
	have a place in your program where execution can do a stack unwind in an
	orderly fashion. I have a hack in winterp.c:main() and xlisp/xldbug.c
	that does this for event driven programs such as those running under
	the X toolkit (e.g. WINTERP). There are comments in the code that should
	help you do what you're trying to do.

-------------------------------------------------------------------------------
            Niels Mayer -- hplabs!mayer -- mayer@hplabs.hp.com
                  Human-Computer Interaction Department
                       Hewlett-Packard Laboratories
                              Palo Alto, CA.
                                   *