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