jagota@sunybcs.uucp (Arun Jagota) (06/25/88)
I've been able to call C functions from Franz Lisp but am having
trouble creating Lisp lists in C and passing them back to Franz Lisp.
I'm running this on a Vax 11-785 running Unix 4.3 BSD.
My application can be thought of as a data base with an AI front end.
The data base operations are implemented in C for speed and efficiency
but I'd like to perform certain higher level operations on retrieved
data in Franz Lisp and SNePS, a semantic network embedded in Franz Lisp.
Most of my C functions retrieve certain words from the data base,
create a list (in lisp format) to store them and pass them back to
the lisp program that called the C function.
I AM HAVING PROBLEMS IN PASSING BACK THE LIST I CREATE IN THE C
FUNCTION.
Lisp format in C that I use (As documented in the Franz Lisp manual).
struct lisplist
{ struct lisplist *cdr;
int car;
}
My C function then creates a list as follows.
struct lisplist *temp,*current;
-- Assume "word" is a new item to be inserted into list
-- char *word;
-- Adding "word" to the list as the first atom
temp = (struct lisplist *) malloc(sizeof(*temp));
temp->car = (int) word;
temp->cdr = current;
current = temp;
Any help will be DEEPLY APPRECIATED.
Thanks,
Arun Jagota
UUCP : {cmc12,hao,harpo}!seismo!rochester!rocksvax!sunybcs!jagota
...{allegra,decvax,watmath}!sunybcs!jagota
CSNET : jagota@cs.buffalo.edu
BITNET : jagota@sunybcs
jeff@aiva.ed.ac.uk (Jeff Dalton) (07/06/88)
In article <12196@sunybcs.UUCP> jagota@sunybcs.uucp (Arun Jagota) writes: >I AM HAVING PROBLEMS IN PASSING BACK THE LIST I CREATE IN THE C >FUNCTION. I can give a more or less complete answer to your question but don't have time to do it today. I'll send this in the hope that it's some help and try to say more if it appears that no one else has already covered everything. >Lisp format in C that I use (As documented in the Franz Lisp manual). > >struct lisplist > { struct lisplist *cdr; > int car; > } OK, the first thing to not is that this isn't the real definition of Lisp data used by the Franz system. For some purposes, you need the real definition in `franz/h/global.h' in the Franz source directory. To access it, use -I with cc. A makefile makes this easier. However, you may be able to avoid this. >My C function then creates a list as follows. >struct lisplist *temp,*current; >char *word; > >temp = (struct lisplist *) malloc(sizeof(*temp)); >temp->car = (int) word; >temp->cdr = current; >current = temp; This is where the problems come in. (1) In many versions of Franz, you may not be able to use malloc without confusing Lisp. I've never actually used malloc, though, so I am not sure of this. The reason I don't use malloc is: (2) Franz determines the type of an object by looking at the high-order bits of its address. It divides memory into (logical) pages where each page contains objects of a single type. The high order bits give the page, and then there's a table giving the type of each page. So, in order to allocate a cons cell (what Franz calls a dtpr (dotted pair), you can't just allocate it anywhere: you have to allocate it on a cons cell page. The same applies to strings: they must be allocated on string pages. Of course, you can still make pointers to randon storage, but problems may appear later if Lisp ever wants to check the object's type. Unfortunately, I can't tell you how to create Lisp objects in C because, without writing some code, I can't be sure just how much I'll have to tell you about. (I do have code that does this sort of thing, but I'm hoping to avoid describing everything it does.) (3) You don't say how you actually return the list. Remember that your C function has to be made known to Lisp (with getaddress, say) and have discipline "function". Then you can just return the pointer to the start of the list in the usual C way (modulo the problems mentioned above). What it comes down to is that it is a pain to write C code that creates Lisp data. In addition to the things already mentioned, you may have to worry about garbage collection (if you allocate a Lisp object, the garbage collector may be called). Consequently, you may want to protect objects from collection, and that brings you into contact with Franz internals that you may not want to know about. Other things: >I'm running this on a Vax 11-785 running Unix 4.3 BSD. What version of Franz are you using? >Most of my C functions retrieve certain words from the data base, >create a list (in lisp format) to store them and pass them back to >the lisp program that called the C function. You might want to consider a different organization of your program. You could have a C function that acted as a generator. It would pass back the next item each time called, and the Lisp code that called it could build the list. Of course, this may not be easy to do, but often it is (you have to keep track of some state in the C code). Another approach is to preallocate a list amd pass it to your C code. It is much easier to modify existing data than to create new data. Jeff Dalton, JANET: J.Dalton@uk.ac.ed AI Applications Institute, ARPA: J.Dalton%uk.ac.ed@nss.cs.ucl.ac.uk Edinburgh University. UUCP: ...!ukc!ed.ac.uk!J.Dalton
chris@mimsy.UUCP (Chris Torek) (07/08/88)
In article <484@aiva.ed.ac.uk> jeff@aiva.ed.ac.uk (Jeff Dalton) writes: >... For some purposes, you need the real definition in >`franz/h/global.h' in the Franz source directory. ... >(1) In many versions of Franz, you may not be able to use malloc >without confusing Lisp. The Lisp allocator does not care if something else steals pages, but the malloc allocator might. (I am not sure that this is true of all versions of Franz, but note that stdio uses malloc, and Franz uses stdio.) >... So, in order to allocate a cons cell (what Franz calls a >dtpr (dotted pair), you can't just allocate it anywhere: you have to >allocate it on a cons cell page. ... The function `newdot()' allocates a cons cell. `inewint(int value)' allocates an integer with value `value'. `matom(char *name)' makes an atom; `mstr(char *str)' makes a string; and `mfun(char *name, lispval fun, lispval type)' creates a function, where type is either lambda or nlambda (or, I suppose, flambda, although I am not sure that is done as a separate type). >(3) You don't say how you actually return the list. Remember that >your C function has to be made known to Lisp (with getaddress, say) >and have discipline "function". Things generally work better if you have an auxiliary setup function call mfun to make the functions. >What it comes down to is that it is a pain to write C code that >creates Lisp data. In addition to the things already mentioned, you >may have to worry about garbage collection (if you allocate a Lisp >object, the garbage collector may be called). You must use the `protect()' macro: >Consequently, you may >want to protect objects from collection, and that brings you into >contact with Franz internals that you may not want to know about. ... such as, for instance, that on a Vax you may not use more than four register variables, because what appear to be globals (np and lbot) must be translated into registers r6 and r7 by a `sed' script working on the assembly output of the compiler. protect() works by saving its lispval argument in *np++; np and lbot are used to implement the Lisp namestack. lbot[0] is the first argument to a function, and lbot[1] the second, and so forth; the number of actual arguments is np-lbot. The sed script also translates calls to newdot into `jsb' instructions, to avoid the Vax `calls' instruction overhead, so it must be used even if you are only allocating one dptr and never check any arguments. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
chris@mimsy.UUCP (Chris Torek) (07/09/88)
In article <12363@mimsy.UUCP> I wrote, in response to >In article <484@aiva.ed.ac.uk> jeff@aiva.ed.ac.uk (Jeff Dalton) writes: >>(1) In many versions of Franz, you may not be able to use malloc >>without confusing Lisp. the following confusing paragraph: >The Lisp allocator does not care if something else steals pages, >but the malloc allocator might. (I am not sure that this is true >of all versions of Franz, but note that stdio uses malloc, and >Franz uses stdio.) What I meant is that calling malloc after Franz starts up may not confuse Franz, but may confuse malloc. (The 4BSD malloc()s are safe, though.) -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
markhof@exunido.uucp (Ingolf Markhof) (07/11/88)
Hi there! I'm a member of a group which implemets a floorplanner. We use Franz Lisp, Flavors, and Yaps. To manage the used/free spaces of the chip area, we use a corner stitching package written in C. So we have to import some C functions into Lisp. These C functions return simple values or Lisp lists of integers. Now, the problem is that some of the imported C functions do their work n times, but the Lisp system crashes with the (n+1)th call. By placing some (msg ...) statements in the Lisp code and by placing some printf statements in the C code, I found that the error occurs when the flow of controll reaches the C return statement. The system "hangs up" then. All you can do is to stop the Lisp job by pressing <ctrl>-Z and then kill it by the unix kill command. Other <ctrl>-<Key> combinations have no effect. There is is passage in the paper "The Franz Lisp - C Interface", written by Fred P. Andresen, wich may be meaningful for our problem. On Page 9 it says: "7.1 When creating a list in C (...) don't leave any stray lispobjs lying around which have no other lispobjs pointing to them (C pointers don't count)." But what is exactly the meaning of "C Pointers don't count"? I programmed the creation of lists in a similar way as it can be seen in the examle on page 18 of Andresens paper (lispval lst; lst = newdot (); ...). So, I can't believe that I did it wrong. Ok, I hope this short explanation shows our problem. Can anyone help? Ingolf Markhof!
chris@mimsy.UUCP (Chris Torek) (07/12/88)
In article <433@laura.UUCP> markhof@exunido.uucp (Ingolf Markhof) writes: > There is is passage in the paper "The Franz Lisp - C Interface", written >by Fred P. Andresen, ... (I think it is `Anderson'---he was `fpa@cvl' but is not there anymore. Ah well.) >"7.1 When creating a list in C (...) don't leave any stray lispobjs >lying around which have no other lispobjs pointing to them (C pointers >don't count)." > > But what is exactly the meaning of "C Pointers don't count"? That means that code like this is wrong: Lfoo() { register lispval node; chkarg(0, "foo"); node = newdot(); node->d.car = inewint(1); node->d.cdr = matom("bar"); return (node); } Instead, you must write Lfoo() { register lispval node; chkarg(0, "foo"); node = newdot(); protect(node); /* important! */ node->d.car = inewint(1); node->d.cdr = matom("bar"); return (node); } On the other hand, Lbaz() { lispval l; chkarg(1, "baz"); l = lbot[0].val; if (TYPE(l) != DTPR) ncerror("baz() needs a dotted pair"); /* like rplacd */ l->d.cdr = newdot(); l->d.cdr->d.car = inewint(1); l->d.cdr->d.cdr = matom("bar"); } *is* correct, because there is a pointer to the new dot somewhere in the lisp system (namely lbot[0].val->d.cdr). -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
jdp@adiron.UUCP (Powell) (07/13/88)
The way we pass C and LISP arguments is through a pipe from LISP to C and back. If the lisp call with all arguments evaluated is (fun a b c), we would call (print '(fun a b c) cinport) and call (setq result (read coutport)). The C program itself would find the function name and pass the string as an argument to the function. The function would return a char string that would be printed to the stdout which is connected to the coutport. This is not high speed, but it appears to be portable as far as I can see (remember all arguments are evaluated before being sent to C). Well, if you're using the Franz available as part of the 4.3 distribution, you're used to inefficiency anyway. Good luck John D. Powell Par Technology