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. *