From: Arun Jagota
Subject: Calling C functions from Franz Lisp
Date: 
Message-ID: <12196@sunybcs.UUCP>
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  :  ······@cs.buffalo.edu
BITNET :  ······@sunybcs

From: Jeff Dalton
Subject: Re: Calling C functions from Franz Lisp
Date: 
Message-ID: <484@aiva.ed.ac.uk>
In article <·····@sunybcs.UUCP> ······@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: ········@uk.ac.ed             
AI Applications Institute,        ARPA:  ·················@nss.cs.ucl.ac.uk
Edinburgh University.             UUCP:  ...!ukc!ed.ac.uk!J.Dalton
From: Chris Torek
Subject: Re: Calling C functions from Franz Lisp
Date: 
Message-ID: <12363@mimsy.UUCP>
In article <···@aiva.ed.ac.uk> ····@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:	·····@mimsy.umd.edu	Path:	uunet!mimsy!chris
From: Chris Torek
Subject: Re: Calling C functions from Franz Lisp
Date: 
Message-ID: <12373@mimsy.UUCP>
In article <·····@mimsy.UUCP> I wrote, in response to

>In article <···@aiva.ed.ac.uk> ····@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:	·····@mimsy.umd.edu	Path:	uunet!mimsy!chris
From: Ingolf Markhof
Subject: Re: Calling C functions from Franz Lisp
Date: 
Message-ID: <433@laura.UUCP>
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!
From: Chris Torek
Subject: Re: Calling C functions from Franz Lisp
Date: 
Message-ID: <12417@mimsy.UUCP>
In article <···@laura.UUCP> ·······@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 ····@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:	·····@mimsy.umd.edu	Path:	uunet!mimsy!chris
From: Powell
Subject: Re: Calling C functions from Franz Lisp
Date: 
Message-ID: <385@adiron.UUCP>
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