[comp.lang.prolog] Passing a C STRUCT to Quintas Prolog

victor@sherlock.cs.concordia.ca (Victor Krawczuk) (11/02/89)

Hello:

    I'm new to Prolog.  I am wondering if and how a C process
can send a data structure to a Quintas Prolog process to be added
as a fact (I guess using the assert() predicate).

    What I am really interested is how the translation of a C
structure to a Prolog fact can be realized.  Are there any quick
solutions or examples of this in any text book one has come across??


                                             Victor.
 


---------------------------------------------------------------------------
|     Victor Krawczuk                            /. .\                    |
|     victor@concour.cs.concordia.ca               *                      |
|     victor@jupiter.cs.concordia.ca               -                      |

ok@mudla.cs.mu.OZ.AU (Richard O'Keefe) (11/15/89)

In article <1532@clyde.Concordia.CA>, victor@sherlock.cs.concordia.ca (Victor Krawczuk) writes:
>     I'm new to Prolog.  I am wondering if and how a C process
> can send a data structure to a Quintas Prolog process to be added
> as a fact (I guess using the assert() predicate).

That's Quintus with a "u", not an "a".  Once upon a time Roman parents
            *
with a lot of sons would start naming them with numbers: Tertius (3),
Quadratus(?) (4), Quintus (5), Sixtus (6), Septimus (7) and so on.  The
company is called Quintus because they make a 5th Generation language.

You say that you want a C *process* to send a data structure to a
Prolog *process*.  For that you want to look in the IPC section of
the library manual; there is an IPC package to let UNIX processes
running Prolog talk to UNIX processes running C.

A very simple method which will work no matter whose Prolog you are
using (other than Borland's) is to have the C process write the fact
out to a file:
	ftell(PrologFile, 0L, 0);
	fprintf(PrologFile, "to_be_greeted(%s).\n", "world");
	fflush(PrologFile);
	/* make sure the Prolog process knows the input is ready for it */

and have the Prolog process read the file:

	see('InputFromC'),
	read(Fact),
	seen,
	assert(Fact)

after which you can do

	to_be_greeted(X),
	write('Hello '), write(X), nl.

You can set up a one-way communication path like this with library(pipe):

	:- ensure_loaded(library(pipe)).
	:- dynamic
		file_matched/1.

	get_matching_files :-
		retractall(file_matched(_)),
		popen('for f in p*pl; do echo "match(''$f'')." ; done',
			read, Stream),
		repeat,
		    read(Stream, Term),
		    process_match(Term),
		!,
		close(Stream).

	process_match(end_of_file).
	process_match(match(Name)) :-
		assert(file_matched(Name)),
		fail.

For this particular task it is better to use library(directory); I'm just
using it as an example of getting terms from another process.  There are
other ways of exchanging data between processes (such as the use of
shared memory); the conversion predicates
	chars_to_term/2
	term_to_chars/2
in library(charsio) may be useful here.

It's possible that you may not have separate processes in mind
Some Prolog systems expose their data structures directly to C code in
order to make it easy for you to build Prolog terms in C.  LPA Prolog
does this, and as I recall it so does IF Prolog.

Quintus Prolog _doesn't_ expose its data structures (which means that
Quintus are free to improve them any time they get a bright idea), but
it _does_ come with a library package that may be of use to you.
Oddly enough, it's called library(terms).

Suppose you want to write a predicate (the guts of which will be written
in C) that is going to return a list of character codes representing the
printname of a floating-point number.  The function is to receive a
floating-point number as argument, and return a list of characters.
(There are about a dozen other ways at least of doing this.)

:- ensure_loaded(library(terms)).

float_to_chars(Float, Chars) :-
	number(Float),
	'FltToChars'(Float, Handle),
	c_to_prolog(Handle, Result),
	erase_c_term(Handle),
	Chars = Result.

foreign('FltToChars', 'FltToChars'(+float,[-address(long)])).

Load FltToChars in the usual way.  It will look something like this:

#include "quintus.h"            /* from the Quintus library directory */
#include "terms.h"              /* from the Quintus library directory */

TermP FltToChars(flt)
    double flt;
    {
        char buffer[28];
        int n;
        char *p;
        TermP r;    
        static QPatom dot, nil = 0;
 
        if (nil == 0) {
            dot = QP_atom_from_string(".");
            nil = QP_atom_from_string("[]");
        } 
        sprintf(buffer, "%.17e", flt);
        n = strlen(buffer);     /* number of characters to return */
        /* we need 2 cells per cons, 2 per integer, 2 per atom */
        if (QTallo(4*n+2)) return 0;
        p = buffer;
        while (--n >= 0) {
            QTpshA(dot, 2);     /* ./2 is the list functor */
            QTpshI(*p++);       /* integer */
        } 
        QTpshA(nil, 0);         /* []/0 is the list terminator */
        n = QTaddr(&r);
printf("n = QTaddr(&r) returned n = %d, r = %x\n", n, r);
        return r;
    }
 
(This has been tested and does work.)  This particular library package is
not very polished; it was mainly set up for sending terms from Prolog to
C.  Please, please, please, would any Quintus customers who are interested
in exchanging terms between Prolog and C (or other languages) (a) look at
this library package -- it's not listed as "supported", so that means that
Quintus feel free to improve it beyond recognition -- and tell Quintus how
it could be made more useful and (b) tell Quintus what you _really_ want
to do that makes you _think_ you want to exchange terms between Prolog
and C -- perhaps some higher-level construct can be provided that will be
a better solution for your real problems.

>     What I am really interested is how the translation of a C
> structure to a Prolog fact can be realized.

But what exactly do you want to do?  Is it that you _have_ some C structures
which you would like to be able to access from Prolog?  If so, ask Quintus
about the "structs" package.  When you say "a C structure", do you mean
things at the level of records, or things at the level of C++ objects?

Without any more information, all I can say is that a C "structure"
(whatever that is) belongs to one conceptual category and a Prolog fact
belongs to a different category:  there is no unique mapping between
the two categories.  Somehow, _you_ have to supply the mapping that makes
sense for your application.  Look at the Quintus library for examples of
how this has been done in some specific cases.

One last example.  Suppose you have a binary tree in C:

	typedef struct AVL *AVL_p;
	struct AVL
	    {
		char *key, *val;
		int balance;
		AVL_p left, right;
	    };

and you would like a way of converting such trees to Prolog terms:

	:- type avl --> empty_avl | avl(atom,atom,integer,avl,avl).

You can pass a pointer through the Prolog/C interface using the
address(_) type.  So you would write

	void destAVL(p, key, val, balance, left, right)
	    register AVL_p p;
	    char *key, *val;
	    int *balance;
	    AVL_p *left, *right;
	    {
		key = p->key, val = p->val, balance = p->balance,
		left = p->left, right = p->right;
	    }

	foreign(destAVL,
		destAVL(+address('struct AVL'),
			-string, -string, -integer,
			-address('struct AVL'), -address('struct AVL'))).

	pick_up_avl(0, empty_avl) :- !.
	pick_up_avl(P, avl(K,V,B,L,R)) :-
		P =\= 0,
		destAVL(P, K, V, B, PL, PR),
		pick_up_avl(PL, L),
		pick_up_avl(PR, R).

It is difficult to be more helpful without knowing what your
problem really is.