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