C:/Users/Dennis/src/lang/Life_start/Life/life-1.02/source/built_in.c

Go to the documentation of this file.
00001 /* Copyright 1991 Digital Equipment Corporation.
00002 ** All Rights Reserved.
00003 *****************************************************************/
00004 /*      $Id: built_ins.c,v 1.14 1995/07/27 21:26:28 duchier Exp $        */
00005 
00006 #ifndef lint
00007 static char vcid[] = "$Id: built_ins.c,v 1.14 1995/07/27 21:26:28 duchier Exp $";
00008 #endif /* lint */
00009 #ifdef OS2_PORT_2
00010 #include <direct.h>
00011 #endif
00012 #include "extern.h"
00013 #include "trees.h"
00014 #include "login.h"
00015 #include "types.h"
00016 #include "parser.h"
00017 #include "copy.h"
00018 #include "token.h"
00019 #include "print.h"
00020 #include "lefun.h"
00021 #include "memory.h"
00022 #ifndef OS2_PORT
00023 #include "built_ins.h"
00024 #else
00025 #include "built_in.h"
00026 #endif
00027 #include "error.h" 
00028 #include "modules.h"  /*  RM: Jan  8 1993  */
00029 
00030 #ifdef X11
00031 #include "xpred.h"
00032 #endif
00033 
00034 #ifdef SOLARIS
00035 #include <stdlib.h>
00036 static unsigned int randomseed;
00037 #endif
00038 
00039 
00040 long (* c_rule[MAX_BUILT_INS])();
00041 
00042 ptr_definition abortsym; /* 26.1 */
00043 ptr_definition aborthooksym; /* 26.1 */
00044 
00045 ptr_definition add_module1;  /*  RM: Mar 12 1993  */
00046 ptr_definition add_module2;
00047 ptr_definition add_module3;
00048 
00049 ptr_definition and;
00050 ptr_definition apply;
00051 ptr_definition boolean;
00052 ptr_definition boolpredsym;
00053 ptr_definition built_in;
00054 ptr_definition calloncesym;
00055 ptr_definition colonsym;
00056 ptr_definition commasym;
00057 ptr_definition comment;
00058 /* ptr_definition conjunction; 19.8 */
00059 ptr_definition constant;
00060 ptr_definition cut;
00061 ptr_definition disjunction;
00062 ptr_definition disj_nil;/*  RM: Feb  1 1993  */
00063 ptr_definition eof;
00064 ptr_definition eqsym;
00065 ptr_definition leftarrowsym;
00066 ptr_definition false;
00067 ptr_definition funcsym;
00068 ptr_definition functor;
00069 ptr_definition iff;
00070 ptr_definition integer;
00071 ptr_definition alist;
00072 ptr_definition life_or; /*  RM: Apr  6 1993  */
00073 ptr_definition minus_symbol; /*  RM: Jun 21 1993  */
00074 ptr_definition nil; /*** RM 9 Dec 1992 ***/
00075 ptr_definition nothing;
00076 ptr_definition predsym;
00077 ptr_definition quote;
00078 ptr_definition quoted_string;
00079 ptr_definition real;
00080 ptr_definition stream;
00081 ptr_definition succeed;
00082 ptr_definition such_that;
00083 ptr_definition top;
00084 ptr_definition true;
00085 ptr_definition timesym;
00086 ptr_definition tracesym; /* 26.1 */
00087 ptr_definition typesym;
00088 ptr_definition variable;
00089 ptr_definition opsym;
00090 ptr_definition loadsym;
00091 ptr_definition dynamicsym;
00092 ptr_definition staticsym;
00093 ptr_definition encodesym;
00094 ptr_definition listingsym;
00095 /* ptr_definition provesym; */
00096 ptr_definition delay_checksym;
00097 ptr_definition eval_argsym;
00098 ptr_definition inputfilesym;
00099 ptr_definition call_handlersym;
00100 ptr_definition xf_sym;
00101 ptr_definition fx_sym;
00102 ptr_definition yf_sym;
00103 ptr_definition fy_sym;
00104 ptr_definition xfx_sym;
00105 ptr_definition xfy_sym;
00106 ptr_definition yfx_sym;
00107 ptr_definition nullsym;
00108 
00109 
00110 /*  RM: Jul  7 1993  */
00111 ptr_definition final_dot;
00112 ptr_definition final_question;
00113 
00114 
00115 ptr_psi_term null_psi_term;
00116 
00117 char *one;
00118 char *two;
00119 char *three;
00120 char *year_attr;
00121 char *month_attr;
00122 char *day_attr;
00123 char *hour_attr;
00124 char *minute_attr;
00125 char *second_attr;
00126 char *weekday_attr;
00127 
00128 static long built_in_index=0;
00129 
00130 int all_public_symbols();  /* RM: Jan 28 1994  */
00131 
00132 /*  RM: Sep 20 1993  */
00133 int arg_c;
00134 char **arg_v;
00135 
00136 
00137 
00138 /***  RM: Dec  9 1992  (START) ***/
00139 
00140 /********* STACK_NIL
00141   Create the NIL object on the stack.
00142   */
00143 
00144 ptr_psi_term stack_nil()
00145 
00146 {
00147   ptr_psi_term empty;
00148 
00149   
00150   empty=stack_psi_term(4);
00151   empty->type=nil;
00152 
00153   return empty;
00154 }
00155 
00156 
00157 
00158 /******** STACK_CONS(head,tail)
00159   Create a CONS object.
00160   */
00161 
00162 ptr_psi_term stack_cons(head,tail)
00163      ptr_psi_term head;
00164      ptr_psi_term tail;
00165 {
00166   ptr_psi_term cons;
00167 
00168   cons=stack_psi_term(4);
00169   cons->type=alist;
00170   if(head)
00171     stack_insert(featcmp,one,&(cons->attr_list),head);
00172   if(tail)
00173     stack_insert(featcmp,two,&(cons->attr_list),tail);
00174 
00175   return cons;
00176 }
00177 
00178 /********* STACK_PAIR(left,right)
00179   create a PAIR object.
00180   */
00181 
00182 ptr_psi_term stack_pair(left,right)
00183      ptr_psi_term left;
00184      ptr_psi_term right;
00185 {
00186   ptr_psi_term pair;
00187 
00188   pair=stack_psi_term(4);
00189   pair->type=and;
00190   if(left)
00191     stack_insert(featcmp,one,&(pair->attr_list),left);
00192   if(right)
00193     stack_insert(featcmp,two,&(pair->attr_list),right);
00194 
00195   return pair;
00196 }
00197 
00198 /********* STACK_INT(n)
00199   create an INT object
00200   */
00201 
00202 ptr_psi_term stack_int(n)
00203      long n;
00204 {
00205   ptr_psi_term m;
00206   m=stack_psi_term(4);
00207   m->type=integer;
00208   m->value=heap_alloc(sizeof(REAL));
00209   *(REAL *)m->value=(REAL)n;
00210   return m;
00211 }
00212 
00213 /********* STACK_STRING(s)
00214   create a STRING object
00215   */
00216 
00217 ptr_psi_term stack_string(s)
00218      char *s;
00219 {
00220   ptr_psi_term t = stack_psi_term(4);
00221   t->type = quoted_string;
00222   t->value=(GENERIC)heap_copy_string(s);
00223   return t;
00224 }
00225 
00226 /***  RM: Dec  9 1992  (END) ***/
00227 
00228 /********* STACK_BYTES(s,n)
00229   create a STRING object given a sequence of bytes
00230   */
00231 
00232 ptr_psi_term stack_bytes(s,n)
00233      char *s;
00234      int n;
00235 {
00236   ptr_psi_term t = stack_psi_term(4);
00237   t->type = quoted_string;
00238   t->value=(GENERIC)heap_ncopy_string(s,n);
00239   return t;
00240 }
00241 
00242   
00243 
00244 /********* PSI_TO_STRING(t,fn)
00245   Get the value of a Life string, or the name of a non-string psi-term.
00246   Return TRUE iff a valid string is found.
00247 */
00248 long psi_to_string(t, fn)
00249 ptr_psi_term t;
00250 char **fn;
00251 {
00252   if (equal_types(t->type,quoted_string)) {
00253     if (t->value) {
00254       *fn = (char *) t->value;
00255       return TRUE;
00256     }
00257     else {
00258       *fn = quoted_string->keyword->symbol;
00259       return TRUE;
00260     }
00261   }
00262   else {
00263     *fn = t->type->keyword->symbol;
00264     return TRUE;
00265   }
00266 }
00267 
00268 
00269 /***  RM: Dec  9 1992  (START) ***/
00270 
00271 ptr_psi_term make_feature_list(tree,tail,module,val)
00272      
00273      ptr_node tree;
00274      ptr_psi_term tail;
00275      ptr_module module;
00276      int val;
00277      
00278 {
00279   ptr_psi_term new;
00280   ptr_definition def;
00281   double d, strtod();
00282   
00283   
00284   if(tree) {
00285     if(tree->right)
00286       tail=make_feature_list(tree->right,tail,module,val);
00287 
00288     /* Insert the feature name into the list */
00289     
00290     d=str_to_int(tree->key);
00291     if (d== -1) { /* Feature is not a number */
00292       def=update_feature(module,tree->key); /* Extract module RM: Feb 3 1993 */
00293       if(def) {
00294         if(val) /* RM: Mar  3 1994 Distinguish between features & values */
00295           tail=stack_cons(tree->data,tail);
00296         else {
00297           new=stack_psi_term(4);      
00298           new->type=def;
00299           tail=stack_cons(new,tail);
00300         }
00301       }
00302     }
00303     else { /* Feature is a number */
00304       if(val) /* RM: Mar  3 1994 Distinguish between features & values */
00305         tail=stack_cons(tree->data,tail);
00306       else {
00307         new=stack_psi_term(4);      
00308         new->type=(d==floor(d))?integer:real;
00309         new->value=heap_alloc(sizeof(REAL));
00310         *(REAL *)new->value=(REAL)d;
00311         tail=stack_cons(new,tail);
00312       }
00313     }
00314     
00315     if(tree->left)
00316       tail=make_feature_list(tree->left,tail,module,val);
00317   }
00318   
00319   return tail;
00320 }
00321 
00322 /***  RM: Dec  9 1992  (END) ***/
00323 
00324 
00325 
00326 
00327 
00328 
00329 /******** CHECK_REAL(t,v,n)
00330   Like get_real_value, but does not force the type of T to be real.
00331 */
00332 long check_real(t,v,n)
00333 ptr_psi_term t;
00334 REAL *v;
00335 long *n;
00336 {
00337   long success=FALSE;
00338   long smaller;
00339 
00340   if (t) {
00341     success=matches(t->type,real,&smaller);
00342     if (success) {
00343       *n=FALSE;
00344       if (smaller && t->value) {
00345         *v= *(REAL *)t->value;
00346         *n=TRUE;
00347       }
00348     }
00349   }
00350   return success;
00351 }
00352 
00353 
00354 
00355 /******** GET_REAL_VALUE(t,v,n)
00356   Check if psi_term T is a real number.  Return N=TRUE iff T <| REAL.
00357   If T has a real value then set V to that value.
00358   Also force the type of T to REAL if REAL <| T.
00359   This is used in all the arithmetic built-in functions to get their arguments.
00360 */
00361 long get_real_value(t,v,n)
00362 ptr_psi_term t;
00363 REAL *v;
00364 long *n;
00365 {
00366   long success=FALSE;
00367   long smaller;
00368   
00369   if (t) {
00370     success=matches(t->type,real,&smaller);
00371     if (success) {
00372       *n=FALSE;
00373       if (smaller) {
00374         if (t->value) {
00375           *v= *(REAL *)t->value;
00376           *n=TRUE;
00377         }
00378       }
00379       else {
00380         if((GENERIC)t<heap_pointer) { /*  RM: Jun  8 1993  */
00381           push_ptr_value(def_ptr,&(t->type));
00382           push_ptr_value(int_ptr,&(t->status));
00383           t->type=real;
00384           t->status=0;
00385           i_check_out(t);
00386         }
00387       }
00388     }
00389   }
00390   return success;
00391 }
00392 
00393 
00394 
00395 /******** GET_BOOL_VALUE(t,v,n)
00396   This is identical in nature to
00397   GET_REAL_VALUE. The values handled here have to be booleans.
00398   Check if psi_term T is a boolean. V <- TRUE or FALSE value of T.
00399 */
00400 static long get_bool_value(t,v,n)
00401 ptr_psi_term t;
00402 REAL *v;
00403 long *n;
00404 {
00405   long success=FALSE;
00406   long smaller;
00407   
00408   
00409   if(t) {
00410     success=matches(t->type,boolean,&smaller);
00411     if(success) {
00412       *n=FALSE;
00413       if(smaller) {
00414         if(matches(t->type,false,&smaller) && smaller) {
00415           *v= 0;
00416           *n=TRUE;
00417         }
00418         else
00419           if(matches(t->type,true,&smaller) && smaller) {
00420             *v= 1;
00421             *n=TRUE;
00422           }
00423       }
00424       else {
00425         if((GENERIC)t<heap_pointer) { /*  RM: Jun  8 1993  */
00426           push_ptr_value(def_ptr,&(t->type));
00427           push_ptr_value(int_ptr,&(t->status));
00428           t->type=boolean;
00429           t->status=0;
00430           i_check_out(t);
00431         }
00432       }      
00433     }
00434   }
00435   
00436   return success;
00437 }
00438 
00439 
00440 
00441 /******** UNIFY_BOOL_RESULT(t,v)
00442   Unify psi_term T to the boolean value V = TRUE or FALSE.
00443   This is used by built-in logical functions to return their result.
00444 */
00445 void unify_bool_result(t,v)
00446 ptr_psi_term t;
00447 long v;
00448 {
00449   ptr_psi_term u;
00450 
00451   u=stack_psi_term(4);
00452   u->type=v?true:false;
00453   push_goal(unify,t,u,NULL);
00454   
00455   /* Completely commented out by Richard on Nov 25th 1993
00456      What's *your* Birthday? Maybe you'd like a Birthday-Bug-Card!
00457      
00458   if((GENERIC)t<heap_pointer) {
00459     push_ptr_value(def_ptr,&(t->type));
00460     if (v) {
00461       t->type=true;
00462       t->status=0;
00463     }
00464     else {
00465       t->type=false;
00466       t->status=0;
00467     }
00468   
00469     i_check_out(t);
00470     if (t->resid)
00471       release_resid(t);
00472   }
00473   else {
00474     Warningline("the persistent term '%P' appears in a boolean constraint and cannot be refined\n",t);
00475     }
00476     */
00477 }
00478 
00479 
00480 
00481 
00482 /******** UNIFY_REAL_RESULT(t,v)
00483   Unify psi_term T to the real value V.
00484   This is used by built-in arithmetic functions to return their result.
00485 */
00486 long unify_real_result(t,v)
00487 ptr_psi_term t;
00488 REAL v;
00489 {
00490   long smaller;
00491   long success=TRUE;
00492 
00493 #ifdef prlDEBUG
00494   if (t->value) {
00495     printf("*** BUG: value already present in UNIFY_REAL_RESULT\n");
00496   }
00497 #endif
00498 
00499   if((GENERIC)t<heap_pointer) { /*  RM: Jun  8 1993  */
00500     deref_ptr(t);
00501     assert(t->value==NULL); /* 10.6 */
00502     push_ptr_value(int_ptr,&(t->value));
00503     t->value=heap_alloc(sizeof(REAL)); /* 12.5 */
00504     *(REAL *)t->value = v;
00505     
00506     matches(t->type,integer,&smaller);
00507     
00508     if (v==floor(v)){
00509       if (!smaller) {
00510         push_ptr_value(def_ptr,&(t->type));
00511         t->type=integer;
00512         t->status=0;
00513       }
00514     }
00515     else
00516       if (smaller)
00517         success=FALSE;
00518     
00519     if (success) {
00520       i_check_out(t);
00521       if (t->resid)
00522         release_resid(t);
00523     }
00524   }
00525   else {
00526     Warningline("the persistent term '%P' appears in an arithmetic constraint and cannot be refined\n",t);
00527   }
00528   
00529   return success;
00530 }
00531 
00532 
00533 
00534 /******** C_GT
00535   Greater than.
00536 */
00537 static long c_gt()
00538 {
00539   long success=TRUE;
00540   ptr_psi_term arg1,arg2,arg3,t;
00541   long num1,num2,num3;
00542   REAL val1,val2,val3;
00543   
00544   t=aim->a;
00545   deref_ptr(t);
00546   get_two_args(t->attr_list,&arg1,&arg2);
00547   arg3=aim->b;
00548   
00549   if (arg1) {
00550     deref(arg1);
00551     success=get_real_value(arg1,&val1,&num1);
00552     if(success && arg2) {
00553       deref(arg2);
00554       deref_args(t,set_1_2);
00555       success=get_real_value(arg2,&val2,&num2);
00556     }
00557   }
00558   
00559   if(success)
00560     if(arg1 && arg2) {
00561       deref(arg3);
00562       success=get_bool_value(arg3,&val3,&num3);
00563       if(success)
00564         switch(num1+num2*2+num3*4) {
00565         case 0:
00566           residuate2(arg1,arg2);
00567           break;
00568         case 1:
00569           residuate(arg2);
00570           break;
00571         case 2:
00572           residuate(arg1);
00573           break;
00574         case 3:
00575           unify_bool_result(arg3,(val1>val2));
00576           break;
00577         case 4:
00578           residuate2(arg1,arg2);
00579           break;
00580         case 5:
00581           residuate(arg2);
00582           break;
00583         case 6:
00584           residuate(arg1);
00585           break;
00586         case 7:
00587           success=(val3==(REAL)(val1>val2));
00588           break;
00589         } 
00590     }
00591     else
00592       curry();
00593   
00594   nonnum_warning(t,arg1,arg2);
00595   return success;
00596 }
00597 
00598 
00599 
00600 /******** C_EQUAL
00601   Arithmetic equality.
00602 */
00603 static long c_equal()
00604 {
00605   long success=TRUE;
00606   ptr_psi_term arg1,arg2,arg3,t;
00607   long num1,num2,num3;
00608   REAL val1,val2,val3;
00609   
00610   t=aim->a;
00611   deref_ptr(t);
00612   get_two_args(t->attr_list,&arg1,&arg2);
00613   arg3=aim->b;
00614   
00615   if(arg1) {
00616     deref(arg1);
00617     success=get_real_value(arg1,&val1,&num1);
00618     if(success && arg2) {
00619       deref(arg2);
00620       deref_args(t,set_1_2);
00621       success=get_real_value(arg2,&val2,&num2);
00622     }
00623   }
00624   
00625   if(success)
00626     if(arg1 && arg2) {
00627       deref(arg3);
00628       success=get_bool_value(arg3,&val3,&num3);
00629       if(success)
00630         switch(num1+2*num2+4*num3) {
00631         case 0:
00632           if(arg1==arg2)
00633             unify_bool_result(arg3,TRUE);
00634           else
00635             residuate2(arg1,arg2);
00636           break;
00637         case 1:
00638           residuate2(arg2,arg3);
00639           break;
00640         case 2:
00641           residuate2(arg1,arg3);
00642           break;
00643         case 3:
00644           unify_bool_result(arg3,(val1==val2));
00645           break;
00646         case 4:
00647           if(arg1==arg2 && !val3)
00648             success=FALSE;
00649           else
00650             residuate2(arg1,arg2);
00651           break;
00652         case 5:
00653           if(!val3)
00654             residuate(arg2);
00655           else
00656             success=unify_real_result(arg2,val1);
00657           break;
00658         case 6:
00659           if(!val3)
00660             residuate(arg1);
00661           else
00662             success=unify_real_result(arg1,val2);
00663           break;
00664         case 7:
00665           success=(val3==(REAL)(val1==val2));
00666           break;
00667         }
00668     }
00669     else
00670       curry();
00671   
00672   nonnum_warning(t,arg1,arg2);
00673   return success;
00674 }
00675 
00676 
00677 
00678 /*** RM: 9 Dec 1992 (START) ***/
00679 
00680 /******** C_EVAL_DISJUNCTION
00681   Evaluate a disjunction.
00682   */
00683 
00684 static long c_eval_disjunction()
00685      
00686 {
00687   ptr_psi_term arg1,arg2,funct,result;
00688 
00689   
00690   funct=aim->a;
00691   deref_ptr(funct);
00692   result=aim->b;
00693   get_two_args(funct->attr_list,&arg1,&arg2);
00694 
00695   /* deref_args(funct,set_1_2); Don't know about this */
00696   
00697   if (arg1 && arg2) {
00698     deref_ptr(arg1);
00699     deref_ptr(arg2);
00700 
00701     resid_aim=NULL; /* Function evaluation is over */
00702 
00703     if(arg2->type!=disj_nil) /*  RM: Feb  1 1993  */
00704       /* Create the alternative */
00705       push_choice_point(eval,arg2,result,funct->type->rule);
00706     
00707     /* Unify the result with the first argument */
00708     push_goal(unify,result,arg1,NULL);
00709     i_check_out(arg1);
00710   }
00711   else {
00712     Errorline("malformed disjunction '%P'\n",funct);
00713     return (c_abort());
00714   }
00715   
00716   return TRUE;
00717 }
00718 
00719 /*** RM: 9 Dec 1992 (END) ***/
00720 
00721   
00722 
00723 
00724   
00725 /******** C_LT
00726   Less than.
00727 */
00728 static long c_lt()
00729 {
00730   long success=TRUE;
00731   ptr_psi_term arg1,arg2,arg3,t;
00732   long num1,num2,num3;
00733   REAL val1,val2,val3;
00734   
00735   t=aim->a;
00736   deref_ptr(t);
00737   get_two_args(t->attr_list,&arg1,&arg2);
00738   arg3=aim->b;
00739   
00740   if(arg1) {
00741     deref(arg1);
00742     success=get_real_value(arg1,&val1,&num1);
00743     if(success && arg2) {
00744       deref(arg2);
00745       deref_args(t,set_1_2);
00746       success=get_real_value(arg2,&val2,&num2);
00747     }
00748   }
00749   
00750   if(success)
00751     if(arg1 && arg2) {
00752       deref(arg3);
00753       success=get_bool_value(arg3,&val3,&num3);
00754       if(success)
00755         switch(num1+num2*2+num3*4) {
00756         case 0:
00757           residuate2(arg1,arg2);
00758           break;
00759         case 1:
00760           residuate(arg2);
00761           break;
00762         case 2:
00763           residuate(arg1);
00764           break;
00765         case 3:
00766           unify_bool_result(arg3,(val1<val2));
00767           break;
00768         case 4:
00769           residuate2(arg1,arg2);
00770           break;
00771         case 5:
00772           residuate(arg2);
00773           break;
00774         case 6:
00775           residuate(arg1);
00776           break;
00777         case 7:
00778           success=(val3==(REAL)(val1<val2));
00779           break;
00780         }
00781     }
00782     else
00783       curry();
00784   
00785   nonnum_warning(t,arg1,arg2);
00786   return success;
00787 }
00788 
00789 
00790 
00791 
00792 /******** C_GTOE
00793   Greater than or equal.
00794 */
00795 static long c_gtoe()
00796 {
00797   long success=TRUE;
00798   ptr_psi_term arg1,arg2,arg3,t;
00799   long num1,num2,num3;
00800   REAL val1,val2,val3;
00801   
00802   t=aim->a;
00803   deref_ptr(t);
00804   get_two_args(t->attr_list,&arg1,&arg2);
00805   arg3=aim->b;
00806   
00807   if(arg1) {
00808     deref(arg1);
00809     success=get_real_value(arg1,&val1,&num1);
00810     if(success && arg2) {
00811       deref(arg2);
00812       deref_args(t,set_1_2);
00813       success=get_real_value(arg2,&val2,&num2);
00814     }
00815   }
00816   
00817   if(success)
00818     if(arg1 && arg2) {
00819       deref(arg3);
00820       success=get_bool_value(arg3,&val3,&num3);
00821       if(success)
00822         switch(num1+num2*2+num3*4) {
00823         case 0:
00824           residuate2(arg1,arg2);
00825           break;
00826         case 1:
00827           residuate(arg2);
00828           break;
00829         case 2:
00830           residuate(arg1);
00831           break;
00832         case 3:
00833           unify_bool_result(arg3,(val1>=val2));
00834           break;
00835         case 4:
00836           residuate2(arg1,arg2);
00837           break;
00838         case 5:
00839           residuate(arg2);
00840           break;
00841         case 6:
00842           residuate(arg1);
00843           break;
00844         case 7:
00845           success=(val3==(REAL)(val1>=val2));
00846           break;
00847         }      
00848     }
00849     else
00850       curry();
00851   
00852   nonnum_warning(t,arg1,arg2);
00853   return success;
00854 }
00855 
00856 
00857 
00858 /******** C_LTOE
00859   Less than or equal.
00860 */
00861 static long c_ltoe()
00862 {
00863   long success=TRUE;
00864   ptr_psi_term arg1,arg2,arg3,t;
00865   long num1,num2,num3;
00866   REAL val1,val2,val3;
00867   
00868   t=aim->a;
00869   deref_ptr(t);
00870   get_two_args(t->attr_list,&arg1,&arg2);
00871   arg3=aim->b;
00872   
00873   if(arg1) {
00874     deref(arg1);
00875     success=get_real_value(arg1,&val1,&num1);
00876     if(success && arg2) {
00877       deref(arg2);
00878       deref_args(t,set_1_2);
00879       success=get_real_value(arg2,&val2,&num2);
00880     }
00881   }
00882   
00883   if(success)
00884     if(arg1 && arg2) {
00885       deref(arg3);
00886       success=get_bool_value(arg3,&val3,&num3);
00887       if(success)
00888         switch(num1+num2*2+num3*4) {
00889         case 0:
00890           residuate2(arg1,arg2);
00891           break;
00892         case 1:
00893           residuate(arg2);
00894           break;
00895         case 2:
00896           residuate(arg1);
00897           break;
00898         case 3:
00899           unify_bool_result(arg3,(val1<=val2));
00900           break;
00901         case 4:
00902           residuate2(arg1,arg2);
00903           break;
00904         case 5:
00905           residuate(arg2);
00906           break;
00907         case 6:
00908           residuate(arg1);
00909           break;
00910         case 7:
00911           success=(val3==(REAL)(val1<=val2));
00912           break;
00913         }
00914     }
00915     else
00916       curry();
00917   
00918   nonnum_warning(t,arg1,arg2);
00919   return success;
00920 }
00921 
00922 
00923 
00924 
00925 /******** C_BOOLPRED
00926   Internal built-in predicate that handles functions in predicate positions.
00927   This predicate should never be called directly by the user.
00928 */
00929 
00930 static long c_boolpred()
00931 {
00932   long success=TRUE,succ,lesseq;
00933   ptr_psi_term t,arg1;
00934 
00935   t=aim->a;
00936   deref_ptr(t);
00937   get_one_arg(t->attr_list,&arg1);
00938   if (arg1) {
00939     deref(arg1);
00940     deref_args(t,set_1);
00941     if (sub_type(boolean,arg1->type)) {
00942       residuate(arg1);
00943     }
00944     else {
00945       succ=matches(arg1->type,true,&lesseq);
00946       if (succ) {
00947         if (lesseq) {
00948           /* Function returns true: success. */
00949         }
00950         else
00951           residuate(arg1);
00952       }
00953       else {
00954         succ=matches(arg1->type,false,&lesseq);
00955         if (succ) {
00956           if (lesseq) {
00957             /* Function returns false: failure. */
00958             success=FALSE;
00959           }
00960           else
00961             residuate(arg1);
00962         }
00963         else {
00964           /* Both true and false are disentailed. */
00965           if (arg1->type->type==predicate) {
00966             push_goal(prove,arg1,DEFRULES,NULL);
00967           }
00968           else {
00969             Errorline("function result '%P' should be a boolean or a predicate.\n",
00970                       arg1);
00971             return (c_abort());
00972           }
00973         }
00974       }
00975     }
00976   }
00977   else {
00978     Errorline("missing argument to '*boolpred*'.\n");
00979     return (c_abort());
00980   }
00981 
00982   return success;
00983 }
00984 
00985 static long get_bool(typ)
00986 ptr_definition typ;
00987 {
00988   if (sub_type(typ,true)) return TRUE;
00989   else if (sub_type(typ,false)) return FALSE;
00990   else return UNDEF;
00991 }
00992 
00993 static long unify_bool(arg)
00994 ptr_psi_term arg;
00995 {
00996   ptr_psi_term tmp;
00997 
00998   tmp=stack_psi_term(4);
00999   tmp->type=boolean;
01000   push_goal(unify,tmp,arg,NULL);
01001 }
01002 
01003 /* Main routine to handle the and & or functions. */
01004 /* sel = TRUE (for and) or FALSE (for or) */
01005 static long c_logical_main(sel)
01006 long sel;
01007 {
01008   long success=TRUE;
01009   ptr_psi_term funct,arg1,arg2,arg3;
01010   long sm1, sm2, sm3;
01011   long a1comp, a2comp, a3comp;
01012   long a1, a2, a3;
01013 
01014   funct=aim->a;
01015   deref_ptr(funct);
01016   get_two_args(funct->attr_list,&arg1,&arg2);
01017   if (arg1 && arg2) {
01018     deref(arg1);
01019     deref(arg2);
01020     deref_args(funct,set_1_2);
01021     arg3=aim->b;
01022     deref(arg3);
01023 
01024     a1comp = matches(arg1->type,boolean,&sm1);
01025     a2comp = matches(arg2->type,boolean,&sm2);
01026     a3comp = matches(arg3->type,boolean,&sm3);
01027     if (a1comp && a2comp && a3comp) {
01028       a1 = get_bool(arg1->type);
01029       a2 = get_bool(arg2->type);
01030       a3 = get_bool(arg3->type);
01031       if (a1== !sel || a2== !sel) {
01032         unify_bool_result(arg3,!sel);
01033       } else if (a1==sel) {
01034         /* tmp=stack_psi_term(4); */
01035         /* tmp->type=boolean; */
01036         /* push_goal(unify,tmp,arg3,NULL); */
01037         push_goal(unify,arg2,arg3,NULL);
01038       } else if (a2==sel) {
01039         /* tmp=stack_psi_term(4); */
01040         /* tmp->type=boolean; */
01041         /* push_goal(unify,tmp,arg3,NULL); */
01042         push_goal(unify,arg1,arg3,NULL);
01043       } else if (a3==sel) {
01044         unify_bool_result(arg1,sel);
01045         unify_bool_result(arg2,sel);
01046       } else if (arg1==arg2) {
01047         /* tmp=stack_psi_term(4); */
01048         /* tmp->type=boolean; */
01049         /* push_goal(unify,tmp,arg3,NULL); */
01050         push_goal(unify,arg1,arg3,NULL);
01051       } else {
01052         if (a1==UNDEF) residuate(arg1);
01053         if (a2==UNDEF) residuate(arg2);
01054         if (a3==UNDEF) residuate(arg3);
01055       }
01056       if (!sm1) unify_bool(arg1);
01057       if (!sm2) unify_bool(arg2);
01058       if (!sm3) unify_bool(arg3);
01059     }
01060     else {
01061       success=FALSE;
01062       Errorline("Non-boolean argument or result in '%P'.\n",funct);
01063     }
01064   }
01065   else
01066     curry();
01067 
01068   return success;
01069 }
01070 
01071 
01072 
01073 
01074 /******** C_AND, C_OR
01075   Logical and & or.
01076   These functions do all possible local propagations.
01077 */
01078 static long c_and()
01079 {
01080   return c_logical_main(TRUE);
01081 }
01082 
01083 static long c_or()
01084 {
01085   return c_logical_main(FALSE);
01086 }
01087 
01088 
01089 
01090 
01091 /******** C_NOT
01092   Logical not.
01093   This function does all possible local propagations.
01094 */
01095 static long c_not()
01096 {
01097   long success=TRUE;
01098   ptr_psi_term funct,arg1,arg2;
01099   long sm1, sm2;
01100   long a1comp, a2comp;
01101   long a1, a2;
01102 
01103   funct=aim->a;
01104   deref_ptr(funct);
01105   get_one_arg(funct->attr_list,&arg1);
01106   if (arg1) {
01107     deref(arg1);
01108     deref_args(funct,set_1);
01109     arg2=aim->b;
01110     deref(arg2);
01111  
01112     a1comp = matches(arg1->type,boolean,&sm1);
01113     a2comp = matches(arg2->type,boolean,&sm2);
01114     if (a1comp && a2comp) {
01115       a1 = get_bool(arg1->type);
01116       a2 = get_bool(arg2->type);
01117       if (a1==TRUE || a1==FALSE) {
01118         unify_bool_result(arg2,!a1);
01119       } else if (a2==TRUE || a2==FALSE) {
01120         unify_bool_result(arg1,!a2);
01121       } else if (arg1==arg2) {
01122         success=FALSE;
01123       } else {
01124         if (a1==UNDEF) residuate(arg1);
01125         if (a2==UNDEF) residuate(arg2);
01126       }
01127       if (!sm1) unify_bool(arg1);
01128       if (!sm2) unify_bool(arg2);
01129     }
01130     else {
01131       success=FALSE;
01132       Errorline("Non-boolean argument or result in '%P'.\n",funct);
01133     }
01134   }
01135   else
01136     curry();
01137 
01138   return success;
01139 }
01140 
01141 
01142 
01143 
01144 /******** C_XOR
01145   Logical exclusive or.
01146   This function does all possible local propagations.
01147 */
01148 static long c_xor()
01149 {
01150   long success=TRUE;
01151   ptr_psi_term funct,arg1,arg2,arg3;
01152   long sm1, sm2, sm3;
01153   long a1comp, a2comp, a3comp;
01154   long a1, a2, a3;
01155 
01156   funct=aim->a;
01157   deref_ptr(funct);
01158   get_two_args(funct->attr_list,&arg1,&arg2);
01159   if (arg1 && arg2) {
01160     deref(arg1);
01161     deref(arg2);
01162     deref_args(funct,set_1_2);
01163     arg3=aim->b;
01164     deref(arg3);
01165 
01166     a1comp = matches(arg1->type,boolean,&sm1);
01167     a2comp = matches(arg2->type,boolean,&sm2);
01168     a3comp = matches(arg3->type,boolean,&sm3);
01169     if (a1comp && a2comp && a3comp) {
01170       a1 = get_bool(arg1->type);
01171       a2 = get_bool(arg2->type);
01172       a3 = get_bool(arg3->type);
01173       if ((a1==TRUE || a1==FALSE) && (a2==TRUE || a2==FALSE)) {
01174         unify_bool_result(arg3, a1^a2);
01175       } else if ((a1==TRUE || a1==FALSE) && (a3==TRUE || a3==FALSE)) {
01176         unify_bool_result(arg2, a1^a3);
01177       } else if ((a3==TRUE || a3==FALSE) && (a2==TRUE || a2==FALSE)) {
01178         unify_bool_result(arg1, a3^a2);
01179 
01180       } else if (a1==TRUE && arg3==arg2) {
01181         success=FALSE;
01182       } else if (a2==TRUE && arg3==arg2) {
01183         success=FALSE;
01184       } else if (a3==TRUE && arg1==arg2) {
01185         success=FALSE;
01186 
01187       } else if (a1==FALSE) {
01188         push_goal(unify,arg2,arg3,NULL);
01189       } else if (a2==FALSE) {
01190         push_goal(unify,arg1,arg3,NULL);
01191       } else if (a3==FALSE) {
01192         push_goal(unify,arg1,arg2,NULL);
01193 
01194       } else if (arg1==arg2) {
01195         unify_bool_result(arg3,FALSE);
01196       } else if (arg1==arg3) {
01197         unify_bool_result(arg2,FALSE);
01198       } else if (arg3==arg2) {
01199         unify_bool_result(arg1,FALSE);
01200       } else {
01201         if (a1==UNDEF) residuate(arg1);
01202         if (a2==UNDEF) residuate(arg2);
01203         if (a3==UNDEF) residuate(arg3);
01204       }
01205       if (!sm1) unify_bool(arg1);
01206       if (!sm2) unify_bool(arg2);
01207       if (!sm3) unify_bool(arg3);
01208     }
01209     else {
01210       success=FALSE;
01211       Errorline("Non-boolean argument or result in '%P'.\n",funct);
01212     }
01213   }
01214   else
01215     curry();
01216 
01217   return success;
01218 }
01219 
01220 
01221 
01222 
01223 /******** C_APPLY
01224   This evaluates "apply(functor => F,Args)".  If F is
01225   a known function, then it builds the psi-term F(Args), and evaluates it.
01226 */
01227 static long c_apply()
01228 {
01229   long success=TRUE;
01230   ptr_psi_term funct,other;
01231   ptr_node n,fattr;
01232   
01233   funct=aim->a;
01234   deref_ptr(funct);
01235   n=find(featcmp,functor->keyword->symbol,funct->attr_list);
01236   if (n) {
01237     other=(ptr_psi_term )n->data;
01238     deref(other);
01239     if (other->type==top)
01240       residuate(other);
01241     else
01242       if(other->type && other->type->type!=function) {
01243         success=FALSE;
01244         Errorline("argument is not a function in %P.\n",funct);
01245       }
01246       else {
01247         /* What we really want here is to merge all attributes in       */
01248         /* funct->attr_list, except '*functor*', into other->attr_list. */
01249         clear_copy();
01250         other=distinct_copy(other);
01251         fattr=distinct_tree(funct->attr_list); /* Make distinct copy: PVR */
01252         push_goal(eval,other,aim->b,other->type->rule);
01253         merge_unify(&(other->attr_list),fattr);
01254         /* We don't want to remove anything from funct->attr_list here. */
01255         delete_attr(functor->keyword->symbol,&(other->attr_list));
01256       }
01257   }
01258   else
01259     curry();
01260   
01261   return success;
01262 }
01263 
01264 
01265 
01266 /******** C_PROJECT   /*  RM: Jan  7 1993 
01267   Here we evaluate "project(Psi-term,Label)". This
01268   returns the psi-term associated to label Label in Psi-term.
01269   It is identical to C_PROJECT except that the order of the arguments is
01270   inversed.
01271 */
01272 static long c_project()
01273 
01274 {
01275   long success=TRUE;
01276   ptr_psi_term arg1,arg2,funct,result;
01277   ptr_node n;
01278   char *label;
01279   double v;
01280  
01281   /* char *thebuffer="integer"; 18.5 */
01282   char thebuffer[20]; /* Maximum number of digits in an integer */
01283   
01284   funct=aim->a;
01285   deref_ptr(funct);
01286   result=aim->b;
01287   get_two_args(funct->attr_list,&arg1,&arg2);
01288   if (arg2 && arg1) {
01289     deref(arg1);
01290     deref(arg2);
01291     deref_args(funct,set_1_2);
01292     
01293     label=NULL;
01294 
01295     /*  RM: Jul 20 1993: Don't residuate on 'string' etc...  */
01296     if(arg2->type!=top) {
01297       if(arg2->value && sub_type(arg2->type,quoted_string)) /* 10.8 */
01298         label=(char *)arg2->value;
01299       else
01300         if(arg2->value && sub_type(arg2->type,integer)) { /* 10.8 */
01301           v= *(REAL *)arg2->value;
01302           if(v==floor(v)) {
01303             sprintf(thebuffer,"%ld",(long)v);
01304             label=heap_copy_string(thebuffer); /* A little voracious */
01305           }
01306           else { /*  RM: Jul 28 1993  */
01307             Errorline("non-integer numeric feature in %P\n",funct);
01308             return FALSE;
01309           }
01310         }
01311         else {
01312           if(arg2->type->keyword->private_feature) /*  RM: Mar 12 1993  */
01313             label=arg2->type->keyword->combined_name;
01314           else
01315             label=arg2->type->keyword->symbol; 
01316         }
01317     }
01318     
01319     if (label) {
01320       n=find(featcmp,label,arg1->attr_list);
01321       
01322       if (n)
01323         push_goal(unify,result,n->data,NULL);
01324       else if (arg1->type->type==function && !(arg1->flags&QUOTED_TRUE)) {
01325         Errorline("attempt to add a feature to curried function %P\n",
01326                   arg1);
01327         return FALSE;
01328       }
01329       else {
01330         deref_ptr(result);
01331         if((GENERIC)arg1>=heap_pointer) { /*  RM: Feb  9 1993  */
01332           if((GENERIC)result<heap_pointer)
01333             push_psi_ptr_value(result,&(result->coref));
01334           clear_copy();
01335           result->coref=inc_heap_copy(result);
01336           heap_insert(featcmp,label,&(arg1->attr_list),result->coref);
01337         }
01338         else {
01339     
01340 #ifdef ARITY  /*  RM: Mar 29 1993  */
01341           arity_add(arg1,label);
01342 #endif
01343           
01344           /*  RM: Mar 25 1993  */
01345           if(arg1->type->always_check || arg1->attr_list)
01346             bk_stack_insert(featcmp,label,&(arg1->attr_list),result);
01347           else {
01348             bk_stack_insert(featcmp,label,&(arg1->attr_list),result);
01349             fetch_def_lazy(arg1, arg1->type,arg1->type,NULL,NULL);
01350           }
01351           
01352           if (arg1->resid)
01353             release_resid(arg1);
01354         }
01355       } 
01356     }
01357     else
01358       residuate(arg2);
01359   }
01360   else
01361     curry();
01362   
01363   return success;
01364 }
01365 
01366 
01367 
01368 
01369 /******** C_DIFF
01370   Arithmetic not-equal.
01371 */
01372 static long c_diff()
01373 {
01374   long success=TRUE;
01375   ptr_psi_term arg1,arg2,arg3,t;
01376   long num1,num2,num3;
01377   REAL val1,val2,val3;
01378   
01379   t=aim->a;
01380   deref_ptr(t);
01381   get_two_args(t->attr_list,&arg1,&arg2);
01382   arg3=aim->b;
01383   
01384   if(arg1) {
01385     deref(arg1);
01386     success=get_real_value(arg1,&val1,&num1);
01387     if(success && arg2) {
01388       deref(arg2);
01389       deref_args(t,set_1_2);
01390       success=get_real_value(arg2,&val2,&num2);
01391     }
01392   }
01393   
01394   if(success)
01395     if(arg1 && arg2) {
01396       deref(arg3);
01397       success=get_bool_value(arg3,&val3,&num3);
01398       if(success)
01399         switch(num1+2*num2+4*num3) {
01400         case 0:
01401           if(arg1==arg2)
01402             unify_bool_result(arg3,FALSE);
01403           else
01404             residuate2(arg1,arg2);
01405           break;
01406         case 1:
01407           residuate2(arg2,arg3);
01408           break;
01409         case 2:
01410           residuate2(arg1,arg3);
01411           break;
01412         case 3:
01413           unify_bool_result(arg3,(val1!=val2));
01414           break;
01415         case 4:
01416           if(arg1==arg2 && val3)
01417             success=FALSE;
01418           else
01419             residuate2(arg1,arg2);
01420           break;
01421         case 5:
01422           if(val3)
01423             residuate(arg2);
01424           else
01425             success=unify_real_result(arg2,val1);
01426           break;
01427         case 6:
01428           if(val3)
01429             residuate(arg1);
01430           else
01431             success=unify_real_result(arg1,val2);
01432           break;
01433         case 7:
01434           success=(val3==(REAL)(val1!=val2));
01435           break;
01436         }
01437     }
01438     else
01439       curry();
01440   
01441   nonnum_warning(t,arg1,arg2);
01442   return success;
01443 }
01444 
01445 
01446 
01447 
01448 /******** C_FAIL
01449   Always fail.
01450 */
01451 static long c_fail()
01452 {
01453   return FALSE;
01454 }
01455 
01456 
01457 
01458 /******** C_SUCCEED
01459   Always succeed.
01460 */
01461 static long c_succeed()
01462 {
01463   ptr_psi_term t;
01464 
01465   t=aim->a;
01466   deref_args(t,set_empty);
01467   return TRUE;
01468 }
01469 
01470 
01471 
01472 /******** C_REPEAT
01473   Succeed indefinitely on backtracking.
01474 */
01475 static long c_repeat()
01476 {
01477   ptr_psi_term t;
01478 
01479   t=aim->a;
01480   deref_args(t,set_empty);
01481   push_choice_point(prove,t,DEFRULES,NULL);
01482   return TRUE;
01483 }
01484 
01485 
01486 /******** C_VAR
01487   Return true/false iff argument is/is not '@' (top with no attributes).
01488 */
01489 static long c_var()
01490 {
01491   long success=TRUE;
01492   ptr_psi_term arg1,result,g,other;
01493   
01494   g=aim->a;
01495   deref_ptr(g);
01496   result=aim->b;
01497   deref(result);
01498   get_one_arg(g->attr_list,&arg1);
01499   if (arg1) {
01500     deref(arg1);
01501     deref_args(g,set_1);
01502     other=stack_psi_term(4); /* 19.11 */
01503     other->type=((arg1->type==top)&&(arg1->attr_list==NULL))?true:false;
01504     resid_aim=NULL;
01505     push_goal(unify,result,other,NULL);
01506   }
01507   else {
01508     curry();
01509     /* Errorline("argument missing in %P.\n",t); */
01510     /* return c_abort(); */
01511   }
01512   
01513   return success;
01514 }
01515 
01516 
01517 /******** C_NONVAR
01518   Return true/false iff argument is not/is '@' (top with no attributes).
01519 */
01520 static long c_nonvar()
01521 {
01522   long success=TRUE;
01523   ptr_psi_term arg1,result,g,other;
01524   
01525   g=aim->a;
01526   deref_ptr(g);
01527   result=aim->b;
01528   deref(result);
01529   get_one_arg(g->attr_list,&arg1);
01530   if (arg1) {
01531     deref(arg1);
01532     deref_args(g,set_1);
01533     other=stack_psi_term(4); /* 19.11 */
01534     other->type=((arg1->type==top)&&(arg1->attr_list==NULL))?false:true;
01535     resid_aim=NULL;
01536     push_goal(unify,result,other,NULL);
01537   }
01538   else {
01539     curry();
01540     /* Errorline("argument missing in %P.\n",t); */
01541     /* return c_abort(); */
01542   }
01543   
01544   return success;
01545 }
01546 
01547 
01548 /******** C_IS_FUNCTION
01549   Succeed iff argument is a function (built-in or user-defined).
01550 */
01551 static long c_is_function()
01552 {
01553   long success=TRUE;
01554   ptr_psi_term arg1,result,g,other;
01555   
01556   g=aim->a;
01557   deref_ptr(g);
01558   result=aim->b;
01559   deref(result);
01560   get_one_arg(g->attr_list,&arg1);
01561   if (arg1) {
01562     deref(arg1);
01563     deref_args(g,set_1);
01564     other=stack_psi_term(4); /* 19.11 */
01565     other->type=(arg1->type->type==function)?true:false;
01566     resid_aim=NULL;
01567     push_goal(unify,result,other,NULL);
01568   }
01569   else {
01570     curry();
01571     /* Errorline("argument missing in %P.\n",t); */
01572     /* return c_abort(); */
01573   }
01574   
01575   return success;
01576 }
01577 
01578 
01579 /******** C_IS_PREDICATE
01580   Succeed iff argument is a predicate (built-in or user-defined).
01581 */
01582 static long c_is_predicate()
01583 {
01584   long success=TRUE;
01585   ptr_psi_term arg1,result,g,other;
01586   
01587   g=aim->a;
01588   deref_ptr(g);
01589   result=aim->b;
01590   deref(result);
01591   get_one_arg(g->attr_list,&arg1);
01592   if (arg1) {
01593     deref(arg1);
01594     deref_args(g,set_1);
01595     other=stack_psi_term(4); /* 19.11 */
01596     other->type=(arg1->type->type==predicate)?true:false;
01597     resid_aim=NULL;
01598     push_goal(unify,result,other,NULL);
01599   }
01600   else {
01601     curry();
01602     /* Errorline("argument missing in %P.\n",t); */
01603     /* return c_abort(); */
01604   }
01605   
01606   return success;
01607 }
01608 
01609 
01610 /******** C_IS_SORT
01611   Succeed iff argument is a sort (built-in or user-defined).
01612 */
01613 static long c_is_sort()
01614 {
01615   long success=TRUE;
01616   ptr_psi_term arg1,result,g,other;
01617   
01618   g=aim->a;
01619   deref_ptr(g);
01620   result=aim->b;
01621   deref(result);
01622   get_one_arg(g->attr_list,&arg1);
01623   if (arg1) {
01624     deref(arg1);
01625     deref_args(g,set_1);
01626     other=stack_psi_term(4); /* 19.11 */
01627     other->type=(arg1->type->type==type)?true:false;
01628     resid_aim=NULL;
01629     push_goal(unify,result,other,NULL);
01630   }
01631   else {
01632     curry();
01633     /* Errorline("argument missing in %P.\n",t); */
01634     /* return c_abort(); */
01635   }
01636   
01637   return success;
01638 }
01639 
01640 
01641 
01642 /* Return TRUE iff t has only argument "1", and return the argument. */
01643 long only_arg1(t, arg1)
01644 ptr_psi_term t;
01645 ptr_psi_term *arg1;
01646 {
01647   ptr_node n=t->attr_list;
01648 
01649   if (n && n->left==NULL && n->right==NULL && !featcmp(n->key,one)) {
01650     *arg1=(ptr_psi_term)n->data;
01651     return TRUE;
01652   }
01653   else
01654     return FALSE;
01655 }
01656 
01657 
01658 
01659 /******** C_DYNAMIC()
01660   Mark all the arguments as 'unprotected', i.e. they may be changed
01661   by assert/retract/redefinition.
01662 */
01663 static long c_dynamic()
01664 {
01665   ptr_psi_term t=aim->a;
01666   deref_ptr(t);
01667   /* mark_quote(t); 14.9 */
01668   assert_protected(t->attr_list,FALSE);
01669   return TRUE;
01670 }
01671 
01672 
01673 
01674 /******** C_STATIC()
01675   Mark all the arguments as 'protected', i.e. they may not be changed
01676   by assert/retract/redefinition.
01677 */
01678 static long c_static()
01679 {
01680   ptr_psi_term t=aim->a;
01681   deref_ptr(t);
01682   /* mark_quote(t); 14.9 */
01683   assert_protected(t->attr_list,TRUE);
01684   return TRUE;
01685 }
01686 
01687 
01688 
01689 /******** C_DELAY_CHECK()
01690   Mark that the properties of the types in the arguments are delay checked
01691   during unification (i.e. they are only checked when the psi-term is
01692   given attributes, and they are not checked as long as the psi-term has
01693   no attributes.)
01694 */
01695 static long c_delay_check()
01696 {
01697   ptr_psi_term t=aim->a;
01698 
01699   deref_ptr(t);
01700   /* mark_quote(t); 14.9 */
01701   assert_delay_check(t->attr_list);
01702   inherit_always_check();
01703   return TRUE;
01704 }
01705 
01706 
01707 
01708 /******** C_NON_STRICT()
01709   Mark that the function or predicate's arguments are not evaluated when
01710   the function or predicate is called.
01711 */
01712 static long c_non_strict()
01713 {
01714   ptr_psi_term t=aim->a;
01715 
01716   deref_ptr(t);
01717   /* mark_quote(t); 14.9 */
01718   assert_args_not_eval(t->attr_list);
01719   return TRUE;
01720 }
01721 
01722 
01723 
01724 /******** C_OP()
01725   Declare an operator.
01726 */
01727 static long c_op()
01728 {
01729   long declare_operator();
01730   ptr_psi_term t=aim->a;
01731 
01732   return declare_operator(t);
01733 }
01734 
01735 
01736 
01737 long file_exists(s)
01738 char *s;
01739 {
01740   FILE *f;
01741   char *e;
01742   long success=FALSE;
01743   
01744   e=expand_file_name(s);
01745   if (f=fopen(e,"r")) {
01746     fclose(f);
01747     success=TRUE;
01748   }
01749   return success;
01750 }
01751 
01752 
01753 
01754 /******** C_EXISTS
01755   Succeed iff a file can be read in (i.e. if it exists).
01756 */
01757 static long c_exists()
01758 {
01759   ptr_psi_term g;
01760   ptr_node n;
01761   long success=TRUE;
01762   ptr_psi_term arg1; 
01763   char *c_arg1; 
01764 
01765   g=aim->a;
01766   deref_ptr(g);
01767 
01768   if (success) {
01769     n=find(featcmp,one,g->attr_list);
01770     if (n) {
01771       arg1= (ptr_psi_term )n->data;
01772       deref(arg1);
01773       deref_args(g,set_1);
01774       if (!psi_to_string(arg1,&c_arg1)) {
01775         success=FALSE;
01776         Errorline("bad argument in %P.\n",g);
01777       }
01778     }
01779     else {
01780       success=FALSE;
01781       Errorline("bad argument in %P.\n",g);
01782     }
01783   }
01784 
01785   if (success)
01786     success=file_exists(c_arg1);
01787 
01788   return success;
01789 }
01790 
01791 
01792 
01793 /******** C_LOAD
01794   Load a file.  This load accepts and executes any queries in the loaded
01795   file, including calls to user-defined predicates and other load predicates.
01796 */
01797 static long c_load()
01798 {
01799   long success=FALSE;
01800   ptr_psi_term arg1,arg2,t;
01801   char *fn;
01802 
01803   t=aim->a;
01804   deref_ptr(t);
01805   get_two_args(t->attr_list,&arg1,&arg2);
01806   if(arg1) {
01807     deref(arg1);
01808     deref_args(t,set_1);
01809     if (psi_to_string(arg1,&fn)) {
01810       success=open_input_file(fn);
01811       if (success) {
01812         file_date+=2;
01813         push_goal(load,input_state,file_date,fn);
01814         file_date+=2;
01815       }
01816     }
01817     else {
01818       Errorline("bad file name in %P.\n",t);
01819       success=FALSE;
01820     }
01821   }
01822   else {
01823     Errorline("no file name in %P.\n",t);
01824     success=FALSE;
01825   }
01826 
01827   return success;
01828 }
01829 
01830 
01831 
01832 /******** C_GET_CHOICE()
01833   Return the current state of the choice point stack (i.e., the time stamp
01834   of the current choice point).
01835 */
01836 static long c_get_choice()
01837 {
01838   long gts,success=TRUE;
01839   ptr_psi_term funct,result;
01840 
01841   funct=aim->a;
01842   deref_ptr(funct);
01843   result=aim->b;
01844   deref_args(funct,set_empty);
01845   if (choice_stack)
01846     gts=choice_stack->time_stamp;
01847   else
01848     gts=global_time_stamp-1;
01849     /* gts=INIT_TIME_STAMP; PVR 11.2.94 */
01850   push_goal(unify,result,real_stack_psi_term(4,(REAL)gts),NULL);
01851 
01852   return success;
01853 }
01854 
01855 
01856 
01857 /******** C_SET_CHOICE()
01858   Set the choice point stack to a state no later than (i.e. the same or earlier
01859   than) the state of the first argument (i.e., remove all choice points up to
01860   the first one whose time stamp is =< the first argument).  This predicate
01861   will remove zero or more choice points, never add them.  The first argument
01862   must come from a past call to get_choice.
01863   Together, get_choice and set_choice allow one to implement an "ancestor cut"
01864   that removes all choice points created between the current execution point
01865   and an execution point arbitarily remote in the past.
01866   The built-ins get_choice, set_choice, and exists_choice are implemented
01867   using the timestamping mechanism in the interpreter.  The two
01868   relevant properties of the timestamping mechanism are that each choice
01869   point is identified by an integer and that the integers are in increasing
01870   order (but not necessarily consecutive) from the bottom to the top of the
01871   choice point stack.
01872 */
01873 static long c_set_choice()
01874 {
01875   REAL gts_r;
01876   long gts;
01877   long num,success=TRUE;
01878   ptr_psi_term t,arg1;
01879   ptr_choice_point cutpt;
01880 
01881   t=aim->a;
01882   deref_ptr(t);
01883   get_one_arg(t->attr_list,&arg1);
01884   if (arg1) {
01885     deref(arg1);
01886     deref_args(t,set_1);
01887     success = get_real_value(arg1,&gts_r,&num);
01888     if (success) {
01889       if (num) {
01890         gts=(unsigned long)gts_r;
01891         if (choice_stack) {
01892           cutpt=choice_stack;
01893           while (cutpt && cutpt->time_stamp>gts) cutpt=cutpt->next;
01894           if (choice_stack!=cutpt) {
01895             choice_stack=cutpt;
01896 #ifdef CLEAN_TRAIL
01897             clean_trail(choice_stack);
01898 #endif
01899           }
01900         }
01901       }
01902       else {
01903         Errorline("bad argument to %P.\n",t);
01904         success=FALSE;
01905       }
01906     }
01907     else {
01908       Errorline("bad argument %P.\n",t);
01909       success=FALSE;
01910     }
01911   }
01912   else
01913     curry();
01914 
01915   return success;
01916 }
01917 
01918 
01919 
01920 /******** C_EXISTS_CHOICE()
01921   Return true iff there exists a choice point A such that arg1 < A <= arg2,
01922   i.e. A is more recent than the choice point marked by arg1 and no more
01923   recent than the choice point marked by arg2.  The two arguments to
01924   exists_choice must come from past calls to get_choice.
01925   This function allows one to check whether a choice point exists between
01926   any two arbitrary execution points of the program.
01927 */
01928 static long c_exists_choice()
01929 {
01930   REAL gts_r;
01931   long ans,gts1,gts2,num,success=TRUE;
01932   ptr_psi_term funct,result,arg1,arg2,ans_term;
01933   ptr_choice_point cp;
01934 
01935   funct=aim->a;
01936   deref_ptr(funct);
01937   result=aim->b;
01938   deref_args(funct,set_empty);
01939   get_two_args(funct->attr_list,&arg1,&arg2);
01940   if (arg1 && arg2) {
01941     deref(arg1);
01942     deref(arg2);
01943     deref_args(funct,set_1_2);
01944     success = get_real_value(arg1,&gts_r,&num);
01945     if (success && num) {
01946       gts1 = (unsigned long) gts_r;
01947       success = get_real_value(arg2,&gts_r,&num);
01948       if (success && num) {
01949         gts2 = (unsigned long) gts_r;
01950         cp = choice_stack;
01951         if (cp) {
01952           while (cp && cp->time_stamp>gts2) cp=cp->next;
01953           ans=(cp && cp->time_stamp>gts1);
01954         }
01955         else
01956           ans=FALSE;
01957         ans_term=stack_psi_term(4);
01958         ans_term->type=ans?true:false;
01959         push_goal(unify,result,ans_term,NULL);
01960       }
01961       else {
01962         Errorline("bad second argument to %P.\n",funct);
01963         success=FALSE;
01964       }
01965     }
01966     else {
01967       Errorline("bad first argument %P.\n",funct);
01968       success=FALSE;
01969     }
01970   }
01971   else
01972     curry();
01973 
01974   return success;
01975 }
01976 
01977 
01978 
01979 /******** C_PRINT_VARIABLES
01980   Print the global variables and their values,
01981   in the same way as is done in the user interface.
01982 */
01983 static long c_print_variables()
01984 {
01985   long success=TRUE;
01986 
01987   print_variables(TRUE); /* 21.1 */
01988 
01989   return success;
01990 }
01991 
01992 
01993 
01994 static void set_parse_queryflag(thelist, sort)
01995 ptr_node thelist;
01996 long sort;
01997 {
01998   ptr_node n;             /* node pointing to argument 2  */
01999   ptr_psi_term arg;       /* argumenrt 2 psi-term */
02000   ptr_psi_term queryflag; /* query term created by this function */
02001 
02002   n=find(featcmp,two,thelist);
02003   if (n) {
02004     /* there was a second argument */
02005     arg=(ptr_psi_term)n->data;
02006     queryflag=stack_psi_term(4);
02007     queryflag->type =
02008     update_symbol(bi_module,
02009                   ((sort==QUERY)?"query":
02010                   ((sort==FACT)?"declaration":"error")));
02011     push_goal(unify,queryflag,arg,NULL);
02012   }
02013 }
02014 
02015 
02016 /******** C_PARSE
02017   Parse a string and return a quoted psi-term.
02018   The global variable names are recognized (see the built-in
02019   print_variables).  All variables in the parsed string
02020   are added to the set of global variables.
02021 */
02022 static long c_parse()
02023 {
02024   long success=TRUE;
02025   ptr_psi_term arg1,arg2,arg3,funct,result;
02026   long smaller,sort,old_var_occurred;
02027   ptr_node n;
02028   parse_block pb;
02029 
02030   funct=aim->a;
02031   deref_ptr(funct);
02032   result=aim->b;
02033   get_one_arg(funct->attr_list,&arg1);
02034   if (arg1) {
02035     deref(arg1);
02036     deref_args(funct,set_1);
02037     success=matches(arg1->type,quoted_string,&smaller);
02038     if (success) {
02039       if (arg1->value) {
02040         ptr_psi_term t;
02041 
02042         /* Parse the string in its own state */
02043         save_parse_state(&pb);
02044         init_parse_state();
02045         stringparse=TRUE;
02046         stringinput=(char*)arg1->value;
02047 
02048         old_var_occurred=var_occurred;
02049         var_occurred=FALSE;
02050         t=stack_copy_psi_term(parse(&sort));
02051         
02052           /* Optional second argument returns 'query', 'declaration', or
02053           /* 'error'. */
02054           n=find(featcmp,two,funct->attr_list);
02055           if (n) {
02056             ptr_psi_term queryflag;
02057             arg2=(ptr_psi_term)n->data;
02058             queryflag=stack_psi_term(4);
02059             queryflag->type=
02060               update_symbol(bi_module,
02061                 ((sort==QUERY)?"query":((sort==FACT)?"declaration":"error"))
02062               );
02063             push_goal(unify,queryflag,arg2,NULL);
02064           }
02065   
02066           /* Optional third argument returns true or false if the psi-term
02067           /* contains a variable or not. */
02068           n=find(featcmp,three,funct->attr_list);
02069           if (n) {
02070             ptr_psi_term varflag;
02071             arg3=(ptr_psi_term)n->data;
02072             varflag=stack_psi_term(4);
02073             varflag->type=var_occurred?true:false;
02074             push_goal(unify,varflag,arg3,NULL);
02075           }
02076 
02077         var_occurred = var_occurred || old_var_occurred;
02078         stringparse=FALSE;
02079         restore_parse_state(&pb);
02080 
02081         /* parse_ok flag says whether there was a syntax error. */
02082         if (TRUE /*parse_ok*/) {
02083           mark_quote(t);
02084           push_goal(unify,t,result,NULL);
02085         }
02086         else
02087           success=FALSE;
02088       }
02089       else
02090         residuate(arg1);
02091     }
02092     else
02093       success=FALSE;
02094   }
02095   else
02096    curry();
02097 
02098   return success;
02099 }
02100 
02101 
02102 
02103 
02104 
02105 /******** C_READ
02106   Read a psi_term or a token from the current input stream.
02107   The variables in the object read are not added to the set
02108   of global variables.
02109 */
02110 
02111 static long c_read();
02112      
02113 static long c_read_psi() { return (c_read(TRUE)); }
02114 
02115 static long c_read_token() { return (c_read(FALSE)); }
02116 
02117 static long c_read(psi_flag)     
02118 long psi_flag;
02119 {
02120   long success=TRUE;
02121   long sort;
02122   ptr_psi_term arg1,arg2,arg3,g,t;
02123   ptr_node old_var_tree;
02124   ptr_node n;
02125   int line=line_count+1;
02126   
02127   g=aim->a;
02128   deref_ptr(g);
02129   get_one_arg(g->attr_list,&arg1);
02130   if (arg1) {
02131     deref_args(g,set_1);
02132     if (eof_flag) {
02133       Errorline("attempt to read past end of file (%E).\n");
02134       return (abort_life(TRUE));
02135     }
02136     else {
02137       prompt="";
02138       old_var_tree=var_tree;
02139       var_tree=NULL;
02140       if (psi_flag) {
02141         t=stack_copy_psi_term(parse(&sort));
02142 
02143 
02144         /* Optional second argument returns 'query', 'declaration', or
02145            'error'. */
02146         n=find(featcmp,two,g->attr_list); /*  RM: Jun  8 1993  */
02147         if (n) {
02148           ptr_psi_term queryflag;
02149           arg2=(ptr_psi_term)n->data;
02150           queryflag=stack_psi_term(4);
02151           queryflag->type=
02152             update_symbol(bi_module,
02153                           ((sort==QUERY)?"query":((sort==FACT)?"declaration":"error"))
02154                           );
02155           push_goal(unify,queryflag,arg2,NULL);
02156         }
02157 
02158 
02159         /* Optional third argument returns the starting line number */
02160         /*  RM: Oct 11 1993  */
02161         n=find(featcmp,three,g->attr_list);
02162         if (n) {
02163           arg3=(ptr_psi_term)n->data;
02164           g=stack_psi_term(4);
02165           g->type=integer;
02166           g->value=heap_alloc(sizeof(REAL));
02167           *(REAL *)g->value=line;
02168           push_goal(unify,g,arg3,NULL);
02169         }
02170         
02171       }
02172       else {
02173         t=stack_psi_term(0);
02174         read_token_b(t);
02175         /*  RM: Jan  5 1993  removed spurious argument: &quot (??) */
02176         
02177       }
02178       if (t->type==eof) eof_flag=TRUE;
02179       var_tree=old_var_tree;
02180     }
02181     
02182     if (success) {
02183       mark_quote(t);
02184       push_goal(unify,t,arg1,NULL);
02185       /* i_check_out(t); */
02186     }
02187   }
02188   else {
02189     Errorline("argument missing in %P.\n",g);
02190     success=FALSE;
02191   }
02192   
02193   return success;
02194 }
02195 
02196 
02197 
02198 /******** C_HALT
02199   Exit the Wild_Life interpreter.
02200 */
02201 int c_halt()   /*  RM: Jan  8 1993  Used to be 'void' */
02202 {
02203   exit_life(TRUE);
02204 }
02205 
02206 
02207 void exit_life(nl_flag)
02208 long nl_flag;
02209 {
02210   open_input_file("stdin");
02211   times(&life_end);
02212   if (NOTQUIET) { /* 21.1 */
02213     if (nl_flag) printf("\n");
02214     printf("*** Exiting Wild_Life  ");
02215 #ifndef OS2_PORT
02216     printf("[%1.3fs cpu, %1.3fs gc (%2.1f%%)]\n",
02217            (life_end.tms_utime-life_start.tms_utime)/60.0,
02218            garbage_time,
02219            garbage_time*100 / ((life_end.tms_utime-life_start.tms_utime)/60.0)
02220            );
02221 #else
02222     printf("[%1.3fs cpu, %1.3fs gc (%2.1f%%)]\n",
02223            (life_end-life_start)/60.0,
02224            garbage_time,
02225            garbage_time*100 / ((life_end-life_start)/60.0)
02226            );
02227 #endif
02228   }
02229 
02230 #ifdef ARITY  /*  RM: Mar 29 1993  */
02231   arity_end();
02232 #endif
02233   
02234   exit(1);
02235 }
02236 
02237 
02238 
02239 /******** C_ABORT
02240   Return to the top level of the interpreter.
02241 */
02242 long c_abort()   /*  RM: Feb 15 1993  */
02243 {
02244   return (abort_life(TRUE));
02245 }
02246 
02247 
02248 /* 26.1 */
02249 long abort_life(nlflag) /*  RM: Feb 15 1993  */
02250 int nlflag;
02251 {
02252   if ( aborthooksym->type!=function ||
02253        !aborthooksym->rule->b ||
02254        aborthooksym->rule->b->type==abortsym) {
02255     /* Do a true abort if aborthook is not a function or is equal to 'abort'.*/
02256     main_loop_ok = FALSE;
02257     undo(NULL); /* 8.10 */
02258     if(NOTQUIET) fprintf(stderr,"\n*** Abort"); /*  RM: Feb 17 1993  */
02259     if(NOTQUIET && nlflag) fprintf(stderr,"\n");/*  RM: Feb 17 1993  */
02260   } else {
02261     /* Do a 'user-defined abort': initialize the system, then */
02262     /* prove the user-defined abort routine (which is set by  */
02263     /* means of 'setq(aborthook,user_defined_abort)'.         */
02264     ptr_psi_term aborthook;
02265 
02266     undo(NULL);
02267     init_system();
02268     var_occurred=FALSE;
02269     stdin_cleareof();
02270     if(NOTQUIET) fprintf(stderr,"\n*** Abort"); /*  RM: Feb 17 1993  */
02271     if(NOTQUIET && nlflag) fprintf(stderr,"\n");/*  RM: Feb 17 1993  */
02272     aborthook=stack_psi_term(0);
02273     aborthook->type=aborthooksym;
02274     push_goal(prove,aborthook,DEFRULES,NULL);
02275   }
02276   return TRUE;
02277 }
02278 
02279 
02280 
02281 /******** C_NOT_IMPLEMENTED
02282   This function always fails, it is in fact identical to BOTTOM.
02283 */
02284 static long c_not_implemented()
02285 {
02286   ptr_psi_term t;
02287   
02288   t=aim->a;
02289   deref_ptr(t);
02290   Errorline("built-in %P is not implemented yet.\n",t);
02291   return FALSE;
02292 }
02293 
02294 
02295 
02296 /******** C_DECLARATION
02297   This function always fails, it is in fact identical to BOTTOM.
02298 */
02299 static long c_declaration()
02300 {
02301   ptr_psi_term t;
02302   
02303   t=aim->a;
02304   deref_ptr(t);
02305   Errorline("%P is a declaration, not a query.\n",t);
02306   return FALSE;
02307 }
02308 
02309 
02310 
02311 /******** C_SETQ
02312 
02313   Create a function with one rule F -> X, where F and X are the
02314   arguments of setq.  Setq evaluates its first argument and quotes the first.
02315   away any previous definition of F.  F must be undefined or a function, there
02316   is an error if F is a sort or a predicate.  This gives an error for a static
02317   function, but none for an undefined (i.e. uninterpreted) psi-term, which is
02318   made dynamic.  */
02319 
02320 
02321 static long c_setq()
02322 {
02323   long success=FALSE;
02324   ptr_psi_term arg1,arg2,g;
02325   ptr_pair_list p;
02326   ptr_definition d;
02327 
02328   g=aim->a;
02329   get_two_args(g->attr_list,&arg1,&arg2);
02330   if (arg1 && arg2) {
02331     deref_rec(arg2); /*  RM: Jan  6 1993  */
02332     deref_ptr(arg1);
02333     d=arg1->type;
02334     if (d->type==function || d->type==undef) {
02335       if (d->type==undef || !d->protected) {
02336         if (!arg1->attr_list) {
02337           d->type=function;
02338           d->protected=FALSE;
02339           p=HEAP_ALLOC(pair_list);
02340           p->a=heap_psi_term(4);
02341           p->a->type=d;
02342           clear_copy();
02343           p->b=quote_copy(arg2,HEAP);
02344           p->next=NULL;
02345           d->rule=p;
02346           success=TRUE;
02347         }
02348         else
02349          Errorline("%P may not have arguments in %P.\n",arg1,g);
02350       }
02351       else
02352         Errorline("%P should be dynamic in %P.\n",arg1,g);
02353     }
02354     else
02355       Errorline("%P should be a function or uninterpreted in %P.\n",arg1,g);
02356   }
02357   else
02358     Errorline("%P is missing one or both arguments.\n",g);
02359 
02360   return success;
02361 }
02362 
02363 
02364 
02365 /******** C_ASSERT_FIRST
02366   Assert a fact, inserting it as the first clause
02367   for that predicate or function.
02368 */
02369 static long c_assert_first()
02370 {
02371   long success=FALSE;
02372   ptr_psi_term arg1,g;
02373   
02374   g=aim->a;
02375   bk_mark_quote(g); /*  RM: Apr  7 1993  */
02376   get_one_arg(g->attr_list,&arg1);
02377   assert_first=TRUE;
02378   if (arg1) {
02379     deref_ptr(arg1);
02380     assert_clause(arg1);
02381     encode_types();
02382     success=assert_ok;
02383   }
02384   else {
02385     success=FALSE;
02386     Errorline("bad clause in %P.\n",g);
02387   }
02388   
02389   return success;
02390 }
02391 
02392 
02393 
02394 /******** C_ASSERT_LAST
02395   Assert a fact, inserting as the last clause for that predicate or function.
02396 */
02397 static long c_assert_last()
02398 {
02399   long success=FALSE;
02400   ptr_psi_term arg1,g;
02401   
02402   g=aim->a;
02403   bk_mark_quote(g); /*  RM: Apr  7 1993  */
02404   get_one_arg(g->attr_list,&arg1);
02405   assert_first=FALSE;
02406   if (arg1) {
02407     deref_ptr(arg1);
02408     assert_clause(arg1);
02409     encode_types();
02410     success=assert_ok;
02411   }
02412   else {
02413     success=FALSE;
02414     Errorline("bad clause in %P.\n",g);
02415   }
02416   
02417   return success;
02418 }
02419 
02420 
02421 
02422 /******** PRED_CLAUSE(t,r,g)
02423   Set about finding a clause that unifies with psi_term T.
02424   This routine is used both for CLAUSE and RETRACT.
02425   If R==TRUE then delete the first clause which unifies with T.
02426 */
02427 long pred_clause(t,r,g)
02428 ptr_psi_term t, g;
02429 long r;
02430 {
02431   long success=FALSE;
02432   ptr_psi_term head,body;
02433   
02434   bk_mark_quote(g); /*  RM: Apr  7 1993  */
02435   if (t) {
02436     deref_ptr(t);
02437     
02438     if (!strcmp(t->type->keyword->symbol,"->")) {
02439       get_two_args(t->attr_list,&head,&body);
02440       if (head) {
02441         deref_ptr(head);
02442         if (head && body &&
02443             (head->type->type==function || head->type->type==undef))
02444           success=TRUE;
02445       }
02446     }
02447     else if (!strcmp(t->type->keyword->symbol,":-")) {
02448       get_two_args(t->attr_list,&head,&body);
02449       if (head) {
02450         deref_ptr(head);
02451         if (head &&
02452             (head->type->type==predicate || head->type->type==undef)) {
02453           success=TRUE;
02454           if (!body) {
02455             body=stack_psi_term(4);
02456             body->type=succeed;
02457           }
02458         }
02459       }
02460     }
02461     /* There is no body, so t is a fact */
02462     else if (t->type->type==predicate || t->type->type==undef) {
02463       head=t;
02464       body=stack_psi_term(4);
02465       body->type=succeed;
02466       success=TRUE;
02467     }
02468   }
02469   
02470   if (success) {
02471     if (r) {
02472       if (redefine(head))
02473         push_goal(del_clause,head,body,&(head->type->rule));
02474       else
02475         success=FALSE;
02476     }
02477     else
02478       push_goal(clause,head,body,&(head->type->rule));
02479   }
02480   else
02481     Errorline("bad argument in %s.\n", (r?"retract":"clause"));
02482   
02483   return success;
02484 }
02485 
02486 
02487 
02488 /******** C_CLAUSE
02489   Find the clauses that unify with the argument in the rules.
02490   The argument must be a predicate or a function.
02491   Use PRED_CLAUSE to perform the search.
02492 */
02493 static long c_clause()
02494 {
02495   long success=FALSE;
02496   ptr_psi_term arg1,arg2,g;
02497   
02498   g=aim->a;
02499   get_two_args(g->attr_list,&arg1,&arg2);
02500   success=pred_clause(arg1,0,g);
02501   return success;
02502 }
02503 
02504 
02505 
02506 /******** C_RETRACT
02507   Retract the first clause that unifies with the argument.
02508   Use PRED_CLAUSE to perform the search.
02509 */
02510 static long c_retract()
02511 {
02512   long success=FALSE;
02513   ptr_psi_term arg1,arg2,g;
02514   
02515   g=aim->a;
02516   get_two_args(g->attr_list,&arg1,&arg2);
02517   success=pred_clause(arg1,1,g);
02518   
02519   return success;
02520 }
02521 
02522 
02523 void global_error_check();
02524 void global_tree();
02525 void global_one();
02526 
02527 /******** C_GLOBAL
02528   Declare that a symbol is a global variable.
02529   Handle multiple arguments and initialization
02530   (the initialization term is evaluated).
02531   If there is an error anywhere in the declaration,
02532   then evaluate and declare nothing.
02533 */
02534 static long c_global()    /*  RM: Feb 10 1993  */
02535 {
02536   long error=FALSE, eval=FALSE;
02537   ptr_psi_term g;
02538   
02539   g=aim->a;
02540   deref_ptr(g);
02541   if (g->attr_list) {
02542     /* Do error check of all arguments first: */
02543     global_error_check(g->attr_list, &error, &eval);
02544     if (eval) return !error;
02545     /* If no errors, then make the arguments global: */
02546     if (!error)
02547       global_tree(g->attr_list);
02548   } else {
02549     Errorline("argument(s) missing in %P\n",g);
02550   }
02551   
02552   return !error;
02553 }
02554 
02555 
02556 
02557 void global_error_check(n, error, eval)
02558 ptr_node n;
02559 int *error, *eval;
02560 {
02561   if (n) {
02562     ptr_psi_term t,a1,a2;
02563     int bad_init=FALSE;
02564     global_error_check(n->left, error, eval);
02565 
02566     t=(ptr_psi_term)n->data;
02567     deref_ptr(t);
02568     if (t->type==leftarrowsym) {
02569       get_two_args(t->attr_list,&a1,&a2);
02570       if (a1==NULL || a2==NULL) {
02571         Errorline("%P is an incorrect global variable declaration (%E).\n",t);
02572         *error=TRUE;
02573         bad_init=TRUE;
02574       } else {
02575         deref_ptr(a1);
02576         deref_ptr(a2);
02577         t=a1;
02578         if (deref_eval(a2)) *eval=TRUE;
02579       }
02580     }
02581     if (!bad_init && t->type->type!=undef && t->type->type!=global) {
02582       Errorline("%T %P cannot be redeclared as a global variable (%E).\n",
02583                 t->type->type,
02584                 t);
02585       t->type=error_psi_term->type;
02586       t->value=NULL; /*  RM: Mar 23 1993  */
02587       *error=TRUE;
02588     }
02589 
02590     global_error_check(n->right, error, eval);
02591   }
02592 }
02593 
02594 
02595 void global_tree(n)
02596 ptr_node n;
02597 {
02598   if (n) {
02599     ptr_psi_term t;
02600     global_tree(n->left);
02601 
02602     t=(ptr_psi_term)n->data;
02603     deref_ptr(t);
02604     global_one(t);
02605 
02606     global_tree(n->right);
02607   }
02608 }
02609 
02610 
02611 void global_one(t)
02612 ptr_psi_term t;
02613 {
02614   ptr_psi_term u,val;
02615 
02616   if (t->type==leftarrowsym) {
02617     get_two_args(t->attr_list,&t,&u);
02618     deref_ptr(t);
02619     deref_ptr(u);
02620   }
02621   else
02622     u=stack_psi_term(4);
02623   
02624   clear_copy();
02625   t->type->type=global;
02626   t->type->init_value=quote_copy(u,HEAP); /*  RM: Mar 23 1993  */
02627 
02628   /* eval_global_var(t);   RM: Feb  4 1994  */
02629   
02630   /*  RM: Nov 10 1993 
02631       val=t->type->global_value;
02632       if (val && (GENERIC)val<heap_pointer) {
02633       deref_ptr(val);
02634       push_psi_ptr_value(val,&(val->coref));
02635       val->coref=u;
02636       } else
02637       t->type->global_value=u;
02638   */
02639 }
02640 
02641 
02642 
02643 /******** C_PERSISTENT
02644   Declare that a symbol is a persistent variable.
02645 */
02646 static long c_persistent()     /*  RM: Feb 10 1993  */
02647 {
02648   long error=FALSE;
02649   ptr_psi_term g;
02650 
02651   g=aim->a;
02652   deref_ptr(g);
02653   if (g->attr_list) {
02654     /* Do error check of all arguments first: */
02655     persistent_error_check(g->attr_list, &error);
02656     /* If no errors, then make the arguments persistent: */
02657     if (!error)
02658       persistent_tree(g->attr_list);
02659   } else {
02660     Errorline("argument(s) missing in %P\n",g);
02661   }
02662 
02663   return !error;
02664 }
02665 
02666 
02667 persistent_error_check(n, error)
02668 ptr_node n;
02669 int *error;
02670 {
02671   if (n) {
02672     ptr_psi_term t;
02673     persistent_error_check(n->left, error);
02674 
02675     t=(ptr_psi_term)n->data;
02676     deref_ptr(t);
02677     if (t->type->type!=undef && t->type->type!=global) {
02678       Errorline("%T %P cannot be redeclared persistent (%E).\n",
02679                  t->type->type,
02680                  t);
02681       t->type=error_psi_term->type;
02682       *error=TRUE;
02683     }
02684 
02685     persistent_error_check(n->right, error);
02686   }
02687 }
02688 
02689 
02690 persistent_tree(n)
02691 ptr_node n;
02692 {
02693   if (n) {
02694     ptr_psi_term t;
02695     persistent_tree(n->left);
02696 
02697     t=(ptr_psi_term)n->data;
02698     deref_ptr(t);
02699     persistent_one(t);
02700 
02701     persistent_tree(n->right);
02702   }
02703 }
02704 
02705 
02706 persistent_one(t)
02707 ptr_psi_term t;
02708 {
02709   t->type->type=global;
02710   if ((GENERIC)t->type->global_value<(GENERIC)heap_pointer)
02711     t->type->global_value=heap_psi_term(4);
02712 }
02713 
02714 
02715 
02716 /******** C_OPEN_IN
02717   Create a stream for input from the specified file.
02718 */
02719 static long c_open_in()
02720 {
02721   long success=FALSE;
02722   ptr_psi_term arg1,arg2,g;
02723   char *fn;
02724   
02725   g=aim->a;
02726   deref_ptr(g);
02727   get_two_args(g->attr_list,&arg1,&arg2);
02728   if(arg1) {
02729     deref(arg1);
02730     if (psi_to_string(arg1,&fn))
02731       if (arg2) {
02732         deref(arg2);
02733         deref_args(g,set_1_2);
02734         if (is_top(arg2)) {
02735           if (open_input_file(fn)) {
02736             /* push_ptr_value(psi_term_ptr,&(arg2->coref)); 9.6 */
02737             push_psi_ptr_value(arg2,&(arg2->coref));
02738             arg2->coref=input_state;
02739             success=TRUE;
02740           }
02741           else
02742             success=FALSE;
02743         }
02744         else
02745           Errorline("bad input stream in %P.\n",g);
02746       }
02747       else
02748         Errorline("no stream in %P.\n",g);
02749     else
02750       Errorline("bad file name in %P.\n",g);
02751   }
02752   else
02753     Errorline("no file name in %P.\n",g);
02754 
02755   return success;
02756 }
02757 
02758 
02759 
02760 /******** C_OPEN_OUT
02761   Create a stream for output from the specified file.
02762 */
02763 static long c_open_out()
02764 {
02765   long success=FALSE;
02766   ptr_psi_term arg1,arg2,arg3,g;
02767   char *fn;
02768   
02769   g=aim->a;
02770   deref_ptr(g);
02771   get_two_args(g->attr_list,&arg1,&arg2);
02772   if(arg1) {
02773     deref(arg1);
02774     if (psi_to_string(arg1,&fn))
02775       if (arg2) {
02776         deref(arg2);
02777         deref(g);
02778         if (overlap_type(arg2->type,stream)) /* 10.8 */
02779           if (open_output_file(fn)) {
02780             arg3=stack_psi_term(4);
02781             arg3->type=stream;
02782             arg3->value=(GENERIC)output_stream;
02783             /* push_ptr_value(psi_term_ptr,&(arg2->coref)); 9.6 */
02784             push_psi_ptr_value(arg2,&(arg2->coref));
02785             arg2->coref=arg3;
02786             success=TRUE;
02787           }
02788           else
02789             success=FALSE;
02790         else
02791           Errorline("bad stream in %P.\n",g);
02792       }
02793       else
02794         Errorline("no stream in %P.\n",g);
02795     else
02796       Errorline("bad file name in %P.\n",g);
02797   }
02798   else
02799     Errorline("no file name in %P.\n",g);
02800   
02801   return success;
02802 }
02803 
02804 
02805 
02806 /******** C_SET_INPUT
02807   Set the current input stream to a given stream.
02808   If the given stream is closed, then do nothing.
02809 */
02810 static long c_set_input()
02811 {
02812   long success=FALSE;
02813   ptr_psi_term arg1,arg2,g;
02814   FILE *thestream;
02815   
02816   g=aim->a;
02817   deref_ptr(g);
02818   get_two_args(g->attr_list,&arg1,&arg2);
02819   if (arg1) {
02820     deref(arg1);
02821     deref_args(g,set_1);
02822     if (equal_types(arg1->type,inputfilesym)) {
02823       success=TRUE;
02824       save_state(input_state);
02825       thestream=get_stream(arg1);
02826       if (thestream!=NULL) {
02827         input_state=arg1;
02828         restore_state(input_state);
02829       }
02830     }
02831     else
02832       Errorline("bad stream in %P.\n",g);
02833   }
02834   else
02835     Errorline("no stream in %P.\n",g);
02836   
02837   return success;
02838 }
02839 
02840 
02841 
02842 /******** C_SET_OUTPUT
02843   Set the current output stream.
02844 */
02845 static long c_set_output()
02846 {
02847   long success=FALSE;
02848   ptr_psi_term arg1,arg2,g;
02849   
02850   g=aim->a;
02851   deref_ptr(g);
02852   get_two_args(g->attr_list,&arg1,&arg2);
02853   if(arg1) {
02854     deref(arg1);
02855     deref_args(g,set_1);
02856     if(equal_types(arg1->type,stream) && arg1->value) {
02857       success=TRUE;
02858       output_stream=(FILE *)arg1->value;
02859     }
02860     else
02861       Errorline("bad stream in %P.\n",g);
02862   }
02863   else
02864     Errorline("no stream in %P.\n",g);
02865   
02866   return success;
02867 }
02868 
02869 /******** C_CLOSE
02870   Close a stream.
02871 */
02872 static long c_close()
02873 {
02874   long success=FALSE;
02875   long inclose,outclose;
02876   ptr_psi_term arg1,arg2,g,s;
02877   
02878   g=aim->a;
02879   deref_ptr(g);
02880   get_two_args(g->attr_list,&arg1,&arg2);
02881   if (arg1) {
02882     deref(arg1);
02883     deref_args(g,set_1);
02884 /*
02885     if (sub_type(arg1->type,sys_stream))
02886       return sys_close(arg1);
02887 */
02888     outclose=equal_types(arg1->type,stream) && arg1->value;
02889     inclose=FALSE;
02890     if (equal_types(arg1->type,inputfilesym)) {
02891       ptr_node n=find(featcmp,STREAM,arg1->attr_list);
02892       if (n) {
02893         arg1=(ptr_psi_term)n->data;
02894         inclose=(arg1->value!=NULL);
02895       }
02896     }
02897 
02898     if (inclose || outclose) {
02899       success=TRUE;
02900       fclose((FILE *)arg1->value);
02901       
02902       if (inclose && arg1->value==(GENERIC)input_stream)
02903         open_input_file("stdin");
02904       else if (outclose && arg1->value==(GENERIC)output_stream)
02905         open_output_file("stdout");
02906       
02907       arg1->value=NULL;
02908     }
02909     else
02910       Errorline("bad stream in %P.\n",g);
02911   }
02912   else
02913     Errorline("no stream in %P.\n",g);
02914   
02915   return success;
02916 }
02917 
02918 
02919  
02920 
02921 /******** C_GET
02922   Read the next character from the current input stream and return
02923   its Ascii code.  This includes blank characters, so this predicate
02924   differs slightly from Edinburgh Prolog's get(X).
02925   At end of file, return the psi-term 'end_of_file'.
02926 */
02927 static long c_get()
02928 {
02929   long success=TRUE;
02930   ptr_psi_term arg1,arg2,g,t;
02931   long c;
02932   
02933   g=aim->a;
02934   deref_ptr(g);
02935   get_two_args(g->attr_list,&arg1,&arg2);
02936   if (arg1) {
02937     deref(arg1);
02938     deref_args(g,set_1);
02939 
02940     if (eof_flag) {
02941       success=FALSE;
02942     }
02943     else {
02944       prompt="";
02945       c=read_char();
02946       t=stack_psi_term(0);
02947       if (c==EOF) {
02948         t->type=eof;
02949         eof_flag=TRUE;
02950       }
02951       else {
02952         t->type=integer;
02953         t->value=heap_alloc(sizeof(REAL)); /* 12.5 */
02954         * (REAL *)t->value = (REAL) c;
02955       }
02956     }
02957     
02958     if (success) {
02959       push_goal(unify,t,arg1,NULL);
02960       i_check_out(t);
02961     }
02962   }
02963   else {
02964     Errorline("argument missing in %P.\n",g);
02965     success=FALSE;
02966   }
02967  
02968   return success;
02969 }
02970 
02971 
02972 
02973 /******** C_PUT, C_PUT_ERR
02974   Write the root of a psi-term to the current output stream or to stderr.
02975   This routine accepts the string type (which is written without quotes),
02976   a number type (whose integer part is considered an Ascii code if it is
02977   in the range 0..255), and any other psi-term (in which case its name is
02978   written).
02979 */
02980 static long c_put_main(); /* Forward declaration */
02981 
02982 static long c_put()
02983 {
02984   return c_put_main(FALSE);
02985 }
02986 
02987 static long c_put_err()
02988 {
02989   return c_put_main(TRUE);
02990 }
02991 
02992 static long c_put_main(to_stderr)
02993 long to_stderr;
02994 {
02995   long i,success=FALSE;
02996   ptr_psi_term arg1,arg2,g;
02997   char tstr[2], *str=tstr;
02998   
02999   g=aim->a;
03000   deref_ptr(g);
03001   get_two_args(g->attr_list,&arg1,&arg2);
03002   if (arg1) {
03003     deref(arg1);
03004     deref_args(g,set_1);
03005     if ((equal_types(arg1->type,integer) || equal_types(arg1->type,real))
03006         && arg1->value) {
03007       i = (unsigned long) floor(*(REAL *) arg1->value);
03008       if (i==(unsigned long)(unsigned char)i) {
03009         str[0] = i; str[1] = 0;
03010         success=TRUE;
03011       }
03012       else {
03013         Errorline("out-of-range character value in %P.\n",g);
03014       }
03015     }
03016     else if (psi_to_string(arg1,&str)) {
03017       success=TRUE;
03018     }
03019     if (success)
03020       fprintf((to_stderr?stderr:output_stream),"%s",str);
03021   }
03022   else
03023     Errorline("argument missing in %P.\n",g);
03024   
03025   return success;
03026 }
03027 
03028 
03029 
03030 /******** GENERIC_WRITE
03031   Implements write, writeq, pretty_write, pretty_writeq.
03032 */
03033 static long generic_write()
03034 {
03035   ptr_psi_term g;
03036 
03037   g=aim->a;
03038   /* deref_rec(g); */
03039   deref_args(g,set_empty);
03040   pred_write(g->attr_list);
03041   /* fflush(output_stream); */
03042   return TRUE;
03043 }
03044 
03045 /******** C_WRITE_ERR
03046   Write a list of arguments to stderr.  Print cyclical terms
03047   correctly, but don't use the pretty printer indentation.
03048 */
03049 static long c_write_err()
03050 {
03051   indent=FALSE;
03052   const_quote=FALSE;
03053   write_stderr=TRUE;
03054   write_corefs=FALSE;
03055   write_resids=FALSE;
03056   write_canon=FALSE;
03057   return generic_write();
03058 }
03059 
03060 /******** C_WRITEQ_ERR
03061   Write a list of arguments to stderr in a form that allows them to be
03062   read in again.  Print cyclical terms correctly, but don't use the pretty
03063   printer indentation.
03064 */
03065 static long c_writeq_err()
03066 {
03067   indent=FALSE;
03068   const_quote=TRUE;
03069   write_stderr=TRUE;
03070   write_corefs=FALSE;
03071   write_resids=FALSE;
03072   write_canon=FALSE;
03073   return generic_write();
03074 }
03075 
03076 /******** C_WRITE
03077   Write a list of arguments. Print cyclical terms
03078   correctly, but don't use the pretty printer indentation.
03079 */
03080 static long c_write()
03081 {
03082   indent=FALSE;
03083   const_quote=FALSE;
03084   write_stderr=FALSE;
03085   write_corefs=FALSE;
03086   write_resids=FALSE;
03087   write_canon=FALSE;
03088   return generic_write();
03089 }
03090 
03091 /******** C_WRITEQ
03092   Write a list of arguments in a form that allows them to be read in
03093   again.  Print cyclical terms correctly, but don't use the pretty
03094   printer indentation.
03095 */
03096 static long c_writeq()
03097 {
03098   indent=FALSE;
03099   const_quote=TRUE;
03100   write_stderr=FALSE;
03101   write_corefs=FALSE;
03102   write_resids=FALSE;
03103   write_canon=FALSE;
03104   return generic_write();
03105 }
03106 
03107 /******** C_WRITE_CANONICAL
03108   Write a list of arguments in a form that allows them to be read in
03109   again.  Print cyclical terms correctly, but don't use the pretty
03110   printer indentation.
03111 */
03112 static long c_write_canonical()
03113 {
03114   indent=FALSE;
03115   const_quote=TRUE;
03116   write_stderr=FALSE;
03117   write_corefs=FALSE;
03118   write_resids=FALSE;
03119   write_canon=TRUE;
03120   return generic_write();
03121 }
03122 
03123 /******** C_PRETTY_WRITE
03124   The same as write, only indenting if output is wider than PAGEWIDTH.
03125 */
03126 static long c_pwrite()
03127 {
03128   indent=TRUE;
03129   const_quote=FALSE;
03130   write_stderr=FALSE;
03131   write_corefs=FALSE;
03132   write_resids=FALSE;
03133   write_canon=FALSE;
03134   return generic_write();
03135 }
03136 
03137 
03138 /******** C_PRETTY_WRITEQ
03139   The same as writeq, only indenting if output is wider than PAGEWIDTH.
03140 */
03141 static long c_pwriteq()
03142 {
03143   indent=TRUE;
03144   const_quote=TRUE;
03145   write_stderr=FALSE;
03146   write_corefs=FALSE;
03147   write_resids=FALSE;
03148   write_canon=FALSE;
03149   return generic_write();
03150 }
03151 
03152 
03153 
03154 /******** C_PAGE_WIDTH
03155   Set the page width.
03156 */
03157 static long c_page_width()
03158 {
03159   long success=FALSE;
03160   ptr_psi_term arg1,arg2,g;
03161   long pw;
03162   
03163   g=aim->a;
03164   deref_ptr(g);
03165   get_two_args(g->attr_list,&arg1,&arg2);
03166   if(arg1) {
03167     deref(arg1);
03168     deref_args(g,set_1);
03169     if (equal_types(arg1->type,integer) && arg1->value) {
03170       pw = *(REAL *)arg1->value;
03171       if (pw>0)
03172         page_width=pw;
03173       else
03174         Errorline("argument in %P must be positive.\n",g);
03175       success=TRUE;
03176     }
03177     else if (sub_type(integer,arg1->type)) {
03178       push_goal(unify,arg1,real_stack_psi_term(4,(REAL)page_width),NULL);
03179       success=TRUE;
03180     }
03181     else
03182       Errorline("bad argument in %P.\n",g);
03183   }
03184   else
03185     Errorline("argument missing in %P.\n",g);
03186   
03187   return success;
03188 }
03189 
03190 
03191 
03192 /******** C_PRINT_DEPTH
03193   Set the depth limit of printing.
03194 */
03195 static long c_print_depth()
03196 {
03197   long success=FALSE;
03198   ptr_psi_term arg1,arg2,g;
03199   long dl;
03200   
03201   g=aim->a;
03202   deref_ptr(g);
03203   get_two_args(g->attr_list,&arg1,&arg2);
03204   if (arg1) {
03205     deref(arg1);
03206     deref_args(g,set_1);
03207     if (equal_types(arg1->type,integer) && arg1->value) {
03208       dl = *(REAL *)arg1->value;
03209       if (dl>=0)
03210         print_depth=dl;
03211       else
03212         Errorline("argument in %P must be positive or zero.\n",g);
03213       success=TRUE;
03214     }
03215     else if (sub_type(integer,arg1->type)) {
03216       push_goal(unify,arg1,real_stack_psi_term(4,(REAL)print_depth),NULL);
03217       success=TRUE;
03218     }
03219     else
03220       Errorline("bad argument in %P.\n",g);
03221   }
03222   else {
03223     /* No arguments: reset print depth to default value */
03224     print_depth=PRINT_DEPTH;
03225     success=TRUE;
03226   }
03227   
03228   return success;
03229 }
03230 
03231 
03232 
03233 /******** C_ROOTSORT
03234   Return the principal sort of the argument == create a copy with the
03235   attributes detached.
03236 */
03237 static long c_rootsort()
03238 {
03239   long success=TRUE;
03240   ptr_psi_term arg1,arg2,arg3,g,other;
03241   
03242   g=aim->a;
03243   deref_ptr(g);
03244   arg3=aim->b;
03245   deref(arg3);
03246   get_two_args(g->attr_list,&arg1,&arg2);
03247   if(arg1) {
03248     deref(arg1);
03249     deref_args(g,set_1);
03250     other=stack_psi_term(4); /* 19.11 */
03251     other->type=arg1->type;    
03252     other->value=arg1->value;
03253     resid_aim=NULL;
03254     push_goal(unify,arg3,other,NULL);
03255   }
03256   else
03257     curry();
03258   
03259   return success;
03260 }
03261 
03262 
03263 
03264 
03265 /******** C_DISJ
03266   This implements disjunctions (A;B).
03267   A nonexistent A or B is taken to mean 'fail'.
03268   Disjunctions should not be implemented in Life, because doing so results in
03269   both A and B being evaluated before the disjunction is.
03270   Disjunctions could be implemented in Life if there were a 'melt' predicate.
03271   */
03272 static long c_disj()
03273 {
03274   long success=TRUE;
03275   ptr_psi_term arg1,arg2,g;
03276 
03277   g=aim->a;
03278   resid_aim=NULL;
03279   deref_ptr(g);
03280   get_two_args(g->attr_list,&arg1,&arg2);
03281   deref_args(g,set_1_2);
03282   Traceline("pushing predicate disjunction choice point for %P\n",g);
03283   if (arg2) push_choice_point(prove,arg2,DEFRULES,NULL);
03284   if (arg1) push_goal(prove,arg1,DEFRULES,NULL);
03285   if (!arg1 && !arg2) {
03286     success=FALSE;
03287     Errorline("neither first nor second arguments exist in %P.\n",g);
03288   }
03289 
03290   return success;
03291 }
03292 
03293 
03294 
03295 /******** C_COND
03296   This implements COND(Condition,Then,Else).
03297   First Condition is evaluated.  If it returns true, return the Then value.
03298   If it returns false, return the Else value.  Either the Then or the Else
03299   values may be omitted, in which case they are considered to be true.
03300 */
03301 static long c_cond()
03302 {
03303   long success=TRUE;
03304   ptr_psi_term arg1,arg2,result,g;
03305   ptr_psi_term *arg1addr;
03306   REAL val1;
03307   long num1;
03308   ptr_node n;
03309   
03310   g=aim->a;
03311   deref_ptr(g);
03312   result=aim->b;
03313   deref(result);
03314   
03315   get_one_arg_addr(g->attr_list,&arg1addr);
03316   if (arg1addr) {
03317     arg1= *arg1addr;
03318     deref_ptr(arg1);
03319     if (arg1->type->type==predicate) {
03320       ptr_psi_term call_once;
03321       ptr_node ca;
03322 
03323       /* Transform cond(pred,...) into cond(call_once(pred),...) */
03324       goal_stack=aim;
03325       call_once=stack_psi_term(0);
03326       call_once->type=calloncesym;
03327       call_once->attr_list=(ca=STACK_ALLOC(node));
03328       ca->key=one;
03329       ca->left=ca->right=NULL;
03330       ca->data=(GENERIC)arg1;
03331       push_ptr_value(psi_term_ptr,arg1addr);
03332       *arg1addr=call_once;
03333       return success;
03334     }
03335     deref(arg1);
03336     deref_args(g,set_1_2_3);
03337     success=get_bool_value(arg1,&val1,&num1);
03338     if (success) {
03339       if (num1) {
03340         resid_aim=NULL;
03341         n=find(featcmp,(val1?two:three),g->attr_list);
03342         if (n) {
03343           arg2=(ptr_psi_term)n->data;
03344           /* mark_eval(arg2); XXX 24.8 */
03345           push_goal(unify,result,arg2,NULL);
03346           i_check_out(arg2);
03347         }
03348         else {
03349           ptr_psi_term trueterm;
03350           trueterm=stack_psi_term(4);
03351           trueterm->type=true;
03352           push_goal(unify,result,trueterm,NULL);
03353         }
03354       }
03355       else
03356         residuate(arg1);
03357     }
03358     else /*  RM: Apr 15 1993  */
03359       Errorline("argument to cond is not boolean in %P\n",g);
03360   }
03361   else
03362     curry();
03363   
03364   return success;
03365 }
03366 
03367 
03368 
03369 /******** C_EXIST_FEATURE
03370   Here we evaluate "has_feature(Label,Psi-term,Value)". This
03371   is a boolean function that returns true iff Psi-term
03372   has the feature Label.
03373 
03374   Added optional 3rd argument which is unified with the feature value if it exists.
03375   */
03376 
03377 static long c_exist_feature()  /*  PVR: Dec 17 1992  */  /* PVR 11.4.94 */
03378 {
03379   long success=TRUE,v;
03380   ptr_psi_term arg1,arg2,arg3,funct,result,ans;
03381   ptr_node n;
03382   char *label;
03383   /* char *thebuffer="integer"; 18.5 */
03384   char thebuffer[20]; /* Maximum number of digits in an integer */
03385 
03386   funct=aim->a;
03387   deref_ptr(funct);
03388   result=aim->b;
03389   get_two_args(funct->attr_list,&arg1,&arg2);
03390 
03391   
03392   n=find(featcmp,three,funct->attr_list,&arg3); /*  RM: Feb 10 1993  */
03393   if(n)
03394     arg3=(ptr_psi_term)n->data;
03395   else
03396     arg3=NULL;
03397   
03398   if (arg1 && arg2) {
03399     deref(arg1);
03400     deref(arg2);
03401     
03402     if(arg3) /*  RM: Feb 10 1993  */
03403       deref(arg3);
03404     
03405     deref_args(funct,set_1_2);
03406     label=NULL;
03407     
03408     if (arg1->value && sub_type(arg1->type,quoted_string))
03409       label=(char *)arg1->value;
03410     else if (arg1->value && sub_type(arg1->type,integer)) {
03411       v= *(REAL *)arg1->value;
03412       sprintf(thebuffer,"%ld",(long)v);
03413       label=heap_copy_string(thebuffer); /* A little voracious */
03414     } else if (arg1->type->keyword->private_feature) {
03415       label=arg1->type->keyword->combined_name;
03416     } else
03417       label=arg1->type->keyword->symbol;
03418 
03419     n=find(featcmp,label,arg2->attr_list);
03420     ans=stack_psi_term(4);
03421     ans->type=(n!=NULL)?true:false;
03422       
03423     if(arg3 && n) /*  RM: Feb 10 1993  */
03424       push_goal(unify,arg3,n->data,NULL);
03425       
03426     push_goal(unify,result,ans,NULL);
03427   }
03428   else
03429     curry();
03430 
03431   return success;
03432 }
03433 
03434 
03435 
03436 
03437 /******** C_FEATURES
03438   Convert the feature names of a psi_term into a list of psi-terms.
03439   This uses the MAKE_FEATURE_LIST routine.
03440 */
03441 static long c_features()
03442 {
03443   long success=TRUE;
03444   ptr_psi_term arg1,arg2,funct,result;
03445   ptr_psi_term the_list; /*  RM: Dec  9 1992
03446                              Modified the routine to use 'cons'
03447                              instead of the old list representation.
03448                              */
03449   /*  RM: Mar 11 1993  Added MODULE argument */
03450   ptr_module module=NULL;
03451   ptr_module save_current;
03452 
03453 
03454 
03455   
03456   funct=aim->a;
03457   deref_ptr(funct);
03458   result=aim->b;
03459   get_two_args(funct->attr_list,&arg1,&arg2);
03460 
03461   
03462   if(arg2) {
03463     deref(arg2);
03464     success=get_module(arg2,&module);
03465   }
03466   else
03467     module=current_module;
03468 
03469   
03470   if(arg1 && success) {
03471     deref(arg1);
03472     deref_args(funct,set_1);
03473     resid_aim=NULL;
03474 
03475     save_current=current_module;
03476     if(module)
03477       current_module=module;
03478     
03479     push_goal(unify,
03480               result,
03481               make_feature_list(arg1->attr_list,stack_nil(),module,0),
03482               NULL);
03483     
03484     current_module=save_current;
03485   }
03486   else
03487     curry();
03488   
03489   return success;
03490 }
03491 
03492 
03493 
03494 /******** C_FEATURES
03495   Return the list of values of the features of a term.
03496   */
03497 static long c_feature_values()
03498 {
03499   long success=TRUE;
03500   ptr_psi_term arg1,arg2,funct,result;
03501   ptr_psi_term the_list; /*  RM: Dec  9 1992
03502                              Modified the routine to use 'cons'
03503                              instead of the old list representation.
03504                              */
03505   /*  RM: Mar 11 1993  Added MODULE argument */
03506   ptr_module module=NULL;
03507   ptr_module save_current;
03508 
03509   
03510   funct=aim->a;
03511   deref_ptr(funct);
03512   result=aim->b;
03513   get_two_args(funct->attr_list,&arg1,&arg2);
03514 
03515   
03516   if(arg2) {
03517     deref(arg2);
03518     success=get_module(arg2,&module);
03519   }
03520   else
03521     module=current_module;
03522 
03523   
03524   if(arg1 && success) {
03525     deref(arg1);
03526     deref_args(funct,set_1);
03527     resid_aim=NULL;
03528 
03529     save_current=current_module;
03530     if(module)
03531       current_module=module;
03532     
03533     push_goal(unify,
03534               result,
03535               make_feature_list(arg1->attr_list,stack_nil(),module,1),
03536               NULL);
03537     
03538     current_module=save_current;
03539   }
03540   else
03541     curry();
03542   
03543   return success;
03544 }
03545 
03546 
03547 
03548 /* Return TRUE iff T is a type that should not show up as part of the
03549    type hierarchy, i.e. it is an internal hidden type. */
03550 long hidden_type(t)
03551 ptr_definition t;
03552 {
03553    return (/* (t==conjunction) || 19.8 */
03554            /* (t==disjunction) || RM: Dec  9 1992 */
03555            (t==constant) || (t==variable) ||
03556            (t==comment) || (t==functor));
03557 }
03558 
03559 
03560 
03561 /* Collect properties of the symbols in the symbol table, and make a
03562    psi-term list of them.
03563    This routine is parameterized (by sel) to collect three properties:
03564    1. All symbols that are types with no parents.
03565    2. All symbols that are of 'undef' type.
03566    3. The operator triples of all operators.
03567 
03568    Note the similarity between this routine and a tree-to-list
03569    routine in Prolog.  The pointer manipulations are simpler in
03570    Prolog, though.
03571 
03572    If the number of symbols is very large, this routine may run out of space
03573    before garbage collection.
03574 */
03575 ptr_psi_term collect_symbols(sel) /*  RM: Feb  3 1993  */
03576      long sel;
03577 
03578 {
03579   ptr_psi_term new;
03580   ptr_definition def;
03581   long botflag;
03582   ptr_psi_term result;
03583 
03584 
03585   result=stack_nil();
03586   
03587   for(def=first_definition;def;def=def->next) {
03588 
03589     if (sel==least_sel || sel==greatest_sel) {
03590       botflag=(sel==least_sel);
03591 
03592       /* Insert the node if it's a good one */
03593       if (((botflag?def->children:def->parents)==NULL &&
03594            def!=top && def!=nothing &&
03595            def->type==type ||
03596            def->type==undef)
03597           && !hidden_type(def)) {
03598         /* Create the node that will be inserted */
03599         new=stack_psi_term(4);
03600         new->type=def;
03601         result=stack_cons(new,result);
03602       }
03603     }
03604     else if (sel==op_sel) {
03605       ptr_operator_data od=def->op_data;
03606 
03607       while (od) {
03608         ptr_psi_term name,type;
03609 
03610         new=stack_psi_term(4);
03611         new->type=opsym;
03612         result=stack_cons(new,result);
03613         
03614         stack_add_int_attr(new,one,od->precedence);
03615 
03616         type=stack_psi_term(4);
03617         switch (od->type) {
03618         case xf:
03619           type->type=xf_sym;
03620           break;
03621         case yf:
03622           type->type=yf_sym;
03623           break;
03624         case fx:
03625           type->type=fx_sym;
03626           break;
03627         case fy:
03628           type->type=fy_sym;
03629           break;
03630         case xfx:
03631           type->type=xfx_sym;
03632           break;
03633         case xfy:
03634           type->type=xfy_sym;
03635           break;
03636         case yfx:
03637           type->type=yfx_sym;
03638           break;
03639         }
03640         stack_add_psi_attr(new,two,type);
03641 
03642         name=stack_psi_term(4);
03643         name->type=def;
03644         stack_add_psi_attr(new,three,name);
03645 
03646         od=od->next;
03647       }
03648     }
03649   }
03650   
03651   return result;
03652 }
03653 
03654 
03655 
03656 /******** C_OPS
03657   Return a list of all operators (represented as 3-tuples op(prec,type,atom)).
03658   This function has no arguments.
03659 */
03660 static long c_ops()
03661 {
03662   long success=TRUE;
03663   ptr_psi_term result, g, t;
03664 
03665   g=aim->a;
03666   deref_args(g,set_empty);
03667   result=aim->b;
03668   t=collect_symbols(op_sel);   /*  RM: Feb  3 1993  */
03669   push_goal(unify,result,t,NULL);
03670 
03671   return success;
03672 }
03673 
03674 
03675 
03676 
03677 /* PVR 23.2.94 -- Added this to fix c_strip and c_copy_pointer */
03678 /* Make a copy of an attr_list structure, keeping the same leaf pointers */
03679 static ptr_node copy_attr_list(n)
03680 ptr_node n;
03681 {
03682   ptr_node m;
03683 
03684   if (n==NULL) return NULL;
03685 
03686   m = STACK_ALLOC(node);
03687   m->key = n->key;
03688   m->data = n->data;
03689   m->left = copy_attr_list(n->left);
03690   m->right = copy_attr_list(n->right);
03691   return m;
03692 }
03693 
03694 
03695 /******** C_STRIP
03696   Return the attributes of a psi-term, that is, a psi-term of type @ but with
03697   all the attributes of the argument.
03698 */
03699 static long c_strip()
03700 {
03701   long success=TRUE;
03702   ptr_psi_term arg1,arg2,funct,result;
03703   
03704   funct=aim->a;
03705   deref_ptr(funct);
03706   result=aim->b;
03707   get_two_args(funct->attr_list,&arg1,&arg2);
03708   if(arg1) {
03709     deref(arg1);
03710     deref_args(funct,set_1);
03711     resid_aim=NULL;
03712     /* PVR 23.2.94 */
03713     merge_unify(&(result->attr_list),copy_attr_list(arg1->attr_list));
03714   }
03715   else
03716     curry();
03717   
03718   return success;
03719 }
03720 
03721 
03722 
03723 
03724 /******** C_SAME_ADDRESS
03725   Return TRUE if two arguments share the same address.
03726 */
03727 static long c_same_address()
03728 {
03729   long success=TRUE;
03730   ptr_psi_term arg1,arg2,funct,result;
03731   REAL val3;
03732   long num3;
03733   
03734   funct=aim->a;
03735   deref_ptr(funct);
03736   result=aim->b;
03737   get_two_args(funct->attr_list,&arg1,&arg2);
03738   
03739   if (arg1 && arg2) {
03740     success=get_bool_value(result,&val3,&num3);
03741     resid_aim=NULL;
03742     deref(arg1);
03743     deref(arg2);
03744     deref_args(funct,set_1_2);
03745     
03746     if (num3) {
03747       if (val3)
03748         push_goal(unify,arg1,arg2,NULL);
03749       else
03750         success=(arg1!=arg2);
03751     }
03752     else
03753       if (arg1==arg2)
03754         unify_bool_result(result,TRUE);
03755       else
03756         unify_bool_result(result,FALSE);
03757   }
03758   else
03759     curry();
03760   
03761   return success;
03762 }
03763 
03764 
03765 
03766 /******** C_DIFF_ADDRESS
03767   Return TRUE if two arguments have different addresses.
03768 */
03769 static long c_diff_address()
03770 {
03771   long success=TRUE;
03772   ptr_psi_term arg1,arg2,funct,result;
03773   REAL val3;
03774   long num3;
03775   
03776   funct=aim->a;
03777   deref_ptr(funct);
03778   result=aim->b;
03779   get_two_args(funct->attr_list,&arg1,&arg2);
03780   
03781   if (arg1 && arg2) {
03782     success=get_bool_value(result,&val3,&num3);
03783     resid_aim=NULL;
03784     deref(arg1);
03785     deref(arg2);
03786     deref_args(funct,set_1_2);
03787     
03788     if (num3) {
03789       if (val3)
03790         push_goal(unify,arg1,arg2,NULL);
03791       else
03792         success=(arg1==arg2);
03793     }
03794     else
03795       if (arg1==arg2)
03796         unify_bool_result(result,FALSE);
03797       else
03798         unify_bool_result(result,TRUE);
03799   }
03800   else
03801     curry();
03802   
03803   return success;
03804 }
03805 
03806 
03807 
03808 
03809 /******** C_EVAL
03810   Evaluate an expression and return its value.
03811 */
03812 static long c_eval()
03813 {
03814   long success=TRUE;
03815   ptr_psi_term arg1, copy_arg1, arg2, funct, result;
03816 
03817   funct = aim->a;
03818   deref_ptr(funct);
03819   result = aim->b;
03820   deref(result);
03821   get_two_args(funct->attr_list, &arg1, &arg2);
03822   if (arg1) {
03823     deref(arg1);
03824     deref_args(funct,set_1);
03825     assert((unsigned long)(arg1->type)!=4);
03826     clear_copy();
03827     copy_arg1 = eval_copy(arg1,STACK);
03828     resid_aim = NULL;
03829     push_goal(unify,copy_arg1,result,NULL);
03830     i_check_out(copy_arg1);
03831   } else
03832     curry();
03833 
03834   return success;
03835 }
03836 
03837 
03838 
03839 
03840 /******** C_EVAL_INPLACE
03841   Evaluate an expression and return its value.
03842 */
03843 static long c_eval_inplace()
03844 {
03845   long success=TRUE;
03846   ptr_psi_term arg1, copy_arg1, arg2, funct, result;
03847 
03848   funct = aim->a;
03849   deref_ptr(funct);
03850   result = aim->b;
03851   deref(result);
03852   get_two_args(funct->attr_list, &arg1, &arg2);
03853   if (arg1) {
03854     deref(arg1);
03855     deref_args(funct,set_1);
03856     resid_aim = NULL;
03857     mark_eval(arg1);
03858     push_goal(unify,arg1,result,NULL);
03859     i_check_out(arg1);
03860   } else
03861     curry();
03862 
03863   return success;
03864 }
03865 
03866 
03867 
03868 
03869 /******** C_QUOTE
03870   Quote an expression, i.e. do not evaluate it but mark it as completely
03871   evaluated.
03872   This works if the function is declared as non_strict.
03873 */
03874 static long c_quote()
03875 {
03876   long success=TRUE;
03877   ptr_psi_term arg1,arg2,funct,result;
03878 
03879   funct = aim->a;
03880   deref_ptr(funct);
03881   result = aim->b;
03882   deref(result);
03883   get_two_args(funct->attr_list, &arg1, &arg2);
03884   if (arg1) {
03885     push_goal(unify,arg1,result,NULL);
03886   } else
03887     curry();
03888 
03889   return success;
03890 }
03891 
03892 
03893 
03894 /******** C_SPLIT_DOUBLE
03895   Split a double into two 32-bit words.
03896   */
03897 
03898 static long c_split_double()
03899 {
03900   long success=FALSE;
03901   ptr_psi_term arg1,arg2,funct,result;
03902   int n;
03903   union {
03904     double d;
03905     struct {
03906       int hi;
03907       int lo;
03908     } w2;
03909   }hack;
03910   double hi,lo;
03911   int n1,n2;
03912   
03913   funct = aim->a;
03914   deref_ptr(funct);
03915   result=aim->b;
03916   
03917   get_two_args(funct->attr_list, &arg1, &arg2);
03918   if(arg1 && arg2) {
03919     deref_ptr(arg1);
03920     deref_ptr(arg2);
03921     deref_ptr(result);
03922     if(get_real_value(result,&(hack.d),&n)  &&
03923        get_real_value(arg1  ,&hi      ,&n1) &&
03924        get_real_value(arg2  ,&lo      ,&n2)) {
03925       
03926       
03927       if(n) {
03928         unify_real_result(arg1,(REAL)hack.w2.hi);
03929         unify_real_result(arg2,(REAL)hack.w2.lo);
03930         success=TRUE;
03931       }
03932       else
03933         if(n1 && n2) {
03934           hack.w2.hi=(int)hi;
03935           hack.w2.lo=(int)lo;
03936           unify_real_result(result,hack.d);
03937           success=TRUE;
03938         }
03939         else {
03940           residuate(result);
03941           residuate2(arg1,arg2);
03942         }
03943     }
03944     else
03945       Errorline("non-numeric arguments in %P\n",funct);
03946   }
03947   else
03948     curry();
03949   
03950   return success;
03951 }
03952 
03953 
03954 
03955 /******** C_STRING_ADDRESS
03956   Return the address of a string.
03957   */
03958 
03959 static long c_string_address()
03960 {
03961   long success=FALSE;
03962   ptr_psi_term arg1,arg2,funct,result,t;
03963   double val;
03964   int num;
03965   int smaller;
03966   
03967   
03968   funct = aim->a;
03969   deref_ptr(funct);
03970   result=aim->b;
03971   
03972   get_two_args(funct->attr_list, &arg1, &arg2);
03973   if(arg1) {
03974     deref_ptr(arg1);
03975     deref_ptr(result);
03976       success=matches(arg1->type,quoted_string,&smaller);
03977       if (success) {
03978         if (arg1->value) {
03979           unify_real_result(result,(REAL)(long)(arg1->value));
03980         }
03981         else {
03982           if(success=get_real_value(result,&val,&num)) {
03983             if(num) {
03984               t=stack_psi_term(4);
03985               t->type=quoted_string;
03986               t->value=(GENERIC)(long)val;
03987               push_goal(unify,t,arg1,NULL);
03988             }
03989             else
03990               residuate2(arg1,result);
03991           
03992           }
03993           else
03994             Errorline("result is not a real in %P\n",funct);
03995         }
03996       }
03997       else
03998         Errorline("argument is not a string in %P\n",funct);
03999   }
04000   else
04001     curry();
04002   
04003   return success;
04004 }
04005 
04006 
04007 
04008 /******** C_CHDIR
04009   Change the current working directory
04010   */
04011 
04012 static long c_chdir()
04013 {
04014   long success=FALSE;
04015   ptr_psi_term arg1,arg2,funct,result,t;
04016   double val;
04017   int num;
04018   int smaller;
04019   
04020   
04021   funct = aim->a;
04022   deref_ptr(funct);
04023   
04024   get_two_args(funct->attr_list, &arg1, &arg2);
04025   if(arg1) {
04026     deref_ptr(arg1);
04027     if(matches(arg1->type,quoted_string,&smaller) && arg1->value)
04028       success=!chdir(expand_file_name((char *)arg1->value));
04029     else
04030       Errorline("bad argument in %P\n",funct);
04031   }
04032   else
04033     Errorline("argument missing in %P\n",funct);
04034   
04035   return success;
04036 }
04037 
04038 
04039 
04040 /******** C_CALL_ONCE
04041   Prove a predicate, return true or false if it succeeds or fails.
04042   An implicit cut is performed: only only solution is given.
04043 */
04044 #if 0   /* DENYS Jan 25 1995 */
04045 static long c_call_once()
04046 {
04047   long success=TRUE;
04048   ptr_psi_term arg1,arg2,funct,result,other;
04049   ptr_choice_point cutpt; 
04050 
04051   funct=aim->a;
04052   deref_ptr(funct);
04053   result=aim->b;
04054   get_two_args(funct->attr_list,&arg1,&arg2);
04055   if (arg1) {
04056     deref_ptr(arg1);
04057     deref_args(funct,set_1);
04058     if(arg1->type==top)
04059       residuate(arg1);
04060     else
04061       if(FALSE /*arg1->type->type!=predicate*/) {
04062         success=FALSE;
04063         Errorline("argument of %P should be a predicate.\n",funct);
04064       }
04065       else {
04066         resid_aim=NULL;
04067         cutpt=choice_stack;
04068 
04069         /* Result is FALSE */
04070         other=stack_psi_term(0);
04071         other->type=false;
04072 
04073         push_choice_point(unify,result,other,NULL);
04074 
04075         /* Result is TRUE */
04076         other=stack_psi_term(0);
04077         other->type=true;
04078 
04079         push_goal(unify,result,other,NULL);
04080         push_goal(eval_cut,other,cutpt,NULL);
04081         push_goal(prove,arg1,DEFRULES,NULL);
04082       }
04083   }
04084   else
04085     curry();
04086 
04087   return success;
04088 }
04089 #endif
04090 
04091 
04092 
04093 /******** C_CALL
04094   Prove a predicate, return true or false if it succeeds or fails.
04095   No implicit cut is performed.
04096 */
04097 static long c_call()
04098 {
04099   long success=TRUE;
04100   ptr_psi_term arg1,arg2,funct,result,other;
04101   ptr_choice_point cutpt; 
04102 
04103   funct=aim->a;
04104   deref_ptr(funct);
04105   result=aim->b;
04106   get_two_args(funct->attr_list,&arg1,&arg2);
04107   if (arg1) {
04108     deref_ptr(arg1);
04109     deref_args(funct,set_1);
04110     if(arg1->type==top)
04111       residuate(arg1);
04112     else
04113       if(FALSE /*arg1->type->type!=predicate*/) {
04114         success=FALSE;
04115         Errorline("argument of %P should be a predicate.\n",funct);
04116       }
04117       else {
04118         resid_aim=NULL;
04119         cutpt=choice_stack;
04120 
04121         /* Result is FALSE */
04122         other=stack_psi_term(0);
04123         other->type=false;
04124 
04125         push_choice_point(unify,result,other,NULL);
04126 
04127         /* Result is TRUE */
04128         other=stack_psi_term(0);
04129         other->type=true;
04130 
04131         push_goal(unify,result,other,NULL);
04132         push_goal(prove,arg1,DEFRULES,NULL);
04133       }
04134   }
04135   else
04136     curry();
04137 
04138   return success;
04139 }
04140 
04141 
04142 
04143 /******** C_BK_ASSIGN()
04144   This implements backtrackable assignment.
04145 */
04146 static long c_bk_assign()
04147 {
04148   long success=FALSE;
04149   ptr_psi_term arg1,arg2,g;
04150   
04151   g=aim->a;
04152   deref_ptr(g);
04153   get_two_args(g->attr_list,&arg1,&arg2);
04154   if (arg1 && arg2) {
04155     success=TRUE;
04156     deref(arg1);
04157     deref_rec(arg2); /* 17.9 */
04158     /* deref(arg2); 17.9 */
04159     deref_args(g,set_1_2);
04160     if (arg1 != arg2) {
04161 
04162       /*  RM: Mar 10 1993  */
04163       if((GENERIC)arg1>=heap_pointer) {
04164         Errorline("cannot use '<-' on persistent value in %P\n",g);
04165         return c_abort();
04166       }
04167 
04168 
04169 #ifdef TS
04170       if (!TRAIL_CONDITION(arg1)) {
04171         /* If no trail, then can safely overwrite the psi-term */
04172         release_resid_notrail(arg1);
04173         *arg1 = *arg2;
04174         push_psi_ptr_value(arg2,&(arg2->coref)); /* 14.12 */
04175         arg2->coref=arg1; /* 14.12 */
04176       }
04177       else {
04178         push_psi_ptr_value(arg1,&(arg1->coref));
04179         arg1->coref=arg2;
04180         release_resid(arg1);
04181       }
04182 #else
04183       push_psi_ptr_value(arg1,&(arg1->coref));
04184       arg1->coref=arg2;
04185       release_resid(arg1);
04186 #endif
04187     }
04188   }
04189   else
04190     Errorline("argument missing in %P.\n",g);
04191   
04192   return success;
04193 }
04194 
04195 
04196 
04197 
04198 /******** C_ASSIGN()
04199   This implements non-backtrackable assignment.
04200   It doesn't work because backtrackable unifications can have been made before
04201   this assignment was reached. It is complicated by the fact that the assigned
04202   term has to be copied into the heap as it becomes a permanent object.
04203 */
04204 static long c_assign()
04205 {
04206   long success=FALSE;
04207   ptr_psi_term arg1,arg2,g,perm,smallest;
04208   
04209   g=aim->a;
04210   deref_ptr(g);
04211   get_two_args(g->attr_list,&arg1,&arg2);
04212   if (arg1 && arg2) {
04213     success=TRUE;
04214     deref_ptr(arg1);
04215     deref_rec(arg2); /* 17.9 */
04216     /* deref(arg2); 17.9 */
04217     deref_args(g,set_1_2);
04218     if ((GENERIC)arg1<heap_pointer || arg1!=arg2) {
04219       clear_copy();
04220       *arg1 = *exact_copy(arg2,HEAP);
04221     }
04222   }
04223   else
04224     Errorline("argument missing in %P.\n",g);
04225   
04226   return success;
04227 }
04228 
04229 
04230 
04231 /******** C_GLOBAL_ASSIGN()
04232   This implements non-backtrackable assignment on global variables.
04233 
04234   Closely modelled on 'c_assign', except that pointers to the heap are not
04235   copied again onto the heap.
04236   */
04237 
04238 static long c_global_assign()
04239 {
04240   long success=FALSE;
04241   ptr_psi_term arg1,arg2,g,perm,smallest;
04242   ptr_psi_term new;
04243   
04244   g=aim->a;
04245   deref_ptr(g);
04246   get_two_args(g->attr_list,&arg1,&arg2);
04247   if (arg1 && arg2) {
04248     success=TRUE;
04249     deref_rec(arg1);
04250     deref_rec(arg2);
04251     deref_args(g,set_1_2);
04252     if (arg1!=arg2) {
04253 
04254       clear_copy();
04255       new=inc_heap_copy(arg2);
04256       
04257       if((GENERIC)arg1<heap_pointer) {
04258         push_psi_ptr_value(arg1,&(arg1->coref));
04259         arg1->coref= new;
04260       }
04261       else {
04262         *arg1= *new; /* Overwrite in-place */
04263         new->coref=arg1;
04264       }
04265     }
04266   }
04267   else
04268     Errorline("argument missing in %P.\n",g);
04269   
04270   return success;
04271 }
04272 
04273 
04274 
04275 /******** C_UNIFY_FUNC
04276   An explicit unify function that curries on its two arguments.
04277 */
04278 static long c_unify_func()
04279 {
04280   long success=TRUE;
04281   ptr_psi_term funct,arg1,arg2,result;
04282 
04283   funct=aim->a;
04284   deref_ptr(funct);
04285   get_two_args(funct->attr_list,&arg1,&arg2);
04286   if (arg1 && arg2) {
04287     deref(arg1);
04288     deref(arg2);
04289     deref_args(funct,set_1_2);
04290     result=aim->b;
04291     push_goal(unify,arg1,result,NULL);
04292     push_goal(unify,arg1,arg2,NULL);
04293   }
04294   else
04295     curry();
04296 
04297   return success;
04298 }
04299 
04300 
04301 
04302 
04303 /******** C_UNIFY_PRED()
04304   This unifies its two arguments (i.e. implements the predicate A=B).
04305 */
04306 static long c_unify_pred()
04307 {
04308   long success=FALSE;
04309   ptr_psi_term arg1,arg2,g;
04310   
04311   g=aim->a;
04312   deref_ptr(g);
04313   get_two_args(g->attr_list,&arg1,&arg2);
04314   if (arg1 && arg2) {
04315     deref_args(g,set_1_2);
04316     success=TRUE;
04317     push_goal(unify,arg1,arg2,NULL);
04318   }
04319   else
04320     Errorline("argument missing in %P.\n",g);
04321   
04322   return success;
04323 }
04324 
04325 
04326 
04327 
04328 /******** C_COPY_POINTER
04329   Make a fresh copy of the input's sort, keeping exactly the same
04330   arguments as before (i.e., copying the sort and feature table but not
04331   the feature values).
04332 */
04333 static long c_copy_pointer()   /*  PVR: Dec 17 1992  */
04334 {
04335   long success=TRUE;
04336   ptr_psi_term funct,arg1,result,other;
04337 
04338   funct=aim->a;
04339   deref_ptr(funct);
04340   get_one_arg(funct->attr_list,&arg1);
04341   if (arg1) {
04342     deref(arg1);
04343     deref_args(funct,set_1);
04344     other=stack_psi_term(4);
04345     other->type=arg1->type;
04346     other->value=arg1->value;
04347     other->attr_list=copy_attr_list(arg1->attr_list); /* PVR 23.2.94 */
04348     result=aim->b;
04349     push_goal(unify,other,result,NULL);
04350   }
04351   else
04352     curry();
04353 
04354   return success;
04355 }
04356 
04357 
04358 
04359 /******** C_COPY_TERM
04360   Make a fresh copy of the input argument, keeping its structure
04361   but with no connections to the input.
04362 */
04363 static long c_copy_term()
04364 {
04365   long success=TRUE;
04366   ptr_psi_term funct,arg1,copy_arg1,result;
04367 
04368   funct=aim->a;
04369   deref_ptr(funct);
04370   get_one_arg(funct->attr_list,&arg1);
04371   if (arg1) {
04372     deref(arg1);
04373     deref_args(funct,set_1);
04374     result=aim->b;
04375     clear_copy();
04376     copy_arg1=exact_copy(arg1,STACK);
04377     push_goal(unify,copy_arg1,result,NULL);
04378   }
04379   else
04380     curry();
04381 
04382   return success;
04383 }
04384 
04385 
04386 
04387 
04388 /******** C_UNDO
04389   This will prove a goal on backtracking.
04390   This is a completely uninteresting implmentation which is equivalent to:
04391 
04392   undo.
04393   undo(G) :- G.
04394 
04395   The problem is that it can be affected by CUT.
04396   A correct implementation would be very simple:
04397   stack the pair (ADDRESS=NULL, VALUE=GOAL) onto the trail and when undoing
04398   push the goal onto the goal-stack.
04399 */
04400 static long c_undo()
04401 {
04402   long success=TRUE;
04403   ptr_psi_term arg1,arg2,g;
04404   
04405   g=aim->a;
04406   deref_ptr(g);
04407   get_two_args(g->attr_list,&arg1,&arg2);
04408   if (arg1) {
04409     deref_args(g,set_1);
04410     push_choice_point(prove,arg1,DEFRULES,NULL);
04411   }
04412   else {
04413     success=FALSE;
04414     Errorline("argument missing in %P.\n",g);
04415   }
04416   
04417   return success;
04418 }
04419 
04420 
04421 
04422 
04423 /******** C_FREEZE_INNER
04424   This implements the freeze and implies predicates.
04425   For example:
04426 
04427     freeze(g)
04428 
04429   The proof will use matching on the heads of g's definition rather than
04430   unification to prove Goal.  An implicit cut is put at the beginning
04431   of each clause body.  Body goals are executed in the same way as
04432   without freeze.  Essentially, the predicate is called as if it were
04433   a function.
04434 
04435     implies(g)
04436 
04437   The proof will use matching as for freeze, but there is no cut at the
04438   beginning of the clause body & no residuation is done (the clause
04439   fails if its head is not implied by the caller).  Essentially, the
04440   predicate is called as before except that matching is used instead
04441   of unification to decide whether to enter a clause.
04442 */
04443 static long c_freeze_inner(freeze_flag)
04444 long freeze_flag;
04445 {
04446   long success=TRUE;
04447   ptr_psi_term arg1,g;
04448   ptr_psi_term head, body;
04449   ptr_pair_list rule;
04450   /* RESID */ ptr_resid_block rb;
04451   ptr_choice_point cutpt;
04452   ptr_psi_term match_date;
04453   
04454   g=aim->a;
04455   deref_ptr(g);
04456   get_one_arg(g->attr_list,&arg1);
04457   
04458   if (arg1) {
04459     deref_ptr(arg1);
04460     /* if (!arg1->type->evaluate_args) mark_quote(arg1); 8.9 */ /* 18.2 PVR */
04461     deref_args(g,set_1);
04462     deref_ptr(arg1);
04463     
04464     if (arg1->type->type!=predicate) {
04465       success=FALSE;
04466       Errorline("the argument %P of freeze must be a predicate.\n",arg1);
04467       /* main_loop_ok=FALSE; 8.9 */
04468       return success;
04469     }
04470     resid_aim=aim;
04471     match_date=(ptr_psi_term)stack_pointer;
04472     cutpt=choice_stack; /* 13.6 */
04473     /* Third argument of freeze's aim is used to keep track of which */
04474     /* clause is being tried in the frozen goal. */
04475     rule=(ptr_pair_list)aim->c; /* 8.9 */ /* Isn't aim->c always NULL? */
04476     resid_vars=NULL;
04477     curried=FALSE;
04478     can_curry=TRUE; /* 8.9 */
04479 
04480     if (!rule) rule=arg1->type->rule; /* 8.9 */
04481     /* if ((unsigned long)rule==DEFRULES) rule=arg1->type->rule; 8.9 */
04482 
04483     if (rule) {
04484       Traceline("evaluate frozen predicate %P\n",g);
04485       /* resid_limit=(ptr_goal )stack_pointer; 12.6 */
04486       
04487       if ((unsigned long)rule<=MAX_BUILT_INS) {
04488         success=FALSE; /* 8.9 */
04489         Errorline("the argument %P of freeze must be user-defined.\n",arg1); /* 8.9 */
04490         return success; /* 8.9 */
04491         /* Removed obsolete stuff here 11.9 */
04492       }
04493       else {
04494         while (rule && (rule->a==NULL || rule->b==NULL)) {
04495           rule=rule->next;
04496           Traceline("alternative clause has been retracted\n");
04497         }
04498         if (rule) {
04499           /* RESID */ rb = STACK_ALLOC(resid_block);
04500           /* RESID */ save_resid(rb,match_date);
04501           /* RESID */ /* resid_aim = NULL; */
04502 
04503           clear_copy();
04504           if (