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.