1 /* GNU Prolog Common Foreign Language Interface.
2 Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
3 Copyright (C) 2010-2016 BUGSENG srl (http://bugseng.com)
4
5 This file is part of the Parma Polyhedra Library (PPL).
6
7 The PPL is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11
12 The PPL is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
20
21 For the most up-to-date information see the Parma Polyhedra Library
22 site: http://bugseng.com/products/ppl/ . */
23
24 #ifndef PCFLI_gprolog_cfli_hh
25 #define PCFLI_gprolog_cfli_hh 1
26
27 #if SIZEOF_FP == SIZEOF_INTP
28 // Horrible kludge working around an horrible bug in <gprolog.h> (see
29 // http://www.cs.unipr.it/pipermail/ppl-devel/2008-August/012277.html).
30 #define byte_code byte_code(void)
31 #define last_read_line last_read_line(void)
32 #define last_read_col last_read_col(void)
33 #include <gprolog.h>
34 #undef byte_code
35 #undef last_read_line
36 #undef last_read_col
37 #else
38 #include <gprolog.h>
39 #endif
40
41 #if defined(__GPROLOG_VERSION__) && __GPROLOG_VERSION__ >= 10301
42 #define PPL_GPROLOG_H_IS_CLEAN
43 #endif
44
45 #ifndef PPL_GPROLOG_H_IS_CLEAN
46 // <gprolog.h> pollutes the namespace: try to clean up
47 // (see http://www.cs.unipr.it/pipermail/ppl-devel/2004-April/004270.html).
48 #ifdef B
49 #undef B
50 #endif
51 #ifdef H
52 #undef H
53 #endif
54 #ifdef CP
55 #undef CP
56 #endif
57 #ifdef E
58 #undef E
59 #endif
60 #ifdef CS
61 #undef CS
62 #endif
63 #ifdef S
64 #undef S
65 #endif
66 #ifdef STAMP
67 #undef STAMP
68 #endif
69 #endif
70
71 #include <cassert>
72 #include <cstdlib>
73
74 typedef PlTerm Prolog_term_ref;
75 typedef int Prolog_atom;
76 #ifndef PPL_GPROLOG_H_IS_CLEAN
77 typedef Bool Prolog_foreign_return_type;
78
79 const Prolog_foreign_return_type PROLOG_SUCCESS = TRUE;
80 const Prolog_foreign_return_type PROLOG_FAILURE = FALSE;
81 #else
82 typedef PlBool Prolog_foreign_return_type;
83
84 const Prolog_foreign_return_type PROLOG_SUCCESS = PL_TRUE;
85 const Prolog_foreign_return_type PROLOG_FAILURE = PL_FALSE;
86 #endif
87
88 namespace {
89
90 inline Prolog_atom
a_dollar_address()91 a_dollar_address() {
92 // We use the `name' variable, instead of directly using the string
93 // literal, in order to avoid a compiler warning.
94 static char name[] = "$address";
95 static Prolog_atom atom = Create_Allocate_Atom(name);
96 return atom;
97 }
98
99 inline Prolog_atom
a_throw()100 a_throw() {
101 // We use the `name' variable, instead of directly using the string
102 // literal, in order to avoid a compiler warning.
103 static char name[] = "throw";
104 static Prolog_atom a = Find_Atom(name);
105 return a;
106 }
107
108 } // namespace
109
110 /*!
111 Return a new term reference.
112 */
113 inline Prolog_term_ref
Prolog_new_term_ref()114 Prolog_new_term_ref() {
115 return 0;
116 }
117
118 /*!
119 Make \p t be a reference to the same term referenced by \p u,
120 i.e., assign \p u to \p t.
121 */
122 inline int
Prolog_put_term(Prolog_term_ref & t,Prolog_term_ref u)123 Prolog_put_term(Prolog_term_ref& t, Prolog_term_ref u) {
124 t = u;
125 return 1;
126 }
127
128 /*!
129 Assign to \p t a Prolog integer with value \p l.
130 */
131 inline int
Prolog_put_long(Prolog_term_ref & t,long l)132 Prolog_put_long(Prolog_term_ref& t, long l) {
133 if (l < INT_LOWEST_VALUE || l > INT_GREATEST_VALUE)
134 return 0;
135 else {
136 t = Mk_Integer(l);
137 return 1;
138 }
139 }
140
141 /*!
142 Assign to \p t a Prolog integer with value \p ul.
143 */
144 inline int
Prolog_put_ulong(Prolog_term_ref & t,unsigned long ul)145 Prolog_put_ulong(Prolog_term_ref& t, unsigned long ul) {
146 if (ul > static_cast<unsigned long>(INT_GREATEST_VALUE))
147 return 0;
148 else {
149 t = Mk_Integer(ul);
150 return 1;
151 }
152 }
153
154 /*!
155 Assign to \p t an atom whose name is given
156 by the null-terminated string \p s.
157 */
158 inline int
Prolog_put_atom_chars(Prolog_term_ref & t,const char * s)159 Prolog_put_atom_chars(Prolog_term_ref& t, const char* s) {
160 t = Mk_Atom(Create_Allocate_Atom(const_cast<char*>(s)));
161 return 1;
162 }
163
164 /*!
165 Assign to \p t the Prolog atom \p a.
166 */
167 inline int
Prolog_put_atom(Prolog_term_ref & t,Prolog_atom a)168 Prolog_put_atom(Prolog_term_ref& t, Prolog_atom a) {
169 t = Mk_Atom(a);
170 return 1;
171 }
172
173 /*!
174 Return an atom whose name is given by the null-terminated string \p s.
175 */
176 inline Prolog_atom
Prolog_atom_from_string(const char * s)177 Prolog_atom_from_string(const char* s) {
178 return Create_Allocate_Atom(const_cast<char*>(s));
179 }
180
181 /*!
182 Assign to \p t a compound term whose principal functor is \p f
183 of arity 1 with argument \p a1.
184 */
185 inline int
Prolog_construct_compound(Prolog_term_ref & t,Prolog_atom f,Prolog_term_ref a1)186 Prolog_construct_compound(Prolog_term_ref& t, Prolog_atom f,
187 Prolog_term_ref a1) {
188 Prolog_term_ref args[1];
189 args[0] = a1;
190 t = Mk_Compound(f, 1, args);
191 return 1;
192 }
193
194 /*!
195 Assign to \p t a compound term whose principal functor is \p f
196 of arity 2 with arguments \p a1 and \p a2.
197 */
198 inline int
Prolog_construct_compound(Prolog_term_ref & t,Prolog_atom f,Prolog_term_ref a1,Prolog_term_ref a2)199 Prolog_construct_compound(Prolog_term_ref& t, Prolog_atom f,
200 Prolog_term_ref a1, Prolog_term_ref a2) {
201 Prolog_term_ref args[2];
202 args[0] = a1;
203 args[1] = a2;
204 t = Mk_Compound(f, 2, args);
205 return 1;
206 }
207
208 /*!
209 Assign to \p t a compound term whose principal functor is \p f
210 of arity 3 with arguments \p a1, \p a2 and \p a3.
211 */
212 inline int
Prolog_construct_compound(Prolog_term_ref & t,Prolog_atom f,Prolog_term_ref a1,Prolog_term_ref a2,Prolog_term_ref a3)213 Prolog_construct_compound(Prolog_term_ref& t, Prolog_atom f,
214 Prolog_term_ref a1, Prolog_term_ref a2,
215 Prolog_term_ref a3) {
216 Prolog_term_ref args[3];
217 args[0] = a1;
218 args[1] = a2;
219 args[2] = a3;
220 t = Mk_Compound(f, 3, args);
221 return 1;
222 }
223
224 /*!
225 Assign to \p t a compound term whose principal functor is \p f
226 of arity 4 with arguments \p a1, \p a2, \p a3 and \p a4.
227 */
228 inline int
Prolog_construct_compound(Prolog_term_ref & t,Prolog_atom f,Prolog_term_ref a1,Prolog_term_ref a2,Prolog_term_ref a3,Prolog_term_ref a4)229 Prolog_construct_compound(Prolog_term_ref& t, Prolog_atom f,
230 Prolog_term_ref a1, Prolog_term_ref a2,
231 Prolog_term_ref a3, Prolog_term_ref a4) {
232 Prolog_term_ref args[4];
233 args[0] = a1;
234 args[1] = a2;
235 args[2] = a3;
236 args[3] = a4;
237 t = Mk_Compound(f, 4, args);
238 return 1;
239 }
240
241 /*!
242 Assign to \p c a Prolog list whose head is \p h and tail is \p t.
243 */
244 inline int
Prolog_construct_cons(Prolog_term_ref & c,Prolog_term_ref h,Prolog_term_ref t)245 Prolog_construct_cons(Prolog_term_ref& c,
246 Prolog_term_ref h, Prolog_term_ref t) {
247 Prolog_term_ref args[2];
248 args[0] = h;
249 args[1] = t;
250 c = Mk_List(args);
251 return 1;
252 }
253
254 /*!
255 Assign to \p t the list terminator <CODE>[]</CODE> (which needs not
256 be an atom).
257 */
258 inline int
Prolog_put_nil(Prolog_term_ref & t)259 Prolog_put_nil(Prolog_term_ref& t) {
260 t = Mk_Atom(atom_nil);
261 return 1;
262 }
263
264 /*!
265 Assign to \p t a term representing the address contained in \p p.
266 */
267 inline int
Prolog_put_address(Prolog_term_ref & t,void * p)268 Prolog_put_address(Prolog_term_ref& t, void* p) {
269 union {
270 void* l;
271 unsigned short s[sizeof(void*)/sizeof(unsigned short)];
272 } u;
273 u.l = reinterpret_cast<void*>(p);
274 if (sizeof(unsigned short)*2 == sizeof(void*))
275 return Prolog_construct_compound(t, a_dollar_address(),
276 Mk_Positive(u.s[0]),
277 Mk_Positive(u.s[1]));
278 else if (sizeof(unsigned short)*4 == sizeof(void*))
279 return Prolog_construct_compound(t, a_dollar_address(),
280 Mk_Positive(u.s[0]),
281 Mk_Positive(u.s[1]),
282 Mk_Positive(u.s[2]),
283 Mk_Positive(u.s[3]));
284 else
285 abort();
286 }
287
288 /*!
289 Raise a Prolog exception with \p t as the exception term.
290 */
291 inline void
Prolog_raise_exception(Prolog_term_ref t)292 Prolog_raise_exception(Prolog_term_ref t) {
293 Pl_Exec_Continuation(a_throw(), 1, &t);
294 }
295
296 /*!
297 Return true if \p t is a Prolog variable, false otherwise.
298 */
299 inline int
Prolog_is_variable(Prolog_term_ref t)300 Prolog_is_variable(Prolog_term_ref t) {
301 return Blt_Var(t) != FALSE;
302 }
303
304 /*!
305 Return true if \p t is a Prolog atom, false otherwise.
306 */
307 inline int
Prolog_is_atom(Prolog_term_ref t)308 Prolog_is_atom(Prolog_term_ref t) {
309 return Blt_Atom(t) != FALSE;
310 }
311
312 /*!
313 Return true if \p t is a Prolog integer, false otherwise.
314 */
315 inline int
Prolog_is_integer(Prolog_term_ref t)316 Prolog_is_integer(Prolog_term_ref t) {
317 return Blt_Integer(t) != FALSE;
318 }
319
320 /*!
321 Return true if \p t is a Prolog compound term, false otherwise.
322 */
323 inline int
Prolog_is_compound(Prolog_term_ref t)324 Prolog_is_compound(Prolog_term_ref t) {
325 return Blt_Compound(t) != FALSE;
326 }
327
328 /*!
329 Return true if \p t is a Prolog cons (list constructor), false otherwise.
330 */
331 inline int
Prolog_is_cons(Prolog_term_ref t)332 Prolog_is_cons(Prolog_term_ref t) {
333 if (Blt_Compound(t) == FALSE)
334 return 0;
335 Prolog_atom name;
336 int arity;
337 Rd_Compound(t, &name, &arity);
338 return name == ATOM_CHAR('.') && arity == 2;
339 }
340
341 /*!
342 Assuming \p t is a Prolog integer, return true if its value fits
343 in a long, in which case the value is assigned to \p v,
344 return false otherwise. The behavior is undefined if \p t is
345 not a Prolog integer.
346 */
347 inline int
Prolog_get_long(Prolog_term_ref t,long * lp)348 Prolog_get_long(Prolog_term_ref t, long* lp) {
349 assert(Prolog_is_integer(t));
350 *lp = Rd_Integer_Check(t);
351 return 1;
352 }
353
354 /*!
355 Return true if \p t is the representation of an address, false otherwise.
356 */
357 inline int
Prolog_is_address(Prolog_term_ref t)358 Prolog_is_address(Prolog_term_ref t) {
359 if (!Prolog_is_compound(t))
360 return 0;
361 Prolog_atom name;
362 int arity;
363 Prolog_term_ref* a = Rd_Compound_Check(t, &name, &arity);
364 if (name != a_dollar_address()
365 || sizeof(unsigned short)*arity != sizeof(void*))
366 return 0;
367 for (unsigned i = 0; i < sizeof(void*)/sizeof(unsigned short); ++i) {
368 if (!Prolog_is_integer(a[i]))
369 return 0;
370 long l;
371 if (!Prolog_get_long(a[i], &l))
372 return 0;
373 if (l < 0 || l > USHRT_MAX)
374 return 0;
375 }
376 return 1;
377 }
378
379 /*!
380 If \p t is the Prolog representation for a memory address, return
381 true and store that address into \p v; return false otherwise.
382 The behavior is undefined if \p t is not an address.
383 */
384 inline int
Prolog_get_address(Prolog_term_ref t,void ** vpp)385 Prolog_get_address(Prolog_term_ref t, void** vpp) {
386 assert(Prolog_is_address(t));
387 static Prolog_atom dummy_name;
388 static int dummy_arity;
389 Prolog_term_ref* a = Rd_Compound_Check(t, &dummy_name, &dummy_arity);
390 union {
391 void* l;
392 unsigned short s[sizeof(void*)/sizeof(unsigned short)];
393 } u;
394 assert(dummy_arity >= 2);
395 u.s[0] = Rd_Integer_Check(a[0]);
396 u.s[1] = Rd_Integer_Check(a[1]);
397 if (sizeof(unsigned short)*4 == sizeof(void*)) {
398 assert(dummy_arity == 4);
399 u.s[2] = Rd_Integer_Check(a[2]);
400 u.s[3] = Rd_Integer_Check(a[3]);
401 }
402 *vpp = reinterpret_cast<void*>(u.l);
403 return 1;
404 }
405
406 /*!
407 If \p t is a Prolog atom, return true and store its name into \p name.
408 The behavior is undefined if \p t is not a Prolog atom.
409 */
410 inline int
Prolog_get_atom_name(Prolog_term_ref t,Prolog_atom * ap)411 Prolog_get_atom_name(Prolog_term_ref t, Prolog_atom* ap) {
412 assert(Prolog_is_atom(t));
413 *ap = Rd_Atom_Check(t);
414 return 1;
415 }
416
417 /*!
418 If \p t is a Prolog compound term, return true and store its name
419 and arity into \p name and \p arity, respectively.
420 The behavior is undefined if \p t is not a Prolog compound term.
421 */
422 inline int
Prolog_get_compound_name_arity(Prolog_term_ref t,Prolog_atom * ap,int * ip)423 Prolog_get_compound_name_arity(Prolog_term_ref t, Prolog_atom* ap, int* ip) {
424 assert(Prolog_is_compound(t));
425 Rd_Compound_Check(t, ap, ip);
426 return 1;
427 }
428
429 /*!
430 If \p t is a Prolog compound term and \p i is a positive integer
431 less than or equal to its arity, return true and assign to \p a the
432 i-th (principal) argument of \p t.
433 The behavior is undefined if \p t is not a Prolog compound term.
434 */
435 inline int
Prolog_get_arg(int i,Prolog_term_ref t,Prolog_term_ref & a)436 Prolog_get_arg(int i, Prolog_term_ref t, Prolog_term_ref& a) {
437 assert(Prolog_is_compound(t));
438 static Prolog_atom dummy_name;
439 static int dummy_arity;
440 a = Rd_Compound_Check(t, &dummy_name, &dummy_arity)[i-1];
441 return 1;
442 }
443
444 /*!
445 Succeeds if and only if \p t represents the list terminator <CODE>[]</CODE>
446 (which needs not be an atom).
447 */
448 inline int
Prolog_get_nil(Prolog_term_ref t)449 Prolog_get_nil(Prolog_term_ref t) {
450 if (Blt_Atom(t) == FALSE) {
451 return 0;
452 }
453 else {
454 int a = atom_nil;
455 return Rd_Atom_Check(t) == a;
456 }
457 }
458
459 /*!
460 If \p c is a Prolog cons (list constructor), assign its head and
461 tail to \p h and \p t, respectively.
462 The behavior is undefined if \p c is not a Prolog cons.
463 */
464 inline int
Prolog_get_cons(Prolog_term_ref c,Prolog_term_ref & h,Prolog_term_ref & t)465 Prolog_get_cons(Prolog_term_ref c, Prolog_term_ref& h, Prolog_term_ref& t) {
466 assert(Prolog_is_cons(c));
467 Prolog_term_ref* ht = Rd_List_Check(c);
468 h = ht[0];
469 t = ht[1];
470 return 1;
471 }
472
473 /*!
474 Unify the terms referenced by \p t and \p u and return true
475 if the unification is successful; return false otherwise.
476 */
477 inline int
Prolog_unify(Prolog_term_ref t,Prolog_term_ref u)478 Prolog_unify(Prolog_term_ref t, Prolog_term_ref u) {
479 #ifndef PPL_GPROLOG_H_IS_CLEAN
480 return Unify(t, u) != FALSE;
481 #else
482 return Pl_Unif(t, u) != PL_FALSE;
483 #endif
484 }
485
486 #endif // !defined(PCFLI_gprolog_cfli_hh)
487