9.2.9 An Alternative Way to Define C Predicates

SP_define_c_predicate() defines a Prolog predicate such that when the Prolog predicate is called it will call a C function with a term corresponding to the Prolog goal. The arguments to the predicate can then be examined using the usual term access functions, e.g. SP_get_arg() (see Accessing Prolog Terms).

     typedef int SP_CPredFun(SP_term_ref goal, void *stash);
     int SP_define_c_predicate(char *name, int arity, char *module,
                               SP_CPredFun *proc, void *stash)

The Prolog predicate module:name/arity will be defined (the module module must already exist). The stash argument can be anything and is simply passed as the second argument to the C function proc.

The C function should return SP_SUCCESS for success and SP_FAILURE for failure. The C function may also call SP_fail() or SP_raise_exception() in which case the return value will be ignored.

Here is an end-to-end example of the above:

                                
% square.pl
foreign_resource(square, [init(square_init)]). :- load_foreign_resource(square).
/* square.c */
#include <sicstus/sicstus.h> static int square_it(SP_term_ref goal, void *stash) { long arg1; SP_term_ref tmp = SP_new_term_ref(); SP_term_ref square_term = SP_new_term_ref(); long the_square; /* goal will be a term like square(42,X) */ SP_get_arg(1,goal,tmp); /* extract first arg */ if (!SP_get_integer(tmp,&arg1)) return SP_FAILURE; /* type check first arg */ SP_put_integer(square_term, arg1*arg1); SP_get_arg(2,goal,tmp); /* extract second arg */ /* Unify output argument. SP_put_integer(tmp,...) would *not* work! */ return (SP_unify(tmp, square_term) ? SP_SUCCESS : SP_FAILURE); } void square_init(int when) { (void)when; /* unused */ /* Install square_it as user:square/2 */ SP_define_c_predicate("square", 2, "user", square_it, NULL /* unused */); }
# terminal
% splfr square.pl square.c % sicstus -f -l square % compiling /home/matsc/tmp/square.pl... % loading foreign resource /home/matsc/tmp/square.so in module user % compiled /home/matsc/tmp/square.pl in module user, 0 msec 816 bytes SICStus 3.12.11 ... Licensed to SICS | ?- square(4711, X). X = 22193521 ? yes | ?- square(not_an_int, X). no