The Prolog engine can be called from C. There are two interfaces for this. For the first, a term is created that could be used as an argument to call/1, and then PL_call() is used to call Prolog. This system is simple, but does not allow to inspect the different answers to a non-deterministic goal and is relatively slow as the runtime system needs to find the predicate. The other interface is based on PL_open_query(), PL_next_solution() and PL_cut_query() or PL_close_query(). This mechanism is more powerful, but also more complicated to use.
This section discusses the functions used to communicate about
predicates. Though a Prolog predicate may be defined or not, redefined,
etc., a Prolog predicate has a handle that is neither destroyed nor
moved. This handle is known by the type predicate_t
.
NULL
, the
current context module is used. If the target predicate does not exist a
handle to a new undefined predicate is returned. The predicate
may fail, returning (predicate_t)0
after setting a resource
exception, if the target module has a limit on the
program_space
, see set_module/1.
Currently aborts the process with a fatal error when out of
memory. Future versions may raise a resource exception and return (predicate_t)0
.NULL
.
This section discusses the functions for creating and manipulating queries from C. Note that a foreign context can have at most one active query. This implies that it is allowed to make strictly nested calls between C and Prolog (Prolog calls C, calls Prolog, calls C, etc.), but it is not allowed to open multiple queries and start generating solutions for each of them by calling PL_next_solution(). Be sure to call PL_cut_query() or PL_close_query() on any query you opened before opening the next or returning control back to Prolog.
Opens a query and returns an identifier for it. ctx is the context
module of the goal. When NULL
, the context module of
the calling context will be used, or user
if there is no
calling context (as may happen in embedded systems). Note that the
context module only matters for meta-predicates. See meta_predicate/1,
context_module/1
and module_transparent/1.
The p argument specifies the predicate, and should be the
result of a call to PL_pred()
or PL_predicate().
Note that it is allowed to store this handle as global data and reuse it
for future queries. The term reference t0 is the first of a
vector of term references as returned by
PL_new_term_refs(n).
Raise a resource exception and returns
(qid_t)0
on failure.
The flags arguments provides some additional options concerning debugging and exception handling. It is a bitwise or of the following values:
PL_Q_NORMAL
PL_Q_NODEBUG
for backward compatibility reasons.PL_Q_NODEBUG
PL_Q_CATCH_EXCEPTION
PL_Q_PASS_EXCEPTION
PL_Q_CATCH_EXCEPTION
, but do not invalidate the
exception-term while calling PL_close_query().
This option is experimental.PL_Q_ALLOW_YIELD
I_YIELD
instruction for engine-based
coroutining. See $engine_yield/2 in boot/init.pl
for
details.PL_Q_EXT_STATUS
TRUE
or FALSE
extended status as illustrated
in the following table:
Extended | Normal | |
PL_S_EXCEPTION | FALSE | Exception available through PL_exception() |
PL_S_FALSE | FALSE | Query failed |
PL_S_TRUE | TRUE | Query succeeded with choicepoint |
PL_S_LAST | TRUE | Query succeeded without choicepoint |
PL_open_query() can return the query identifier‘0' if there is not enough space on the environment stack. This function succeeds, even if the referenced predicate is not defined. In this case, running the query using PL_next_solution() will return an existence_error. See PL_exception().
The example below opens a query to the predicate is_a/2
to find the ancestor of‘me'. The reference to the predicate is
valid for the duration of the process and may be cached by the client.
char * ancestor(const char *me) { term_t a0 = PL_new_term_refs(2); static predicate_t p; if ( !p ) p = PL_predicate("is_a", 2, "database"); PL_put_atom_chars(a0, me); PL_open_query(NULL, PL_Q_NORMAL, p, a0); ... }
TRUE
if a solution was found, or FALSE
to
indicate the query could not be proven. This function may be called
repeatedly until it fails to generate all solutions to the query.FALSE
and the exception is accessible
through PL_exception(0)
.0
if the
current thread is not executing any queries.TRUE
if the call succeeds, FALSE
otherwise.
Figure 7 shows
an example to obtain the number of defined atoms. All checks are omitted
to improve readability.