File: gprolog069.html

package info (click to toggle)
gprolog 1.3.0-6.1
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd, squeeze, wheezy
  • size: 13,512 kB
  • ctags: 8,954
  • sloc: ansic: 57,431; perl: 16,620; sh: 5,900; makefile: 1,284
file content (303 lines) | stat: -rw-r--r-- 12,718 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
            "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML>
<HEAD>



<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<META name="GENERATOR" content="hevea 1.08">
<LINK rel="stylesheet" type="text/css" href="gprolog.css">
<TITLE>
Calling Prolog from C
</TITLE>
</HEAD>
<BODY TEXT=black BGCOLOR=white>
<A HREF="gprolog068.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="gprolog065.html"><IMG SRC ="contents_motif.gif" ALT="Up"></A>
<A HREF="gprolog070.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
<HR>

<H3 CLASS="subsection"><A NAME="htoc374">9.4</A>&nbsp;&nbsp;Calling Prolog from C</H3><UL>
<LI><A HREF="gprolog069.html#toc307">Introduction</A>
<LI><A HREF="gprolog069.html#toc308">Example: <TT>my_call/1</TT> - a <TT>call/1</TT> clone</A>
<LI><A HREF="gprolog069.html#toc309">Example: recovering the list of all operators</A>
</UL>

<A NAME="toc307"></A>
<H4 CLASS="subsubsection"><A NAME="htoc375">9.4.1</A>&nbsp;&nbsp;Introduction</H4>
The following functions allows a C function to call a Prolog predicate:
<DL CLASS="list" COMPACT="compact"><DT CLASS="dt-list"><DD CLASS="dd-list">
<PRE CLASS="verbatim">
void   Pl_Query_Begin        (Bool recoverable)
int    Pl_Query_Call         (int functor, int arity, PlTerm *arg)
int    Pl_Query_Next_Solution(void)
void   Pl_Query_End          (int op)
PlTerm Pl_Get_Exception      (void)
void   Pl_Exec_Continuation  (int functor, int arity, PlTerm *arg)
</PRE></DL>
The invocation of a Prolog predicate should be done as follows:
<UL CLASS="itemize"><LI CLASS="li-itemize">open a query using <TT>Pl_Query_Begin()</TT><BR>
<BR>
<LI CLASS="li-itemize">compute the first solution using <TT>Pl_Query_Call()</TT><BR>
<BR>
<LI CLASS="li-itemize">eventually compute next solutions using
<TT>Pl_Query_Next_Solution()</TT><BR>
<BR>
<LI CLASS="li-itemize">close the query using <TT>Pl_Query_End()</TT></UL>
The function <TT>Pl_Query_Begin(recoverable)</TT> is used to initialize a query. The argument <TT>recoverable</TT> shall be set to
<TT>TRUE</TT> if the user wants to recover, at the end of the query, the
memory space consumed by the query (in that case an additional choice-point
is created). All terms created in the heap, e.g. using <TT>Mk_...</TT>
family functions (section&nbsp;<A HREF="gprolog067.html#Creating-Prolog-terms">9.2.5</A>), after the invocation of
<TT>Pl_Query_Begin()</TT> can be recovered when calling
<TT>Pl_Query_End(TRUE)</TT> (see below).<BR>
<BR>
The function <TT>Pl_Query_Call(functor, arity, arg)</TT> calls a predicate
passing arguments. It is then used to compute the first solution. The
arguments <TT>functor</TT>, <TT>arity</TT> and <TT>arg</TT> are similar to
those of the functions handling complex terms
(section&nbsp;<A HREF="gprolog067.html#Introduction:(Manipulating-Prolog-terms)">9.2.1</A>). This function returns:
<UL CLASS="itemize"><LI CLASS="li-itemize"><TT>PL_FAILURE</TT> (a constant equal to <TT>FALSE</TT>, i.e. 0) if
the query fails.<BR>
<BR>
<LI CLASS="li-itemize"><TT>PL_SUCCESS</TT> (a constant equal to <TT>TRUE</TT>, i.e. 1) in
case of success. In that case the argument array <TT>arg</TT> can be used to
obtain the unification performed by the query.<BR>
<BR>
<LI CLASS="li-itemize"><TT>PL_EXCEPTION</TT> (a constant equal to 2). In that case function
<TT>Pl_Get_Exception()</TT> can be used to obtained the exceptional term
raised by <TT>throw/1</TT> (section&nbsp;<A HREF="gprolog022.html#catch/3">6.2.4</A>).</UL>
The function <TT>Pl_Query_Next_Solution()</TT> is used to compute a new
solution. It must be only used if the result of the previous solution was
<TT>PL_SUCCESS</TT>. This functions returns the same kind of values as
<TT>Pl_Query_Call()</TT> (see above).<BR>
<BR>
The function <TT>Pl_Query_End(op)</TT> is used to finish a query. This
function mainly manages the remaining alternatives of the query. However,
even if the query has no alternatives this function must be used to
correctly finish the query. The value of <TT>op</TT> is:
<UL CLASS="itemize"><LI CLASS="li-itemize"><TT>PL_RECOVER</TT>: to recover the memory space consumed by the
query. After that the state of Prolog stacks is exactly the same as before
opening the query. To use this option the query must have been initialized
specifying <TT>TRUE</TT> for <TT>recoverable</TT> (see above).<BR>
<BR>
<LI CLASS="li-itemize"><TT>PL_CUT</TT>: to cut remaining alternatives. The effect of this
option is similar to a cut after the query.<BR>
<BR>
<LI CLASS="li-itemize"><TT>PL_KEEP_FOR_PROLOG</TT>: to keep the alternatives for Prolog.
This is useful when the query was invoked in a foreign C function. In that
case, when the predicate corresponding to the C foreign function is invoked
a query is executed and the remaining alternatives are then available as
alternatives of that predicate.</UL>
Note that several queries can be nested since a stack of queries is
maintained. For instance, it is possible to call a query and before
terminating it to call another query. In that case the first execution of
<TT>Pl_Query_End()</TT> will finish the second query (i.e. the inner) and
the next execution of <TT>Pl_Query_End()</TT> will finish the first query.<BR>
<BR>
Finally, the function <TT>Pl_Exec_Continuation(functor, arity,
arg)</TT> replaces the current calculus by the execution of the specified
predicate. The arguments <TT>functor</TT>, <TT>arity</TT> and
<TT>arg</TT> are similar to those of the functions handling complex
terms (section&nbsp;<A HREF="gprolog067.html#Introduction:(Manipulating-Prolog-terms)">9.2.1</A>).<BR>
<BR>
<A NAME="toc308"></A>
<H4 CLASS="subsubsection"><A NAME="htoc376">9.4.2</A>&nbsp;&nbsp;Example: <TT>my_call/1</TT> - a <TT>call/1</TT> clone</H4>
We here define a predicate <TT>my_call(Goal)</TT> which acts like
<TT>call(Goal)</TT> except that we do not handle exceptions (if an exception
occurs the goal simply fails):<BR>
<BR>
In the prolog file <TT>examp.pl</TT>:
<DL CLASS="list" COMPACT="compact"><DT CLASS="dt-list"><DD CLASS="dd-list"><TT>:- foreign(my_call(term)).</TT></DL>
In the C file <TT>examp_c.c</TT>:
<DL CLASS="list" COMPACT="compact"><DT CLASS="dt-list"><DD CLASS="dd-list">
<PRE CLASS="verbatim">
#include &lt;string.h&gt;
#include "gprolog.h"

Bool
my_call(PlTerm goal)

{
  PlTerm *arg;
  int functor, arity;
  int result;

  arg = Rd_Callable_Check(goal, &amp;functor, &amp;arity);
  Pl_Query_Begin(FALSE);
  result = Pl_Query_Call(functor, arity, arg);
  Pl_Query_End(PL_KEEP_FOR_PROLOG);
  return (result == PL_SUCCESS);
}
</PRE></DL>
The compilation produces an executable called <TT>examp</TT>:
<DL CLASS="list" COMPACT="compact"><DT CLASS="dt-list"><DD CLASS="dd-list"><TT>% gplc examp.pl examp_c.c</TT></DL>
Examples of use:
<DL CLASS="list" COMPACT="compact"><DT CLASS="dt-list"><DD CLASS="dd-list"><TABLE CELLSPACING=2 CELLPADDING=0>
<TR><TD ALIGN=left NOWRAP COLSPAN=3><TT>| ?- my_call(write(hello)).</TT></TD>
</TR>
<TR><TD ALIGN=left NOWRAP COLSPAN=3><TT>hello</TT></TD>
</TR>
<TR><TD ALIGN=left NOWRAP COLSPAN=3>&nbsp;</TD>
</TR>
<TR><TD ALIGN=left NOWRAP COLSPAN=3><TT>| ?- my_call(for(X,1,3)).</TT></TD>
</TR>
<TR><TD ALIGN=left NOWRAP COLSPAN=3>&nbsp;</TD>
</TR>
<TR><TD ALIGN=left NOWRAP><TT>X = 1 ?</TT></TD>
<TD VALIGN=top ALIGN=center NOWRAP>&nbsp;&nbsp;</TD>
<TD ALIGN=left NOWRAP>(here the user presses <TT>;</TT> to compute another solution)</TD>
</TR>
<TR><TD ALIGN=left NOWRAP COLSPAN=3>&nbsp;</TD>
</TR>
<TR><TD ALIGN=left NOWRAP><TT>X = 2 ?</TT></TD>
<TD VALIGN=top ALIGN=center NOWRAP>&nbsp;&nbsp;</TD>
<TD ALIGN=left NOWRAP>(here the user presses <TT>;</TT> to compute another solution)</TD>
</TR>
<TR><TD ALIGN=left NOWRAP COLSPAN=3>&nbsp;</TD>
</TR>
<TR><TD ALIGN=left NOWRAP><TT>X = 3</TT></TD>
<TD VALIGN=top ALIGN=center NOWRAP>&nbsp;&nbsp;</TD>
<TD ALIGN=left NOWRAP>(here the user is not prompted since there is no more alternative)</TD>
</TR>
<TR><TD ALIGN=left NOWRAP COLSPAN=3>&nbsp;</TD>
</TR>
<TR><TD ALIGN=left NOWRAP COLSPAN=3><TT>| ?- my_call(1).</TT></TD>
</TR>
<TR><TD ALIGN=left NOWRAP COLSPAN=3><TT>{exception:&nbsp;error(type_error(callable,1),my_call/1)}</TT></TD>
</TR>
<TR><TD ALIGN=left NOWRAP COLSPAN=3>&nbsp;</TD>
</TR>
<TR><TD ALIGN=left NOWRAP COLSPAN=3><TT>| ?- my_call(call(1)).</TT></TD>
</TR>
<TR><TD ALIGN=left NOWRAP COLSPAN=3>&nbsp;</TD>
</TR>
<TR><TD ALIGN=left NOWRAP COLSPAN=3><TT>no</TT></TD>
</TR></TABLE></DL>
When <TT>my_call(1)</TT> is called an error is raised due to the use of
<TT>Rd_Callable_Check()</TT>. However the error raised by
<TT>my_call(call(1))</TT> is ignored and <TT>FALSE</TT> (i.e. a failure) is
returned by the foreign function. <BR>
<BR>
To really simulate the behavior of <TT>call/1</TT> when an exception
is recovered it should be re-raised to be captured by an earlier
handler. The idea is then to execute a <TT>throw/1</TT> as the
continuation. This is what it is done by the following code:
<DL CLASS="list" COMPACT="compact"><DT CLASS="dt-list"><DD CLASS="dd-list">
<PRE CLASS="verbatim">
#include &lt;string.h&gt;
#include "gprolog.h"

Bool
my_call(PlTerm goal)
{
  PlTerm *args;
  int functor, arity;
  int result;

  args = Rd_Callable_Check(goal, &amp;functor, &amp;arity);
  Pl_Query_Begin(FALSE);
  result = Pl_Query_Call(functor, arity, args);
  Pl_Query_End(PL_KEEP_FOR_PROLOG);
  if (result == PL_EXCEPTION)
    {
      PlTerm except = Pl_Get_Exception();
      Pl_Exec_Continuation(Find_Atom("throw"), 1, &amp;except);
    }

  return result;
}
</PRE></DL>
The following code propagates the error raised by <TT>call/1</TT>.
<DL CLASS="list" COMPACT="compact"><DT CLASS="dt-list"><DD CLASS="dd-list"><TABLE CELLSPACING=2 CELLPADDING=0>
<TR><TD ALIGN=left NOWRAP COLSPAN=3><TT>| ?- my_call(call(1)).</TT></TD>
</TR>
<TR><TD ALIGN=left NOWRAP COLSPAN=3><TT>{exception:&nbsp;error(type_error(callable,1),my_call/1)}</TT></TD>
</TR></TABLE></DL>
Finally note that a simpler way to define <TT>my_call/1</TT> is to use 
<TT>Pl_Exec_Continuation()</TT> as follows:
<DL CLASS="list" COMPACT="compact"><DT CLASS="dt-list"><DD CLASS="dd-list">
<PRE CLASS="verbatim">
#include &lt;string.h&gt;
#include "gprolog.h"

Bool
my_call(PlTerm goal)
{
  PlTerm *args;
  int functor, arity;

  args = Rd_Callable_Check(goal, &amp;functor, &amp;arity);
  Pl_Exec_Continuation(functor, arity, args);
  return TRUE;
}
</PRE></DL>
<A NAME="toc309"></A>
<H4 CLASS="subsubsection"><A NAME="htoc377">9.4.3</A>&nbsp;&nbsp;Example: recovering the list of all operators</H4>
We here define a predicate <TT>all_op(List)</TT> which unifies
<TT>List</TT> with the list of all currently defined operators as would be done by: <TT>findall(X,current_op(_,_,X),List)</TT>.<BR>
<BR>
In the prolog file <TT>examp.pl</TT>:
<DL CLASS="list" COMPACT="compact"><DT CLASS="dt-list"><DD CLASS="dd-list"><TT>:- foreign(all_op(term)).</TT></DL>
In the C file <TT>examp_c.c</TT>:
<DL CLASS="list" COMPACT="compact"><DT CLASS="dt-list"><DD CLASS="dd-list">
<PRE CLASS="verbatim">
#include &lt;string.h&gt;
#include "gprolog.h"

Bool
all_op(PlTerm list)
{
  PlTerm op[1024];
  PlTerm args[3];
  int n = 0;
  int result;

  Pl_Query_Begin(TRUE);
  args[0] = Mk_Variable();
  args[1] = Mk_Variable();
  args[2] = Mk_Variable();
  result = Pl_Query_Call(Find_Atom("current_op"), 3, args);
  while (result)
    {
      op[n++] = Mk_Atom(Rd_Atom(args[2])); /* arg #2 is the name of the op */
      result = Pl_Query_Next_Solution();
    }
  Pl_Query_End(PL_RECOVER);

  return Un_Proper_List_Check(n, op, list);
}
</PRE></DL>
Note that we know here that there is no source for exception. In that case
the result of <TT>Pl_Query_Call</TT> and <TT>Pl_Query_Next_Solution</TT>
can be considered as a boolean.<BR>
<BR>
The compilation produces an executable called <TT>examp</TT>:
<DL CLASS="list" COMPACT="compact"><DT CLASS="dt-list"><DD CLASS="dd-list"><TT>% gplc examp.pl examp_c.c</TT></DL>
Example of use:
<DL CLASS="list" COMPACT="compact"><DT CLASS="dt-list"><DD CLASS="dd-list">
<PRE CLASS="verbatim">
| ?- all_op(L).

L = [:-,:-,\=,=:=,#&gt;=,#&lt;#,@&gt;=,--&gt;,mod,#&gt;=#,**,*,+,+,',',...]

| ?- findall(X,current_op(_,_,X),L).

L = [:-,:-,\=,=:=,#&gt;=,#&lt;#,@&gt;=,--&gt;,mod,#&gt;=#,**,*,+,+,',',...]
</PRE></DL>

<HR SIZE=2>
Copyright (C) 1999-2007 Daniel Diaz
<BR>
<BR>
Verbatim copying and distribution of this entire article is permitted in any
medium, provided this notice is preserved. <BR>
<BR>
<A HREF="index.html#copyright">More about the copyright</A>
<HR>
<A HREF="gprolog068.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="gprolog065.html"><IMG SRC ="contents_motif.gif" ALT="Up"></A>
<A HREF="gprolog070.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
</BODY>
</HTML>