Next: Backtracking Loops, Previous: Finding One Solution of a Call, Up: Calling Prolog from C [Contents][Index]
If you are interested in more than one solution, then a more complicated scheme is used. You find the predicate definition as above, but you do not call the predicate directly.
SP_open_query()
SP_next_solution()
to find a solution. Call this
predicate again to find more solutions if there are any.
SP_close_query()
or SP_cut_query()
The function SP_open_query()
will return an identifier of type
SP_qid
that you use in successive calls. Note that if a new query is
opened while another is already open, then the new query must be
terminated before exploring the solutions of the old one. That is,
queries must be strictly nested.
The function SP_next_solution()
will cause the Prolog engine to
backtrack over any current solution of an open query and
look for a new one.
A query must be terminated in either of two ways. The function
SP_cut_query()
will discard the choices created since the
corresponding SP_open_query()
, like the goal !
. The
current solution is retained in the arguments until
backtracking into any enclosing query.
Alternatively, the function SP_close_query()
will discard the
choices created since the corresponding SP_open_query()
, and then
backtrack into the query, throwing away any current
solution, like the goal !, fail
.
A simple way to call arbitrary Prolog code, whether for one solution or
for multiple solutions, is to use SP_read_from_string()
(see Creating Prolog Terms) to create an argument to
call/1
. It is a good idea to always explicitly specify the module
context when using call/1
or other meta-predicates from C.
It is important to understand the rules governing the scope of SP_term_refs, and the terms they hold, in conjunction with calls from Prolog to C and vice versa. SP_term_refs are internally stored on a stack, which is manipulated by the various API functions as follows:
SP_new_term_ref()
The new SP_term_ref is pushed onto the stack.
SP_query()
SP_query_cut_fail()
The top of the stack is saved on call and restored upon return.
SP_open_query()
The top of the stack is saved in the new query.
SP_close_query()
SP_cut_query()
SP_next_solution()
The top of the stack is restored from the query argument.
Among other things, this means that an SP_term_ref cannot be saved across multiple calls from Prolog to C. Thus it makes no sense to declare an SP_term_ref as a static C variable.
Prolog terms are also generally stored on a stack, which keeps growing
until the execution backtracks, either spontaneously or by calling
SP_close_query()
or SP_next_solution()
. It is an abuse of
the SP_open_query()
API to assign a term to an SP_term_ref, and
then backtrack over the term while the SP_term_ref is still live. Such
abuse results in a dangling pointer that can potentially crash SICStus
Prolog. The API typically follows the pattern:
... SP_pred_ref pred = SP_predicate(...); SP_term_ref ref1 = SP_new_term_ref(); SP_qid goal = SP_open_query(pred,ref1,...); /* * PART A: perform some initializations, and * loop through all solutions. */ while (SP_next_solution(goal)==SP_SUCCESS) { /* * PART B: perform some action on the current solution. */ } SP_close_query(goal); ...
In order to avoid dangling pointer hazards, we recommend some simple coding rules:
In this part of the code, do not call SP_new_term_ref()
or the
functions in Creating Prolog Terms at all.
In this part of the code, do not call SP_new_term_ref()
except to
initialize any SP_term_refs declared locally to Part B. Do Not call the
functions in Creating Prolog Terms, except to set SP_term_refs
declared locally to Part B.