1/* BEGIN LICENSE BLOCK
2 * Version: CMPL 1.1
3 *
4 * The contents of this file are subject to the Cisco-style Mozilla Public
5 * License Version 1.1 (the "License"); you may not use this file except
6 * in compliance with the License.  You may obtain a copy of the License
7 * at www.eclipse-clp.org/license.
8 *
9 * Software distributed under the License is distributed on an "AS IS"
10 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
11 * the License for the specific language governing rights and limitations
12 * under the License.
13 *
14 * The Original Code is  The ECLiPSe Constraint Logic Programming System.
15 * The Initial Developer of the Original Code is  Cisco Systems, Inc.
16 * Portions created by the Initial Developer are
17 * Copyright (C) 1989-2006 Cisco Systems, Inc.  All Rights Reserved.
18 *
19 * Contributor(s):
20 *
21 * END LICENSE BLOCK */
22
23/*
24 * VERSION	$Id: bip_comp.c,v 1.8 2015/05/20 23:55:36 jschimpf Exp $
25 */
26
27/****************************************************************************
28 *
29 *		SEPIA Built-in Predicates: Term comparison
30 *
31 *
32 *	name		C func		type
33 *	----------------------------------------------------------------
34 *	=/2				B_EXPANDED	in emu.c
35 *	\=/2				B_EXPANDED	in emu.c
36 *	==/2				B_EXPANDED	in emu.c
37 *	\==/2				B_EXPANDED	in emu.c
38 *	@</2		p_termless	B_FUNCTION
39 *	@=</2		p_termlesseq	B_FUNCTION
40 *	@>/2		p_termgreater	B_FUNCTION
41 *	@>=/2		p_termgreatereq	B_FUNCTION
42 *	occurs/2	p_occurs	B_UNSAFE
43 *	variant/2	p_variant	B_UNSAFE
44 *	instance/2	p_instance	B_UNSAFE
45 *	nonground/1	p_nonground	B_FUNCTION
46 *
47 *****************************************************************************/
48
49#include 	"config.h"
50#include        "sepia.h"
51#include        "types.h"
52#include        "embed.h"
53#include        "mem.h"
54#include        "error.h"
55#include 	"dict.h"
56#include 	"opcode.h"
57#include 	"emu_export.h"		/* to perform a binding */
58
59#ifdef HAVE_STRING_H
60#include <string.h>
61#endif
62
63#define LESS		-1
64#define EQUAL		 0
65#define GREATER		 1
66#define TRUE		1
67#define FALSE		0
68#define Set_Bit(mask,pw)	(pw)->tag.kernel |= (mask);
69#define Clr_Bit(mask,pw)	(pw)->tag.kernel &= ~(mask);
70#define Marked(tag)		((tag).kernel & MARK)
71
72
73static int	p_termless(value v1, type t1, value v2, type t2),
74		p_termlesseq(value v1, type t1, value v2, type t2),
75		p_termgreater(value v1, type t1, value v2, type t2),
76		p_termgreatereq(value v1, type t1, value v2, type t2),
77		p_unify(value v1, type t1, value v2, type t2, value vl, type tl),
78		p_acyclic_term(value v, type t),
79		p_ground(value v, type t),
80		p_nonground(value v, type t),
81		p_occurs(value vs, type ts, value vt, type tt),
82		p_compare_instances4(value vr, type tr, value v1, type t1, value v2, type t2, value vl, type tl),
83		p_merge5(value vk, type tk, value vo, type to, value v1, type t1, value v2, type t2, value v, type t),
84		p_number_merge5(value vk, type tk, value vo, type to, value v1, type t1, value v2, type t2, value v, type t),
85		p_sort4(value vk, type tk, value vo, type to, value v1, type t1, value v2, type t2),
86		p_array_sort(value vk, type tk, value vo, type to, value v1, type t1, value v2, type t2),
87		p_number_sort4(value vk, type tk, value vo, type to, value v1, type t1, value v2, type t2);
88
89static int	_instance(int rel, value v1, type t1, value v2, type t2, pword *meta);
90
91
92void
93bip_comp_init(int flags)
94{
95    if (flags & INIT_SHARED)
96    {
97	(void) built_in(d_.less,		p_termless,	B_SAFE);
98	(void) built_in(d_.lessq,		p_termlesseq,	B_SAFE);
99	(void) built_in(d_.greater,		p_termgreater,	B_SAFE);
100	(void) built_in(d_.greaterq,		p_termgreatereq,B_SAFE);
101	exported_built_in(in_dict("unify", 3), p_unify,
102	    B_UNSAFE|U_UNIFY) -> mode =
103	    BoundArg(1, NONVAR) | BoundArg(2, NONVAR) | BoundArg(3, NONVAR);
104	exported_built_in(in_dict("compare_instances", 4),
105				p_compare_instances4,	B_UNSAFE|U_UNIFY)
106	    -> mode = BoundArg(1, CONSTANT) |
107			BoundArg(4, NONVAR);
108	(void) built_in(in_dict("occurs", 2),	p_occurs,	B_UNSAFE);
109	(void) built_in(d_.nonground,		p_nonground,	B_SAFE);
110	(void) built_in(d_.ground,		p_ground,	B_SAFE);
111	(void) built_in(in_dict("acyclic_term",1),	p_acyclic_term,	B_SAFE);
112	built_in(in_dict("merge", 5), 	p_merge5, 	B_UNSAFE|U_UNIFY)
113	    -> mode = BoundArg(3, NONVAR) | BoundArg(4, NONVAR) | BoundArg(5, NONVAR);
114	built_in(in_dict("number_merge", 5), 	p_number_merge5, 	B_UNSAFE|U_UNIFY)
115	    -> mode = BoundArg(3, NONVAR) | BoundArg(4, NONVAR) | BoundArg(5, NONVAR);
116	built_in(in_dict("sort", 4), 	p_sort4, 	B_UNSAFE|U_UNIFY)
117	    -> mode = BoundArg(3, NONVAR) | BoundArg(4, NONVAR);
118	built_in(in_dict("number_sort", 4), 	p_number_sort4, 	B_UNSAFE|U_UNIFY)
119	    -> mode = BoundArg(3, NONVAR) | BoundArg(4, NONVAR);
120	built_in(in_dict("array_sort", 4), 	p_array_sort, 	B_UNSAFE|U_UNIFY)
121	    -> mode = BoundArg(3, NONVAR) | BoundArg(4, NONVAR);
122    }
123}
124
125
126/*
127 * @</2 - term ordering
128 */
129static int
130p_termless(value v1, type t1, value v2, type t2)
131{
132	Succeed_If(ec_compare_terms(v1, t1, v2, t2) < 0);
133}
134
135/*
136 * @=</2 - term ordering
137 */
138static int
139p_termlesseq(value v1, type t1, value v2, type t2)
140{
141	Succeed_If(ec_compare_terms(v1, t1, v2, t2) <= 0);
142}
143
144/*
145 * @>/2 - term ordering
146 */
147static int
148p_termgreater(value v1, type t1, value v2, type t2)
149{
150	Succeed_If(ec_compare_terms(v1, t1, v2, t2) > 0);
151}
152
153/*
154 * @>=/2 - term ordering
155 */
156static int
157p_termgreatereq(value v1, type t1, value v2, type t2)
158{
159	Succeed_If(ec_compare_terms(v1, t1, v2, t2) >= 0);
160}
161
162/*
163 * unify(Term1, Term2, List)
164 *
165 *	Unify the two terms and return in List the list of metaterms
166 *	and their mates encountered during the unification
167 */
168static int
169p_unify(value v1, type t1, value v2, type t2, value vl, type tl)
170{
171    pword	*list = (pword *) 0;
172    int		res;
173
174    res = ec_unify_(v1, t1, v2, t2, &list);
175    if (res == PSUCCEED) {
176	if (list == (pword *) 0) {
177	    Return_Unify_Nil(vl, tl)
178	} else {
179	    Return_Unify_List(vl, tl, list)
180	}
181    } else
182	return res;
183}
184
185
186/*
187 * compare two sepia strings, given their value parts
188 * return value is like strcmp()
189 */
190int
191compare_strings(value v1, value v2)
192{
193    register word		len = StringLength(v1);
194    register unsigned char	*s1 = (unsigned char *) StringStart(v1);
195    register unsigned char	*s2 = (unsigned char *) StringStart(v2);
196    register int		res;
197
198    if (len > StringLength(v2))
199	len = StringLength(v2);
200    while (len--)
201	if (res = *s1++ - *s2++)
202	    return res;
203
204    return StringLength(v1) - StringLength(v2);
205}
206
207/*
208 * compare two Prolog terms, returns <0 if T1 < T2, 0 if T1 = T2, >0 if T1 > T2
209 */
210int
211ec_compare_terms(value v1, type t1, value v2, type t2)
212{
213	dident          wdid, wdid2;
214	pword		*arg1, *arg2;
215	int		arity, res;
216
217_compare_loop_:
218	if (IsRef(t1))
219	{
220	    return IsRef(t2) ? v1.ptr - v2.ptr : LESS;
221	}
222	else if (IsRef(t2))
223	{
224	    return GREATER;
225	}
226	else if (res = tag_desc[TagType(t1)].order - tag_desc[TagType(t2)].order)
227	{
228	    return res;		/* types are ordered */
229	}
230	else			/* compare the values */
231	{
232	    double d1, d2;
233
234	    switch (TagType(t1))
235	    {
236	    case TINT:
237		if (IsTag(t2.kernel,TINT))	/* TINT x TINT */
238		{
239		    return v1.nint < v2.nint ? LESS :
240			v1.nint > v2.nint ? GREATER : 0;
241		}
242		/* else fall through */
243
244	    case TBIG:
245		/* this case handles TINT x TBIG, TBIG x TINT, TBIG x TBIG */
246		(void) arith_compare(v1, t1, v2, t2, &res);
247		return res;
248
249	    case TSTRG:
250		return compare_strings(v1, v2);
251
252	    case TNIL:
253		return IsNil(t2) ? EQUAL :
254			strcmp(DidName(d_.nil), DidName(v2.did));
255
256	    case TDICT:
257		return IsNil(t2) ? strcmp(DidName(v1.did), DidName(d_.nil)) :
258			strcmp(DidName(v1.did), DidName(v2.did));
259
260	    case TLIST:
261		if (IsList(t2))
262		{
263		    if (v1.ptr == v2.ptr)
264			return EQUAL;
265		    arity = 2;
266		    goto _compare_args_;
267		}
268		else	/* TCOMP */
269		{
270		    wdid2 = v2.ptr->val.did;	/* wdid2 != d_.list */
271		    arity = DidArity(wdid2);
272		    if (2 != arity)
273			return 2 - arity;
274		    else
275			return strcmp(DidName(d_.list), DidName(wdid2));
276		}
277
278	    case TCOMP:
279		if (IsList(t2))
280		{
281		    wdid = v1.ptr->val.did; /* wdid != d_.list */
282		    arity = DidArity(wdid);
283		    if (arity != 2)
284			return arity -2;
285		    else
286			return strcmp(DidName(wdid), DidName(d_.list));
287		}
288		else	/* TCOMP */
289		{
290		    if (v1.ptr == v2.ptr)
291			return EQUAL;
292		    wdid = (v1.ptr++)->val.did;
293		    arity = DidArity(wdid);
294		    wdid2 = (v2.ptr++)->val.did;
295		    if (wdid != wdid2)
296			if (arity != DidArity(wdid2))
297			    return arity - DidArity(wdid2);
298			else
299			   return strcmp(DidName(wdid), DidName(wdid2));
300		    if (arity == 0)
301			return EQUAL;
302_compare_args_:						/* (arity, v1, v2) */
303		    for(;;)
304		    {
305			arg1 = v1.ptr++;
306			arg2 = v2.ptr++;
307			Dereference_(arg1)
308			Dereference_(arg2)
309			if (--arity == 0)
310			    break;
311			res = ec_compare_terms
312				(arg1->val, arg1->tag,
313				 arg2->val, arg2->tag);
314			if (res != EQUAL)
315			    return res;
316		    }
317		    /* remove tail recursion */
318		    v1.all = arg1->val.all;
319		    t1.all = arg1->tag.all;
320		    v2.all = arg2->val.all;
321		    t2.all = arg2->tag.all;
322		    goto _compare_loop_;
323		}
324
325	    default:
326		return tag_desc[TagType(t1)].compare(v1, v2);
327	    }
328	}
329}
330
331
332/*
333 * MU-Prolog's occurs/2: occurs(Simple, Term) is true if Simple is a variable
334 * or a constant and it occurs in the term Term.
335 */
336static int
337p_occurs(value vs, type ts, value vt, type tt)
338{
339	if (!IsRef(ts) && !IsDouble(ts) && !IsSimple(ts))
340	{
341		Bip_Error(TYPE_ERROR);
342	}
343	Succeed_If(ec_occurs(vs, ts, vt, tt));
344}
345
346/* returns true if the first (simple) term occurs in the second one */
347int
348ec_occurs(value vs, type ts, value vterm, type tterm)
349{
350	int		arity;
351	pword		*arg;
352
353    for(;;)
354    {
355	if (IsRef(tterm))
356		return (IsRef(ts) && vs.all == vterm.all);
357	switch (TagType(tterm))
358	{
359	case TCOMP:
360		arity = DidArity(vterm.ptr->val.did);
361		vterm.ptr++;
362		break;
363
364	case TLIST:
365		arity = 2;
366		break;
367
368	case TNIL:
369		return (IsNil(ts));
370
371	case TSTRG:
372		return IsString(ts) && !compare_strings(vs, vterm);
373
374	case TDBL:
375		return IsDouble(ts) && Dbl(vs) == Dbl(vterm);
376
377	default:
378		return SameType(ts, tterm) && SimpleEq(ts.kernel, vs, vterm);
379	}
380
381	for (; arity > 1; arity--)
382	{
383		arg = vterm.ptr++;
384		Dereference_(arg);
385		if (ec_occurs(vs, ts, arg->val, arg->tag))
386			return 1;
387	}
388	arg = vterm.ptr;	/* tail recursion optimised */
389	Dereference_(arg);
390	vterm = arg->val;
391	tterm = arg->tag;
392    }
393}
394
395#ifdef OC
396/* returns true if the first (compound) term occurs in the second one */
397int
398occurs_compound(pword *comp, pword *term)
399{
400	int		arity;
401	pword		*arg;
402
403    for(;;)
404    {
405	switch (TagType(term->tag))
406	{
407	case TCOMP:
408		if (comp == term)
409			return 1;
410		term = term->val.ptr;
411		arity = DidArity(term->val.did);
412		term++;
413		break;
414
415	case TLIST:
416		if (comp == term)
417			return 1;
418		arity = 2;
419		term = term->val.ptr;
420		break;
421
422	default:
423		return 0;
424	}
425
426	for (; arity > 1; arity--)
427	{
428		arg = term++;
429		Dereference_(arg);
430		if (occurs_compound(comp, arg))
431			return 1;
432	}
433	/* tail recursion optimised */
434	Dereference_(term);
435    }
436}
437#endif
438
439
440/*
441 * compare_instances(?Res, ?Term1, ?Term2, -MetaList)
442 *		Res == '<' iff Term1 is an instance of Term2
443 *		Res == '>' iff Term2 is an instance of Term1
444 *		Res == '=' iff Term1 is a variant of Term2
445 *	fails if none of the above applies (terms not unifiable)
446 *	MetaList is a list of all subterm pairs where at least one side
447 *	is an attributed variable - these are handled later by the
448 *	attribute's compare_instances handlers.
449 *
450 * This is the basis for the builtins
451 *	variant(Term1, Term2)
452 *	instance(Instance, Term)
453 *	compare_instances(Rel, Term1, Term2)
454 *
455 * Uses the common routine _instance(), which does the work in a single
456 * pass through the two terms. The complexity is linear in the size of
457 * the larger term. Failures are detected early (the return value is 0).
458 *
459 * Algorithm:
460 *	var-var pairs: bind the variables together and instantiate
461 *		with a unique constant (TVARNUM with self-ref)
462 *	var-nonvar pairs: bind the variable to the nonvariable. Such a
463 *		binding means that one term is more general than the other.
464 *		Therefore, for variant test, it causes failure, for instance
465 *		test only variables on one side may be bound.
466 *		The nonvariable term is instantiated with TVARNUMs.
467 *
468 * The results may be counter-intuitive when the two terms share variables.
469 * Our exact definition is: A term subsumes another one iff by binding some
470 * of its variables it can be made to unify with the other one (the instance).
471 * e.g. the following succeed:
472 *
473 *	instance(s(Y, X), s(X, Y))	with substitution X=Y
474 *	instance(s(a, X), s(X, X))	with substitution X=a
475 *
476 *	instance(f(X), X)	succeeds iff occur check disabled
477 */
478
479#define ANY_INST	7
480#define LT		4
481#define EQ		2
482#define GT		1
483
484static int
485p_compare_instances4(value vr, type tr,
486	value v1, type t1,
487	value v2, type t2,
488	value vl, type tl)
489{
490	int             code;
491	dident 		res;
492	pword		list;
493	pword		**save_tt = TT;
494
495	list.tag.kernel = TNIL;
496
497	if (IsRef(tr))
498	{
499	    code = _instance(ANY_INST, v1, t1, v2, t2, &list);
500	    if (code == 0)
501		{ Fail_; }
502	    if (code & EQ)
503		res = d_.unify0;
504	    else if (code & LT)
505		res = d_.inf0;
506	    else /* if (code & GT) */
507		res = d_.sup0;
508	    Untrail_Variables(save_tt);
509	    Bind_Var(vr, tr, res, TDICT)
510	}
511	else if (IsAtom(tr))
512	{
513	    if (vr.did == d_.unify0)
514	    {
515		if (!_instance(EQ,v1,t1,v2,t2, &list))
516		    { Fail_; }
517	    }
518	    else if (vr.did == d_.inf0)
519	    {
520		code = _instance(EQ|LT,v1,t1,v2,t2, &list);
521		if (code != LT) {Fail_; }
522	    }
523	    else if (vr.did == d_.sup0)
524	    {
525		code = _instance(EQ|GT,v1,t1,v2,t2, &list);
526		if (code != GT) {Fail_; }
527	    }
528	    else
529		{ Bip_Error(RANGE_ERROR); }
530	    Untrail_Variables(save_tt);
531	}
532	else
533	    { Bip_Error(TYPE_ERROR); }
534
535	Return_Unify_Pw(vl, tl, list.val, list.tag)
536}
537
538/*
539 * Instantiate all variables in a term to unique terms. It is like
540 * numbervars(), but it uses terms with the special tag TVARNUM.
541 */
542static void
543_instantiate(value v1, type t1)
544{
545    int		arity;
546    pword	*arg1;
547
548    for (;;)
549    {
550	if (IsRef(t1))
551	{
552	    if (IsVar(t1)) Trail_(v1.ptr) else Trail_Tag(v1.ptr);
553	    v1.ptr->tag.kernel = TVARNUM;
554	    return;
555	}
556	else if (IsStructure(t1))
557	{
558	    arity = DidArity(v1.ptr->val.did);
559	    v1.ptr++;
560	}
561	else if (IsList(t1))
562	    arity = 2;
563	else
564	    return;
565
566	for (;;)
567	{
568	    arg1 = v1.ptr++;
569	    Dereference_(arg1);
570	    if (--arity == 0)
571		break;
572	    _instantiate(arg1->val, arg1->tag);
573	}
574	v1.all = arg1->val.all;		/* tail recursion */
575	t1.all = arg1->tag.all;
576    }
577}
578
579
580/*
581 * General instance check
582 * Untrail after calling!
583 */
584
585static int
586_instance(int rel,		/* relation type asked for */
587	value v1, type t1,
588	value v2, type t2,
589	pword *meta)		/* output list of meta pairs */
590{
591    int		arity;
592    pword	*arg1, *arg2;
593
594    for (;;)
595    {
596	if (IsMeta(t1) || IsMeta(t2))	/* make list of meta pairs */
597	{
598	    arg1 = TG;
599	    TG += 4;
600	    Check_Gc
601	    arg1[0].val.ptr = v1.ptr;
602	    arg1[0].tag.kernel = IsTag(t1.kernel, TVARNUM) ? TREF : t1.kernel;
603	    arg1[1].val.ptr = v2.ptr;
604	    arg1[1].tag.kernel = IsTag(t2.kernel, TVARNUM) ? TREF : t2.kernel;
605	    arg1[2].val.ptr = arg1;
606	    arg1[2].tag.kernel = TLIST;
607	    arg1[3] = *meta;
608	    meta->val.ptr = &arg1[2];
609	    meta->tag.kernel = TLIST;
610	}
611	if (IsRef(t1))
612	{
613	    if (IsRef(t2))		/* var - var */
614	    {
615		if (v1.ptr != v2.ptr)
616		{
617		    if (IsVar(t1)) Trail_(v1.ptr) else Trail_Tag(v1.ptr);
618		    if (IsVar(t2)) Trail_(v2.ptr) else Trail_Tag(v2.ptr);
619		    v1.ptr->tag.kernel = TVARNUM;
620		    v2.ptr->tag.kernel = TREF;
621		    v2.ptr->val.ptr = v1.ptr;
622		}
623		return rel;
624	    }
625	    else			/* var - nonvar */
626	    {
627		/* Ground the term we bind to in order to make sure that
628		 * the variables inside are not bound later by mistake.
629		 * This also makes simple occur check possible.
630		 */
631		_instantiate(v2, t2);
632		if (!IsTag(v1.ptr->tag.kernel, TVARNUM))
633		{
634		    if (IsVar(t1)) Trail_(v1.ptr) else Trail_Tag(v1.ptr);
635		}
636		else if (OccurCheckEnabled())
637		    return 0;
638		/* t1 is now trailed, bind it */
639		v1.ptr->val.all = v2.all;
640		v1.ptr->tag.all = t2.all;
641		return rel & ~(LT|EQ);
642	    }
643	}
644	else if (IsRef(t2))		/* nonvar - var */
645	{
646	    /* see comment above */
647	    _instantiate(v1, t1);
648	    if (!IsTag(v2.ptr->tag.kernel, TVARNUM))
649	    {
650		if (IsVar(t2)) Trail_(v2.ptr) else Trail_Tag(v2.ptr);
651	    }
652	    else if (OccurCheckEnabled())
653		return 0;
654	    /* t2 is now trailed, bind it */
655	    v2.ptr->val.all = v1.all;
656	    v2.ptr->tag.all = t1.all;
657	    return rel & ~(GT|EQ);
658	}
659	else if (IsTag(t1.kernel, TVARNUM))
660	{
661	    if (IsTag(t2.kernel, TVARNUM) && v1.ptr == v2.ptr)
662	    {
663		return rel;
664	    }
665	    if (OccurCheckEnabled() && ec_occurs(v1, t1, v2, t2))
666		return 0;
667	    /* t1 is already trailed */
668	    v1.ptr->val.all = v2.all;
669	    v1.ptr->tag.all = t2.all;
670	    return rel & ~(GT|EQ|LT);	/* not instances, but still unify */
671	}
672	else if (IsTag(t2.kernel, TVARNUM))
673	{
674	    if (OccurCheckEnabled() && ec_occurs(v2, t2, v1, t1))
675		return 0;
676	    /* t2 is already trailed */
677	    v2.ptr->val.all = v1.all;
678	    v2.ptr->tag.all = t1.all;
679	    return rel & ~(GT|EQ|LT);	/* not instances, but still unify */
680	}
681
682	switch (TagType(t1))
683	{
684	case TLIST:
685	    if (!IsTag(t2.kernel, TLIST))
686		return 0;
687	    arity = 2;
688	    break;
689
690	case TCOMP:
691	    if (!IsTag(t2.kernel, TCOMP) || v1.ptr->val.did != v2.ptr->val.did)
692		return 0;
693	    arity = DidArity(v1.ptr->val.did);
694	    v1.ptr++;
695	    v2.ptr++;
696	    break;
697
698	case TSTRG:
699	    return (IsString(t2) && !compare_strings(v1, v2)) ? rel : 0;
700
701	case TINT:
702	case TDICT:
703	case TNIL:
704	case TPTR:
705#ifdef UNBOXED_DOUBLES
706	case TDBL:
707#endif
708	    return (SameType(t1, t2) && SimpleEq(t1.kernel, v1, v2)) ? rel : 0;
709
710	default:
711	    if (TagType(t1) >= 0 && TagType(t1) <= NTYPES)
712	    {
713		if (SameType(t1, t2) &&
714			tag_desc[TagType(t1)].equal(v1.ptr, v2.ptr))
715		    return rel;
716		else
717		    return 0;
718	    }
719	    p_fprintf(current_err_,
720		"_instance(): unknown tag (%x) encountered\n", t1.kernel);
721	    ec_flush(current_err_);
722	    return 0;
723	}
724
725	if (v1.ptr == v2.ptr)		/* detect sharing */
726	    return rel;
727
728	for (;;)
729	{
730	    arg1 = v1.ptr++;
731	    arg2 = v2.ptr++;
732	    Dereference_(arg1);
733	    Dereference_(arg2);
734	    if (--arity == 0)
735		break;
736	    rel = _instance(rel, arg1->val, arg1->tag,
737			    arg2->val, arg2->tag, meta);
738
739	    if (rel == 0)		/* fail early */
740		return rel;
741	}
742
743	v1.all = arg1->val.all;		/* tail recursion */
744	t1.all = arg1->tag.all;
745	v2.all = arg2->val.all;
746	t2.all = arg2->tag.all;
747    }
748}
749
750
751/*
752	nonground/1
753	succeeds if the term is not fully instantiated
754*/
755
756static int
757p_nonground(value v, type t)
758{
759    Succeed_If(ec_nonground(v, t))
760}
761
762int
763p_ground(value v, type t)
764{
765    Succeed_If(!ec_nonground(v, t))
766}
767
768
769/*
770 * Check if a term is cyclic. We mark the target of every TLIST or TCOMP
771 * pointer, and if we encouter it withing its descendants, we know we have
772 * a cycle and stop. This algorithm is very naive and simple. It is not
773 * tail recursive and therefore may nest deeply. It also does not detect
774 * shared (already traversed) subtrees, and thus traverses them again.
775 */
776
777static int
778_cyclic_term(value val, type tag)	/* expects a dereferenced argument */
779
780{
781    pword *arg_i;
782    int arity;
783
784    if (IsList(tag))
785    {
786	if (val.ptr->tag.kernel & MARK)
787	    return 1;
788	arity = 2;
789	arg_i = val.ptr;
790    }
791    else if (IsStructure(tag))
792    {
793	if (val.ptr->tag.kernel & MARK)
794	    return 1;
795	arity = DidArity(val.ptr->val.did);
796	arg_i = val.ptr + 1;
797    }
798    else
799	return 0;
800
801    val.ptr->tag.kernel |= MARK;
802    for(; arity > 0; arity--,arg_i++)
803    {
804	pword *pw = arg_i;
805	Dereference_(pw);
806	if (IsCompound(pw->tag) && _cyclic_term(pw->val, pw->tag))
807	{
808	    val.ptr->tag.kernel &= ~MARK;
809	    return 1;
810	}
811    }
812    val.ptr->tag.kernel &= ~MARK;
813    return 0;
814}
815
816static int
817p_acyclic_term(value v, type t)
818{
819    Succeed_If(!_cyclic_term(v, t));
820}
821
822
823
824/*
825 * FUNCTION NAME:       p_sort4()
826 *
827 * PARAMETERS:          vk,tk	sorting key, if 0 the whole term is the key
828 *			vo,to	one of the atoms <,=<,>,>=
829 *			v1,t1	a list or nil (the input list)
830 *			v2,t2	list, nil or variable (the sorted list)
831 *
832 * DESCRIPTION:         sort(+Key, +Order, +Random, ?Sorted)
833 *			The sorting method is natural merge. It takes advantage
834 *			of existing order or reverse order in the input list.
835 *			The worst case time complexity is n*log(n).
836 *			Space on the global stack is only needed for the
837 *			resulting list. The sort is stable, ie. if the input
838 *			list contains elements with the equal keys, their
839 *			order in the output list is the same as in the input
840 *			list. This is important if we want to (key)sort a list
841 *			according to multiple keys.
842 */
843
844#define ASCENDING	1
845#define DESCENDING	(-1)
846
847#define Set_Ordering_Options(d) {\
848	char *os = DidName(d);\
849	if (os[0] == '@') {\
850	    ++os; number_sort = FALSE;\
851	} else if (os[0] == '$') {\
852	    ++os; number_sort = TRUE;\
853	} else {\
854	    number_sort = FALSE;\
855	}\
856	if (os[0]=='=' && os[1]=='<' && os[2]==0) {\
857	    reverse = FALSE; keep_duplicates = TRUE;\
858	} else if (os[0]=='<' && os[1]==0) {\
859	    reverse = FALSE; keep_duplicates = FALSE;\
860	} else if (os[0]=='>') {\
861	    reverse = TRUE;\
862	    if (os[1]=='=' && os[2]==0)\
863		keep_duplicates = TRUE;\
864	    else if (os[1]==0)\
865		keep_duplicates = FALSE;\
866	    else { Bip_Error(RANGE_ERROR) }\
867	} else {\
868	    Bip_Error(RANGE_ERROR)\
869	}\
870    }
871
872static int
873p_sort4(value vk, type tk, value vo, type to, value v1, type t1, value v2, type t2)
874{
875    pword 	*list;
876    int		err, reverse, keep_duplicates, number_sort;
877
878    Check_Output_List(t2);	/* type checks	*/
879    Check_List(t1);
880    Check_Atom(to);
881
882    if(IsInteger(tk) && vk.nint < 0)	/* range checks	*/
883    {
884	Bip_Error(RANGE_ERROR)
885    }
886    Set_Ordering_Options(vo.did);
887
888    if(IsNil(t1))		/* empty list -> return []	*/
889    {
890	Return_Unify_Nil(v2, t2)
891    }
892    list = ec_keysort(v1, vk, tk, reverse, keep_duplicates, number_sort, &err);
893    if (!list) {
894	Bip_Error(err)
895    } else {
896	Return_Unify_List(v2, t2, list);
897    }
898}
899
900
901/*
902 * FUNCTION NAME:       p_number_sort4()
903 *
904 * PARAMETERS:          vk,tk	sorting key, if 0 the whole term is the key
905 *			vo,to	one of the atoms <,=<,>,>=
906 *			v1,t1	a list or nil (the input list)
907 *			v2,t2	list, nil or variable (the sorted list)
908 *
909 * DESCRIPTION:         sort(+Key, +Order, +Random, ?Sorted)
910 *			The sorting method is natural merge. It takes advantage
911 *			of existing order or reverse order in the input list.
912 *			The worst case time complexity is n*log(n).
913 *			Space on the global stack is only needed for the
914 *			resulting list. The sort is stable, ie. if the input
915 *			list contains elements with the equal keys, their
916 *			order in the output list is the same as in the input
917 *			list. This is important if we want to (key)sort a list
918 *			according to multiple keys.
919 */
920
921static int
922p_number_sort4(value vk, type tk, value vo, type to, value v1, type t1, value v2, type t2)
923{
924    register pword 	*list;
925    register int	reverse, keep_duplicates;
926    int			err;
927
928    Check_Output_List(t2);	/* type checks	*/
929    Check_List(t1);
930    Check_Atom(to);
931
932    if(IsInteger(tk) && vk.nint < 0)	/* range checks	*/
933    {
934	Bip_Error(RANGE_ERROR)
935    }
936
937    if(vo.did == d_.inf0) {
938	reverse = FALSE;
939	keep_duplicates = FALSE;
940    } else if(vo.did == d_.infq0) {
941	reverse = FALSE;
942	keep_duplicates = TRUE;
943    } else if(vo.did == d_.sup0) {
944	reverse = TRUE;
945	keep_duplicates = FALSE;
946    } else if(vo.did == d_.supq0) {
947	reverse = TRUE;
948	keep_duplicates = TRUE;
949    } else {
950	Bip_Error(RANGE_ERROR)
951    }
952
953    if(IsNil(t1))		/* empty list -> return []	*/
954    {
955	Return_Unify_Nil(v2, t2)
956    }
957    list = ec_keysort(v1, vk, tk, reverse, keep_duplicates, TRUE, &err);
958    if (!list) {
959	Bip_Error(err)
960    } else {
961	Return_Unify_List(v2, t2, list);
962    }
963}
964
965
966/*
967 * array_sort(+Key, +Order, +RandomArray, -SortedArray)
968 *
969 * This is equivalent to
970 * 	array_list(RandomArray, RandomList),
971 *	sort(Key, Order, RandomList, SortedList),
972 * 	array_list(SortedArray, SortedList).
973 * but doesn't not leave any garbage behind.
974 */
975
976static int
977p_array_sort(value vk, type tk, value vo, type to, value v1, type t1, value v2, type t2)
978{
979    pword 	*arr;
980    pword 	*list;
981    pword 	*start_tg;
982    value	vlist;
983    int		err, reverse, keep_duplicates, number_sort;
984    word	arity, i;
985
986    Check_Array_Or_Nil(v1, t1, &arity);
987    Check_Atom(to);
988
989    if(IsInteger(tk) && vk.nint < 0)	/* range checks	*/
990    {
991	Bip_Error(RANGE_ERROR)
992    }
993    Set_Ordering_Options(vo.did);
994
995    if(IsNil(t1) || ArraySize(v1) < 2)
996    {
997    	Return_Unify_Pw(v2, t2, v1, t1);	/* nothing to sort */
998    }
999
1000    /* convert array to auxiliary list */
1001    vlist.ptr = list = start_tg = TG;
1002    TG += 2*arity;
1003    Check_Gc;
1004    for(i=1; i<arity; ++i,list+=2)
1005    {
1006	*list = v1.ptr[i];
1007	Make_List(list+1, list+2);
1008    }
1009    *list = v1.ptr[i];
1010    Make_Nil(list+1);
1011    list = ec_keysort(vlist, vk, tk, reverse, keep_duplicates, number_sort, &err);
1012    if (!list) {
1013	TG = start_tg;
1014	Bip_Error(err)
1015    }
1016
1017    /* Convert sorted list back to an array.
1018     * CAUTION: we assume that ec_keysort has copied the input list and not
1019     * created anything on the global stack except the result list!  We
1020     * overwrite the input list with the sorted array and pop everything else.
1021     */
1022    arr = vlist.ptr;	/* overwrite */
1023    for(i=1;;i++)
1024    {
1025	arr[i] = *list++;
1026	if (IsNil(list->tag))
1027	    break;
1028	list = list->val.ptr;
1029    }
1030    TG = arr + i+1;		/* adjust for actual result size */
1031    Make_Atom(arr, add_dict(d_.nil, i));
1032    Return_Unify_Structure(v2, t2, arr);
1033}
1034
1035
1036/*
1037 * Return a dereferenced pointer to argument k (whole term if 0)
1038 * of term pw.  On error, return NULL and error code in *perr.
1039 */
1040static inline pword *
1041_get_key(pword *pw, value vk, type tk, int *perr)
1042{
1043    Dereference_(pw);
1044    if (!IsInteger(tk) || vk.nint != 0)
1045    {
1046	pword *ec_chase_arg(value vn, type tn, value vt, type tt, int *perr);
1047
1048	if (pw = ec_chase_arg(vk, tk, pw->val, pw->tag, perr))
1049	{
1050	    Dereference_(pw);
1051	}
1052    }
1053    return pw;
1054}
1055
1056
1057pword *
1058ec_keysort(value v1, value vk, type tk, int reverse, int keep_duplicates, int number_sort, int *err)
1059{
1060    register pword 	*h1, *h2, *comp_ptr, *append;
1061    pword 		*key_ptr1, *key_ptr2, *old_tg, *next_append;
1062    pword		list1, list2;
1063    int         	comp, sequence;
1064
1065    if (number_sort)
1066    	number_sort = keep_duplicates ? BILeGe : BINe;
1067
1068    old_tg = Gbl_Tg;		/* to reset TG on errors	*/
1069
1070    /*
1071     * We first split the list (v1, t1) into two lists list1 and list2.
1072     * The list cells are copied, the elements and tails of the
1073     * copied lists are dereferenced.
1074     */
1075
1076    h1 = v1.ptr;
1077    append = &list1;
1078    next_append = &list2;
1079    h2 = Gbl_Tg;
1080    Gbl_Tg +=2;
1081    Check_Gc;
1082    comp_ptr = h1;
1083    Dereference_(comp_ptr);
1084    if (!(key_ptr1 = _get_key(comp_ptr, vk, tk, err)))
1085    {
1086	TG = old_tg;
1087	return 0;
1088    }
1089    if (number_sort && !IsNumber(key_ptr1->tag))
1090    {
1091        TG = old_tg;
1092	*err = IsRef(key_ptr1->tag) ? INSTANTIATION_FAULT : TYPE_ERROR;
1093	return 0;
1094    }
1095    *h2 = *comp_ptr;
1096    sequence = 0;
1097    h1++;
1098    Dereference_(h1);
1099    while(! IsRef(h1->tag) && IsList(h1->tag))
1100    {
1101	h1 = h1->val.ptr;
1102	comp_ptr = h1;
1103	Dereference_(comp_ptr);
1104	if (!(key_ptr2 = _get_key(comp_ptr, vk, tk, err)))
1105	{
1106	    TG = old_tg;
1107	    return 0;
1108	}
1109	if (number_sort)
1110	{
1111	    if (!IsNumber(key_ptr2->tag))
1112	    {
1113	        TG = old_tg;
1114		*err = IsRef(key_ptr2->tag) ? INSTANTIATION_FAULT : TYPE_ERROR;
1115		return 0;
1116	    }
1117	    comp = number_sort;	/* input for breal comparison */
1118	    int res = arith_compare(key_ptr1->val, key_ptr1->tag,
1119				 key_ptr2->val, key_ptr2->tag, &comp);
1120	    if (res != PSUCCEED)
1121	    {
1122		Gbl_Tg = old_tg;
1123		*err = ARITH_EXCEPTION;
1124		return 0;
1125	    }
1126	} else {
1127	    comp = ec_compare_terms(key_ptr1->val, key_ptr1->tag,
1128				 key_ptr2->val, key_ptr2->tag);
1129	}
1130	key_ptr1 = key_ptr2;
1131	if(reverse)
1132	    comp = -comp;
1133	/*
1134	 * To make the sort stable, we must treat elements with equal keys
1135	 * as an ascending sequence.
1136	 */
1137	if(comp || keep_duplicates)
1138	{
1139	    Gbl_Tg += 2;
1140	    Check_Gc;
1141	    *(Gbl_Tg - 2) = *comp_ptr;
1142	    if(! sequence)
1143		if(comp <= 0)
1144		    sequence = ASCENDING;
1145		else
1146		    sequence = DESCENDING;
1147	    else if((comp > 0) &&  (sequence == ASCENDING))
1148	    {
1149		/* end of ascending sequence */
1150		append->tag.kernel = TLIST | MARK;
1151		append->val.ptr = h2;
1152		while(h2 < (Gbl_Tg - 4))
1153		{
1154		    h2 += 2;
1155		    (h2-1)->tag.kernel = TLIST;
1156		    (h2-1)->val.ptr = h2;
1157		}
1158		append = next_append;
1159		next_append = h2 + 1;
1160		h2 = Gbl_Tg - 2;
1161		sequence = 0;
1162	    }
1163	    else if ((comp <= 0) && (sequence == DESCENDING))
1164	    {
1165		/* end of descending sequence */
1166		append->tag.kernel = TLIST | MARK;
1167		append->val.ptr = (Gbl_Tg - 4);
1168		comp_ptr = Gbl_Tg - 3;
1169		while(comp_ptr > h2 + 2)
1170		{
1171		    comp_ptr->tag.kernel = TLIST;
1172		    comp_ptr->val.ptr = comp_ptr - 3;
1173		    comp_ptr -= 2;
1174		}
1175		append = next_append;
1176		next_append = comp_ptr;
1177		h2 = Gbl_Tg - 2;
1178		sequence = 0;
1179	    }
1180	}
1181	h1++;
1182	Dereference_(h1);
1183    }  	/* while(! IsRef(h1->tag) && IsList(h1->tag)) */
1184
1185    if(IsRef(h1->tag))
1186    {
1187	Gbl_Tg = old_tg;
1188	*err = INSTANTIATION_FAULT;
1189	return 0;
1190    }
1191    else if(! IsNil(h1->tag))
1192    {
1193	Gbl_Tg = old_tg;
1194	*err = TYPE_ERROR;
1195	return 0;
1196    }
1197    if(sequence != DESCENDING)
1198    {
1199	append->tag.kernel = TLIST | MARK;
1200	append->val.ptr = h2;
1201	while(h2 < (Gbl_Tg - 2))
1202	{
1203	    h2 += 2;
1204	    (h2-1)->tag.kernel = TLIST;
1205	    (h2-1)->val.ptr = h2;
1206	}
1207	(Gbl_Tg - 1)->tag.kernel = TNIL;
1208	append = (Gbl_Tg - 1);
1209	next_append->tag.kernel = TNIL;
1210    }
1211    else
1212    {
1213	append->tag.kernel = TLIST | MARK;
1214	append->val.ptr = (Gbl_Tg - 2);
1215	comp_ptr = Gbl_Tg - 1;
1216	while(comp_ptr > h2 + 2)
1217	{
1218		comp_ptr->tag.kernel = TLIST;
1219		comp_ptr->val.ptr = comp_ptr - 3;
1220		comp_ptr -=2;
1221	}
1222	comp_ptr->tag.kernel = TNIL;
1223	append = comp_ptr;
1224	next_append->tag.kernel = TNIL;
1225    }
1226    if(IsNil(list2.tag))
1227    	return list1.val.ptr;
1228
1229    Set_Bit(MARK, append);
1230    Set_Bit(MARK, next_append);
1231
1232    /*
1233     * Start merging:
1234     * We have two non-empty list in list1 and list2. They consist of
1235     * ascending sequences. The end of every sequence is MARKed.
1236     * list2 has the same number of sequences as list1 or one less.
1237     */
1238    do
1239    {
1240	append = &list1;
1241	next_append = &list2;
1242	h1 = list1.val.ptr;
1243	h2 = list2.val.ptr;
1244
1245	do
1246	{   /* merge lists h1 and h2, appending the result at append */
1247	    for(;;)
1248	    {
1249		/* no need to check that key spec was OK for these terms */
1250		key_ptr1 = _get_key(h1, vk, tk, err);
1251		key_ptr2 = _get_key(h2, vk, tk, err);
1252		if (number_sort)
1253		{
1254		    comp = number_sort;
1255		    int res = arith_compare(key_ptr1->val, key_ptr1->tag,
1256					 key_ptr2->val, key_ptr2->tag, &comp);
1257		    if (res != PSUCCEED)
1258		    {
1259			Gbl_Tg = old_tg;
1260			*err = ARITH_EXCEPTION;
1261			return 0;
1262		    }
1263		} else {
1264		    comp = ec_compare_terms(key_ptr1->val, key_ptr1->tag,
1265					 key_ptr2->val, key_ptr2->tag);
1266		}
1267		if(reverse)
1268		    comp = -comp;
1269
1270		if (comp < 0 || ! comp && keep_duplicates)
1271		{
1272		    append->val.ptr = h1;	/* link element h1	*/
1273		    append = h1 + 1;
1274		    if (!Marked((h1+1)->tag))
1275		    {
1276			h1 = (h1+1)->val.ptr;
1277			continue;
1278		    }
1279		    /* end of sequence 1	*/
1280		    h1 = IsList((h1+1)->tag) ? (h1+1)->val.ptr : (pword *) 0;
1281		    append->tag.kernel = TLIST;	/* and reset mark	*/
1282		    append->val.ptr = h2;
1283		    while (!Marked((h2+1)->tag))
1284			h2 = (h2+1)->val.ptr;
1285		    append = h2 + 1;
1286		    h2 =  IsList(append->tag) ? append->val.ptr : (pword *) 0;
1287		}
1288		else if (comp > 0)
1289		{
1290		    append->val.ptr = h2;	/* link element h2	*/
1291		    append = h2 + 1;
1292		    if (!Marked((h2+1)->tag))
1293		    {
1294			h2 = (h2+1)->val.ptr;
1295			continue;
1296		    }
1297		    /* end of sequence 2	*/
1298		    h2 = IsList((h2+1)->tag) ? (h2+1)->val.ptr : (pword *) 0;
1299		    append->tag.kernel = TLIST;	/* and reset mark	*/
1300		    append->val.ptr = h1;
1301		    while (!Marked((h1+1)->tag))
1302			h1 = (h1+1)->val.ptr;
1303		    append = h1 + 1;
1304		    h1 =  IsList(append->tag) ? append->val.ptr : (pword *) 0;
1305		}
1306		else /* comp == 0 && !keep_duplicates */
1307		{
1308		    if (!Marked((h2+1)->tag))	/* skip element h2	*/
1309		    {
1310			h2 = (h2+1)->val.ptr;
1311			continue;
1312		    }
1313		    Clr_Bit(MARK, h2+1);
1314		    /* end of sequence 2	*/
1315		    h2 = IsList((h2+1)->tag) ? (h2+1)->val.ptr : (pword *) 0;
1316		    append->val.ptr = h1;
1317		    while (!Marked((h1+1)->tag))
1318			h1 = (h1+1)->val.ptr;
1319		    append = h1 + 1;
1320		    h1 =  IsList(append->tag) ? append->val.ptr : (pword *) 0;
1321		}
1322		break;
1323	    } /* for(;;) */
1324
1325	    comp_ptr = append;
1326	    append = next_append;
1327	    next_append = comp_ptr;
1328	} while (h1 && h2);
1329
1330	if (h1 /* && !h2 */)	/* a single sequence is left	*/
1331	{
1332	    append->tag.kernel = MARK|TLIST;
1333	    append->val.ptr = h1;
1334	    while (!Marked((h1+1)->tag))
1335		h1 = (h1+1)->val.ptr;
1336	    append = next_append;
1337	    next_append = h1 + 1;
1338	}
1339	append->tag.kernel = MARK|TNIL;
1340
1341    } while (append != &list2);
1342
1343    Clr_Bit(MARK, next_append);	/* no MARK bits may be left behind !	*/
1344
1345#ifdef DEBUG_SORT
1346
1347    /* check if the list is really sorted */
1348
1349    h1 = list1.val.ptr;
1350    h2 = h1 + 1;
1351
1352    while(IsList(h2->tag))
1353    {
1354	h2 = h2->val.ptr;
1355	/* no need to check that key spec was OK for these terms */
1356	key_ptr1 = _get_key(h1, vk, tk, err);
1357	key_ptr2 = _get_key(h2, vk, tk, err);
1358	comp = ec_compare_terms(key_ptr1->val, key_ptr1->tag,
1359				    key_ptr2->val, key_ptr2->tag);
1360	if(reverse)
1361	    comp = -comp;
1362	if (comp > 0)
1363	{
1364	    p_fprintf(current_err_,"INTERNAL ERROR 1 in sort/4\n");
1365	    ec_flush(current_err_);
1366	}
1367	else if (comp == 0 && !keep_duplicates)
1368	{
1369	    p_fprintf(current_err_,"INTERNAL ERROR 2 in sort/4\n");
1370	    ec_flush(current_err_);
1371	}
1372	h1 = h2;
1373	h2 = h1 + 1;
1374    }
1375    if(!IsNil(h2->tag))
1376    {
1377	p_fprintf(current_err_,"INTERNAL ERROR 3 in sort/4\n");
1378	ec_flush(current_err_);
1379    }
1380
1381    /* check if there are no mark bits left */
1382
1383    for(h1 = old_tg; h1 < Gbl_Tg; h1++)
1384	if (Marked(h1->tag))
1385	{
1386	    p_fprintf(current_err_,"INTERNAL ERROR 4 in sort/4\n");
1387	    ec_flush(current_err_);
1388	}
1389
1390#endif /* DEBUG_SORT */
1391
1392    return list1.val.ptr;
1393}
1394
1395
1396/*
1397 * FUNCTION NAME:       p_merge5()
1398 *			p_number_merge5()
1399 *
1400 * PARAMETERS:          vk,tk	sorting key, if 0 the whole term is the key
1401 *			vo,to	one of the atoms <,=<,>,>=
1402 *			v1,t1	a list or nil (input list)
1403 *			v2,t2	a list or nil (input list)
1404 *			v,t	list, nil or variable (the merged list)
1405 *
1406 * DESCRIPTION:         merge(+Key, +Order, +List1, +List2, ?Merged)
1407 *			Merge two sorted lists. The input lists need
1408 *			to be already sorted according to the specified
1409 *			ordering, otherwise the result is undefined.
1410 *			When keys are identical, their original order within
1411 *			List1 or List2 should be preserved in Merged, and
1412 *			List1's elements should come before List2's elements.
1413 */
1414
1415static int
1416_merge(value vk, type tk,
1417	value v1, type t1, value v2, type t2, value v, type t,
1418	int reverse, int keep_duplicates, int number_sort)
1419{
1420    pword 	*old_tg = TG;
1421    pword 	*h1, *h2, *key_ptr1, *key_ptr2, *append;
1422    pword 	result;
1423    int		comp, err;
1424
1425    Check_Output_List(t);	/* type checks	*/
1426    Check_List(t1);
1427    Check_List(t2);
1428
1429    if(IsInteger(tk) && vk.nint < 0)	/* range checks	*/
1430    {
1431	Bip_Error(RANGE_ERROR)
1432    }
1433
1434    if (IsNil(t1))
1435    {
1436    	Return_Unify_Pw(v2, t2, v, t);
1437    }
1438    else if (IsNil(t2))
1439    {
1440    	Return_Unify_Pw(v1, t1, v, t);
1441    }
1442
1443    append = &result;
1444    h1 = v1.ptr;
1445    h2 = v2.ptr;
1446    if (!(key_ptr1 = _get_key(h1, vk, tk, &err))
1447     || !(key_ptr2 = _get_key(h2, vk, tk, &err)))
1448    {
1449	goto _merge_error_;
1450    }
1451
1452    if (number_sort)
1453    	number_sort = keep_duplicates ? BILeGe : BINe;
1454
1455    for(;;)	/* (h1, key_ptr1, h2, key_ptr2) */
1456    {
1457	if (number_sort)
1458	{
1459	    /* some of these type tests are redundant */
1460	    if (!IsNumber(key_ptr1->tag) || !IsNumber(key_ptr2->tag))
1461	    {
1462		err = IsRef(key_ptr1->tag) ? INSTANTIATION_FAULT : IsRef(key_ptr2->tag) ? INSTANTIATION_FAULT : TYPE_ERROR;
1463		goto _merge_error_;
1464	    }
1465	    comp = number_sort;
1466	    err = arith_compare(key_ptr1->val, key_ptr1->tag,
1467				key_ptr2->val, key_ptr2->tag, &comp);
1468	    if(err != PSUCCEED)
1469	    {
1470	        err = ARITH_EXCEPTION;
1471		goto _merge_error_;
1472	    }
1473	}
1474	else
1475	{
1476	    comp = ec_compare_terms(key_ptr1->val, key_ptr1->tag,
1477				key_ptr2->val, key_ptr2->tag);
1478	}
1479	if(reverse)
1480	    comp = -comp;
1481
1482	if (comp < 0 || ! comp && keep_duplicates)
1483	{
1484	    Make_List(append, TG);
1485	    append = TG;
1486	    Push_List_Frame();
1487	    *append++ = *h1++;		/* copy element h1 */
1488	    Dereference_(h1);
1489	    if (!IsList(h1->tag))
1490	    {
1491		if (IsNil(h1->tag))
1492		{
1493		    Make_List(append, h2);
1494		    break;
1495		}
1496		err = IsRef(h1->tag) ? INSTANTIATION_FAULT : TYPE_ERROR;
1497		goto _merge_error_;
1498	    }
1499	    h1 = h1->val.ptr;
1500	    if (!(key_ptr1 = _get_key(h1, vk, tk, &err)))
1501		goto _merge_error_;
1502	}
1503	else if (comp > 0)
1504	{
1505	    Make_List(append, TG);
1506	    append = TG;
1507	    Push_List_Frame();
1508	    *append++ = *h2++;		/* copy element h2 */
1509	    Dereference_(h2);
1510	    if (!IsList(h2->tag))
1511	    {
1512		if (IsNil(h2->tag))
1513		{
1514		    Make_List(append, h1);
1515		    break;
1516		}
1517		err = IsRef(h2->tag) ? INSTANTIATION_FAULT : TYPE_ERROR;
1518		goto _merge_error_;
1519	    }
1520	    h2 = h2->val.ptr;
1521	    if (!(key_ptr2 = _get_key(h2, vk, tk, &err)))
1522		goto _merge_error_;
1523	}
1524	else /* comp == 0 && !keep_duplicates */
1525	{
1526	    Make_List(append, TG);
1527	    append = TG;
1528	    Push_List_Frame();
1529	    *append++ = *h1++;		/* copy element h1 */
1530	    Dereference_(h1);
1531	    h2++;			/* skip element h2 */
1532	    Dereference_(h2);
1533	    if (!IsList(h1->tag))
1534	    {
1535		if (IsNil(h1->tag))
1536		{
1537		    *append = *h2;
1538		    break;
1539		}
1540		err = IsRef(h1->tag) ? INSTANTIATION_FAULT : TYPE_ERROR;
1541		goto _merge_error_;
1542	    }
1543	    if (!IsList(h2->tag))
1544	    {
1545		if (IsNil(h2->tag))
1546		{
1547		    *append = *h1;
1548		    break;
1549		}
1550		err = IsRef(h2->tag) ? INSTANTIATION_FAULT : TYPE_ERROR;
1551		goto _merge_error_;
1552	    }
1553	    h1 = h1->val.ptr;		/* both tails are lists */
1554	    h2 = h2->val.ptr;
1555	    if (!(key_ptr1 = _get_key(h1, vk, tk, &err))
1556	     || !(key_ptr2 = _get_key(h2, vk, tk, &err)))
1557	    {
1558		goto _merge_error_;
1559	    }
1560	}
1561    } /* for(;;) */
1562
1563    Return_Unify_Pw(result.val, result.tag, v, t);
1564
1565_merge_error_:		/* (err,old_tg) */
1566    TG = old_tg;
1567    Bip_Error(err);
1568}
1569
1570
1571static int
1572p_merge5(value vk, type tk, value vo, type to, value v1, type t1, value v2, type t2, value v, type t)
1573{
1574    int	reverse, keep_duplicates, number_sort;
1575    Set_Ordering_Options(vo.did);
1576    return _merge(vk, tk, v1, t1, v2, t2, v, t, reverse, keep_duplicates, number_sort);
1577}
1578
1579
1580static int
1581p_number_merge5(value vk, type tk, value vo, type to, value v1, type t1, value v2, type t2, value v, type t)
1582{
1583    int	reverse, keep_duplicates;
1584    Check_Atom(to);
1585    if(vo.did == d_.inf0) {
1586	reverse = FALSE;
1587	keep_duplicates = FALSE;
1588    } else if(vo.did == d_.infq0) {
1589	reverse = FALSE;
1590	keep_duplicates = TRUE;
1591    } else if(vo.did == d_.sup0) {
1592	reverse = TRUE;
1593	keep_duplicates = FALSE;
1594    } else if(vo.did == d_.supq0) {
1595	reverse = TRUE;
1596	keep_duplicates = TRUE;
1597    } else {
1598	Bip_Error(RANGE_ERROR)
1599    }
1600    return _merge(vk, tk, v1, t1, v2, t2, v, t, reverse, keep_duplicates, TRUE);
1601}
1602
1603